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