watermark_signal.c 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144
  1. // SPDX-License-Identifier: GPL-2.0
  2. #define _GNU_SOURCE
  3. #include <errno.h>
  4. #include <fcntl.h>
  5. #include <linux/perf_event.h>
  6. #include <stddef.h>
  7. #include <sched.h>
  8. #include <signal.h>
  9. #include <stdlib.h>
  10. #include <string.h>
  11. #include <sys/ioctl.h>
  12. #include <sys/mman.h>
  13. #include <sys/syscall.h>
  14. #include <sys/wait.h>
  15. #include <unistd.h>
  16. #include "kselftest_harness.h"
  17. static int sigio_count;
  18. static void handle_sigio(int signum __maybe_unused,
  19. siginfo_t *oh __maybe_unused,
  20. void *uc __maybe_unused)
  21. {
  22. ++sigio_count;
  23. }
  24. static void do_child(void)
  25. {
  26. raise(SIGSTOP);
  27. for (int i = 0; i < 20; ++i)
  28. sleep(1);
  29. raise(SIGSTOP);
  30. exit(0);
  31. }
  32. TEST(watermark_signal)
  33. {
  34. struct perf_event_attr attr;
  35. struct perf_event_mmap_page *p = NULL;
  36. struct sigaction previous_sigio, sigio = { 0 };
  37. pid_t child = -1;
  38. int child_status;
  39. int fd = -1;
  40. long page_size = sysconf(_SC_PAGE_SIZE);
  41. sigio.sa_sigaction = handle_sigio;
  42. EXPECT_EQ(sigaction(SIGIO, &sigio, &previous_sigio), 0);
  43. memset(&attr, 0, sizeof(attr));
  44. attr.size = sizeof(attr);
  45. attr.type = PERF_TYPE_SOFTWARE;
  46. attr.config = PERF_COUNT_SW_DUMMY;
  47. attr.sample_period = 1;
  48. attr.disabled = 1;
  49. attr.watermark = 1;
  50. attr.context_switch = 1;
  51. attr.wakeup_watermark = 1;
  52. child = fork();
  53. EXPECT_GE(child, 0);
  54. if (child == 0)
  55. do_child();
  56. else if (child < 0) {
  57. perror("fork()");
  58. goto cleanup;
  59. }
  60. if (waitpid(child, &child_status, WSTOPPED) != child ||
  61. !(WIFSTOPPED(child_status) && WSTOPSIG(child_status) == SIGSTOP)) {
  62. fprintf(stderr,
  63. "failed to synchronize with child errno=%d status=%x\n",
  64. errno,
  65. child_status);
  66. goto cleanup;
  67. }
  68. fd = syscall(__NR_perf_event_open, &attr, child, -1, -1,
  69. PERF_FLAG_FD_CLOEXEC);
  70. if (fd < 0) {
  71. fprintf(stderr, "failed opening event %llx\n", attr.config);
  72. goto cleanup;
  73. }
  74. if (fcntl(fd, F_SETFL, FASYNC)) {
  75. perror("F_SETFL FASYNC");
  76. goto cleanup;
  77. }
  78. if (fcntl(fd, F_SETOWN, getpid())) {
  79. perror("F_SETOWN getpid()");
  80. goto cleanup;
  81. }
  82. if (fcntl(fd, F_SETSIG, SIGIO)) {
  83. perror("F_SETSIG SIGIO");
  84. goto cleanup;
  85. }
  86. p = mmap(NULL, 2 * page_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
  87. if (p == NULL) {
  88. perror("mmap");
  89. goto cleanup;
  90. }
  91. if (ioctl(fd, PERF_EVENT_IOC_ENABLE, 0)) {
  92. perror("PERF_EVENT_IOC_ENABLE");
  93. goto cleanup;
  94. }
  95. if (kill(child, SIGCONT) < 0) {
  96. perror("SIGCONT");
  97. goto cleanup;
  98. }
  99. if (waitpid(child, &child_status, WSTOPPED) != -1 || errno != EINTR)
  100. fprintf(stderr,
  101. "expected SIGIO to terminate wait errno=%d status=%x\n%d",
  102. errno,
  103. child_status,
  104. sigio_count);
  105. EXPECT_GE(sigio_count, 1);
  106. cleanup:
  107. if (p != NULL)
  108. munmap(p, 2 * page_size);
  109. if (fd >= 0)
  110. close(fd);
  111. if (child > 0) {
  112. kill(child, SIGKILL);
  113. waitpid(child, NULL, 0);
  114. }
  115. sigaction(SIGIO, &previous_sigio, NULL);
  116. }
  117. TEST_HARNESS_MAIN