cloexec.c 1.7 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586
  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. /*
  25. * Using -1 for the pid is a workaround to avoid gratuitous jump label
  26. * changes.
  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. if (fd >= 0) {
  40. close(fd);
  41. return 1;
  42. }
  43. WARN_ONCE(err != EINVAL && err != EBUSY,
  44. "perf_event_open(..., PERF_FLAG_FD_CLOEXEC) failed with unexpected error %d (%s)\n",
  45. err, strerror_r(err, sbuf, sizeof(sbuf)));
  46. /* not supported, confirm error related to PERF_FLAG_FD_CLOEXEC */
  47. while (1) {
  48. fd = sys_perf_event_open(&attr, pid, cpu, -1, 0);
  49. if (fd < 0 && pid == -1 && errno == EACCES) {
  50. pid = 0;
  51. continue;
  52. }
  53. break;
  54. }
  55. err = errno;
  56. if (fd >= 0)
  57. close(fd);
  58. if (WARN_ONCE(fd < 0 && err != EBUSY,
  59. "perf_event_open(..., 0) failed unexpectedly with error %d (%s)\n",
  60. err, strerror_r(err, sbuf, sizeof(sbuf))))
  61. return -1;
  62. return 0;
  63. }
  64. unsigned long perf_event_open_cloexec_flag(void)
  65. {
  66. static bool probed;
  67. if (!probed) {
  68. if (perf_flag_probe() <= 0)
  69. flag = 0;
  70. probed = true;
  71. }
  72. return flag;
  73. }