mirror of https://github.com/Qortal/Brooklyn
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
133 lines
2.4 KiB
133 lines
2.4 KiB
// 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), 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), 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; |
|
}
|
|
|