1
2
3
4
5
6#define _GNU_SOURCE
7
8#include <errno.h>
9#include <sched.h>
10#include <setjmp.h>
11#include <stdlib.h>
12#include <sys/wait.h>
13
14#include "utils.h"
15#include "lib.h"
16
17
18int bind_to_cpu(int cpu)
19{
20 cpu_set_t mask;
21
22 printf("Binding to cpu %d\n", cpu);
23
24 CPU_ZERO(&mask);
25 CPU_SET(cpu, &mask);
26
27 return sched_setaffinity(0, sizeof(mask), &mask);
28}
29
30#define PARENT_TOKEN 0xAA
31#define CHILD_TOKEN 0x55
32
33int sync_with_child(union pipe read_pipe, union pipe write_pipe)
34{
35 char c = PARENT_TOKEN;
36
37 FAIL_IF(write(write_pipe.write_fd, &c, 1) != 1);
38 FAIL_IF(read(read_pipe.read_fd, &c, 1) != 1);
39 if (c != CHILD_TOKEN)
40 return 1;
41
42 return 0;
43}
44
45int wait_for_parent(union pipe read_pipe)
46{
47 char c;
48
49 FAIL_IF(read(read_pipe.read_fd, &c, 1) != 1);
50 FAIL_IF(c != PARENT_TOKEN);
51
52 return 0;
53}
54
55int notify_parent(union pipe write_pipe)
56{
57 char c = CHILD_TOKEN;
58
59 FAIL_IF(write(write_pipe.write_fd, &c, 1) != 1);
60
61 return 0;
62}
63
64int notify_parent_of_error(union pipe write_pipe)
65{
66 char c = ~CHILD_TOKEN;
67
68 FAIL_IF(write(write_pipe.write_fd, &c, 1) != 1);
69
70 return 0;
71}
72
73int wait_for_child(pid_t child_pid)
74{
75 int rc;
76
77 if (waitpid(child_pid, &rc, 0) == -1) {
78 perror("waitpid");
79 return 1;
80 }
81
82 if (WIFEXITED(rc))
83 rc = WEXITSTATUS(rc);
84 else
85 rc = 1;
86
87 return rc;
88}
89
90int kill_child_and_wait(pid_t child_pid)
91{
92 kill(child_pid, SIGTERM);
93
94 return wait_for_child(child_pid);
95}
96
97static int eat_cpu_child(union pipe read_pipe, union pipe write_pipe)
98{
99 volatile int i = 0;
100
101
102
103
104
105 signal(SIGTERM, SIG_DFL);
106
107 notify_parent(write_pipe);
108 wait_for_parent(read_pipe);
109
110
111 while (1) i++;
112
113 return 0;
114}
115
116pid_t eat_cpu(int (test_function)(void))
117{
118 union pipe read_pipe, write_pipe;
119 int cpu, rc;
120 pid_t pid;
121
122 cpu = pick_online_cpu();
123 FAIL_IF(cpu < 0);
124 FAIL_IF(bind_to_cpu(cpu));
125
126 if (pipe(read_pipe.fds) == -1)
127 return -1;
128
129 if (pipe(write_pipe.fds) == -1)
130 return -1;
131
132 pid = fork();
133 if (pid == 0)
134 exit(eat_cpu_child(write_pipe, read_pipe));
135
136 if (sync_with_child(read_pipe, write_pipe)) {
137 rc = -1;
138 goto out;
139 }
140
141 printf("main test running as pid %d\n", getpid());
142
143 rc = test_function();
144out:
145 kill(pid, SIGKILL);
146
147 return rc;
148}
149
150struct addr_range libc, vdso;
151
152int parse_proc_maps(void)
153{
154 unsigned long start, end;
155 char execute, name[128];
156 FILE *f;
157 int rc;
158
159 f = fopen("/proc/self/maps", "r");
160 if (!f) {
161 perror("fopen");
162 return -1;
163 }
164
165 do {
166
167 rc = fscanf(f, "%lx-%lx %*c%*c%c%*c %*x %*d:%*d %*d %127s\n",
168 &start, &end, &execute, name);
169 if (rc <= 0)
170 break;
171
172 if (execute != 'x')
173 continue;
174
175 if (strstr(name, "libc")) {
176 libc.first = start;
177 libc.last = end - 1;
178 } else if (strstr(name, "[vdso]")) {
179 vdso.first = start;
180 vdso.last = end - 1;
181 }
182 } while(1);
183
184 fclose(f);
185
186 return 0;
187}
188
189#define PARANOID_PATH "/proc/sys/kernel/perf_event_paranoid"
190
191bool require_paranoia_below(int level)
192{
193 long current;
194 char *end, buf[16];
195 FILE *f;
196 int rc;
197
198 rc = -1;
199
200 f = fopen(PARANOID_PATH, "r");
201 if (!f) {
202 perror("fopen");
203 goto out;
204 }
205
206 if (!fgets(buf, sizeof(buf), f)) {
207 printf("Couldn't read " PARANOID_PATH "?\n");
208 goto out_close;
209 }
210
211 current = strtol(buf, &end, 10);
212
213 if (end == buf) {
214 printf("Couldn't parse " PARANOID_PATH "?\n");
215 goto out_close;
216 }
217
218 if (current >= level)
219 goto out_close;
220
221 rc = 0;
222out_close:
223 fclose(f);
224out:
225 return rc;
226}
227
228