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