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