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 setpgid(0, 0); 34 exit(test_function()); 35 } else if (pid == -1) { 36 perror("fork"); 37 return 1; 38 } 39 40 setpgid(pid, pid); 41 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); 56 kill(-pid, SIGKILL); 57 return 1; 58 } else { 59 printf("!! killing %s\n", name); 60 kill(-pid, SIGTERM); 61 terminated = true; 62 alarm(KILL_TIMEOUT); 63 goto wait; 64 } 65 } 66 67 /* Kill anything else in the process group that is still running */ 68 kill(-pid, SIGTERM); 69 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 108 if (rc == MAGIC_SKIP_RETURN_VALUE) 109 test_skip(name); 110 else 111 test_finish(name, rc); 112 113 return rc; 114 } 115