cloexec.c 1.8 KB

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