]>
Commit | Line | Data |
---|---|---|
b2441318 | 1 | // SPDX-License-Identifier: GPL-2.0 |
a43783ae | 2 | #include <errno.h> |
f6edb53c | 3 | #include <sched.h> |
fb71c86c | 4 | #include "util.h" // for sched_getcpu() |
91854f9a | 5 | #include "../perf-sys.h" |
57480d2c | 6 | #include "cloexec.h" |
8520a98d | 7 | #include "event.h" |
57480d2c | 8 | #include "asm/bug.h" |
6e81c74c | 9 | #include "debug.h" |
c7007e98 | 10 | #include <unistd.h> |
c7007e98 | 11 | #include <sys/syscall.h> |
8520a98d | 12 | #include <linux/string.h> |
57480d2c YD |
13 | |
14 | static unsigned long flag = PERF_FLAG_FD_CLOEXEC; | |
15 | ||
e1e455f4 VL |
16 | int __weak sched_getcpu(void) |
17 | { | |
c7007e98 ACM |
18 | #ifdef __NR_getcpu |
19 | unsigned cpu; | |
20 | int err = syscall(__NR_getcpu, &cpu, NULL, NULL); | |
21 | if (!err) | |
22 | return cpu; | |
23 | #else | |
e1e455f4 | 24 | errno = ENOSYS; |
c7007e98 | 25 | #endif |
e1e455f4 VL |
26 | return -1; |
27 | } | |
28 | ||
57480d2c YD |
29 | static int perf_flag_probe(void) |
30 | { | |
ae430892 | 31 | /* use 'safest' configuration as used in evsel__fallback() */ |
57480d2c | 32 | struct perf_event_attr attr = { |
038fa0b9 | 33 | .type = PERF_TYPE_SOFTWARE, |
57480d2c | 34 | .config = PERF_COUNT_SW_CPU_CLOCK, |
a5b0153c | 35 | .exclude_kernel = 1, |
57480d2c YD |
36 | }; |
37 | int fd; | |
38 | int err; | |
f6edb53c AH |
39 | int cpu; |
40 | pid_t pid = -1; | |
6e81c74c | 41 | char sbuf[STRERR_BUFSIZE]; |
57480d2c | 42 | |
f6edb53c AH |
43 | cpu = sched_getcpu(); |
44 | if (cpu < 0) | |
45 | cpu = 0; | |
46 | ||
48536c91 AH |
47 | /* |
48 | * Using -1 for the pid is a workaround to avoid gratuitous jump label | |
49 | * changes. | |
50 | */ | |
f6edb53c AH |
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 | } | |
57480d2c YD |
61 | err = errno; |
62 | ||
63 | if (fd >= 0) { | |
64 | close(fd); | |
65 | return 1; | |
66 | } | |
67 | ||
c1034eb0 | 68 | WARN_ONCE(err != EINVAL && err != EBUSY && err != EACCES, |
57480d2c | 69 | "perf_event_open(..., PERF_FLAG_FD_CLOEXEC) failed with unexpected error %d (%s)\n", |
c8b5f2c9 | 70 | err, str_error_r(err, sbuf, sizeof(sbuf))); |
57480d2c YD |
71 | |
72 | /* not supported, confirm error related to PERF_FLAG_FD_CLOEXEC */ | |
48536c91 AH |
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 | } | |
57480d2c YD |
81 | err = errno; |
82 | ||
48536c91 AH |
83 | if (fd >= 0) |
84 | close(fd); | |
85 | ||
c1034eb0 | 86 | if (WARN_ONCE(fd < 0 && err != EBUSY && err != EACCES, |
57480d2c | 87 | "perf_event_open(..., 0) failed unexpectedly with error %d (%s)\n", |
c8b5f2c9 | 88 | err, str_error_r(err, sbuf, sizeof(sbuf)))) |
57480d2c YD |
89 | return -1; |
90 | ||
57480d2c YD |
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 | } |