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