1 /* 2 * Copyright (C) 2016 Google, Inc. 3 * 4 * This software is licensed under the terms of the GNU General Public 5 * License version 2, as published by the Free Software Foundation, and 6 * may be copied, distributed, and modified under those terms. 7 * 8 * This program is distributed in the hope that it will be useful, 9 * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 * GNU General Public License for more details. 12 * 13 */ 14 15 #define _GNU_SOURCE 16 17 #include <errno.h> 18 #include <fcntl.h> 19 #include <sched.h> 20 #include <signal.h> 21 #include <stdbool.h> 22 #include <stdio.h> 23 #include <string.h> 24 #include <unistd.h> 25 #include <sys/ptrace.h> 26 #include <sys/stat.h> 27 #include <sys/timerfd.h> 28 #include <sys/types.h> 29 #include <sys/wait.h> 30 31 #include "../kselftest.h" 32 33 void child(int cpu) 34 { 35 cpu_set_t set; 36 37 CPU_ZERO(&set); 38 CPU_SET(cpu, &set); 39 if (sched_setaffinity(0, sizeof(set), &set) != 0) { 40 perror("sched_setaffinity() failed"); 41 _exit(1); 42 } 43 44 if (ptrace(PTRACE_TRACEME, 0, NULL, NULL) != 0) { 45 perror("ptrace(PTRACE_TRACEME) failed"); 46 _exit(1); 47 } 48 49 if (raise(SIGSTOP) != 0) { 50 perror("raise(SIGSTOP) failed"); 51 _exit(1); 52 } 53 54 _exit(0); 55 } 56 57 bool run_test(int cpu) 58 { 59 int status; 60 pid_t pid = fork(); 61 pid_t wpid; 62 63 if (pid < 0) { 64 perror("fork() failed"); 65 return false; 66 } 67 if (pid == 0) 68 child(cpu); 69 70 wpid = waitpid(pid, &status, __WALL); 71 if (wpid != pid) { 72 perror("waitpid() failed"); 73 return false; 74 } 75 if (!WIFSTOPPED(status)) { 76 printf("child did not stop\n"); 77 return false; 78 } 79 if (WSTOPSIG(status) != SIGSTOP) { 80 printf("child did not stop with SIGSTOP\n"); 81 return false; 82 } 83 84 if (ptrace(PTRACE_SINGLESTEP, pid, NULL, NULL) < 0) { 85 if (errno == EIO) { 86 printf("ptrace(PTRACE_SINGLESTEP) not supported on this architecture\n"); 87 ksft_exit_skip(); 88 } 89 perror("ptrace(PTRACE_SINGLESTEP) failed"); 90 return false; 91 } 92 93 wpid = waitpid(pid, &status, __WALL); 94 if (wpid != pid) { 95 perror("waitpid() failed"); 96 return false; 97 } 98 if (WIFEXITED(status)) { 99 printf("child did not single-step\n"); 100 return false; 101 } 102 if (!WIFSTOPPED(status)) { 103 printf("child did not stop\n"); 104 return false; 105 } 106 if (WSTOPSIG(status) != SIGTRAP) { 107 printf("child did not stop with SIGTRAP\n"); 108 return false; 109 } 110 111 if (ptrace(PTRACE_CONT, pid, NULL, NULL) < 0) { 112 perror("ptrace(PTRACE_CONT) failed"); 113 return false; 114 } 115 116 wpid = waitpid(pid, &status, __WALL); 117 if (wpid != pid) { 118 perror("waitpid() failed"); 119 return false; 120 } 121 if (!WIFEXITED(status)) { 122 printf("child did not exit after PTRACE_CONT\n"); 123 return false; 124 } 125 126 return true; 127 } 128 129 void suspend(void) 130 { 131 int power_state_fd; 132 struct sigevent event = {}; 133 int timerfd; 134 int err; 135 struct itimerspec spec = {}; 136 137 power_state_fd = open("/sys/power/state", O_RDWR); 138 if (power_state_fd < 0) 139 ksft_exit_fail_msg( 140 "open(\"/sys/power/state\") failed (is this test running as root?)"); 141 142 timerfd = timerfd_create(CLOCK_BOOTTIME_ALARM, 0); 143 if (timerfd < 0) 144 ksft_exit_fail_msg("timerfd_create() failed"); 145 146 spec.it_value.tv_sec = 5; 147 err = timerfd_settime(timerfd, 0, &spec, NULL); 148 if (err < 0) 149 ksft_exit_fail_msg("timerfd_settime() failed"); 150 151 if (write(power_state_fd, "mem", strlen("mem")) != strlen("mem")) 152 ksft_exit_fail_msg("entering suspend failed"); 153 154 close(timerfd); 155 close(power_state_fd); 156 } 157 158 int main(int argc, char **argv) 159 { 160 int opt; 161 bool do_suspend = true; 162 bool succeeded = true; 163 cpu_set_t available_cpus; 164 int err; 165 int cpu; 166 char buf[10]; 167 168 ksft_print_header(); 169 170 while ((opt = getopt(argc, argv, "n")) != -1) { 171 switch (opt) { 172 case 'n': 173 do_suspend = false; 174 break; 175 default: 176 printf("Usage: %s [-n]\n", argv[0]); 177 printf(" -n: do not trigger a suspend/resume cycle before the test\n"); 178 return -1; 179 } 180 } 181 182 if (do_suspend) 183 suspend(); 184 185 err = sched_getaffinity(0, sizeof(available_cpus), &available_cpus); 186 if (err < 0) 187 ksft_exit_fail_msg("sched_getaffinity() failed"); 188 189 for (cpu = 0; cpu < CPU_SETSIZE; cpu++) { 190 bool test_success; 191 192 if (!CPU_ISSET(cpu, &available_cpus)) 193 continue; 194 195 test_success = run_test(cpu); 196 sprintf(buf, "CPU %d", cpu); 197 if (test_success) { 198 ksft_test_result_pass(buf); 199 } else { 200 ksft_test_result_fail(buf); 201 succeeded = false; 202 } 203 } 204 205 if (succeeded) 206 ksft_exit_pass(); 207 else 208 ksft_exit_fail(); 209 } 210