harness.c (2412B)
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 */ 25static uint64_t timeout = 120; 26 27int 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 52wait: 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 90static void sig_handler(int signum) 91{ 92 /* Just wake us up from waitpid */ 93} 94 95static struct sigaction sig_action = { 96 .sa_handler = sig_handler, 97}; 98 99void test_harness_set_timeout(uint64_t time) 100{ 101 timeout = time; 102} 103 104int 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}