123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254 |
- /*
- * Copyright 2014, Michael Ellerman, IBM Corp.
- * Licensed under GPLv2.
- */
- #define _GNU_SOURCE /* For CPU_ZERO etc. */
- #include <errno.h>
- #include <sched.h>
- #include <setjmp.h>
- #include <stdlib.h>
- #include <sys/wait.h>
- #include "utils.h"
- #include "lib.h"
- int pick_online_cpu(void)
- {
- cpu_set_t mask;
- int cpu;
- CPU_ZERO(&mask);
- if (sched_getaffinity(0, sizeof(mask), &mask)) {
- perror("sched_getaffinity");
- return -1;
- }
- /* We prefer a primary thread, but skip 0 */
- for (cpu = 8; cpu < CPU_SETSIZE; cpu += 8)
- if (CPU_ISSET(cpu, &mask))
- return cpu;
- /* Search for anything, but in reverse */
- for (cpu = CPU_SETSIZE - 1; cpu >= 0; cpu--)
- if (CPU_ISSET(cpu, &mask))
- return cpu;
- printf("No cpus in affinity mask?!\n");
- return -1;
- }
- int bind_to_cpu(int cpu)
- {
- cpu_set_t mask;
- printf("Binding to cpu %d\n", cpu);
- CPU_ZERO(&mask);
- CPU_SET(cpu, &mask);
- return sched_setaffinity(0, sizeof(mask), &mask);
- }
- #define PARENT_TOKEN 0xAA
- #define CHILD_TOKEN 0x55
- int sync_with_child(union pipe read_pipe, union pipe write_pipe)
- {
- char c = PARENT_TOKEN;
- FAIL_IF(write(write_pipe.write_fd, &c, 1) != 1);
- FAIL_IF(read(read_pipe.read_fd, &c, 1) != 1);
- if (c != CHILD_TOKEN) /* sometimes expected */
- return 1;
- return 0;
- }
- int wait_for_parent(union pipe read_pipe)
- {
- char c;
- FAIL_IF(read(read_pipe.read_fd, &c, 1) != 1);
- FAIL_IF(c != PARENT_TOKEN);
- return 0;
- }
- int notify_parent(union pipe write_pipe)
- {
- char c = CHILD_TOKEN;
- FAIL_IF(write(write_pipe.write_fd, &c, 1) != 1);
- return 0;
- }
- int notify_parent_of_error(union pipe write_pipe)
- {
- char c = ~CHILD_TOKEN;
- FAIL_IF(write(write_pipe.write_fd, &c, 1) != 1);
- return 0;
- }
- int wait_for_child(pid_t child_pid)
- {
- int rc;
- if (waitpid(child_pid, &rc, 0) == -1) {
- perror("waitpid");
- return 1;
- }
- if (WIFEXITED(rc))
- rc = WEXITSTATUS(rc);
- else
- rc = 1; /* Signal or other */
- return rc;
- }
- int kill_child_and_wait(pid_t child_pid)
- {
- kill(child_pid, SIGTERM);
- return wait_for_child(child_pid);
- }
- static int eat_cpu_child(union pipe read_pipe, union pipe write_pipe)
- {
- volatile int i = 0;
- /*
- * We are just here to eat cpu and die. So make sure we can be killed,
- * and also don't do any custom SIGTERM handling.
- */
- signal(SIGTERM, SIG_DFL);
- notify_parent(write_pipe);
- wait_for_parent(read_pipe);
- /* Soak up cpu forever */
- while (1) i++;
- return 0;
- }
- pid_t eat_cpu(int (test_function)(void))
- {
- union pipe read_pipe, write_pipe;
- int cpu, rc;
- pid_t pid;
- cpu = pick_online_cpu();
- FAIL_IF(cpu < 0);
- FAIL_IF(bind_to_cpu(cpu));
- if (pipe(read_pipe.fds) == -1)
- return -1;
- if (pipe(write_pipe.fds) == -1)
- return -1;
- pid = fork();
- if (pid == 0)
- exit(eat_cpu_child(write_pipe, read_pipe));
- if (sync_with_child(read_pipe, write_pipe)) {
- rc = -1;
- goto out;
- }
- printf("main test running as pid %d\n", getpid());
- rc = test_function();
- out:
- kill(pid, SIGKILL);
- return rc;
- }
- struct addr_range libc, vdso;
- int parse_proc_maps(void)
- {
- unsigned long start, end;
- char execute, name[128];
- FILE *f;
- int rc;
- f = fopen("/proc/self/maps", "r");
- if (!f) {
- perror("fopen");
- return -1;
- }
- do {
- /* This skips line with no executable which is what we want */
- rc = fscanf(f, "%lx-%lx %*c%*c%c%*c %*x %*d:%*d %*d %127s\n",
- &start, &end, &execute, name);
- if (rc <= 0)
- break;
- if (execute != 'x')
- continue;
- if (strstr(name, "libc")) {
- libc.first = start;
- libc.last = end - 1;
- } else if (strstr(name, "[vdso]")) {
- vdso.first = start;
- vdso.last = end - 1;
- }
- } while(1);
- fclose(f);
- return 0;
- }
- #define PARANOID_PATH "/proc/sys/kernel/perf_event_paranoid"
- bool require_paranoia_below(int level)
- {
- unsigned long current;
- char *end, buf[16];
- FILE *f;
- int rc;
- rc = -1;
- f = fopen(PARANOID_PATH, "r");
- if (!f) {
- perror("fopen");
- goto out;
- }
- if (!fgets(buf, sizeof(buf), f)) {
- printf("Couldn't read " PARANOID_PATH "?\n");
- goto out_close;
- }
- current = strtoul(buf, &end, 10);
- if (end == buf) {
- printf("Couldn't parse " PARANOID_PATH "?\n");
- goto out_close;
- }
- if (current >= level)
- goto out;
- rc = 0;
- out_close:
- fclose(f);
- out:
- return rc;
- }
|