92 lines · 1.8 KB · C
RawDownload
// SPDX-License-Identifier: GPL-2.0#include <errno.h>#include <sched.h>#include "util.h" // for sched_getcpu()#include "../perf-sys.h"#include "cloexec.h"#include "event.h"#include "asm/bug.h"#include "debug.h"#include <unistd.h>#include <sys/syscall.h>#include <linux/string.h> static unsigned long flag = PERF_FLAG_FD_CLOEXEC; static int perf_flag_probe(void){	/* use 'safest' configuration as used in evsel__fallback() */	struct perf_event_attr attr = {		.type = PERF_TYPE_SOFTWARE,		.config = PERF_COUNT_SW_CPU_CLOCK,		.exclude_kernel = 1,	};	int fd;	int err;	int cpu;	pid_t pid = -1;	char sbuf[STRERR_BUFSIZE]; 	cpu = sched_getcpu();	if (cpu < 0)		cpu = 0; 	/*	 * Using -1 for the pid is a workaround to avoid gratuitous jump label	 * changes.	 */	while (1) {		/* check cloexec flag */		fd = sys_perf_event_open(&attr, pid, cpu, -1,					 PERF_FLAG_FD_CLOEXEC);		if (fd < 0 && pid == -1 && errno == EACCES) {			pid = 0;			continue;		}		break;	}	err = errno; 	if (fd >= 0) {		close(fd);		return 1;	} 	WARN_ONCE(err != EINVAL && err != EBUSY && err != EACCES,		  "perf_event_open(..., PERF_FLAG_FD_CLOEXEC) failed with unexpected error %d (%s)\n",		  err, str_error_r(err, sbuf, sizeof(sbuf))); 	/* not supported, confirm error related to PERF_FLAG_FD_CLOEXEC */	while (1) {		fd = sys_perf_event_open(&attr, pid, cpu, -1, 0);		if (fd < 0 && pid == -1 && errno == EACCES) {			pid = 0;			continue;		}		break;	}	err = errno; 	if (fd >= 0)		close(fd); 	if (WARN_ONCE(fd < 0 && err != EBUSY && err != EACCES,		      "perf_event_open(..., 0) failed unexpectedly with error %d (%s)\n",		      err, str_error_r(err, sbuf, sizeof(sbuf))))		return -1; 	return 0;} unsigned long perf_event_open_cloexec_flag(void){	static bool probed; 	if (!probed) {		if (perf_flag_probe() <= 0)			flag = 0;		probed = true;	} 	return flag;}