2013-08-06 17:42:36 +10:00
/*
* Copyright 2013 , Michael Ellerman , IBM Corp .
* Licensed under GPLv2 .
*/
# include <errno.h>
# include <signal.h>
# include <stdbool.h>
# include <stdio.h>
# include <stdlib.h>
# include <sys/types.h>
# include <sys/wait.h>
# include <unistd.h>
# include "subunit.h"
# include "utils.h"
# define TIMEOUT 120
# define KILL_TIMEOUT 5
int run_test ( int ( test_function ) ( void ) , char * name )
{
bool terminated ;
int rc , status ;
pid_t pid ;
/* Make sure output is flushed before forking */
fflush ( stdout ) ;
pid = fork ( ) ;
if ( pid = = 0 ) {
2014-06-10 22:23:08 +10:00
setpgid ( 0 , 0 ) ;
2013-08-06 17:42:36 +10:00
exit ( test_function ( ) ) ;
} else if ( pid = = - 1 ) {
perror ( " fork " ) ;
return 1 ;
}
2014-06-10 22:23:08 +10:00
setpgid ( pid , pid ) ;
2013-08-06 17:42:36 +10:00
/* Wake us up in timeout seconds */
alarm ( TIMEOUT ) ;
terminated = false ;
wait :
rc = waitpid ( pid , & status , 0 ) ;
if ( rc = = - 1 ) {
if ( errno ! = EINTR ) {
printf ( " unknown error from waitpid \n " ) ;
return 1 ;
}
if ( terminated ) {
printf ( " !! force killing %s \n " , name ) ;
2014-06-10 22:23:08 +10:00
kill ( - pid , SIGKILL ) ;
2013-08-06 17:42:36 +10:00
return 1 ;
} else {
printf ( " !! killing %s \n " , name ) ;
2014-06-10 22:23:08 +10:00
kill ( - pid , SIGTERM ) ;
2013-08-06 17:42:36 +10:00
terminated = true ;
alarm ( KILL_TIMEOUT ) ;
goto wait ;
}
}
2014-06-10 22:23:08 +10:00
/* Kill anything else in the process group that is still running */
kill ( - pid , SIGTERM ) ;
2013-08-06 17:42:36 +10:00
if ( WIFEXITED ( status ) )
status = WEXITSTATUS ( status ) ;
else {
if ( WIFSIGNALED ( status ) )
printf ( " !! child died by signal %d \n " , WTERMSIG ( status ) ) ;
else
printf ( " !! child died by unknown cause \n " ) ;
status = 1 ; /* Signal or other */
}
return status ;
}
static void alarm_handler ( int signum )
{
/* Jut wake us up from waitpid */
}
static struct sigaction alarm_action = {
. sa_handler = alarm_handler ,
} ;
int test_harness ( int ( test_function ) ( void ) , char * name )
{
int rc ;
test_start ( name ) ;
test_set_git_version ( GIT_VERSION ) ;
if ( sigaction ( SIGALRM , & alarm_action , NULL ) ) {
perror ( " sigaction " ) ;
test_error ( name ) ;
return 1 ;
}
rc = run_test ( test_function , name ) ;
2014-06-10 22:23:09 +10:00
if ( rc = = MAGIC_SKIP_RETURN_VALUE )
test_skip ( name ) ;
else
test_finish ( name , rc ) ;
2013-08-06 17:42:36 +10:00
return rc ;
}