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