0001
0002
0003
0004
0005
0006 #define _GNU_SOURCE
0007
0008 #include <errno.h>
0009 #include <sched.h>
0010 #include <setjmp.h>
0011 #include <stdlib.h>
0012 #include <sys/wait.h>
0013
0014 #include "utils.h"
0015 #include "lib.h"
0016
0017
0018 int bind_to_cpu(int cpu)
0019 {
0020 cpu_set_t mask;
0021
0022 printf("Binding to cpu %d\n", cpu);
0023
0024 CPU_ZERO(&mask);
0025 CPU_SET(cpu, &mask);
0026
0027 return sched_setaffinity(0, sizeof(mask), &mask);
0028 }
0029
0030 #define PARENT_TOKEN 0xAA
0031 #define CHILD_TOKEN 0x55
0032
0033 int sync_with_child(union pipe read_pipe, union pipe write_pipe)
0034 {
0035 char c = PARENT_TOKEN;
0036
0037 FAIL_IF(write(write_pipe.write_fd, &c, 1) != 1);
0038 FAIL_IF(read(read_pipe.read_fd, &c, 1) != 1);
0039 if (c != CHILD_TOKEN)
0040 return 1;
0041
0042 return 0;
0043 }
0044
0045 int wait_for_parent(union pipe read_pipe)
0046 {
0047 char c;
0048
0049 FAIL_IF(read(read_pipe.read_fd, &c, 1) != 1);
0050 FAIL_IF(c != PARENT_TOKEN);
0051
0052 return 0;
0053 }
0054
0055 int notify_parent(union pipe write_pipe)
0056 {
0057 char c = CHILD_TOKEN;
0058
0059 FAIL_IF(write(write_pipe.write_fd, &c, 1) != 1);
0060
0061 return 0;
0062 }
0063
0064 int notify_parent_of_error(union pipe write_pipe)
0065 {
0066 char c = ~CHILD_TOKEN;
0067
0068 FAIL_IF(write(write_pipe.write_fd, &c, 1) != 1);
0069
0070 return 0;
0071 }
0072
0073 int wait_for_child(pid_t child_pid)
0074 {
0075 int rc;
0076
0077 if (waitpid(child_pid, &rc, 0) == -1) {
0078 perror("waitpid");
0079 return 1;
0080 }
0081
0082 if (WIFEXITED(rc))
0083 rc = WEXITSTATUS(rc);
0084 else
0085 rc = 1;
0086
0087 return rc;
0088 }
0089
0090 int kill_child_and_wait(pid_t child_pid)
0091 {
0092 kill(child_pid, SIGTERM);
0093
0094 return wait_for_child(child_pid);
0095 }
0096
0097 static int eat_cpu_child(union pipe read_pipe, union pipe write_pipe)
0098 {
0099 volatile int i = 0;
0100
0101
0102
0103
0104
0105 signal(SIGTERM, SIG_DFL);
0106
0107 notify_parent(write_pipe);
0108 wait_for_parent(read_pipe);
0109
0110
0111 while (1) i++;
0112
0113 return 0;
0114 }
0115
0116 pid_t eat_cpu(int (test_function)(void))
0117 {
0118 union pipe read_pipe, write_pipe;
0119 int cpu, rc;
0120 pid_t pid;
0121
0122 cpu = pick_online_cpu();
0123 FAIL_IF(cpu < 0);
0124 FAIL_IF(bind_to_cpu(cpu));
0125
0126 if (pipe(read_pipe.fds) == -1)
0127 return -1;
0128
0129 if (pipe(write_pipe.fds) == -1)
0130 return -1;
0131
0132 pid = fork();
0133 if (pid == 0)
0134 exit(eat_cpu_child(write_pipe, read_pipe));
0135
0136 if (sync_with_child(read_pipe, write_pipe)) {
0137 rc = -1;
0138 goto out;
0139 }
0140
0141 printf("main test running as pid %d\n", getpid());
0142
0143 rc = test_function();
0144 out:
0145 kill(pid, SIGKILL);
0146
0147 return rc;
0148 }
0149
0150 struct addr_range libc, vdso;
0151
0152 int parse_proc_maps(void)
0153 {
0154 unsigned long start, end;
0155 char execute, name[128];
0156 FILE *f;
0157 int rc;
0158
0159 f = fopen("/proc/self/maps", "r");
0160 if (!f) {
0161 perror("fopen");
0162 return -1;
0163 }
0164
0165 do {
0166
0167 rc = fscanf(f, "%lx-%lx %*c%*c%c%*c %*x %*d:%*d %*d %127s\n",
0168 &start, &end, &execute, name);
0169 if (rc <= 0)
0170 break;
0171
0172 if (execute != 'x')
0173 continue;
0174
0175 if (strstr(name, "libc")) {
0176 libc.first = start;
0177 libc.last = end - 1;
0178 } else if (strstr(name, "[vdso]")) {
0179 vdso.first = start;
0180 vdso.last = end - 1;
0181 }
0182 } while(1);
0183
0184 fclose(f);
0185
0186 return 0;
0187 }
0188
0189 #define PARANOID_PATH "/proc/sys/kernel/perf_event_paranoid"
0190
0191 bool require_paranoia_below(int level)
0192 {
0193 long current;
0194 char *end, buf[16];
0195 FILE *f;
0196 bool rc;
0197
0198 rc = false;
0199
0200 f = fopen(PARANOID_PATH, "r");
0201 if (!f) {
0202 perror("fopen");
0203 goto out;
0204 }
0205
0206 if (!fgets(buf, sizeof(buf), f)) {
0207 printf("Couldn't read " PARANOID_PATH "?\n");
0208 goto out_close;
0209 }
0210
0211 current = strtol(buf, &end, 10);
0212
0213 if (end == buf) {
0214 printf("Couldn't parse " PARANOID_PATH "?\n");
0215 goto out_close;
0216 }
0217
0218 if (current >= level)
0219 goto out_close;
0220
0221 rc = true;
0222 out_close:
0223 fclose(f);
0224 out:
0225 return rc;
0226 }
0227