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 perror("open(\"/sys/power/state\") failed (is this test running as root?)"); 140 ksft_exit_fail(); 141 } 142 143 timerfd = timerfd_create(CLOCK_BOOTTIME_ALARM, 0); 144 if (timerfd < 0) { 145 perror("timerfd_create() failed"); 146 ksft_exit_fail(); 147 } 148 149 spec.it_value.tv_sec = 5; 150 err = timerfd_settime(timerfd, 0, &spec, NULL); 151 if (err < 0) { 152 perror("timerfd_settime() failed"); 153 ksft_exit_fail(); 154 } 155 156 if (write(power_state_fd, "mem", strlen("mem")) != strlen("mem")) { 157 perror("entering suspend failed"); 158 ksft_exit_fail(); 159 } 160 161 close(timerfd); 162 close(power_state_fd); 163 } 164 165 int main(int argc, char **argv) 166 { 167 int opt; 168 bool do_suspend = true; 169 bool succeeded = true; 170 cpu_set_t available_cpus; 171 int err; 172 int cpu; 173 174 while ((opt = getopt(argc, argv, "n")) != -1) { 175 switch (opt) { 176 case 'n': 177 do_suspend = false; 178 break; 179 default: 180 printf("Usage: %s [-n]\n", argv[0]); 181 printf(" -n: do not trigger a suspend/resume cycle before the test\n"); 182 return -1; 183 } 184 } 185 186 if (do_suspend) 187 suspend(); 188 189 err = sched_getaffinity(0, sizeof(available_cpus), &available_cpus); 190 if (err < 0) { 191 perror("sched_getaffinity() failed"); 192 ksft_exit_fail(); 193 } 194 195 for (cpu = 0; cpu < CPU_SETSIZE; cpu++) { 196 bool test_success; 197 198 if (!CPU_ISSET(cpu, &available_cpus)) 199 continue; 200 201 test_success = run_test(cpu); 202 printf("CPU %d: ", cpu); 203 if (test_success) { 204 printf("[OK]\n"); 205 ksft_inc_pass_cnt(); 206 } else { 207 printf("[FAILED]\n"); 208 ksft_inc_fail_cnt(); 209 succeeded = false; 210 } 211 } 212 213 ksft_print_cnts(); 214 if (succeeded) 215 ksft_exit_pass(); 216 else 217 ksft_exit_fail(); 218 } 219