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