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) {
33 		exit(test_function());
34 	} else if (pid == -1) {
35 		perror("fork");
36 		return 1;
37 	}
38 
39 	/* Wake us up in timeout seconds */
40 	alarm(TIMEOUT);
41 	terminated = false;
42 
43 wait:
44 	rc = waitpid(pid, &status, 0);
45 	if (rc == -1) {
46 		if (errno != EINTR) {
47 			printf("unknown error from waitpid\n");
48 			return 1;
49 		}
50 
51 		if (terminated) {
52 			printf("!! force killing %s\n", name);
53 			kill(pid, SIGKILL);
54 			return 1;
55 		} else {
56 			printf("!! killing %s\n", name);
57 			kill(pid, SIGTERM);
58 			terminated = true;
59 			alarm(KILL_TIMEOUT);
60 			goto wait;
61 		}
62 	}
63 
64 	if (WIFEXITED(status))
65 		status = WEXITSTATUS(status);
66 	else {
67 		if (WIFSIGNALED(status))
68 			printf("!! child died by signal %d\n", WTERMSIG(status));
69 		else
70 			printf("!! child died by unknown cause\n");
71 
72 		status = 1; /* Signal or other */
73 	}
74 
75 	return status;
76 }
77 
78 static void alarm_handler(int signum)
79 {
80 	/* Jut wake us up from waitpid */
81 }
82 
83 static struct sigaction alarm_action = {
84 	.sa_handler = alarm_handler,
85 };
86 
87 int test_harness(int (test_function)(void), char *name)
88 {
89 	int rc;
90 
91 	test_start(name);
92 	test_set_git_version(GIT_VERSION);
93 
94 	if (sigaction(SIGALRM, &alarm_action, NULL)) {
95 		perror("sigaction");
96 		test_error(name);
97 		return 1;
98 	}
99 
100 	rc = run_test(test_function, name);
101 
102 	test_finish(name, rc);
103 
104 	return rc;
105 }
106