diff options
Diffstat (limited to 'tools/perf/util/cloexec.c')
-rw-r--r-- | tools/perf/util/cloexec.c | 57 |
1 files changed, 57 insertions, 0 deletions
diff --git a/tools/perf/util/cloexec.c b/tools/perf/util/cloexec.c new file mode 100644 index 000000000000..c5d05ec17220 --- /dev/null +++ b/tools/perf/util/cloexec.c | |||
@@ -0,0 +1,57 @@ | |||
1 | #include "util.h" | ||
2 | #include "../perf.h" | ||
3 | #include "cloexec.h" | ||
4 | #include "asm/bug.h" | ||
5 | |||
6 | static unsigned long flag = PERF_FLAG_FD_CLOEXEC; | ||
7 | |||
8 | static int perf_flag_probe(void) | ||
9 | { | ||
10 | /* use 'safest' configuration as used in perf_evsel__fallback() */ | ||
11 | struct perf_event_attr attr = { | ||
12 | .type = PERF_COUNT_SW_CPU_CLOCK, | ||
13 | .config = PERF_COUNT_SW_CPU_CLOCK, | ||
14 | }; | ||
15 | int fd; | ||
16 | int err; | ||
17 | |||
18 | /* check cloexec flag */ | ||
19 | fd = sys_perf_event_open(&attr, 0, -1, -1, | ||
20 | PERF_FLAG_FD_CLOEXEC); | ||
21 | err = errno; | ||
22 | |||
23 | if (fd >= 0) { | ||
24 | close(fd); | ||
25 | return 1; | ||
26 | } | ||
27 | |||
28 | WARN_ONCE(err != EINVAL, | ||
29 | "perf_event_open(..., PERF_FLAG_FD_CLOEXEC) failed with unexpected error %d (%s)\n", | ||
30 | err, strerror(err)); | ||
31 | |||
32 | /* not supported, confirm error related to PERF_FLAG_FD_CLOEXEC */ | ||
33 | fd = sys_perf_event_open(&attr, 0, -1, -1, 0); | ||
34 | err = errno; | ||
35 | |||
36 | if (WARN_ONCE(fd < 0, | ||
37 | "perf_event_open(..., 0) failed unexpectedly with error %d (%s)\n", | ||
38 | err, strerror(err))) | ||
39 | return -1; | ||
40 | |||
41 | close(fd); | ||
42 | |||
43 | return 0; | ||
44 | } | ||
45 | |||
46 | unsigned long perf_event_open_cloexec_flag(void) | ||
47 | { | ||
48 | static bool probed; | ||
49 | |||
50 | if (!probed) { | ||
51 | if (perf_flag_probe() <= 0) | ||
52 | flag = 0; | ||
53 | probed = true; | ||
54 | } | ||
55 | |||
56 | return flag; | ||
57 | } | ||