Commit | Line | Data |
---|---|---|
2fae0d7c ME |
1 | /* |
2 | * Copyright 2013, Michael Ellerman, IBM Corp. | |
3 | * Licensed under GPLv2. | |
4 | */ | |
5 | ||
6 | #include <errno.h> | |
7 | #include <signal.h> | |
8 | #include <stdbool.h> | |
9 | #include <stdio.h> | |
10 | #include <stdlib.h> | |
11 | #include <sys/types.h> | |
12 | #include <sys/wait.h> | |
13 | #include <unistd.h> | |
14 | ||
15 | #include "subunit.h" | |
16 | #include "utils.h" | |
17 | ||
18 | #define TIMEOUT 120 | |
19 | #define KILL_TIMEOUT 5 | |
20 | ||
21 | ||
22 | int run_test(int (test_function)(void), char *name) | |
23 | { | |
24 | bool terminated; | |
25 | int rc, status; | |
26 | pid_t pid; | |
27 | ||
28 | /* Make sure output is flushed before forking */ | |
29 | fflush(stdout); | |
30 | ||
31 | pid = fork(); | |
32 | if (pid == 0) { | |
de506f73 | 33 | setpgid(0, 0); |
2fae0d7c ME |
34 | exit(test_function()); |
35 | } else if (pid == -1) { | |
36 | perror("fork"); | |
37 | return 1; | |
38 | } | |
39 | ||
de506f73 ME |
40 | setpgid(pid, pid); |
41 | ||
2fae0d7c ME |
42 | /* Wake us up in timeout seconds */ |
43 | alarm(TIMEOUT); | |
44 | terminated = false; | |
45 | ||
46 | wait: | |
47 | rc = waitpid(pid, &status, 0); | |
48 | if (rc == -1) { | |
49 | if (errno != EINTR) { | |
50 | printf("unknown error from waitpid\n"); | |
51 | return 1; | |
52 | } | |
53 | ||
54 | if (terminated) { | |
55 | printf("!! force killing %s\n", name); | |
de506f73 | 56 | kill(-pid, SIGKILL); |
2fae0d7c ME |
57 | return 1; |
58 | } else { | |
59 | printf("!! killing %s\n", name); | |
de506f73 | 60 | kill(-pid, SIGTERM); |
2fae0d7c ME |
61 | terminated = true; |
62 | alarm(KILL_TIMEOUT); | |
63 | goto wait; | |
64 | } | |
65 | } | |
66 | ||
de506f73 ME |
67 | /* Kill anything else in the process group that is still running */ |
68 | kill(-pid, SIGTERM); | |
69 | ||
2fae0d7c ME |
70 | if (WIFEXITED(status)) |
71 | status = WEXITSTATUS(status); | |
72 | else { | |
73 | if (WIFSIGNALED(status)) | |
74 | printf("!! child died by signal %d\n", WTERMSIG(status)); | |
75 | else | |
76 | printf("!! child died by unknown cause\n"); | |
77 | ||
78 | status = 1; /* Signal or other */ | |
79 | } | |
80 | ||
81 | return status; | |
82 | } | |
83 | ||
84 | static void alarm_handler(int signum) | |
85 | { | |
86 | /* Jut wake us up from waitpid */ | |
87 | } | |
88 | ||
89 | static struct sigaction alarm_action = { | |
90 | .sa_handler = alarm_handler, | |
91 | }; | |
92 | ||
93 | int test_harness(int (test_function)(void), char *name) | |
94 | { | |
95 | int rc; | |
96 | ||
97 | test_start(name); | |
98 | test_set_git_version(GIT_VERSION); | |
99 | ||
100 | if (sigaction(SIGALRM, &alarm_action, NULL)) { | |
101 | perror("sigaction"); | |
102 | test_error(name); | |
103 | return 1; | |
104 | } | |
105 | ||
106 | rc = run_test(test_function, name); | |
107 | ||
33b4819f ME |
108 | if (rc == MAGIC_SKIP_RETURN_VALUE) |
109 | test_skip(name); | |
110 | else | |
111 | test_finish(name, rc); | |
2fae0d7c ME |
112 | |
113 | return rc; | |
114 | } |