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 ksft_print_msg("sched_setaffinity() failed: %s\n", 41 strerror(errno)); 42 _exit(1); 43 } 44 45 if (ptrace(PTRACE_TRACEME, 0, NULL, NULL) != 0) { 46 ksft_print_msg("ptrace(PTRACE_TRACEME) failed: %s\n", 47 strerror(errno)); 48 _exit(1); 49 } 50 51 if (raise(SIGSTOP) != 0) { 52 ksft_print_msg("raise(SIGSTOP) failed: %s\n", strerror(errno)); 53 _exit(1); 54 } 55 56 _exit(0); 57 } 58 59 bool run_test(int cpu) 60 { 61 int status; 62 pid_t pid = fork(); 63 pid_t wpid; 64 65 if (pid < 0) { 66 ksft_print_msg("fork() failed: %s\n", strerror(errno)); 67 return false; 68 } 69 if (pid == 0) 70 child(cpu); 71 72 wpid = waitpid(pid, &status, __WALL); 73 if (wpid != pid) { 74 ksft_print_msg("waitpid() failed: %s\n", strerror(errno)); 75 return false; 76 } 77 if (!WIFSTOPPED(status)) { 78 ksft_print_msg("child did not stop: %s\n", strerror(errno)); 79 return false; 80 } 81 if (WSTOPSIG(status) != SIGSTOP) { 82 ksft_print_msg("child did not stop with SIGSTOP: %s\n", 83 strerror(errno)); 84 return false; 85 } 86 87 if (ptrace(PTRACE_SINGLESTEP, pid, NULL, NULL) < 0) { 88 if (errno == EIO) { 89 ksft_exit_skip( 90 "ptrace(PTRACE_SINGLESTEP) not supported on this architecture: %s\n", 91 strerror(errno)); 92 } 93 ksft_print_msg("ptrace(PTRACE_SINGLESTEP) failed: %s\n", 94 strerror(errno)); 95 return false; 96 } 97 98 wpid = waitpid(pid, &status, __WALL); 99 if (wpid != pid) { 100 ksft_print_msg("waitpid() failed: $s\n", strerror(errno)); 101 return false; 102 } 103 if (WIFEXITED(status)) { 104 ksft_print_msg("child did not single-step: %s\n", 105 strerror(errno)); 106 return false; 107 } 108 if (!WIFSTOPPED(status)) { 109 ksft_print_msg("child did not stop: %s\n", strerror(errno)); 110 return false; 111 } 112 if (WSTOPSIG(status) != SIGTRAP) { 113 ksft_print_msg("child did not stop with SIGTRAP: %s\n", 114 strerror(errno)); 115 return false; 116 } 117 118 if (ptrace(PTRACE_CONT, pid, NULL, NULL) < 0) { 119 ksft_print_msg("ptrace(PTRACE_CONT) failed: %s\n", 120 strerror(errno)); 121 return false; 122 } 123 124 wpid = waitpid(pid, &status, __WALL); 125 if (wpid != pid) { 126 ksft_print_msg("waitpid() failed: %s\n", strerror(errno)); 127 return false; 128 } 129 if (!WIFEXITED(status)) { 130 ksft_print_msg("child did not exit after PTRACE_CONT: %s\n", 131 strerror(errno)); 132 return false; 133 } 134 135 return true; 136 } 137 138 void suspend(void) 139 { 140 int power_state_fd; 141 struct sigevent event = {}; 142 int timerfd; 143 int err; 144 struct itimerspec spec = {}; 145 146 if (getuid() != 0) 147 ksft_exit_skip("Please run the test as root - Exiting.\n"); 148 149 power_state_fd = open("/sys/power/state", O_RDWR); 150 if (power_state_fd < 0) 151 ksft_exit_fail_msg( 152 "open(\"/sys/power/state\") failed %s)\n", 153 strerror(errno)); 154 155 timerfd = timerfd_create(CLOCK_BOOTTIME_ALARM, 0); 156 if (timerfd < 0) 157 ksft_exit_fail_msg("timerfd_create() failed\n"); 158 159 spec.it_value.tv_sec = 5; 160 err = timerfd_settime(timerfd, 0, &spec, NULL); 161 if (err < 0) 162 ksft_exit_fail_msg("timerfd_settime() failed\n"); 163 164 if (write(power_state_fd, "mem", strlen("mem")) != strlen("mem")) 165 ksft_exit_fail_msg("Failed to enter Suspend state\n"); 166 167 close(timerfd); 168 close(power_state_fd); 169 } 170 171 int main(int argc, char **argv) 172 { 173 int opt; 174 bool do_suspend = true; 175 bool succeeded = true; 176 cpu_set_t available_cpus; 177 int err; 178 int cpu; 179 180 ksft_print_header(); 181 182 while ((opt = getopt(argc, argv, "n")) != -1) { 183 switch (opt) { 184 case 'n': 185 do_suspend = false; 186 break; 187 default: 188 printf("Usage: %s [-n]\n", argv[0]); 189 printf(" -n: do not trigger a suspend/resume cycle before the test\n"); 190 return -1; 191 } 192 } 193 194 if (do_suspend) 195 suspend(); 196 197 err = sched_getaffinity(0, sizeof(available_cpus), &available_cpus); 198 if (err < 0) 199 ksft_exit_fail_msg("sched_getaffinity() failed\n"); 200 201 for (cpu = 0; cpu < CPU_SETSIZE; cpu++) { 202 bool test_success; 203 204 if (!CPU_ISSET(cpu, &available_cpus)) 205 continue; 206 207 test_success = run_test(cpu); 208 if (test_success) { 209 ksft_test_result_pass("CPU %d\n", cpu); 210 } else { 211 ksft_test_result_fail("CPU %d\n", cpu); 212 succeeded = false; 213 } 214 } 215 216 if (succeeded) 217 ksft_exit_pass(); 218 else 219 ksft_exit_fail(); 220 } 221