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