cloexec.c 1.7 KB

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