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