lib.c 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254
  1. /*
  2. * Copyright 2014, Michael Ellerman, IBM Corp.
  3. * Licensed under GPLv2.
  4. */
  5. #define _GNU_SOURCE /* For CPU_ZERO etc. */
  6. #include <errno.h>
  7. #include <sched.h>
  8. #include <setjmp.h>
  9. #include <stdlib.h>
  10. #include <sys/wait.h>
  11. #include "utils.h"
  12. #include "lib.h"
  13. int pick_online_cpu(void)
  14. {
  15. cpu_set_t mask;
  16. int cpu;
  17. CPU_ZERO(&mask);
  18. if (sched_getaffinity(0, sizeof(mask), &mask)) {
  19. perror("sched_getaffinity");
  20. return -1;
  21. }
  22. /* We prefer a primary thread, but skip 0 */
  23. for (cpu = 8; cpu < CPU_SETSIZE; cpu += 8)
  24. if (CPU_ISSET(cpu, &mask))
  25. return cpu;
  26. /* Search for anything, but in reverse */
  27. for (cpu = CPU_SETSIZE - 1; cpu >= 0; cpu--)
  28. if (CPU_ISSET(cpu, &mask))
  29. return cpu;
  30. printf("No cpus in affinity mask?!\n");
  31. return -1;
  32. }
  33. int bind_to_cpu(int cpu)
  34. {
  35. cpu_set_t mask;
  36. printf("Binding to cpu %d\n", cpu);
  37. CPU_ZERO(&mask);
  38. CPU_SET(cpu, &mask);
  39. return sched_setaffinity(0, sizeof(mask), &mask);
  40. }
  41. #define PARENT_TOKEN 0xAA
  42. #define CHILD_TOKEN 0x55
  43. int sync_with_child(union pipe read_pipe, union pipe write_pipe)
  44. {
  45. char c = PARENT_TOKEN;
  46. FAIL_IF(write(write_pipe.write_fd, &c, 1) != 1);
  47. FAIL_IF(read(read_pipe.read_fd, &c, 1) != 1);
  48. if (c != CHILD_TOKEN) /* sometimes expected */
  49. return 1;
  50. return 0;
  51. }
  52. int wait_for_parent(union pipe read_pipe)
  53. {
  54. char c;
  55. FAIL_IF(read(read_pipe.read_fd, &c, 1) != 1);
  56. FAIL_IF(c != PARENT_TOKEN);
  57. return 0;
  58. }
  59. int notify_parent(union pipe write_pipe)
  60. {
  61. char c = CHILD_TOKEN;
  62. FAIL_IF(write(write_pipe.write_fd, &c, 1) != 1);
  63. return 0;
  64. }
  65. int notify_parent_of_error(union pipe write_pipe)
  66. {
  67. char c = ~CHILD_TOKEN;
  68. FAIL_IF(write(write_pipe.write_fd, &c, 1) != 1);
  69. return 0;
  70. }
  71. int wait_for_child(pid_t child_pid)
  72. {
  73. int rc;
  74. if (waitpid(child_pid, &rc, 0) == -1) {
  75. perror("waitpid");
  76. return 1;
  77. }
  78. if (WIFEXITED(rc))
  79. rc = WEXITSTATUS(rc);
  80. else
  81. rc = 1; /* Signal or other */
  82. return rc;
  83. }
  84. int kill_child_and_wait(pid_t child_pid)
  85. {
  86. kill(child_pid, SIGTERM);
  87. return wait_for_child(child_pid);
  88. }
  89. static int eat_cpu_child(union pipe read_pipe, union pipe write_pipe)
  90. {
  91. volatile int i = 0;
  92. /*
  93. * We are just here to eat cpu and die. So make sure we can be killed,
  94. * and also don't do any custom SIGTERM handling.
  95. */
  96. signal(SIGTERM, SIG_DFL);
  97. notify_parent(write_pipe);
  98. wait_for_parent(read_pipe);
  99. /* Soak up cpu forever */
  100. while (1) i++;
  101. return 0;
  102. }
  103. pid_t eat_cpu(int (test_function)(void))
  104. {
  105. union pipe read_pipe, write_pipe;
  106. int cpu, rc;
  107. pid_t pid;
  108. cpu = pick_online_cpu();
  109. FAIL_IF(cpu < 0);
  110. FAIL_IF(bind_to_cpu(cpu));
  111. if (pipe(read_pipe.fds) == -1)
  112. return -1;
  113. if (pipe(write_pipe.fds) == -1)
  114. return -1;
  115. pid = fork();
  116. if (pid == 0)
  117. exit(eat_cpu_child(write_pipe, read_pipe));
  118. if (sync_with_child(read_pipe, write_pipe)) {
  119. rc = -1;
  120. goto out;
  121. }
  122. printf("main test running as pid %d\n", getpid());
  123. rc = test_function();
  124. out:
  125. kill(pid, SIGKILL);
  126. return rc;
  127. }
  128. struct addr_range libc, vdso;
  129. int parse_proc_maps(void)
  130. {
  131. unsigned long start, end;
  132. char execute, name[128];
  133. FILE *f;
  134. int rc;
  135. f = fopen("/proc/self/maps", "r");
  136. if (!f) {
  137. perror("fopen");
  138. return -1;
  139. }
  140. do {
  141. /* This skips line with no executable which is what we want */
  142. rc = fscanf(f, "%lx-%lx %*c%*c%c%*c %*x %*d:%*d %*d %127s\n",
  143. &start, &end, &execute, name);
  144. if (rc <= 0)
  145. break;
  146. if (execute != 'x')
  147. continue;
  148. if (strstr(name, "libc")) {
  149. libc.first = start;
  150. libc.last = end - 1;
  151. } else if (strstr(name, "[vdso]")) {
  152. vdso.first = start;
  153. vdso.last = end - 1;
  154. }
  155. } while(1);
  156. fclose(f);
  157. return 0;
  158. }
  159. #define PARANOID_PATH "/proc/sys/kernel/perf_event_paranoid"
  160. bool require_paranoia_below(int level)
  161. {
  162. unsigned long current;
  163. char *end, buf[16];
  164. FILE *f;
  165. int rc;
  166. rc = -1;
  167. f = fopen(PARANOID_PATH, "r");
  168. if (!f) {
  169. perror("fopen");
  170. goto out;
  171. }
  172. if (!fgets(buf, sizeof(buf), f)) {
  173. printf("Couldn't read " PARANOID_PATH "?\n");
  174. goto out_close;
  175. }
  176. current = strtoul(buf, &end, 10);
  177. if (end == buf) {
  178. printf("Couldn't parse " PARANOID_PATH "?\n");
  179. goto out_close;
  180. }
  181. if (current >= level)
  182. goto out;
  183. rc = 0;
  184. out_close:
  185. fclose(f);
  186. out:
  187. return rc;
  188. }