brintos

brintos / linux-shallow public Read only

0
0
Text · 4.8 KiB · 8d275f0 Raw
229 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * Copyright (C) 2016 Google, Inc.4 */5 6#define _GNU_SOURCE7 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 24void 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 50int 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 130void 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 165int 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	else227		ksft_exit_fail();228}229