Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * Copyright 2014, Michael Ellerman, IBM Corp.
0004  */
0005 
0006 #define _GNU_SOURCE /* For CPU_ZERO etc. */
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) /* sometimes expected */
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; /* Signal or other */
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      * We are just here to eat cpu and die. So make sure we can be killed,
0103      * and also don't do any custom SIGTERM handling.
0104      */
0105     signal(SIGTERM, SIG_DFL);
0106 
0107     notify_parent(write_pipe);
0108     wait_for_parent(read_pipe);
0109 
0110     /* Soak up cpu forever */
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         /* This skips line with no executable which is what we want */
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