test: fix race conditions in test-async

This commit is contained in:
Ben Noordhuis 2012-04-17 15:58:19 +02:00
parent d5e7786885
commit 5345ee36f2
4 changed files with 44 additions and 241 deletions

View File

@ -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);

View File

@ -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);

View File

@ -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);

View File

@ -24,192 +24,90 @@
#include <stdio.h>
#include <stdlib.h>
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;