aboutsummaryrefslogtreecommitdiff
path: root/nptl/sysdeps/pthread/pthread_barrier_wait.c
diff options
context:
space:
mode:
authorUlrich Drepper <drepper@redhat.com>2004-02-19 04:10:16 +0000
committerUlrich Drepper <drepper@redhat.com>2004-02-19 04:10:16 +0000
commit37c054c7c4a969816d2bc3c8284bdcadf68ebeec (patch)
treeec0a8cc53830ddb66445be30615fd15b894495fa /nptl/sysdeps/pthread/pthread_barrier_wait.c
parentdc39124662b25ce2db28454f1749d67550e4de31 (diff)
downloadglibc-37c054c7c4a969816d2bc3c8284bdcadf68ebeec.tar
glibc-37c054c7c4a969816d2bc3c8284bdcadf68ebeec.tar.gz
glibc-37c054c7c4a969816d2bc3c8284bdcadf68ebeec.tar.bz2
glibc-37c054c7c4a969816d2bc3c8284bdcadf68ebeec.zip
Update.
* sysdeps/unix/sysv/linux/i386/i486/pthread_barrier_wait.S (pthread_barrier_wait): After wakeup, release lock only when the last thread stopped using the barrier object. * sysdeps/unix/sysv/linux/x86_64/pthread_barrier_wait.S (pthread_barrier_wait): Likewise. * sysdeps/pthread/pthread_barrier_wait.c (pthread_barrier_wait): Likewise. * Makefile (tests): Add tst-barrier4. * tst-barrier4.c: New file.
Diffstat (limited to 'nptl/sysdeps/pthread/pthread_barrier_wait.c')
-rw-r--r--nptl/sysdeps/pthread/pthread_barrier_wait.c54
1 files changed, 28 insertions, 26 deletions
diff --git a/nptl/sysdeps/pthread/pthread_barrier_wait.c b/nptl/sysdeps/pthread/pthread_barrier_wait.c
index 69274d6d64..f6dc3e5f16 100644
--- a/nptl/sysdeps/pthread/pthread_barrier_wait.c
+++ b/nptl/sysdeps/pthread/pthread_barrier_wait.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2003 Free Software Foundation, Inc.
+/* Copyright (C) 2003, 2004 Free Software Foundation, Inc.
This file is part of the GNU C Library.
Contributed by Martin Schwidefsky <schwidefsky@de.ibm.com>, 2003.
@@ -29,6 +29,7 @@ pthread_barrier_wait (barrier)
pthread_barrier_t *barrier;
{
struct pthread_barrier *ibarrier = (struct pthread_barrier *) barrier;
+ int result = 0;
/* Make sure we are alone. */
lll_lock (ibarrier->lock);
@@ -39,41 +40,42 @@ pthread_barrier_wait (barrier)
/* Are these all? */
if (ibarrier->left == 0)
{
- /* Yes. Restore the barrier to be empty. */
- ibarrier->left = ibarrier->init_count;
-
- /* Increment the event counter to avoid invalid wake-ups and
+ /* Yes. Increment the event counter to avoid invalid wake-ups and
tell the current waiters that it is their turn. */
++ibarrier->curr_event;
/* Wake up everybody. */
lll_futex_wake (&ibarrier->curr_event, INT_MAX);
- /* The barrier is open for business again. */
- lll_unlock (ibarrier->lock);
-
/* This is the thread which finished the serialization. */
- return PTHREAD_BARRIER_SERIAL_THREAD;
+ result = PTHREAD_BARRIER_SERIAL_THREAD;
}
-
- /* The number of the event we are waiting for. The barrier's event
- number must be bumped before we continue. */
- unsigned int event = ibarrier->curr_event;
- do
+ else
{
- /* Before suspending, make the barrier available to others. */
- lll_unlock (ibarrier->lock);
-
- /* Wait for the event counter of the barrier to change. */
- lll_futex_wait (&ibarrier->curr_event, event);
-
- /* We are going to access shared data. */
- lll_lock (ibarrier->lock);
+ /* The number of the event we are waiting for. The barrier's event
+ number must be bumped before we continue. */
+ unsigned int event = ibarrier->curr_event;
+ do
+ {
+ /* Before suspending, make the barrier available to others. */
+ lll_unlock (ibarrier->lock);
+
+ /* Wait for the event counter of the barrier to change. */
+ lll_futex_wait (&ibarrier->curr_event, event);
+
+ /* We are going to access shared data. */
+ lll_lock (ibarrier->lock);
+ }
+ while (event == ibarrier->curr_event);
}
- while (event == ibarrier->curr_event);
- /* We are done, let others use the barrier. */
- lll_unlock (ibarrier->lock);
+ /* Make sure the init_count is stored locally or in a register. */
+ unsigned int init_count = ibarrier->init_count;
+
+ /* If this was the last woken thread, unlock. */
+ if (atomic_exchange_and_add (ibarrier->left, 1) == init_count - 1)
+ /* We are done. */
+ lll_unlock (ibarrier->lock);
- return 0;
+ return result;
}