From 01a36d151b82f6034c9e8721a5f486ab95254d35 Mon Sep 17 00:00:00 2001 From: Samuel Thibault Date: Sun, 2 Nov 2014 15:07:29 +0100 Subject: Fix safety of pthread_barrier_wait The barrier queue uses threads' next field, so it can not actually be safely walked without holding the barrier lock. * sysdeps/generic/pt-barrier-wait.c (pthread_barrier_wait): Record an array of __pthread to wake while holding the lock, and wake them only after unlocking it. --- sysdeps/generic/pt-barrier-wait.c | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) (limited to 'sysdeps') diff --git a/sysdeps/generic/pt-barrier-wait.c b/sysdeps/generic/pt-barrier-wait.c index f1de250..42fbdb0 100644 --- a/sysdeps/generic/pt-barrier-wait.c +++ b/sysdeps/generic/pt-barrier-wait.c @@ -33,16 +33,24 @@ pthread_barrier_wait (pthread_barrier_t *barrier) if (barrier->count > 1) { struct __pthread *wakeup; + unsigned n = 0; - wakeup = barrier->queue; - barrier->queue = NULL; - __pthread_spin_unlock (&barrier->lock); + __pthread_queue_iterate (barrier->queue, wakeup) + n ++; - /* We can safely walk the list of waiting threads without - holding the lock since it is decoupled from the barrier - variable now. */ - __pthread_dequeuing_iterate (wakeup, wakeup) - __pthread_wakeup (wakeup); + { + struct __pthread *wakeups[n]; + unsigned i = 0; + + __pthread_dequeuing_iterate (barrier->queue, wakeup) + wakeups[i ++] = wakeup; + + barrier->queue = NULL; + __pthread_spin_unlock (&barrier->lock); + + for (i = 0; i < n; i ++) + __pthread_wakeup (wakeups[i]); + } } return PTHREAD_BARRIER_SERIAL_THREAD; -- cgit v1.2.3