25
25
#include <stdlib.h>
28
static uv_prepare_t prepare_handle;
30
static uv_async_t async1_handle;
31
/* static uv_handle_t async2_handle; */
33
static int prepare_cb_called = 0;
35
static volatile int async1_cb_called = 0;
36
static int async1_closed = 0;
37
/* static volatile int async2_cb_called = 0; */
39
static int close_cb_called = 0;
41
static uintptr_t thread1_id = 0;
43
static uintptr_t thread2_id = 0;
44
static uintptr_t thread3_id = 0;
48
/* Thread 1 makes sure that async1_cb_called reaches 3 before exiting. */
49
void thread1_entry(void *arg) {
53
switch (async1_cb_called) {
55
uv_async_send(&async1_handle);
59
uv_async_send(&async1_handle);
63
uv_async_send(&async1_handle);
73
/* Thread 2 calls uv_async_send on async_handle_2 8 times. */
74
void thread2_entry(void *arg) {
78
switch (async1_cb_called) {
80
uv_async_send(&async2_handle);
84
uv_async_send(&async2_handle);
88
uv_async_send(&async2_handle);
94
if (async1_cb_called == 20) {
100
/* Thread 3 calls uv_async_send on async_handle_2 8 times
101
* after waiting half a second first.
103
void thread3_entry(void *arg) {
106
for (i = 0; i < 8; i++) {
107
uv_async_send(&async2_handle);
27
static uv_thread_t thread;
28
static uv_mutex_t mutex;
30
static uv_prepare_t prepare;
31
static uv_async_t async;
33
static volatile int async_cb_called;
34
static int prepare_cb_called;
35
static int close_cb_called;
38
static void thread_cb(void *arg) {
43
uv_mutex_lock(&mutex);
45
uv_mutex_unlock(&mutex);
51
r = uv_async_send(&async);
54
/* Work around a bug in Valgrind.
56
* Valgrind runs threads not in parallel but sequentially, i.e. one after
57
* the other. It also doesn't preempt them, instead it depends on threads
58
* yielding voluntarily by making a syscall.
60
* That never happens here: the pipe that is associated with the async
61
* handle is written to once but that's too early for Valgrind's scheduler
62
* to kick in. Afterwards, the thread busy-loops, starving the main thread.
63
* Therefore, we yield.
65
* This behavior has been observed with Valgrind 3.7.0 and 3.9.0.
113
72
static void close_cb(uv_handle_t* handle) {
119
static void async1_cb(uv_async_t* handle, int status) {
120
ASSERT(handle == &async1_handle);
124
printf("async1_cb #%d\n", async1_cb_called);
126
if (async1_cb_called > 2 && !async1_closed) {
128
uv_close((uv_handle_t*)handle, close_cb);
134
static void async2_cb(uv_handle_t* handle, int status) {
135
ASSERT(handle == &async2_handle);
139
printf("async2_cb #%d\n", async2_cb_called);
141
if (async2_cb_called == 16) {
78
static void async_cb(uv_async_t* handle, int status) {
81
ASSERT(handle == &async);
84
uv_mutex_lock(&mutex);
85
n = ++async_cb_called;
86
uv_mutex_unlock(&mutex);
89
uv_close((uv_handle_t*)&async, close_cb);
90
uv_close((uv_handle_t*)&prepare, close_cb);
148
95
static void prepare_cb(uv_prepare_t* handle, int status) {
149
ASSERT(handle == &prepare_handle);
98
ASSERT(handle == &prepare);
150
99
ASSERT(status == 0);
152
switch (prepare_cb_called) {
154
thread1_id = uv_create_thread(thread1_entry, NULL);
155
ASSERT(thread1_id != 0);
160
thread2_id = uv_create_thread(thread2_entry, NULL);
161
ASSERT(thread2_id != 0);
165
thread3_id = uv_create_thread(thread3_entry, NULL);
166
ASSERT(thread3_id != 0);
171
uv_close((uv_handle_t*)handle, close_cb);
175
FATAL("Should never get here");
101
if (prepare_cb_called++)
104
r = uv_thread_create(&thread, thread_cb, NULL);
106
uv_mutex_unlock(&mutex);
182
110
TEST_IMPL(async) {
185
r = uv_prepare_init(uv_default_loop(), &prepare_handle);
187
r = uv_prepare_start(&prepare_handle, prepare_cb);
190
r = uv_async_init(uv_default_loop(), &async1_handle, async1_cb);
194
r = uv_async_init(&async2_handle, async2_cb, close_cb, NULL);
198
r = uv_run(uv_default_loop());
201
r = uv_wait_thread(thread1_id);
204
r = uv_wait_thread(thread2_id);
206
r = uv_wait_thread(thread3_id);
210
ASSERT(prepare_cb_called == 2);
211
ASSERT(async1_cb_called > 2);
212
/* ASSERT(async2_cb_called = 16); */
113
r = uv_mutex_init(&mutex);
115
uv_mutex_lock(&mutex);
117
r = uv_prepare_init(uv_default_loop(), &prepare);
119
r = uv_prepare_start(&prepare, prepare_cb);
122
r = uv_async_init(uv_default_loop(), &async, async_cb);
125
r = uv_run(uv_default_loop(), UV_RUN_DEFAULT);
128
ASSERT(prepare_cb_called > 0);
129
ASSERT(async_cb_called == 3);
213
130
ASSERT(close_cb_called == 2);
132
ASSERT(0 == uv_thread_join(&thread));
134
MAKE_VALGRIND_HAPPY();