diff --git a/Makefile b/Makefile index 27b045ee..298cddb0 100644 --- a/Makefile +++ b/Makefile @@ -25,12 +25,14 @@ LINKFLAGS=-lm TESTS=test/echo-server.c test/test-*.c BENCHMARKS=test/echo-server.c test/benchmark-*.c +RUNNER_LINKFLAGS=$(LINKFLAGS) -pthread + test/run-tests: test/*.h test/run-tests.c test/runner.c test/runner-unix.c $(TESTS) oio.a - $(CC) $(CFLAGS) $(LINKFLAGS) -o test/run-tests test/run-tests.c \ + $(CC) $(CFLAGS) $(RUNNER_LINKFLAGS) -o test/run-tests test/run-tests.c \ test/runner.c test/runner-unix.c $(TESTS) oio.a test/run-benchmarks: test/*.h test/run-benchmarks.c test/runner.c test/runner-unix.c $(BENCHMARKS) oio.a - $(CC) $(CFLAGS) $(LINKFLAGS) -o test/run-benchmarks test/run-benchmarks.c \ + $(CC) $(CFLAGS) $(RUNNER_LINKFLAGS) -o test/run-benchmarks test/run-benchmarks.c \ test/runner.c test/runner-unix.c $(BENCHMARKS) oio.a oio.a: oio-unix.o ev/ev.o diff --git a/test/run-tests.c b/test/run-tests.c index 18a3727b..95259c82 100644 --- a/test/run-tests.c +++ b/test/run-tests.c @@ -30,7 +30,7 @@ /* The time in milliseconds after which a single test times out. */ -#define TEST_TIMEOUT 20000 +#define TEST_TIMEOUT 5000 static void log_progress(int total, int passed, int failed, char* name) { @@ -81,4 +81,4 @@ int main(int argc, char **argv) { return 0; } -} \ No newline at end of file +} diff --git a/test/runner-unix.c b/test/runner-unix.c index b3bd291b..19a6072a 100644 --- a/test/runner-unix.c +++ b/test/runner-unix.c @@ -30,6 +30,10 @@ #include #include #include +#include + +#include +#include #define PATHMAX 1024 static char executable_path[PATHMAX] = { '\0' }; @@ -92,23 +96,122 @@ int process_start(char* name, process_info_t* p) { } +typedef struct { + int pipe[2]; + process_info_t* vec; + int n; +} dowait_args; + + +/* This function is run inside a pthread. We do this so that we can possibly + * timeout. + */ +static void* dowait(void* data) { + dowait_args* args = data; + + int i, status, r; + process_info_t* p; + + for (i = 0; i < args->n; i++) { + p = (process_info_t*)(args->vec + i * sizeof(process_info_t)); + if (p->terminated) continue; + status = 0; + r = waitpid(p->pid, &p->status, 0); + if (r < 0) { + perror("waitpid"); + return NULL; + } + p->terminated = 1; + } + + if (args->pipe[1] >= 0) { + /* Write a character to the main thread to notify it about this. */ + char c = 0; + write(args->pipe[1], &c, 1); + } + + return NULL; +} + + /* Wait for all `n` processes in `vec` to terminate. */ /* Time out after `timeout` msec, or never if timeout == -1 */ /* Return 0 if all processes are terminated, -1 on error, -2 on timeout. */ int process_wait(process_info_t* vec, int n, int timeout) { int i; process_info_t* p; - for (i = 0; i < n; i++) { - p = (process_info_t*)(vec + i * sizeof(process_info_t)); - if (p->terminated) continue; - int status = 0; - int r = waitpid(p->pid, &(p->status), 0); - if (r < 0) { - return -1; - } - p->terminated = 1; + dowait_args args; + args.vec = vec; + args.n = n; + args.pipe[0] = -1; + args.pipe[1] = -1; + + /* The simple case is where there is no timeout */ + if (timeout == -1) { + dowait(&args); + return 0; } - return 0; + + /* Hard case. Do the wait with a timeout. + * + * Assumption: we are the only ones making this call right now. Otherwise + * we'd need to lock vec. + */ + + pthread_t tid; + int retval; + + int r = pipe((int*)&(args.pipe)); + if (r) { + perror("pipe()"); + return -1; + } + + r = pthread_create(&tid, NULL, dowait, &args); + if (r) { + perror("pthread_create()"); + retval = -1; + goto terminate; + } + + struct timeval tv; + tv.tv_sec = timeout / 1000; + tv.tv_usec = 0; + + fd_set fds; + FD_ZERO(&fds); + FD_SET(args.pipe[0], &fds); + + r = select(args.pipe[0] + 1, &fds, NULL, NULL, &tv); + + if (r == -1) { + perror("select()"); + retval = -1; + + } else if (r) { + /* The thread completed successfully. */ + retval = 0; + + } else { + /* Timeout. Kill all the children. */ + for (i = 0; i < n; i++) { + p = (process_info_t*)(vec + i * sizeof(process_info_t)); + kill(p->pid, SIGTERM); + } + retval = -2; + + /* Wait for thread to finish. */ + r = pthread_join(tid, NULL); + if (r) { + perror("pthread_join"); + retval = -1; + } + } + +terminate: + close(args.pipe[0]); + close(args.pipe[1]); + return retval; } diff --git a/test/test-list.h b/test/test-list.h index 1fe607a3..06c64fd7 100644 --- a/test/test-list.h +++ b/test/test-list.h @@ -40,10 +40,8 @@ TASK_LIST_START TEST_ENTRY (delayed_accept) - /* TEST_ENTRY (tcp_writealot) TEST_HELPER (tcp_writealot, echo_server) - */ TEST_ENTRY (bind_error_access)