root/tools/perf/util/cloexec.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. sched_getcpu
  2. perf_flag_probe
  3. perf_event_open_cloexec_flag

   1 // SPDX-License-Identifier: GPL-2.0
   2 #include <errno.h>
   3 #include <sched.h>
   4 #include "util.h" // for sched_getcpu()
   5 #include "../perf-sys.h"
   6 #include "cloexec.h"
   7 #include "event.h"
   8 #include "asm/bug.h"
   9 #include "debug.h"
  10 #include <unistd.h>
  11 #include <sys/syscall.h>
  12 #include <linux/string.h>
  13 
  14 static unsigned long flag = PERF_FLAG_FD_CLOEXEC;
  15 
  16 int __weak sched_getcpu(void)
  17 {
  18 #ifdef __NR_getcpu
  19         unsigned cpu;
  20         int err = syscall(__NR_getcpu, &cpu, NULL, NULL);
  21         if (!err)
  22                 return cpu;
  23 #else
  24         errno = ENOSYS;
  25 #endif
  26         return -1;
  27 }
  28 
  29 static int perf_flag_probe(void)
  30 {
  31         /* use 'safest' configuration as used in perf_evsel__fallback() */
  32         struct perf_event_attr attr = {
  33                 .type = PERF_TYPE_SOFTWARE,
  34                 .config = PERF_COUNT_SW_CPU_CLOCK,
  35                 .exclude_kernel = 1,
  36         };
  37         int fd;
  38         int err;
  39         int cpu;
  40         pid_t pid = -1;
  41         char sbuf[STRERR_BUFSIZE];
  42 
  43         cpu = sched_getcpu();
  44         if (cpu < 0)
  45                 cpu = 0;
  46 
  47         /*
  48          * Using -1 for the pid is a workaround to avoid gratuitous jump label
  49          * changes.
  50          */
  51         while (1) {
  52                 /* check cloexec flag */
  53                 fd = sys_perf_event_open(&attr, pid, cpu, -1,
  54                                          PERF_FLAG_FD_CLOEXEC);
  55                 if (fd < 0 && pid == -1 && errno == EACCES) {
  56                         pid = 0;
  57                         continue;
  58                 }
  59                 break;
  60         }
  61         err = errno;
  62 
  63         if (fd >= 0) {
  64                 close(fd);
  65                 return 1;
  66         }
  67 
  68         WARN_ONCE(err != EINVAL && err != EBUSY,
  69                   "perf_event_open(..., PERF_FLAG_FD_CLOEXEC) failed with unexpected error %d (%s)\n",
  70                   err, str_error_r(err, sbuf, sizeof(sbuf)));
  71 
  72         /* not supported, confirm error related to PERF_FLAG_FD_CLOEXEC */
  73         while (1) {
  74                 fd = sys_perf_event_open(&attr, pid, cpu, -1, 0);
  75                 if (fd < 0 && pid == -1 && errno == EACCES) {
  76                         pid = 0;
  77                         continue;
  78                 }
  79                 break;
  80         }
  81         err = errno;
  82 
  83         if (fd >= 0)
  84                 close(fd);
  85 
  86         if (WARN_ONCE(fd < 0 && err != EBUSY,
  87                       "perf_event_open(..., 0) failed unexpectedly with error %d (%s)\n",
  88                       err, str_error_r(err, sbuf, sizeof(sbuf))))
  89                 return -1;
  90 
  91         return 0;
  92 }
  93 
  94 unsigned long perf_event_open_cloexec_flag(void)
  95 {
  96         static bool probed;
  97 
  98         if (!probed) {
  99                 if (perf_flag_probe() <= 0)
 100                         flag = 0;
 101                 probed = true;
 102         }
 103 
 104         return flag;
 105 }

/* [<][>][^][v][top][bottom][index][help] */