Permalink
Browse files

unix runner: implement timeout on process_wait

  • Loading branch information...
1 parent 1d9e185 commit b4836377f99ff8fcefb879f7bdcea552dd8a81c6 @ry ry committed Apr 26, 2011
Showing with 118 additions and 15 deletions.
  1. +4 −2 Makefile
  2. +2 −2 test/run-tests.c
  3. +112 −9 test/runner-unix.c
  4. +0 −2 test/test-list.h
View
@@ -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
View
@@ -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;
}
-}
+}
View
@@ -30,6 +30,10 @@
#include <signal.h>
#include <sys/wait.h>
#include <sys/stat.h>
+#include <assert.h>
+
+#include <sys/select.h>
+#include <pthread.h>
#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;
+ 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;
+ }
+
+ /* 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;
}
- p->terminated = 1;
}
- return 0;
+
+terminate:
+ close(args.pipe[0]);
+ close(args.pipe[1]);
+ return retval;
}
View
@@ -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)

0 comments on commit b483637

Please sign in to comment.