]>
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> | |
2b03fc1d S |
14 | #include <elf.h> |
15 | #include <fcntl.h> | |
16 | #include <link.h> | |
17 | #include <sys/stat.h> | |
2fae0d7c ME |
18 | |
19 | #include "subunit.h" | |
20 | #include "utils.h" | |
21 | ||
2fae0d7c ME |
22 | #define KILL_TIMEOUT 5 |
23 | ||
0886c6d4 | 24 | static uint64_t timeout = 120; |
2fae0d7c ME |
25 | |
26 | int run_test(int (test_function)(void), char *name) | |
27 | { | |
28 | bool terminated; | |
29 | int rc, status; | |
30 | pid_t pid; | |
31 | ||
32 | /* Make sure output is flushed before forking */ | |
33 | fflush(stdout); | |
34 | ||
35 | pid = fork(); | |
36 | if (pid == 0) { | |
de506f73 | 37 | setpgid(0, 0); |
2fae0d7c ME |
38 | exit(test_function()); |
39 | } else if (pid == -1) { | |
40 | perror("fork"); | |
41 | return 1; | |
42 | } | |
43 | ||
de506f73 ME |
44 | setpgid(pid, pid); |
45 | ||
2fae0d7c | 46 | /* Wake us up in timeout seconds */ |
0886c6d4 | 47 | alarm(timeout); |
2fae0d7c ME |
48 | terminated = false; |
49 | ||
50 | wait: | |
51 | rc = waitpid(pid, &status, 0); | |
52 | if (rc == -1) { | |
53 | if (errno != EINTR) { | |
54 | printf("unknown error from waitpid\n"); | |
55 | return 1; | |
56 | } | |
57 | ||
58 | if (terminated) { | |
59 | printf("!! force killing %s\n", name); | |
de506f73 | 60 | kill(-pid, SIGKILL); |
2fae0d7c ME |
61 | return 1; |
62 | } else { | |
63 | printf("!! killing %s\n", name); | |
de506f73 | 64 | kill(-pid, SIGTERM); |
2fae0d7c ME |
65 | terminated = true; |
66 | alarm(KILL_TIMEOUT); | |
67 | goto wait; | |
68 | } | |
69 | } | |
70 | ||
de506f73 ME |
71 | /* Kill anything else in the process group that is still running */ |
72 | kill(-pid, SIGTERM); | |
73 | ||
2fae0d7c ME |
74 | if (WIFEXITED(status)) |
75 | status = WEXITSTATUS(status); | |
76 | else { | |
77 | if (WIFSIGNALED(status)) | |
78 | printf("!! child died by signal %d\n", WTERMSIG(status)); | |
79 | else | |
80 | printf("!! child died by unknown cause\n"); | |
81 | ||
82 | status = 1; /* Signal or other */ | |
83 | } | |
84 | ||
85 | return status; | |
86 | } | |
87 | ||
88 | static void alarm_handler(int signum) | |
89 | { | |
90 | /* Jut wake us up from waitpid */ | |
91 | } | |
92 | ||
93 | static struct sigaction alarm_action = { | |
94 | .sa_handler = alarm_handler, | |
95 | }; | |
96 | ||
0886c6d4 CB |
97 | void test_harness_set_timeout(uint64_t time) |
98 | { | |
99 | timeout = time; | |
100 | } | |
101 | ||
2fae0d7c ME |
102 | int test_harness(int (test_function)(void), char *name) |
103 | { | |
104 | int rc; | |
105 | ||
106 | test_start(name); | |
107 | test_set_git_version(GIT_VERSION); | |
108 | ||
109 | if (sigaction(SIGALRM, &alarm_action, NULL)) { | |
110 | perror("sigaction"); | |
111 | test_error(name); | |
112 | return 1; | |
113 | } | |
114 | ||
115 | rc = run_test(test_function, name); | |
116 | ||
a6d8a215 | 117 | if (rc == MAGIC_SKIP_RETURN_VALUE) { |
33b4819f | 118 | test_skip(name); |
a6d8a215 SS |
119 | /* so that skipped test is not marked as failed */ |
120 | rc = 0; | |
121 | } else | |
33b4819f | 122 | test_finish(name, rc); |
2fae0d7c ME |
123 | |
124 | return rc; | |
125 | } |