root/tools/testing/selftests/powerpc/pmu/lib.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. bind_to_cpu
  2. sync_with_child
  3. wait_for_parent
  4. notify_parent
  5. notify_parent_of_error
  6. wait_for_child
  7. kill_child_and_wait
  8. eat_cpu_child
  9. eat_cpu
  10. parse_proc_maps
  11. require_paranoia_below

   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 
  18 int 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 
  33 int 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) /* sometimes expected */
  40                 return 1;
  41 
  42         return 0;
  43 }
  44 
  45 int 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 
  55 int 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 
  64 int 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 
  73 int 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; /* Signal or other */
  86 
  87         return rc;
  88 }
  89 
  90 int kill_child_and_wait(pid_t child_pid)
  91 {
  92         kill(child_pid, SIGTERM);
  93 
  94         return wait_for_child(child_pid);
  95 }
  96 
  97 static int eat_cpu_child(union pipe read_pipe, union pipe write_pipe)
  98 {
  99         volatile int i = 0;
 100 
 101         /*
 102          * We are just here to eat cpu and die. So make sure we can be killed,
 103          * and also don't do any custom SIGTERM handling.
 104          */
 105         signal(SIGTERM, SIG_DFL);
 106 
 107         notify_parent(write_pipe);
 108         wait_for_parent(read_pipe);
 109 
 110         /* Soak up cpu forever */
 111         while (1) i++;
 112 
 113         return 0;
 114 }
 115 
 116 pid_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();
 144 out:
 145         kill(pid, SIGKILL);
 146 
 147         return rc;
 148 }
 149 
 150 struct addr_range libc, vdso;
 151 
 152 int 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                 /* This skips line with no executable which is what we want */
 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 
 191 bool require_paranoia_below(int level)
 192 {
 193         long current;
 194         char *end, buf[16];
 195         FILE *f;
 196         bool rc;
 197 
 198         rc = false;
 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 = true;
 222 out_close:
 223         fclose(f);
 224 out:
 225         return rc;
 226 }
 227 

/* [<][>][^][v][top][bottom][index][help] */