cloexec.c 1.4 KB

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