diff options
Diffstat (limited to 'pthread_barrier_wait.c')
-rw-r--r-- | pthread_barrier_wait.c | 55 |
1 files changed, 30 insertions, 25 deletions
diff --git a/pthread_barrier_wait.c b/pthread_barrier_wait.c index 01ae297..182b779 100644 --- a/pthread_barrier_wait.c +++ b/pthread_barrier_wait.c @@ -42,57 +42,62 @@ int pthread_barrier_wait (pthread_barrier_t * barrier) { int result; - int step; pthread_barrier_t b; + ptw32_mcs_local_node_t node; + if (barrier == NULL || *barrier == (pthread_barrier_t) PTW32_OBJECT_INVALID) { return EINVAL; } - b = *barrier; - step = b->iStep; + ptw32_mcs_lock_acquire((ptw32_mcs_lock_t *)&(*barrier)->lock, &node); - if (0 == InterlockedDecrement ((long *) &(b->nCurrentBarrierHeight))) + b = *barrier; + if (--b->nCurrentBarrierHeight == 0) { - /* Must be done before posting the semaphore. */ - b->nCurrentBarrierHeight = b->nInitialBarrierHeight; + /* + * We are the last thread to arrive at the barrier before it releases us. + * Move our MCS local node to the global scope barrier handle so that the + * last thread out (not necessarily us) can release the lock. + */ + ptw32_mcs_node_substitute(&b->proxynode, &node); /* - * There is no race condition between the semaphore wait and post - * because we are using two alternating semas and all threads have - * entered barrier_wait and checked nCurrentBarrierHeight before this - * barrier's sema can be posted. Any threads that have not quite - * entered sem_wait below when the multiple_post has completed - * will nevertheless continue through the semaphore (barrier) - * and will not be left stranded. + * Any threads that have not quite entered sem_wait below when the + * multiple_post has completed will nevertheless continue through + * the semaphore (barrier). */ result = (b->nInitialBarrierHeight > 1 - ? sem_post_multiple (&(b->semBarrierBreeched[step]), + ? sem_post_multiple (&(b->semBarrierBreeched), b->nInitialBarrierHeight - 1) : 0); } else { + ptw32_mcs_lock_release(&node); /* * Use the non-cancelable version of sem_wait(). + * + * It is possible that all nInitialBarrierHeight-1 threads are + * at this point when the last thread enters the barrier, resets + * nCurrentBarrierHeight = nInitialBarrierHeight and leaves. + * If pthread_barrier_destroy is called at that moment then the + * barrier will be destroyed along with the semas. */ - result = ptw32_semwait (&(b->semBarrierBreeched[step])); + result = ptw32_semwait (&(b->semBarrierBreeched)); } + if ((PTW32_INTERLOCKED_LONG)InterlockedIncrement((LPLONG)&b->nCurrentBarrierHeight) + == (PTW32_INTERLOCKED_LONG)b->nInitialBarrierHeight) + { /* - * The first thread across will be the PTHREAD_BARRIER_SERIAL_THREAD. - * This also sets up the alternate semaphore as the next barrier. + * We are the last thread to cross this barrier */ + ptw32_mcs_lock_release(&b->proxynode); if (0 == result) { - result = ((PTW32_INTERLOCKED_LONG) step == - PTW32_INTERLOCKED_COMPARE_EXCHANGE ((PTW32_INTERLOCKED_LPLONG) - & (b->iStep), - (PTW32_INTERLOCKED_LONG) - (1L - step), - (PTW32_INTERLOCKED_LONG) - step) ? - PTHREAD_BARRIER_SERIAL_THREAD : 0); + result = PTHREAD_BARRIER_SERIAL_THREAD; + } } return (result); |