Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v3.18-rc5 300 lines 4.8 kB view raw
1/* 2 * Copyright 2014, Michael Ellerman, IBM Corp. 3 * Licensed under GPLv2. 4 */ 5 6#define _GNU_SOURCE /* For CPU_ZERO etc. */ 7 8#include <elf.h> 9#include <errno.h> 10#include <fcntl.h> 11#include <link.h> 12#include <sched.h> 13#include <setjmp.h> 14#include <stdlib.h> 15#include <sys/stat.h> 16#include <sys/types.h> 17#include <sys/wait.h> 18 19#include "utils.h" 20#include "lib.h" 21 22 23int pick_online_cpu(void) 24{ 25 cpu_set_t mask; 26 int cpu; 27 28 CPU_ZERO(&mask); 29 30 if (sched_getaffinity(0, sizeof(mask), &mask)) { 31 perror("sched_getaffinity"); 32 return -1; 33 } 34 35 /* We prefer a primary thread, but skip 0 */ 36 for (cpu = 8; cpu < CPU_SETSIZE; cpu += 8) 37 if (CPU_ISSET(cpu, &mask)) 38 return cpu; 39 40 /* Search for anything, but in reverse */ 41 for (cpu = CPU_SETSIZE - 1; cpu >= 0; cpu--) 42 if (CPU_ISSET(cpu, &mask)) 43 return cpu; 44 45 printf("No cpus in affinity mask?!\n"); 46 return -1; 47} 48 49int bind_to_cpu(int cpu) 50{ 51 cpu_set_t mask; 52 53 printf("Binding to cpu %d\n", cpu); 54 55 CPU_ZERO(&mask); 56 CPU_SET(cpu, &mask); 57 58 return sched_setaffinity(0, sizeof(mask), &mask); 59} 60 61#define PARENT_TOKEN 0xAA 62#define CHILD_TOKEN 0x55 63 64int sync_with_child(union pipe read_pipe, union pipe write_pipe) 65{ 66 char c = PARENT_TOKEN; 67 68 FAIL_IF(write(write_pipe.write_fd, &c, 1) != 1); 69 FAIL_IF(read(read_pipe.read_fd, &c, 1) != 1); 70 if (c != CHILD_TOKEN) /* sometimes expected */ 71 return 1; 72 73 return 0; 74} 75 76int wait_for_parent(union pipe read_pipe) 77{ 78 char c; 79 80 FAIL_IF(read(read_pipe.read_fd, &c, 1) != 1); 81 FAIL_IF(c != PARENT_TOKEN); 82 83 return 0; 84} 85 86int notify_parent(union pipe write_pipe) 87{ 88 char c = CHILD_TOKEN; 89 90 FAIL_IF(write(write_pipe.write_fd, &c, 1) != 1); 91 92 return 0; 93} 94 95int notify_parent_of_error(union pipe write_pipe) 96{ 97 char c = ~CHILD_TOKEN; 98 99 FAIL_IF(write(write_pipe.write_fd, &c, 1) != 1); 100 101 return 0; 102} 103 104int wait_for_child(pid_t child_pid) 105{ 106 int rc; 107 108 if (waitpid(child_pid, &rc, 0) == -1) { 109 perror("waitpid"); 110 return 1; 111 } 112 113 if (WIFEXITED(rc)) 114 rc = WEXITSTATUS(rc); 115 else 116 rc = 1; /* Signal or other */ 117 118 return rc; 119} 120 121int kill_child_and_wait(pid_t child_pid) 122{ 123 kill(child_pid, SIGTERM); 124 125 return wait_for_child(child_pid); 126} 127 128static int eat_cpu_child(union pipe read_pipe, union pipe write_pipe) 129{ 130 volatile int i = 0; 131 132 /* 133 * We are just here to eat cpu and die. So make sure we can be killed, 134 * and also don't do any custom SIGTERM handling. 135 */ 136 signal(SIGTERM, SIG_DFL); 137 138 notify_parent(write_pipe); 139 wait_for_parent(read_pipe); 140 141 /* Soak up cpu forever */ 142 while (1) i++; 143 144 return 0; 145} 146 147pid_t eat_cpu(int (test_function)(void)) 148{ 149 union pipe read_pipe, write_pipe; 150 int cpu, rc; 151 pid_t pid; 152 153 cpu = pick_online_cpu(); 154 FAIL_IF(cpu < 0); 155 FAIL_IF(bind_to_cpu(cpu)); 156 157 if (pipe(read_pipe.fds) == -1) 158 return -1; 159 160 if (pipe(write_pipe.fds) == -1) 161 return -1; 162 163 pid = fork(); 164 if (pid == 0) 165 exit(eat_cpu_child(write_pipe, read_pipe)); 166 167 if (sync_with_child(read_pipe, write_pipe)) { 168 rc = -1; 169 goto out; 170 } 171 172 printf("main test running as pid %d\n", getpid()); 173 174 rc = test_function(); 175out: 176 kill(pid, SIGKILL); 177 178 return rc; 179} 180 181struct addr_range libc, vdso; 182 183int parse_proc_maps(void) 184{ 185 unsigned long start, end; 186 char execute, name[128]; 187 FILE *f; 188 int rc; 189 190 f = fopen("/proc/self/maps", "r"); 191 if (!f) { 192 perror("fopen"); 193 return -1; 194 } 195 196 do { 197 /* This skips line with no executable which is what we want */ 198 rc = fscanf(f, "%lx-%lx %*c%*c%c%*c %*x %*d:%*d %*d %127s\n", 199 &start, &end, &execute, name); 200 if (rc <= 0) 201 break; 202 203 if (execute != 'x') 204 continue; 205 206 if (strstr(name, "libc")) { 207 libc.first = start; 208 libc.last = end - 1; 209 } else if (strstr(name, "[vdso]")) { 210 vdso.first = start; 211 vdso.last = end - 1; 212 } 213 } while(1); 214 215 fclose(f); 216 217 return 0; 218} 219 220#define PARANOID_PATH "/proc/sys/kernel/perf_event_paranoid" 221 222bool require_paranoia_below(int level) 223{ 224 unsigned long current; 225 char *end, buf[16]; 226 FILE *f; 227 int rc; 228 229 rc = -1; 230 231 f = fopen(PARANOID_PATH, "r"); 232 if (!f) { 233 perror("fopen"); 234 goto out; 235 } 236 237 if (!fgets(buf, sizeof(buf), f)) { 238 printf("Couldn't read " PARANOID_PATH "?\n"); 239 goto out_close; 240 } 241 242 current = strtoul(buf, &end, 10); 243 244 if (end == buf) { 245 printf("Couldn't parse " PARANOID_PATH "?\n"); 246 goto out_close; 247 } 248 249 if (current >= level) 250 goto out; 251 252 rc = 0; 253out_close: 254 fclose(f); 255out: 256 return rc; 257} 258 259static char auxv[4096]; 260 261void *get_auxv_entry(int type) 262{ 263 ElfW(auxv_t) *p; 264 void *result; 265 ssize_t num; 266 int fd; 267 268 fd = open("/proc/self/auxv", O_RDONLY); 269 if (fd == -1) { 270 perror("open"); 271 return NULL; 272 } 273 274 result = NULL; 275 276 num = read(fd, auxv, sizeof(auxv)); 277 if (num < 0) { 278 perror("read"); 279 goto out; 280 } 281 282 if (num > sizeof(auxv)) { 283 printf("Overflowed auxv buffer\n"); 284 goto out; 285 } 286 287 p = (ElfW(auxv_t) *)auxv; 288 289 while (p->a_type != AT_NULL) { 290 if (p->a_type == type) { 291 result = (void *)p->a_un.a_val; 292 break; 293 } 294 295 p++; 296 } 297out: 298 close(fd); 299 return result; 300}