diff options
Diffstat (limited to 'tools/testing/selftests/powerpc/harness.c')
-rw-r--r-- | tools/testing/selftests/powerpc/harness.c | 133 |
1 files changed, 133 insertions, 0 deletions
diff --git a/tools/testing/selftests/powerpc/harness.c b/tools/testing/selftests/powerpc/harness.c new file mode 100644 index 0000000000..5876220d8f --- /dev/null +++ b/tools/testing/selftests/powerpc/harness.c @@ -0,0 +1,133 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright 2013, Michael Ellerman, IBM Corp. + */ + +#include <errno.h> +#include <signal.h> +#include <stdbool.h> +#include <stdio.h> +#include <stdlib.h> +#include <sys/types.h> +#include <sys/wait.h> +#include <unistd.h> +#include <elf.h> +#include <fcntl.h> +#include <link.h> +#include <sys/stat.h> + +#include "subunit.h" +#include "utils.h" + +#define KILL_TIMEOUT 5 + +/* Setting timeout to -1 disables the alarm */ +static uint64_t timeout = 120; + +int run_test(int (test_function)(void), const char *name) +{ + bool terminated; + int rc, status; + pid_t pid; + + /* Make sure output is flushed before forking */ + fflush(stdout); + + pid = fork(); + if (pid == 0) { + setpgid(0, 0); + exit(test_function()); + } else if (pid == -1) { + perror("fork"); + return 1; + } + + setpgid(pid, pid); + + if (timeout != -1) + /* Wake us up in timeout seconds */ + alarm(timeout); + terminated = false; + +wait: + rc = waitpid(pid, &status, 0); + if (rc == -1) { + if (errno != EINTR) { + printf("unknown error from waitpid\n"); + return 1; + } + + if (terminated) { + printf("!! force killing %s\n", name); + kill(-pid, SIGKILL); + return 1; + } else { + printf("!! killing %s\n", name); + kill(-pid, SIGTERM); + terminated = true; + alarm(KILL_TIMEOUT); + goto wait; + } + } + + /* Kill anything else in the process group that is still running */ + kill(-pid, SIGTERM); + + if (WIFEXITED(status)) + status = WEXITSTATUS(status); + else { + if (WIFSIGNALED(status)) + printf("!! child died by signal %d\n", WTERMSIG(status)); + else + printf("!! child died by unknown cause\n"); + + status = 1; /* Signal or other */ + } + + return status; +} + +static void sig_handler(int signum) +{ + /* Just wake us up from waitpid */ +} + +static struct sigaction sig_action = { + .sa_handler = sig_handler, +}; + +void test_harness_set_timeout(uint64_t time) +{ + timeout = time; +} + +int test_harness(int (test_function)(void), const char *name) +{ + int rc; + + test_start(name); + test_set_git_version(GIT_VERSION); + + if (sigaction(SIGINT, &sig_action, NULL)) { + perror("sigaction (sigint)"); + test_error(name); + return 1; + } + + if (sigaction(SIGALRM, &sig_action, NULL)) { + perror("sigaction (sigalrm)"); + test_error(name); + return 1; + } + + rc = run_test(test_function, name); + + if (rc == MAGIC_SKIP_RETURN_VALUE) { + test_skip(name); + /* so that skipped test is not marked as failed */ + rc = 0; + } else + test_finish(name, rc); + + return rc; +} |