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 static int perf_flag_probe(void) 11 { 12 /* use 'safest' configuration as used in perf_evsel__fallback() */ 13 struct perf_event_attr attr = { 14 .type = PERF_TYPE_SOFTWARE, 15 .config = PERF_COUNT_SW_CPU_CLOCK, 16 .exclude_kernel = 1, 17 }; 18 int fd; 19 int err; 20 int cpu; 21 pid_t pid = -1; 22 char sbuf[STRERR_BUFSIZE]; 23 24 cpu = sched_getcpu(); 25 if (cpu < 0) 26 cpu = 0; 27 28 while (1) { 29 /* check cloexec flag */ 30 fd = sys_perf_event_open(&attr, pid, cpu, -1, 31 PERF_FLAG_FD_CLOEXEC); 32 if (fd < 0 && pid == -1 && errno == EACCES) { 33 pid = 0; 34 continue; 35 } 36 break; 37 } 38 err = errno; 39 40 if (fd >= 0) { 41 close(fd); 42 return 1; 43 } 44 45 WARN_ONCE(err != EINVAL && err != EBUSY, 46 "perf_event_open(..., PERF_FLAG_FD_CLOEXEC) failed with unexpected error %d (%s)\n", 47 err, strerror_r(err, sbuf, sizeof(sbuf))); 48 49 /* not supported, confirm error related to PERF_FLAG_FD_CLOEXEC */ 50 fd = sys_perf_event_open(&attr, pid, cpu, -1, 0); 51 err = errno; 52 53 if (WARN_ONCE(fd < 0 && err != EBUSY, 54 "perf_event_open(..., 0) failed unexpectedly with error %d (%s)\n", 55 err, strerror_r(err, sbuf, sizeof(sbuf)))) 56 return -1; 57 58 close(fd); 59 60 return 0; 61 } 62 63 unsigned long perf_event_open_cloexec_flag(void) 64 { 65 static bool probed; 66 67 if (!probed) { 68 if (perf_flag_probe() <= 0) 69 flag = 0; 70 probed = true; 71 } 72 73 return flag; 74 } 75