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