xref: /linux/tools/testing/selftests/arm64/gcs/gcs-stress.c (revision 60675d4ca1ef0857e44eba5849b74a3a998d0c0f)
105e6cfffSMark Brown // SPDX-License-Identifier: GPL-2.0-only
205e6cfffSMark Brown /*
305e6cfffSMark Brown  * Copyright (C) 2022-3 ARM Limited.
405e6cfffSMark Brown  */
505e6cfffSMark Brown 
605e6cfffSMark Brown #define _GNU_SOURCE
705e6cfffSMark Brown #define _POSIX_C_SOURCE 199309L
805e6cfffSMark Brown 
905e6cfffSMark Brown #include <errno.h>
1005e6cfffSMark Brown #include <getopt.h>
1105e6cfffSMark Brown #include <poll.h>
1205e6cfffSMark Brown #include <signal.h>
1305e6cfffSMark Brown #include <stdbool.h>
1405e6cfffSMark Brown #include <stddef.h>
1505e6cfffSMark Brown #include <stdio.h>
1605e6cfffSMark Brown #include <stdlib.h>
1705e6cfffSMark Brown #include <string.h>
1805e6cfffSMark Brown #include <unistd.h>
1905e6cfffSMark Brown #include <sys/auxv.h>
2005e6cfffSMark Brown #include <sys/epoll.h>
2105e6cfffSMark Brown #include <sys/prctl.h>
2205e6cfffSMark Brown #include <sys/types.h>
2305e6cfffSMark Brown #include <sys/uio.h>
2405e6cfffSMark Brown #include <sys/wait.h>
2505e6cfffSMark Brown #include <asm/hwcap.h>
2605e6cfffSMark Brown 
2705e6cfffSMark Brown #include "../../kselftest.h"
2805e6cfffSMark Brown 
2905e6cfffSMark Brown struct child_data {
3005e6cfffSMark Brown 	char *name, *output;
3105e6cfffSMark Brown 	pid_t pid;
3205e6cfffSMark Brown 	int stdout;
3305e6cfffSMark Brown 	bool output_seen;
3405e6cfffSMark Brown 	bool exited;
3505e6cfffSMark Brown 	int exit_status;
3605e6cfffSMark Brown 	int exit_signal;
3705e6cfffSMark Brown };
3805e6cfffSMark Brown 
3905e6cfffSMark Brown static int epoll_fd;
4005e6cfffSMark Brown static struct child_data *children;
4105e6cfffSMark Brown static struct epoll_event *evs;
4205e6cfffSMark Brown static int tests;
4305e6cfffSMark Brown static int num_children;
4405e6cfffSMark Brown static bool terminate;
4505e6cfffSMark Brown 
4605e6cfffSMark Brown static int startup_pipe[2];
4705e6cfffSMark Brown 
4805e6cfffSMark Brown static int num_processors(void)
4905e6cfffSMark Brown {
5005e6cfffSMark Brown 	long nproc = sysconf(_SC_NPROCESSORS_CONF);
5105e6cfffSMark Brown 	if (nproc < 0) {
5205e6cfffSMark Brown 		perror("Unable to read number of processors\n");
5305e6cfffSMark Brown 		exit(EXIT_FAILURE);
5405e6cfffSMark Brown 	}
5505e6cfffSMark Brown 
5605e6cfffSMark Brown 	return nproc;
5705e6cfffSMark Brown }
5805e6cfffSMark Brown 
599b9be782SMark Brown static void start_thread(struct child_data *child, int id)
6005e6cfffSMark Brown {
6105e6cfffSMark Brown 	int ret, pipefd[2], i;
6205e6cfffSMark Brown 	struct epoll_event ev;
6305e6cfffSMark Brown 
6405e6cfffSMark Brown 	ret = pipe(pipefd);
6505e6cfffSMark Brown 	if (ret != 0)
6605e6cfffSMark Brown 		ksft_exit_fail_msg("Failed to create stdout pipe: %s (%d)\n",
6705e6cfffSMark Brown 				   strerror(errno), errno);
6805e6cfffSMark Brown 
6905e6cfffSMark Brown 	child->pid = fork();
7005e6cfffSMark Brown 	if (child->pid == -1)
7105e6cfffSMark Brown 		ksft_exit_fail_msg("fork() failed: %s (%d)\n",
7205e6cfffSMark Brown 				   strerror(errno), errno);
7305e6cfffSMark Brown 
7405e6cfffSMark Brown 	if (!child->pid) {
7505e6cfffSMark Brown 		/*
7605e6cfffSMark Brown 		 * In child, replace stdout with the pipe, errors to
7705e6cfffSMark Brown 		 * stderr from here as kselftest prints to stdout.
7805e6cfffSMark Brown 		 */
7905e6cfffSMark Brown 		ret = dup2(pipefd[1], 1);
8005e6cfffSMark Brown 		if (ret == -1) {
8105e6cfffSMark Brown 			fprintf(stderr, "dup2() %d\n", errno);
8205e6cfffSMark Brown 			exit(EXIT_FAILURE);
8305e6cfffSMark Brown 		}
8405e6cfffSMark Brown 
8505e6cfffSMark Brown 		/*
8605e6cfffSMark Brown 		 * Duplicate the read side of the startup pipe to
8705e6cfffSMark Brown 		 * FD 3 so we can close everything else.
8805e6cfffSMark Brown 		 */
8905e6cfffSMark Brown 		ret = dup2(startup_pipe[0], 3);
9005e6cfffSMark Brown 		if (ret == -1) {
9105e6cfffSMark Brown 			fprintf(stderr, "dup2() %d\n", errno);
9205e6cfffSMark Brown 			exit(EXIT_FAILURE);
9305e6cfffSMark Brown 		}
9405e6cfffSMark Brown 
9505e6cfffSMark Brown 		/*
9605e6cfffSMark Brown 		 * Very dumb mechanism to clean open FDs other than
9705e6cfffSMark Brown 		 * stdio. We don't want O_CLOEXEC for the pipes...
9805e6cfffSMark Brown 		 */
9905e6cfffSMark Brown 		for (i = 4; i < 8192; i++)
10005e6cfffSMark Brown 			close(i);
10105e6cfffSMark Brown 
10205e6cfffSMark Brown 		/*
10305e6cfffSMark Brown 		 * Read from the startup pipe, there should be no data
10405e6cfffSMark Brown 		 * and we should block until it is closed.  We just
10505e6cfffSMark Brown 		 * carry on on error since this isn't super critical.
10605e6cfffSMark Brown 		 */
10705e6cfffSMark Brown 		ret = read(3, &i, sizeof(i));
10805e6cfffSMark Brown 		if (ret < 0)
10905e6cfffSMark Brown 			fprintf(stderr, "read(startp pipe) failed: %s (%d)\n",
11005e6cfffSMark Brown 				strerror(errno), errno);
11105e6cfffSMark Brown 		if (ret > 0)
11205e6cfffSMark Brown 			fprintf(stderr, "%d bytes of data on startup pipe\n",
11305e6cfffSMark Brown 				ret);
11405e6cfffSMark Brown 		close(3);
11505e6cfffSMark Brown 
11605e6cfffSMark Brown 		ret = execl("gcs-stress-thread", "gcs-stress-thread", NULL);
11705e6cfffSMark Brown 		fprintf(stderr, "execl(gcs-stress-thread) failed: %d (%s)\n",
11805e6cfffSMark Brown 			errno, strerror(errno));
11905e6cfffSMark Brown 
12005e6cfffSMark Brown 		exit(EXIT_FAILURE);
12105e6cfffSMark Brown 	} else {
12205e6cfffSMark Brown 		/*
12305e6cfffSMark Brown 		 * In parent, remember the child and close our copy of the
12405e6cfffSMark Brown 		 * write side of stdout.
12505e6cfffSMark Brown 		 */
12605e6cfffSMark Brown 		close(pipefd[1]);
12705e6cfffSMark Brown 		child->stdout = pipefd[0];
12805e6cfffSMark Brown 		child->output = NULL;
12905e6cfffSMark Brown 		child->exited = false;
13005e6cfffSMark Brown 		child->output_seen = false;
13105e6cfffSMark Brown 
13205e6cfffSMark Brown 		ev.events = EPOLLIN | EPOLLHUP;
13305e6cfffSMark Brown 		ev.data.ptr = child;
13405e6cfffSMark Brown 
1359b9be782SMark Brown 		ret = asprintf(&child->name, "Thread-%d", id);
13605e6cfffSMark Brown 		if (ret == -1)
13705e6cfffSMark Brown 			ksft_exit_fail_msg("asprintf() failed\n");
13805e6cfffSMark Brown 
13905e6cfffSMark Brown 		ret = epoll_ctl(epoll_fd, EPOLL_CTL_ADD, child->stdout, &ev);
14005e6cfffSMark Brown 		if (ret < 0) {
14105e6cfffSMark Brown 			ksft_exit_fail_msg("%s EPOLL_CTL_ADD failed: %s (%d)\n",
14205e6cfffSMark Brown 					   child->name, strerror(errno), errno);
14305e6cfffSMark Brown 		}
14405e6cfffSMark Brown 	}
14505e6cfffSMark Brown 
14605e6cfffSMark Brown 	ksft_print_msg("Started %s\n", child->name);
14705e6cfffSMark Brown 	num_children++;
14805e6cfffSMark Brown }
14905e6cfffSMark Brown 
15005e6cfffSMark Brown static bool child_output_read(struct child_data *child)
15105e6cfffSMark Brown {
15205e6cfffSMark Brown 	char read_data[1024];
15305e6cfffSMark Brown 	char work[1024];
15405e6cfffSMark Brown 	int ret, len, cur_work, cur_read;
15505e6cfffSMark Brown 
15605e6cfffSMark Brown 	ret = read(child->stdout, read_data, sizeof(read_data));
15705e6cfffSMark Brown 	if (ret < 0) {
15805e6cfffSMark Brown 		if (errno == EINTR)
15905e6cfffSMark Brown 			return true;
16005e6cfffSMark Brown 
16105e6cfffSMark Brown 		ksft_print_msg("%s: read() failed: %s (%d)\n",
16205e6cfffSMark Brown 			       child->name, strerror(errno),
16305e6cfffSMark Brown 			       errno);
16405e6cfffSMark Brown 		return false;
16505e6cfffSMark Brown 	}
16605e6cfffSMark Brown 	len = ret;
16705e6cfffSMark Brown 
16805e6cfffSMark Brown 	child->output_seen = true;
16905e6cfffSMark Brown 
17005e6cfffSMark Brown 	/* Pick up any partial read */
17105e6cfffSMark Brown 	if (child->output) {
17205e6cfffSMark Brown 		strncpy(work, child->output, sizeof(work) - 1);
17305e6cfffSMark Brown 		cur_work = strnlen(work, sizeof(work));
17405e6cfffSMark Brown 		free(child->output);
17505e6cfffSMark Brown 		child->output = NULL;
17605e6cfffSMark Brown 	} else {
17705e6cfffSMark Brown 		cur_work = 0;
17805e6cfffSMark Brown 	}
17905e6cfffSMark Brown 
18005e6cfffSMark Brown 	cur_read = 0;
18105e6cfffSMark Brown 	while (cur_read < len) {
18205e6cfffSMark Brown 		work[cur_work] = read_data[cur_read++];
18305e6cfffSMark Brown 
18405e6cfffSMark Brown 		if (work[cur_work] == '\n') {
18505e6cfffSMark Brown 			work[cur_work] = '\0';
18605e6cfffSMark Brown 			ksft_print_msg("%s: %s\n", child->name, work);
18705e6cfffSMark Brown 			cur_work = 0;
18805e6cfffSMark Brown 		} else {
18905e6cfffSMark Brown 			cur_work++;
19005e6cfffSMark Brown 		}
19105e6cfffSMark Brown 	}
19205e6cfffSMark Brown 
19305e6cfffSMark Brown 	if (cur_work) {
19405e6cfffSMark Brown 		work[cur_work] = '\0';
19505e6cfffSMark Brown 		ret = asprintf(&child->output, "%s", work);
19605e6cfffSMark Brown 		if (ret == -1)
19705e6cfffSMark Brown 			ksft_exit_fail_msg("Out of memory\n");
19805e6cfffSMark Brown 	}
19905e6cfffSMark Brown 
20005e6cfffSMark Brown 	return false;
20105e6cfffSMark Brown }
20205e6cfffSMark Brown 
20305e6cfffSMark Brown static void child_output(struct child_data *child, uint32_t events,
20405e6cfffSMark Brown 			 bool flush)
20505e6cfffSMark Brown {
20605e6cfffSMark Brown 	bool read_more;
20705e6cfffSMark Brown 
20805e6cfffSMark Brown 	if (events & EPOLLIN) {
20905e6cfffSMark Brown 		do {
21005e6cfffSMark Brown 			read_more = child_output_read(child);
21105e6cfffSMark Brown 		} while (read_more);
21205e6cfffSMark Brown 	}
21305e6cfffSMark Brown 
21405e6cfffSMark Brown 	if (events & EPOLLHUP) {
21505e6cfffSMark Brown 		close(child->stdout);
21605e6cfffSMark Brown 		child->stdout = -1;
21705e6cfffSMark Brown 		flush = true;
21805e6cfffSMark Brown 	}
21905e6cfffSMark Brown 
22005e6cfffSMark Brown 	if (flush && child->output) {
22105e6cfffSMark Brown 		ksft_print_msg("%s: %s<EOF>\n", child->name, child->output);
22205e6cfffSMark Brown 		free(child->output);
22305e6cfffSMark Brown 		child->output = NULL;
22405e6cfffSMark Brown 	}
22505e6cfffSMark Brown }
22605e6cfffSMark Brown 
22705e6cfffSMark Brown static void child_tickle(struct child_data *child)
22805e6cfffSMark Brown {
22905e6cfffSMark Brown 	if (child->output_seen && !child->exited)
23005e6cfffSMark Brown 		kill(child->pid, SIGUSR1);
23105e6cfffSMark Brown }
23205e6cfffSMark Brown 
23305e6cfffSMark Brown static void child_stop(struct child_data *child)
23405e6cfffSMark Brown {
23505e6cfffSMark Brown 	if (!child->exited)
23605e6cfffSMark Brown 		kill(child->pid, SIGTERM);
23705e6cfffSMark Brown }
23805e6cfffSMark Brown 
23905e6cfffSMark Brown static void child_cleanup(struct child_data *child)
24005e6cfffSMark Brown {
24105e6cfffSMark Brown 	pid_t ret;
24205e6cfffSMark Brown 	int status;
24305e6cfffSMark Brown 	bool fail = false;
24405e6cfffSMark Brown 
24505e6cfffSMark Brown 	if (!child->exited) {
24605e6cfffSMark Brown 		do {
24705e6cfffSMark Brown 			ret = waitpid(child->pid, &status, 0);
24805e6cfffSMark Brown 			if (ret == -1 && errno == EINTR)
24905e6cfffSMark Brown 				continue;
25005e6cfffSMark Brown 
25105e6cfffSMark Brown 			if (ret == -1) {
25205e6cfffSMark Brown 				ksft_print_msg("waitpid(%d) failed: %s (%d)\n",
25305e6cfffSMark Brown 					       child->pid, strerror(errno),
25405e6cfffSMark Brown 					       errno);
25505e6cfffSMark Brown 				fail = true;
25605e6cfffSMark Brown 				break;
25705e6cfffSMark Brown 			}
25805e6cfffSMark Brown 
25905e6cfffSMark Brown 			if (WIFEXITED(status)) {
26005e6cfffSMark Brown 				child->exit_status = WEXITSTATUS(status);
26105e6cfffSMark Brown 				child->exited = true;
26205e6cfffSMark Brown 			}
26305e6cfffSMark Brown 
26405e6cfffSMark Brown 			if (WIFSIGNALED(status)) {
26505e6cfffSMark Brown 				child->exit_signal = WTERMSIG(status);
26605e6cfffSMark Brown 				ksft_print_msg("%s: Exited due to signal %d\n",
267*016d659eSCatalin Marinas 					       child->name, child->exit_signal);
26805e6cfffSMark Brown 				fail = true;
26905e6cfffSMark Brown 				child->exited = true;
27005e6cfffSMark Brown 			}
27105e6cfffSMark Brown 		} while (!child->exited);
27205e6cfffSMark Brown 	}
27305e6cfffSMark Brown 
27405e6cfffSMark Brown 	if (!child->output_seen) {
27505e6cfffSMark Brown 		ksft_print_msg("%s no output seen\n", child->name);
27605e6cfffSMark Brown 		fail = true;
27705e6cfffSMark Brown 	}
27805e6cfffSMark Brown 
27905e6cfffSMark Brown 	if (child->exit_status != 0) {
28005e6cfffSMark Brown 		ksft_print_msg("%s exited with error code %d\n",
28105e6cfffSMark Brown 			       child->name, child->exit_status);
28205e6cfffSMark Brown 		fail = true;
28305e6cfffSMark Brown 	}
28405e6cfffSMark Brown 
28505e6cfffSMark Brown 	ksft_test_result(!fail, "%s\n", child->name);
28605e6cfffSMark Brown }
28705e6cfffSMark Brown 
28805e6cfffSMark Brown static void handle_child_signal(int sig, siginfo_t *info, void *context)
28905e6cfffSMark Brown {
29005e6cfffSMark Brown 	int i;
29105e6cfffSMark Brown 	bool found = false;
29205e6cfffSMark Brown 
29305e6cfffSMark Brown 	for (i = 0; i < num_children; i++) {
29405e6cfffSMark Brown 		if (children[i].pid == info->si_pid) {
29505e6cfffSMark Brown 			children[i].exited = true;
29605e6cfffSMark Brown 			children[i].exit_status = info->si_status;
29705e6cfffSMark Brown 			found = true;
29805e6cfffSMark Brown 			break;
29905e6cfffSMark Brown 		}
30005e6cfffSMark Brown 	}
30105e6cfffSMark Brown 
30205e6cfffSMark Brown 	if (!found)
30305e6cfffSMark Brown 		ksft_print_msg("SIGCHLD for unknown PID %d with status %d\n",
30405e6cfffSMark Brown 			       info->si_pid, info->si_status);
30505e6cfffSMark Brown }
30605e6cfffSMark Brown 
30705e6cfffSMark Brown static void handle_exit_signal(int sig, siginfo_t *info, void *context)
30805e6cfffSMark Brown {
30905e6cfffSMark Brown 	int i;
31005e6cfffSMark Brown 
31105e6cfffSMark Brown 	/* If we're already exiting then don't signal again */
31205e6cfffSMark Brown 	if (terminate)
31305e6cfffSMark Brown 		return;
31405e6cfffSMark Brown 
31505e6cfffSMark Brown 	ksft_print_msg("Got signal, exiting...\n");
31605e6cfffSMark Brown 
31705e6cfffSMark Brown 	terminate = true;
31805e6cfffSMark Brown 
31905e6cfffSMark Brown 	/*
32005e6cfffSMark Brown 	 * This should be redundant, the main loop should clean up
32105e6cfffSMark Brown 	 * after us, but for safety stop everything we can here.
32205e6cfffSMark Brown 	 */
32305e6cfffSMark Brown 	for (i = 0; i < num_children; i++)
32405e6cfffSMark Brown 		child_stop(&children[i]);
32505e6cfffSMark Brown }
32605e6cfffSMark Brown 
32705e6cfffSMark Brown /* Handle any pending output without blocking */
32805e6cfffSMark Brown static void drain_output(bool flush)
32905e6cfffSMark Brown {
33005e6cfffSMark Brown 	int ret = 1;
33105e6cfffSMark Brown 	int i;
33205e6cfffSMark Brown 
33305e6cfffSMark Brown 	while (ret > 0) {
33405e6cfffSMark Brown 		ret = epoll_wait(epoll_fd, evs, tests, 0);
33505e6cfffSMark Brown 		if (ret < 0) {
33605e6cfffSMark Brown 			if (errno == EINTR)
33705e6cfffSMark Brown 				continue;
33805e6cfffSMark Brown 			ksft_print_msg("epoll_wait() failed: %s (%d)\n",
33905e6cfffSMark Brown 				       strerror(errno), errno);
34005e6cfffSMark Brown 		}
34105e6cfffSMark Brown 
34205e6cfffSMark Brown 		for (i = 0; i < ret; i++)
34305e6cfffSMark Brown 			child_output(evs[i].data.ptr, evs[i].events, flush);
34405e6cfffSMark Brown 	}
34505e6cfffSMark Brown }
34605e6cfffSMark Brown 
34705e6cfffSMark Brown static const struct option options[] = {
34805e6cfffSMark Brown 	{ "timeout",	required_argument, NULL, 't' },
34905e6cfffSMark Brown 	{ }
35005e6cfffSMark Brown };
35105e6cfffSMark Brown 
35205e6cfffSMark Brown int main(int argc, char **argv)
35305e6cfffSMark Brown {
35405e6cfffSMark Brown 	int seen_children;
35505e6cfffSMark Brown 	bool all_children_started = false;
35605e6cfffSMark Brown 	int gcs_threads;
35705e6cfffSMark Brown 	int timeout = 10;
35805e6cfffSMark Brown 	int ret, cpus, i, c;
35905e6cfffSMark Brown 	struct sigaction sa;
36005e6cfffSMark Brown 
36105e6cfffSMark Brown 	while ((c = getopt_long(argc, argv, "t:", options, NULL)) != -1) {
36205e6cfffSMark Brown 		switch (c) {
36305e6cfffSMark Brown 		case 't':
36405e6cfffSMark Brown 			ret = sscanf(optarg, "%d", &timeout);
36505e6cfffSMark Brown 			if (ret != 1)
36605e6cfffSMark Brown 				ksft_exit_fail_msg("Failed to parse timeout %s\n",
36705e6cfffSMark Brown 						   optarg);
36805e6cfffSMark Brown 			break;
36905e6cfffSMark Brown 		default:
37005e6cfffSMark Brown 			ksft_exit_fail_msg("Unknown argument\n");
37105e6cfffSMark Brown 		}
37205e6cfffSMark Brown 	}
37305e6cfffSMark Brown 
37405e6cfffSMark Brown 	cpus = num_processors();
37505e6cfffSMark Brown 	tests = 0;
37605e6cfffSMark Brown 
37705e6cfffSMark Brown 	if (getauxval(AT_HWCAP) & HWCAP_GCS) {
37805e6cfffSMark Brown 		/* One extra thread, trying to trigger migrations */
37905e6cfffSMark Brown 		gcs_threads = cpus + 1;
38005e6cfffSMark Brown 		tests += gcs_threads;
38105e6cfffSMark Brown 	} else {
38205e6cfffSMark Brown 		gcs_threads = 0;
38305e6cfffSMark Brown 	}
38405e6cfffSMark Brown 
38505e6cfffSMark Brown 	ksft_print_header();
38605e6cfffSMark Brown 	ksft_set_plan(tests);
38705e6cfffSMark Brown 
38805e6cfffSMark Brown 	ksft_print_msg("%d CPUs, %d GCS threads\n",
38905e6cfffSMark Brown 		       cpus, gcs_threads);
39005e6cfffSMark Brown 
39105e6cfffSMark Brown 	if (!tests)
39205e6cfffSMark Brown 		ksft_exit_skip("No tests scheduled\n");
39305e6cfffSMark Brown 
39405e6cfffSMark Brown 	if (timeout > 0)
39505e6cfffSMark Brown 		ksft_print_msg("Will run for %ds\n", timeout);
39605e6cfffSMark Brown 	else
39705e6cfffSMark Brown 		ksft_print_msg("Will run until terminated\n");
39805e6cfffSMark Brown 
39905e6cfffSMark Brown 	children = calloc(sizeof(*children), tests);
40005e6cfffSMark Brown 	if (!children)
40105e6cfffSMark Brown 		ksft_exit_fail_msg("Unable to allocate child data\n");
40205e6cfffSMark Brown 
40305e6cfffSMark Brown 	ret = epoll_create1(EPOLL_CLOEXEC);
40405e6cfffSMark Brown 	if (ret < 0)
40505e6cfffSMark Brown 		ksft_exit_fail_msg("epoll_create1() failed: %s (%d)\n",
40605e6cfffSMark Brown 				   strerror(errno), ret);
40705e6cfffSMark Brown 	epoll_fd = ret;
40805e6cfffSMark Brown 
40905e6cfffSMark Brown 	/* Create a pipe which children will block on before execing */
41005e6cfffSMark Brown 	ret = pipe(startup_pipe);
41105e6cfffSMark Brown 	if (ret != 0)
41205e6cfffSMark Brown 		ksft_exit_fail_msg("Failed to create startup pipe: %s (%d)\n",
41305e6cfffSMark Brown 				   strerror(errno), errno);
41405e6cfffSMark Brown 
41505e6cfffSMark Brown 	/* Get signal handers ready before we start any children */
41605e6cfffSMark Brown 	memset(&sa, 0, sizeof(sa));
41705e6cfffSMark Brown 	sa.sa_sigaction = handle_exit_signal;
41805e6cfffSMark Brown 	sa.sa_flags = SA_RESTART | SA_SIGINFO;
41905e6cfffSMark Brown 	sigemptyset(&sa.sa_mask);
42005e6cfffSMark Brown 	ret = sigaction(SIGINT, &sa, NULL);
42105e6cfffSMark Brown 	if (ret < 0)
42205e6cfffSMark Brown 		ksft_print_msg("Failed to install SIGINT handler: %s (%d)\n",
42305e6cfffSMark Brown 			       strerror(errno), errno);
42405e6cfffSMark Brown 	ret = sigaction(SIGTERM, &sa, NULL);
42505e6cfffSMark Brown 	if (ret < 0)
42605e6cfffSMark Brown 		ksft_print_msg("Failed to install SIGTERM handler: %s (%d)\n",
42705e6cfffSMark Brown 			       strerror(errno), errno);
42805e6cfffSMark Brown 	sa.sa_sigaction = handle_child_signal;
42905e6cfffSMark Brown 	ret = sigaction(SIGCHLD, &sa, NULL);
43005e6cfffSMark Brown 	if (ret < 0)
43105e6cfffSMark Brown 		ksft_print_msg("Failed to install SIGCHLD handler: %s (%d)\n",
43205e6cfffSMark Brown 			       strerror(errno), errno);
43305e6cfffSMark Brown 
43405e6cfffSMark Brown 	evs = calloc(tests, sizeof(*evs));
43505e6cfffSMark Brown 	if (!evs)
43605e6cfffSMark Brown 		ksft_exit_fail_msg("Failed to allocated %d epoll events\n",
43705e6cfffSMark Brown 				   tests);
43805e6cfffSMark Brown 
43905e6cfffSMark Brown 	for (i = 0; i < gcs_threads; i++)
4409b9be782SMark Brown 		start_thread(&children[i], i);
44105e6cfffSMark Brown 
44205e6cfffSMark Brown 	/*
44305e6cfffSMark Brown 	 * All children started, close the startup pipe and let them
44405e6cfffSMark Brown 	 * run.
44505e6cfffSMark Brown 	 */
44605e6cfffSMark Brown 	close(startup_pipe[0]);
44705e6cfffSMark Brown 	close(startup_pipe[1]);
44805e6cfffSMark Brown 
44905e6cfffSMark Brown 	timeout *= 10;
45005e6cfffSMark Brown 	for (;;) {
45105e6cfffSMark Brown 		/* Did we get a signal asking us to exit? */
45205e6cfffSMark Brown 		if (terminate)
45305e6cfffSMark Brown 			break;
45405e6cfffSMark Brown 
45505e6cfffSMark Brown 		/*
45605e6cfffSMark Brown 		 * Timeout is counted in 100ms with no output, the
45705e6cfffSMark Brown 		 * tests print during startup then are silent when
45805e6cfffSMark Brown 		 * running so this should ensure they all ran enough
45905e6cfffSMark Brown 		 * to install the signal handler, this is especially
46005e6cfffSMark Brown 		 * useful in emulation where we will both be slow and
46105e6cfffSMark Brown 		 * likely to have a large set of VLs.
46205e6cfffSMark Brown 		 */
46305e6cfffSMark Brown 		ret = epoll_wait(epoll_fd, evs, tests, 100);
46405e6cfffSMark Brown 		if (ret < 0) {
46505e6cfffSMark Brown 			if (errno == EINTR)
46605e6cfffSMark Brown 				continue;
46705e6cfffSMark Brown 			ksft_exit_fail_msg("epoll_wait() failed: %s (%d)\n",
46805e6cfffSMark Brown 					   strerror(errno), errno);
46905e6cfffSMark Brown 		}
47005e6cfffSMark Brown 
47105e6cfffSMark Brown 		/* Output? */
47205e6cfffSMark Brown 		if (ret > 0) {
47305e6cfffSMark Brown 			for (i = 0; i < ret; i++) {
47405e6cfffSMark Brown 				child_output(evs[i].data.ptr, evs[i].events,
47505e6cfffSMark Brown 					     false);
47605e6cfffSMark Brown 			}
47705e6cfffSMark Brown 			continue;
47805e6cfffSMark Brown 		}
47905e6cfffSMark Brown 
48005e6cfffSMark Brown 		/* Otherwise epoll_wait() timed out */
48105e6cfffSMark Brown 
48205e6cfffSMark Brown 		/*
48305e6cfffSMark Brown 		 * If the child processes have not produced output they
48405e6cfffSMark Brown 		 * aren't actually running the tests yet.
48505e6cfffSMark Brown 		 */
48605e6cfffSMark Brown 		if (!all_children_started) {
48705e6cfffSMark Brown 			seen_children = 0;
48805e6cfffSMark Brown 
48905e6cfffSMark Brown 			for (i = 0; i < num_children; i++)
49005e6cfffSMark Brown 				if (children[i].output_seen ||
49105e6cfffSMark Brown 				    children[i].exited)
49205e6cfffSMark Brown 					seen_children++;
49305e6cfffSMark Brown 
49405e6cfffSMark Brown 			if (seen_children != num_children) {
49505e6cfffSMark Brown 				ksft_print_msg("Waiting for %d children\n",
49605e6cfffSMark Brown 					       num_children - seen_children);
49705e6cfffSMark Brown 				continue;
49805e6cfffSMark Brown 			}
49905e6cfffSMark Brown 
50005e6cfffSMark Brown 			all_children_started = true;
50105e6cfffSMark Brown 		}
50205e6cfffSMark Brown 
50305e6cfffSMark Brown 		ksft_print_msg("Sending signals, timeout remaining: %d00ms\n",
50405e6cfffSMark Brown 			       timeout);
50505e6cfffSMark Brown 
50605e6cfffSMark Brown 		for (i = 0; i < num_children; i++)
50705e6cfffSMark Brown 			child_tickle(&children[i]);
50805e6cfffSMark Brown 
50905e6cfffSMark Brown 		/* Negative timeout means run indefinitely */
51005e6cfffSMark Brown 		if (timeout < 0)
51105e6cfffSMark Brown 			continue;
51205e6cfffSMark Brown 		if (--timeout == 0)
51305e6cfffSMark Brown 			break;
51405e6cfffSMark Brown 	}
51505e6cfffSMark Brown 
51605e6cfffSMark Brown 	ksft_print_msg("Finishing up...\n");
51705e6cfffSMark Brown 	terminate = true;
51805e6cfffSMark Brown 
51905e6cfffSMark Brown 	for (i = 0; i < tests; i++)
52005e6cfffSMark Brown 		child_stop(&children[i]);
52105e6cfffSMark Brown 
52205e6cfffSMark Brown 	drain_output(false);
52305e6cfffSMark Brown 
52405e6cfffSMark Brown 	for (i = 0; i < tests; i++)
52505e6cfffSMark Brown 		child_cleanup(&children[i]);
52605e6cfffSMark Brown 
52705e6cfffSMark Brown 	drain_output(true);
52805e6cfffSMark Brown 
52905e6cfffSMark Brown 	ksft_finished();
53005e6cfffSMark Brown }
531