xref: /linux/tools/testing/selftests/breakpoints/step_after_suspend_test.c (revision 5d7f3375cd574fc83f0cd30839b21455c0e79ae2)
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 #include <time.h>
22 
23 #include "kselftest.h"
24 
25 void child(int cpu)
26 {
27 	cpu_set_t set;
28 
29 	CPU_ZERO(&set);
30 	CPU_SET(cpu, &set);
31 	if (sched_setaffinity(0, sizeof(set), &set) != 0) {
32 		ksft_print_msg("sched_setaffinity() failed: %s\n",
33 			strerror(errno));
34 		_exit(1);
35 	}
36 
37 	if (ptrace(PTRACE_TRACEME, 0, NULL, NULL) != 0) {
38 		ksft_print_msg("ptrace(PTRACE_TRACEME) failed: %s\n",
39 			strerror(errno));
40 		_exit(1);
41 	}
42 
43 	if (raise(SIGSTOP) != 0) {
44 		ksft_print_msg("raise(SIGSTOP) failed: %s\n", strerror(errno));
45 		_exit(1);
46 	}
47 
48 	_exit(0);
49 }
50 
51 int run_test(int cpu)
52 {
53 	int status;
54 	pid_t pid = fork();
55 	pid_t wpid;
56 
57 	if (pid < 0) {
58 		ksft_print_msg("fork() failed: %s\n", strerror(errno));
59 		return KSFT_FAIL;
60 	}
61 	if (pid == 0)
62 		child(cpu);
63 
64 	wpid = waitpid(pid, &status, __WALL);
65 	if (wpid != pid) {
66 		ksft_print_msg("waitpid() failed: %s\n", strerror(errno));
67 		return KSFT_FAIL;
68 	}
69 	if (!WIFSTOPPED(status)) {
70 		ksft_print_msg("child did not stop: %s\n", strerror(errno));
71 		return KSFT_FAIL;
72 	}
73 	if (WSTOPSIG(status) != SIGSTOP) {
74 		ksft_print_msg("child did not stop with SIGSTOP: %s\n",
75 			strerror(errno));
76 		return KSFT_FAIL;
77 	}
78 
79 	if (ptrace(PTRACE_SINGLESTEP, pid, NULL, NULL) < 0) {
80 		if (errno == EIO) {
81 			ksft_print_msg(
82 				"ptrace(PTRACE_SINGLESTEP) not supported on this architecture: %s\n",
83 				strerror(errno));
84 			return KSFT_SKIP;
85 		}
86 		ksft_print_msg("ptrace(PTRACE_SINGLESTEP) failed: %s\n",
87 			strerror(errno));
88 		return KSFT_FAIL;
89 	}
90 
91 	wpid = waitpid(pid, &status, __WALL);
92 	if (wpid != pid) {
93 		ksft_print_msg("waitpid() failed: %s\n", strerror(errno));
94 		return KSFT_FAIL;
95 	}
96 	if (WIFEXITED(status)) {
97 		ksft_print_msg("child did not single-step: %s\n",
98 			strerror(errno));
99 		return KSFT_FAIL;
100 	}
101 	if (!WIFSTOPPED(status)) {
102 		ksft_print_msg("child did not stop: %s\n", strerror(errno));
103 		return KSFT_FAIL;
104 	}
105 	if (WSTOPSIG(status) != SIGTRAP) {
106 		ksft_print_msg("child did not stop with SIGTRAP: %s\n",
107 			strerror(errno));
108 		return KSFT_FAIL;
109 	}
110 
111 	if (ptrace(PTRACE_CONT, pid, NULL, NULL) < 0) {
112 		ksft_print_msg("ptrace(PTRACE_CONT) failed: %s\n",
113 			strerror(errno));
114 		return KSFT_FAIL;
115 	}
116 
117 	wpid = waitpid(pid, &status, __WALL);
118 	if (wpid != pid) {
119 		ksft_print_msg("waitpid() failed: %s\n", strerror(errno));
120 		return KSFT_FAIL;
121 	}
122 	if (!WIFEXITED(status)) {
123 		ksft_print_msg("child did not exit after PTRACE_CONT: %s\n",
124 			strerror(errno));
125 		return KSFT_FAIL;
126 	}
127 
128 	return KSFT_PASS;
129 }
130 
131 /*
132  * Reads the suspend success count from sysfs.
133  * Returns the count on success or exits on failure.
134  */
135 static int get_suspend_success_count_or_fail(void)
136 {
137 	FILE *fp;
138 	int val;
139 
140 	fp = fopen("/sys/power/suspend_stats/success", "r");
141 	if (!fp)
142 		ksft_exit_fail_msg(
143 			"Failed to open suspend_stats/success: %s\n",
144 			strerror(errno));
145 
146 	if (fscanf(fp, "%d", &val) != 1) {
147 		fclose(fp);
148 		ksft_exit_fail_msg(
149 			"Failed to read suspend success count\n");
150 	}
151 
152 	fclose(fp);
153 	return val;
154 }
155 
156 void suspend(void)
157 {
158 	int timerfd;
159 	int err;
160 	int count_before;
161 	int count_after;
162 	struct timespec res;
163 	struct itimerspec spec = {};
164 
165 	if (getuid() != 0)
166 		ksft_exit_skip("Please run the test as root - Exiting.\n");
167 
168 	/*
169 	 * CLOCK_BOOTTIME_ALARM cannot wake up systems that don't have a
170 	 * wakeup capable RTC from suspend. Check if we have a wakeup-capable
171 	 * RTC to prevent this test from causing the system to hang after
172 	 * it suspends.
173 	 */
174 	if (clock_getres(CLOCK_BOOTTIME_ALARM, &res) != 0)
175 		ksft_exit_skip("No wakeup-capable RTC for CLOCK_BOOTTIME_ALARM\n");
176 
177 	timerfd = timerfd_create(CLOCK_BOOTTIME_ALARM, 0);
178 	if (timerfd < 0)
179 		ksft_exit_fail_msg("timerfd_create() failed\n");
180 
181 	spec.it_value.tv_sec = 5;
182 	err = timerfd_settime(timerfd, 0, &spec, NULL);
183 	if (err < 0)
184 		ksft_exit_fail_msg("timerfd_settime() failed\n");
185 
186 	count_before = get_suspend_success_count_or_fail();
187 
188 	system("(echo mem > /sys/power/state) 2> /dev/null");
189 
190 	count_after = get_suspend_success_count_or_fail();
191 	if (count_after <= count_before)
192 		ksft_exit_fail_msg("Failed to enter Suspend state\n");
193 
194 	close(timerfd);
195 }
196 
197 int main(int argc, char **argv)
198 {
199 	int opt;
200 	bool do_suspend = true;
201 	bool succeeded = true;
202 	unsigned int tests = 0;
203 	cpu_set_t available_cpus;
204 	int err;
205 	int cpu;
206 
207 	ksft_print_header();
208 
209 	while ((opt = getopt(argc, argv, "n")) != -1) {
210 		switch (opt) {
211 		case 'n':
212 			do_suspend = false;
213 			break;
214 		default:
215 			printf("Usage: %s [-n]\n", argv[0]);
216 			printf("        -n: do not trigger a suspend/resume cycle before the test\n");
217 			return -1;
218 		}
219 	}
220 
221 	err = sched_getaffinity(0, sizeof(available_cpus), &available_cpus);
222 	if (err < 0)
223 		ksft_exit_fail_msg("sched_getaffinity() failed\n");
224 
225 	for (cpu = 0; cpu < CPU_SETSIZE; cpu++) {
226 		if (!CPU_ISSET(cpu, &available_cpus))
227 			continue;
228 		tests++;
229 	}
230 
231 	if (do_suspend)
232 		suspend();
233 
234 	ksft_set_plan(tests);
235 	for (cpu = 0; cpu < CPU_SETSIZE; cpu++) {
236 		int test_success;
237 
238 		if (!CPU_ISSET(cpu, &available_cpus))
239 			continue;
240 
241 		test_success = run_test(cpu);
242 		switch (test_success) {
243 		case KSFT_PASS:
244 			ksft_test_result_pass("CPU %d\n", cpu);
245 			break;
246 		case KSFT_SKIP:
247 			ksft_test_result_skip("CPU %d\n", cpu);
248 			break;
249 		case KSFT_FAIL:
250 			ksft_test_result_fail("CPU %d\n", cpu);
251 			succeeded = false;
252 			break;
253 		}
254 	}
255 
256 	if (succeeded)
257 		ksft_exit_pass();
258 	else
259 		ksft_exit_fail();
260 }
261