000047cb3fee8849bd926ce7ec9e95861beaf5d6
[firefly-linux-kernel-4.4.55.git] / tools / perf / util / cloexec.c
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_TYPE_SOFTWARE,
13                 .config = PERF_COUNT_SW_CPU_CLOCK,
14                 .exclude_kernel = 1,
15         };
16         int fd;
17         int err;
18
19         /* check cloexec flag */
20         fd = sys_perf_event_open(&attr, 0, -1, -1,
21                                  PERF_FLAG_FD_CLOEXEC);
22         err = errno;
23
24         if (fd >= 0) {
25                 close(fd);
26                 return 1;
27         }
28
29         WARN_ONCE(err != EINVAL && err != EBUSY,
30                   "perf_event_open(..., PERF_FLAG_FD_CLOEXEC) failed with unexpected error %d (%s)\n",
31                   err, strerror(err));
32
33         /* not supported, confirm error related to PERF_FLAG_FD_CLOEXEC */
34         fd = sys_perf_event_open(&attr, 0, -1, -1, 0);
35         err = errno;
36
37         if (WARN_ONCE(fd < 0 && err != EBUSY,
38                       "perf_event_open(..., 0) failed unexpectedly with error %d (%s)\n",
39                       err, strerror(err)))
40                 return -1;
41
42         close(fd);
43
44         return 0;
45 }
46
47 unsigned long perf_event_open_cloexec_flag(void)
48 {
49         static bool probed;
50
51         if (!probed) {
52                 if (perf_flag_probe() <= 0)
53                         flag = 0;
54                 probed = true;
55         }
56
57         return flag;
58 }