From 5345ee36f2fd49ae01a1ee6fe396ffb8291b6641 Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Tue, 17 Apr 2012 15:58:19 +0200 Subject: [PATCH] test: fix race conditions in test-async --- test/runner-unix.c | 24 ------ test/runner-win.c | 63 --------------- test/task.h | 8 -- test/test-async.c | 190 +++++++++++---------------------------------- 4 files changed, 44 insertions(+), 241 deletions(-) diff --git a/test/runner-unix.c b/test/runner-unix.c index 3c78bb50..8d57202e 100644 --- a/test/runner-unix.c +++ b/test/runner-unix.c @@ -285,30 +285,6 @@ void rewind_cursor() { } -typedef void* (*uv_thread_cb)(void* arg); - - -uintptr_t uv_create_thread(void (*entry)(void* arg), void* arg) { - pthread_t t; - uv_thread_cb cb = (uv_thread_cb)entry; - int r = pthread_create(&t, NULL, cb, arg); - - if (r) { - return 0; - } - - return (uintptr_t)t; -} - - -/* Wait for a thread to terminate. Should return 0 if the thread ended, -1 on - * error. - */ -int uv_wait_thread(uintptr_t thread_id) { - return pthread_join((pthread_t)thread_id, NULL); -} - - /* Pause the calling thread for a number of milliseconds. */ void uv_sleep(int msec) { usleep(msec * 1000); diff --git a/test/runner-win.c b/test/runner-win.c index d2a986a7..e758dd1d 100644 --- a/test/runner-win.c +++ b/test/runner-win.c @@ -274,69 +274,6 @@ void rewind_cursor() { } -typedef struct { - void (*entry)(void* arg); - void* arg; -} thread_info_t; - - -static unsigned __stdcall create_thread_helper(void* info) { - /* Copy thread info locally, then free it */ - void (*entry)(void* arg) = ((thread_info_t*) info)->entry; - void* arg = ((thread_info_t*) info)->arg; - - free(info); - - /* Run the actual thread proc */ - entry(arg); - - /* Finalize */ - _endthreadex(0); - return 0; -} - - -/* Create a thread. Returns the thread identifier, or 0 on failure. */ -uintptr_t uv_create_thread(void (*entry)(void* arg), void* arg) { - uintptr_t result; - thread_info_t* info; - - info = (thread_info_t*) malloc(sizeof *info); - if (info == NULL) { - return 0; - } - - info->entry = entry; - info->arg = arg; - - result = _beginthreadex(NULL, - 0, - &create_thread_helper, - (void*) info, - 0, - NULL); - - if (result == 0) { - free(info); - return 0; - } - - return result; -} - - -/* Wait for a thread to terminate. Should return 0 if the thread ended, -1 on - * error. - */ -int uv_wait_thread(uintptr_t thread_id) { - if (WaitForSingleObject((HANDLE)thread_id, INFINITE) != WAIT_OBJECT_0) { - return -1; - } - - return 0; -} - - /* Pause the calling thread for a number of milliseconds. */ void uv_sleep(int msec) { Sleep(msec); diff --git a/test/task.h b/test/task.h index a7938e60..04497342 100644 --- a/test/task.h +++ b/test/task.h @@ -103,14 +103,6 @@ typedef enum { int run_helper_##name() -/* Create a thread. Returns the thread identifier, or 0 on failure. */ -uintptr_t uv_create_thread(void (*entry)(void* arg), void* arg); - -/* Wait for a thread to terminate. Should return 0 if the thread ended, -1 on - * error. - */ -int uv_wait_thread(uintptr_t thread_id); - /* Pause the calling thread for a number of milliseconds. */ void uv_sleep(int msec); diff --git a/test/test-async.c b/test/test-async.c index 3d841518..c6bd71b9 100644 --- a/test/test-async.c +++ b/test/test-async.c @@ -24,192 +24,90 @@ #include #include +static uv_thread_t thread; +static uv_mutex_t mutex; -static uv_prepare_t prepare_handle; +static uv_prepare_t prepare; +static uv_async_t async; -static uv_async_t async1_handle; -/* static uv_handle_t async2_handle; */ - -static int prepare_cb_called = 0; - -static volatile int async1_cb_called = 0; -static int async1_closed = 0; -/* static volatile int async2_cb_called = 0; */ - -static int close_cb_called = 0; - -static uintptr_t thread1_id = 0; -#if 0 -static uintptr_t thread2_id = 0; -static uintptr_t thread3_id = 0; -#endif +static volatile int async_cb_called; +static int prepare_cb_called; +static int close_cb_called; -/* Thread 1 makes sure that async1_cb_called reaches 3 before exiting. */ -void thread1_entry(void *arg) { - uv_sleep(50); +void thread_cb(void *arg) { + int n; + int r; - while (1) { - switch (async1_cb_called) { - case 0: - uv_async_send(&async1_handle); - break; + do { + uv_mutex_lock(&mutex); + n = async_cb_called; + uv_mutex_unlock(&mutex); - case 1: - uv_async_send(&async1_handle); - break; - - case 2: - uv_async_send(&async1_handle); - break; - - default: - return; - } + r = uv_async_send(&async); + ASSERT(r == 0); } + while (n < 3); } -#if 0 -/* Thread 2 calls uv_async_send on async_handle_2 8 times. */ -void thread2_entry(void *arg) { - int i; - - while (1) { - switch (async1_cb_called) { - case 0: - uv_async_send(&async2_handle); - break; - - case 1: - uv_async_send(&async2_handle); - break; - - case 2: - uv_async_send(&async2_handle); - break; - } - uv_sleep(5); - } - - if (async1_cb_called == 20) { - uv_close(handle); - } -} - - -/* Thread 3 calls uv_async_send on async_handle_2 8 times - * after waiting half a second first. - */ -void thread3_entry(void *arg) { - int i; - - for (i = 0; i < 8; i++) { - uv_async_send(&async2_handle); - } -} -#endif - - static void close_cb(uv_handle_t* handle) { ASSERT(handle != NULL); close_cb_called++; } -static void async1_cb(uv_async_t* handle, int status) { - ASSERT(handle == &async1_handle); +static void async_cb(uv_async_t* handle, int status) { + int n; + + ASSERT(handle == &async); ASSERT(status == 0); - async1_cb_called++; - printf("async1_cb #%d\n", async1_cb_called); + uv_mutex_lock(&mutex); + n = ++async_cb_called; + uv_mutex_unlock(&mutex); - if (async1_cb_called > 2 && !async1_closed) { - async1_closed = 1; - uv_close((uv_handle_t*)handle, close_cb); + if (n == 3) { + uv_close((uv_handle_t*)&async, close_cb); + uv_close((uv_handle_t*)&prepare, close_cb); } } -#if 0 -static void async2_cb(uv_handle_t* handle, int status) { - ASSERT(handle == &async2_handle); - ASSERT(status == 0); - - async2_cb_called++; - printf("async2_cb #%d\n", async2_cb_called); - - if (async2_cb_called == 16) { - uv_close(handle); - } -} -#endif - - static void prepare_cb(uv_prepare_t* handle, int status) { - ASSERT(handle == &prepare_handle); + int r; + + ASSERT(handle == &prepare); ASSERT(status == 0); - switch (prepare_cb_called) { - case 0: - thread1_id = uv_create_thread(thread1_entry, NULL); - ASSERT(thread1_id != 0); - break; + if (prepare_cb_called++) + return; -#if 0 - case 1: - thread2_id = uv_create_thread(thread2_entry, NULL); - ASSERT(thread2_id != 0); - break; - - case 2: - thread3_id = uv_create_thread(thread3_entry, NULL); - ASSERT(thread3_id != 0); - break; -#endif - - case 1: - uv_close((uv_handle_t*)handle, close_cb); - break; - - default: - FATAL("Should never get here"); - } - - prepare_cb_called++; + r = uv_thread_create(&thread, thread_cb, NULL); + ASSERT(r == 0); + uv_mutex_unlock(&mutex); } TEST_IMPL(async) { int r; - r = uv_prepare_init(uv_default_loop(), &prepare_handle); + r = uv_mutex_init(&mutex); ASSERT(r == 0); - r = uv_prepare_start(&prepare_handle, prepare_cb); + uv_mutex_lock(&mutex); + + r = uv_prepare_init(uv_default_loop(), &prepare); + ASSERT(r == 0); + r = uv_prepare_start(&prepare, prepare_cb); ASSERT(r == 0); - r = uv_async_init(uv_default_loop(), &async1_handle, async1_cb); + r = uv_async_init(uv_default_loop(), &async, async_cb); ASSERT(r == 0); -#if 0 - r = uv_async_init(&async2_handle, async2_cb, close_cb, NULL); - ASSERT(r == 0); -#endif - r = uv_run(uv_default_loop()); ASSERT(r == 0); - r = uv_wait_thread(thread1_id); - ASSERT(r == 0); -#if 0 - r = uv_wait_thread(thread2_id); - ASSERT(r == 0); - r = uv_wait_thread(thread3_id); - ASSERT(r == 0); -#endif - - ASSERT(prepare_cb_called == 2); - ASSERT(async1_cb_called > 2); - /* ASSERT(async2_cb_called = 16); */ + ASSERT(prepare_cb_called > 0); + ASSERT(async_cb_called == 3); ASSERT(close_cb_called == 2); return 0;