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