Skip to content

Commit 49b8a9f

Browse files
committed
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: libuv#2019 Refs: libuv#2003 Reviewed-By: Santiago Gimeno <santiago.gimeno@gmail.com>
1 parent a3a601c commit 49b8a9f

1 file changed

Lines changed: 10 additions & 12 deletions

File tree

src/unix/thread.c

Lines changed: 10 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,7 @@ int uv_barrier_init(uv_barrier_t* barrier, unsigned int count) {
8686

8787
int uv_barrier_wait(uv_barrier_t* barrier) {
8888
struct _uv_barrier* b;
89+
int last;
8990

9091
if (barrier == NULL || barrier->b == NULL)
9192
return UV_EINVAL;
@@ -95,23 +96,20 @@ int uv_barrier_wait(uv_barrier_t* barrier) {
9596

9697
if (++b->in == b->threshold) {
9798
b->in = 0;
98-
b->out = b->threshold - 1;
99+
b->out = b->threshold;
99100
uv_cond_signal(&b->cond);
100-
uv_mutex_unlock(&b->mutex);
101-
return 1; /* This is the first thread to reach the threshold. */
101+
} else {
102+
do
103+
uv_cond_wait(&b->cond, &b->mutex);
104+
while (b->in != 0);
102105
}
103106

104-
/* Otherwise, wait for other threads until in is set to 0,
105-
then return 0 to indicate this is not the first thread. */
106-
do
107-
uv_cond_wait(&b->cond, &b->mutex);
108-
while (b->in != 0);
107+
last = (--b->out == 0);
108+
if (!last)
109+
uv_cond_signal(&b->cond); /* Not needed for last thread. */
109110

110-
/* mark thread exit */
111-
b->out--;
112-
uv_cond_signal(&b->cond);
113111
uv_mutex_unlock(&b->mutex);
114-
return 0;
112+
return last;
115113
}
116114

117115

0 commit comments

Comments
 (0)