134 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*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 523 24/* Setting timeout to -1 disables the alarm */25static uint64_t timeout = 120;26 27int run_test(int (test_function)(void), const 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 else82 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), const 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 } else130 test_finish(name, rc);131 132 return rc;133}134