1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * Copyright (C) 2016 Google, Inc. 4 */ 5 6 #define _GNU_SOURCE 7 8 #include <errno.h> 9 #include <fcntl.h> 10 #include <sched.h> 11 #include <signal.h> 12 #include <stdbool.h> 13 #include <stdio.h> 14 #include <string.h> 15 #include <unistd.h> 16 #include <sys/ptrace.h> 17 #include <sys/stat.h> 18 #include <sys/timerfd.h> 19 #include <sys/types.h> 20 #include <sys/wait.h> 21 22 #include "../kselftest.h" 23 24 void child(int cpu) 25 { 26 cpu_set_t set; 27 28 CPU_ZERO(&set); 29 CPU_SET(cpu, &set); 30 if (sched_setaffinity(0, sizeof(set), &set) != 0) { 31 ksft_print_msg("sched_setaffinity() failed: %s\n", 32 strerror(errno)); 33 _exit(1); 34 } 35 36 if (ptrace(PTRACE_TRACEME, 0, NULL, NULL) != 0) { 37 ksft_print_msg("ptrace(PTRACE_TRACEME) failed: %s\n", 38 strerror(errno)); 39 _exit(1); 40 } 41 42 if (raise(SIGSTOP) != 0) { 43 ksft_print_msg("raise(SIGSTOP) failed: %s\n", strerror(errno)); 44 _exit(1); 45 } 46 47 _exit(0); 48 } 49 50 int run_test(int cpu) 51 { 52 int status; 53 pid_t pid = fork(); 54 pid_t wpid; 55 56 if (pid < 0) { 57 ksft_print_msg("fork() failed: %s\n", strerror(errno)); 58 return KSFT_FAIL; 59 } 60 if (pid == 0) 61 child(cpu); 62 63 wpid = waitpid(pid, &status, __WALL); 64 if (wpid != pid) { 65 ksft_print_msg("waitpid() failed: %s\n", strerror(errno)); 66 return KSFT_FAIL; 67 } 68 if (!WIFSTOPPED(status)) { 69 ksft_print_msg("child did not stop: %s\n", strerror(errno)); 70 return KSFT_FAIL; 71 } 72 if (WSTOPSIG(status) != SIGSTOP) { 73 ksft_print_msg("child did not stop with SIGSTOP: %s\n", 74 strerror(errno)); 75 return KSFT_FAIL; 76 } 77 78 if (ptrace(PTRACE_SINGLESTEP, pid, NULL, NULL) < 0) { 79 if (errno == EIO) { 80 ksft_print_msg( 81 "ptrace(PTRACE_SINGLESTEP) not supported on this architecture: %s\n", 82 strerror(errno)); 83 return KSFT_SKIP; 84 } 85 ksft_print_msg("ptrace(PTRACE_SINGLESTEP) failed: %s\n", 86 strerror(errno)); 87 return KSFT_FAIL; 88 } 89 90 wpid = waitpid(pid, &status, __WALL); 91 if (wpid != pid) { 92 ksft_print_msg("waitpid() failed: %s\n", strerror(errno)); 93 return KSFT_FAIL; 94 } 95 if (WIFEXITED(status)) { 96 ksft_print_msg("child did not single-step: %s\n", 97 strerror(errno)); 98 return KSFT_FAIL; 99 } 100 if (!WIFSTOPPED(status)) { 101 ksft_print_msg("child did not stop: %s\n", strerror(errno)); 102 return KSFT_FAIL; 103 } 104 if (WSTOPSIG(status) != SIGTRAP) { 105 ksft_print_msg("child did not stop with SIGTRAP: %s\n", 106 strerror(errno)); 107 return KSFT_FAIL; 108 } 109 110 if (ptrace(PTRACE_CONT, pid, NULL, NULL) < 0) { 111 ksft_print_msg("ptrace(PTRACE_CONT) failed: %s\n", 112 strerror(errno)); 113 return KSFT_FAIL; 114 } 115 116 wpid = waitpid(pid, &status, __WALL); 117 if (wpid != pid) { 118 ksft_print_msg("waitpid() failed: %s\n", strerror(errno)); 119 return KSFT_FAIL; 120 } 121 if (!WIFEXITED(status)) { 122 ksft_print_msg("child did not exit after PTRACE_CONT: %s\n", 123 strerror(errno)); 124 return KSFT_FAIL; 125 } 126 127 return KSFT_PASS; 128 } 129 130 void suspend(void) 131 { 132 int power_state_fd; 133 int timerfd; 134 int err; 135 struct itimerspec spec = {}; 136 137 if (getuid() != 0) 138 ksft_exit_skip("Please run the test as root - Exiting.\n"); 139 140 power_state_fd = open("/sys/power/state", O_RDWR); 141 if (power_state_fd < 0) 142 ksft_exit_fail_msg( 143 "open(\"/sys/power/state\") failed %s)\n", 144 strerror(errno)); 145 146 timerfd = timerfd_create(CLOCK_BOOTTIME_ALARM, 0); 147 if (timerfd < 0) 148 ksft_exit_fail_msg("timerfd_create() failed\n"); 149 150 spec.it_value.tv_sec = 5; 151 err = timerfd_settime(timerfd, 0, &spec, NULL); 152 if (err < 0) 153 ksft_exit_fail_msg("timerfd_settime() failed\n"); 154 155 system("(echo mem > /sys/power/state) 2> /dev/null"); 156 157 timerfd_gettime(timerfd, &spec); 158 if (spec.it_value.tv_sec != 0 || spec.it_value.tv_nsec != 0) 159 ksft_exit_fail_msg("Failed to enter Suspend state\n"); 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 unsigned int tests = 0; 171 cpu_set_t available_cpus; 172 int err; 173 int cpu; 174 175 ksft_print_header(); 176 177 while ((opt = getopt(argc, argv, "n")) != -1) { 178 switch (opt) { 179 case 'n': 180 do_suspend = false; 181 break; 182 default: 183 printf("Usage: %s [-n]\n", argv[0]); 184 printf(" -n: do not trigger a suspend/resume cycle before the test\n"); 185 return -1; 186 } 187 } 188 189 err = sched_getaffinity(0, sizeof(available_cpus), &available_cpus); 190 if (err < 0) 191 ksft_exit_fail_msg("sched_getaffinity() failed\n"); 192 193 for (cpu = 0; cpu < CPU_SETSIZE; cpu++) { 194 if (!CPU_ISSET(cpu, &available_cpus)) 195 continue; 196 tests++; 197 } 198 199 if (do_suspend) 200 suspend(); 201 202 ksft_set_plan(tests); 203 for (cpu = 0; cpu < CPU_SETSIZE; cpu++) { 204 int test_success; 205 206 if (!CPU_ISSET(cpu, &available_cpus)) 207 continue; 208 209 test_success = run_test(cpu); 210 switch (test_success) { 211 case KSFT_PASS: 212 ksft_test_result_pass("CPU %d\n", cpu); 213 break; 214 case KSFT_SKIP: 215 ksft_test_result_skip("CPU %d\n", cpu); 216 break; 217 case KSFT_FAIL: 218 ksft_test_result_fail("CPU %d\n", cpu); 219 succeeded = false; 220 break; 221 } 222 } 223 224 if (succeeded) 225 ksft_exit_pass(); 226 else 227 ksft_exit_fail(); 228 } 229
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.