test: fix deadlocks in uv_cond_wait
Calling uv_cond_wait without uv_cond_signal/uv_cond_broadcast may cause deadlock. This commit avoids this situation as well as tests these functions. PR-URL: https://github.com/libuv/libuv/pull/728 Reviewed-By: Saúl Ibarra Corretgé <saghul@gmail.com>
This commit is contained in:
parent
2606ba22a7
commit
ca0b657891
@ -25,24 +25,33 @@
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
|
||||
typedef struct {
|
||||
typedef struct worker_config {
|
||||
uv_mutex_t mutex;
|
||||
uv_cond_t cond;
|
||||
int delay;
|
||||
int signal_delay;
|
||||
int wait_delay;
|
||||
int use_broadcast;
|
||||
volatile int posted;
|
||||
volatile int posted_1;
|
||||
volatile int posted_2;
|
||||
void (*signal_cond)(struct worker_config* c, volatile int* flag);
|
||||
void (*wait_cond)(struct worker_config* c, const volatile int* flag);
|
||||
} worker_config;
|
||||
|
||||
|
||||
static void worker(void* arg) {
|
||||
worker_config* c = arg;
|
||||
c->signal_cond(c, &c->posted_1);
|
||||
c->wait_cond(c, &c->posted_2);
|
||||
}
|
||||
|
||||
if (c->delay)
|
||||
uv_sleep(c->delay);
|
||||
|
||||
static void condvar_signal(worker_config* c, volatile int* flag) {
|
||||
if (c->signal_delay)
|
||||
uv_sleep(c->signal_delay);
|
||||
|
||||
uv_mutex_lock(&c->mutex);
|
||||
ASSERT(c->posted == 0);
|
||||
c->posted = 1;
|
||||
ASSERT(*flag == 0);
|
||||
*flag = 1;
|
||||
if (c->use_broadcast)
|
||||
uv_cond_broadcast(&c->cond);
|
||||
else
|
||||
@ -51,21 +60,33 @@ static void worker(void* arg) {
|
||||
}
|
||||
|
||||
|
||||
static void condvar_wait(worker_config* c, const volatile int* flag) {
|
||||
uv_mutex_lock(&c->mutex);
|
||||
if (c->wait_delay)
|
||||
uv_sleep(c->wait_delay);
|
||||
while (*flag == 0) {
|
||||
uv_cond_wait(&c->cond, &c->mutex);
|
||||
}
|
||||
ASSERT(*flag == 1);
|
||||
uv_mutex_unlock(&c->mutex);
|
||||
}
|
||||
|
||||
|
||||
TEST_IMPL(condvar_1) {
|
||||
uv_thread_t thread;
|
||||
worker_config wc;
|
||||
|
||||
memset(&wc, 0, sizeof(wc));
|
||||
wc.wait_delay = 100;
|
||||
wc.signal_cond = condvar_signal;
|
||||
wc.wait_cond = condvar_wait;
|
||||
|
||||
ASSERT(0 == uv_cond_init(&wc.cond));
|
||||
ASSERT(0 == uv_mutex_init(&wc.mutex));
|
||||
ASSERT(0 == uv_thread_create(&thread, worker, &wc));
|
||||
|
||||
uv_mutex_lock(&wc.mutex);
|
||||
uv_sleep(100);
|
||||
uv_cond_wait(&wc.cond, &wc.mutex);
|
||||
ASSERT(wc.posted == 1);
|
||||
uv_mutex_unlock(&wc.mutex);
|
||||
wc.wait_cond(&wc, &wc.posted_1);
|
||||
wc.signal_cond(&wc, &wc.posted_2);
|
||||
|
||||
ASSERT(0 == uv_thread_join(&thread));
|
||||
uv_mutex_destroy(&wc.mutex);
|
||||
@ -80,15 +101,16 @@ TEST_IMPL(condvar_2) {
|
||||
worker_config wc;
|
||||
|
||||
memset(&wc, 0, sizeof(wc));
|
||||
wc.delay = 100;
|
||||
wc.signal_delay = 100;
|
||||
wc.signal_cond = condvar_signal;
|
||||
wc.wait_cond = condvar_wait;
|
||||
|
||||
ASSERT(0 == uv_cond_init(&wc.cond));
|
||||
ASSERT(0 == uv_mutex_init(&wc.mutex));
|
||||
ASSERT(0 == uv_thread_create(&thread, worker, &wc));
|
||||
|
||||
uv_mutex_lock(&wc.mutex);
|
||||
uv_cond_wait(&wc.cond, &wc.mutex);
|
||||
uv_mutex_unlock(&wc.mutex);
|
||||
wc.wait_cond(&wc, &wc.posted_1);
|
||||
wc.signal_cond(&wc, &wc.posted_2);
|
||||
|
||||
ASSERT(0 == uv_thread_join(&thread));
|
||||
uv_mutex_destroy(&wc.mutex);
|
||||
@ -98,22 +120,35 @@ TEST_IMPL(condvar_2) {
|
||||
}
|
||||
|
||||
|
||||
static void condvar_timedwait(worker_config* c, const volatile int* flag) {
|
||||
int r;
|
||||
|
||||
uv_mutex_lock(&c->mutex);
|
||||
if (c->wait_delay)
|
||||
uv_sleep(c->wait_delay);
|
||||
while (*flag == 0) {
|
||||
r = uv_cond_timedwait(&c->cond, &c->mutex, (uint64_t)(150 * 1e6));
|
||||
ASSERT(r == 0);
|
||||
}
|
||||
uv_mutex_unlock(&c->mutex);
|
||||
}
|
||||
|
||||
|
||||
TEST_IMPL(condvar_3) {
|
||||
uv_thread_t thread;
|
||||
worker_config wc;
|
||||
int r;
|
||||
|
||||
memset(&wc, 0, sizeof(wc));
|
||||
wc.delay = 100;
|
||||
wc.signal_delay = 100;
|
||||
wc.signal_cond = condvar_signal;
|
||||
wc.wait_cond = condvar_timedwait;
|
||||
|
||||
ASSERT(0 == uv_cond_init(&wc.cond));
|
||||
ASSERT(0 == uv_mutex_init(&wc.mutex));
|
||||
ASSERT(0 == uv_thread_create(&thread, worker, &wc));
|
||||
|
||||
uv_mutex_lock(&wc.mutex);
|
||||
r = uv_cond_timedwait(&wc.cond, &wc.mutex, (uint64_t)(50 * 1e6));
|
||||
ASSERT(r == UV_ETIMEDOUT);
|
||||
uv_mutex_unlock(&wc.mutex);
|
||||
wc.wait_cond(&wc, &wc.posted_1);
|
||||
wc.signal_cond(&wc, &wc.posted_2);
|
||||
|
||||
ASSERT(0 == uv_thread_join(&thread));
|
||||
uv_mutex_destroy(&wc.mutex);
|
||||
@ -126,19 +161,18 @@ TEST_IMPL(condvar_3) {
|
||||
TEST_IMPL(condvar_4) {
|
||||
uv_thread_t thread;
|
||||
worker_config wc;
|
||||
int r;
|
||||
|
||||
memset(&wc, 0, sizeof(wc));
|
||||
wc.delay = 100;
|
||||
wc.signal_delay = 100;
|
||||
wc.signal_cond = condvar_signal;
|
||||
wc.wait_cond = condvar_timedwait;
|
||||
|
||||
ASSERT(0 == uv_cond_init(&wc.cond));
|
||||
ASSERT(0 == uv_mutex_init(&wc.mutex));
|
||||
ASSERT(0 == uv_thread_create(&thread, worker, &wc));
|
||||
|
||||
uv_mutex_lock(&wc.mutex);
|
||||
r = uv_cond_timedwait(&wc.cond, &wc.mutex, (uint64_t)(150 * 1e6));
|
||||
ASSERT(r == 0);
|
||||
uv_mutex_unlock(&wc.mutex);
|
||||
wc.wait_cond(&wc, &wc.posted_1);
|
||||
wc.signal_cond(&wc, &wc.posted_2);
|
||||
|
||||
ASSERT(0 == uv_thread_join(&thread));
|
||||
uv_mutex_destroy(&wc.mutex);
|
||||
@ -154,16 +188,16 @@ TEST_IMPL(condvar_5) {
|
||||
|
||||
memset(&wc, 0, sizeof(wc));
|
||||
wc.use_broadcast = 1;
|
||||
wc.signal_delay = 100;
|
||||
wc.signal_cond = condvar_signal;
|
||||
wc.wait_cond = condvar_wait;
|
||||
|
||||
ASSERT(0 == uv_cond_init(&wc.cond));
|
||||
ASSERT(0 == uv_mutex_init(&wc.mutex));
|
||||
ASSERT(0 == uv_thread_create(&thread, worker, &wc));
|
||||
|
||||
uv_mutex_lock(&wc.mutex);
|
||||
uv_sleep(100);
|
||||
uv_cond_wait(&wc.cond, &wc.mutex);
|
||||
ASSERT(wc.posted == 1);
|
||||
uv_mutex_unlock(&wc.mutex);
|
||||
wc.wait_cond(&wc, &wc.posted_1);
|
||||
wc.signal_cond(&wc, &wc.posted_2);
|
||||
|
||||
ASSERT(0 == uv_thread_join(&thread));
|
||||
uv_mutex_destroy(&wc.mutex);
|
||||
|
||||
Loading…
Reference in New Issue
Block a user