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 #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), 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), 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