From 49b8a9f1819cb47f408f7f749b0759a78b0ca139 Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Mon, 8 Oct 2018 11:14:41 +0200 Subject: [PATCH] unix: signal done to last thread barrier waiter Libuv's own thread barrier implementation signaled completion to the first waiter that saw the threshold being reached, contrary to what some native pthreads barrier implementations do, which is to signal it to the _last_ waiter. Libuv's behavior is not strictly non-conforming but it's inconvenient because it means this snippet (that appears in the libuv documentation) has a race condition in it: if (uv_barrier_wait(&barrier) > 0) uv_barrier_destroy(&barrier); // can still have waiters This issue was discovered and fixed by Ali Ijaz Sheikh, a.k.a @ofrobots, but some refactoring introduced conflicts in his pull request and I didn't have the heart to ask him to redo it from scratch. :-) PR-URL: https://github.com/libuv/libuv/pull/2019 Refs: https://github.com/libuv/libuv/pull/2003 Reviewed-By: Santiago Gimeno --- src/unix/thread.c | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/src/unix/thread.c b/src/unix/thread.c index ab8988ef..29004707 100644 --- a/src/unix/thread.c +++ b/src/unix/thread.c @@ -86,6 +86,7 @@ error2: int uv_barrier_wait(uv_barrier_t* barrier) { struct _uv_barrier* b; + int last; if (barrier == NULL || barrier->b == NULL) return UV_EINVAL; @@ -95,23 +96,20 @@ int uv_barrier_wait(uv_barrier_t* barrier) { if (++b->in == b->threshold) { b->in = 0; - b->out = b->threshold - 1; + b->out = b->threshold; uv_cond_signal(&b->cond); - uv_mutex_unlock(&b->mutex); - return 1; /* This is the first thread to reach the threshold. */ + } else { + do + uv_cond_wait(&b->cond, &b->mutex); + while (b->in != 0); } - /* Otherwise, wait for other threads until in is set to 0, - then return 0 to indicate this is not the first thread. */ - do - uv_cond_wait(&b->cond, &b->mutex); - while (b->in != 0); + last = (--b->out == 0); + if (!last) + uv_cond_signal(&b->cond); /* Not needed for last thread. */ - /* mark thread exit */ - b->out--; - uv_cond_signal(&b->cond); uv_mutex_unlock(&b->mutex); - return 0; + return last; }