summaryrefslogtreecommitdiff
path: root/libpthread/nptl/sysdeps/unix/sysv/linux/sem_wait.c
diff options
context:
space:
mode:
Diffstat (limited to 'libpthread/nptl/sysdeps/unix/sysv/linux/sem_wait.c')
-rw-r--r--libpthread/nptl/sysdeps/unix/sysv/linux/sem_wait.c54
1 files changed, 41 insertions, 13 deletions
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sem_wait.c b/libpthread/nptl/sysdeps/unix/sysv/linux/sem_wait.c
index 416d8634b..e661e09c8 100644
--- a/libpthread/nptl/sysdeps/unix/sysv/linux/sem_wait.c
+++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sem_wait.c
@@ -1,5 +1,5 @@
/* sem_wait -- wait on a semaphore. Generic futex-using version.
- Copyright (C) 2003 Free Software Foundation, Inc.
+ Copyright (C) 2003, 2007 Free Software Foundation, Inc.
This file is part of the GNU C Library.
Contributed by Paul Mackerras <paulus@au.ibm.com>, 2003.
@@ -23,34 +23,62 @@
#include <lowlevellock.h>
#include <internaltypes.h>
#include <semaphore.h>
+
#include <pthreadP.h>
+void
+attribute_hidden
+__sem_wait_cleanup (void *arg)
+{
+ struct new_sem *isem = (struct new_sem *) arg;
+
+ atomic_decrement (&isem->nwaiters);
+}
+
+
int
__new_sem_wait (sem_t *sem)
{
- /* First check for cancellation. */
- CANCELLATION_P (THREAD_SELF);
-
- int *futex = (int *) sem;
+ struct new_sem *isem = (struct new_sem *) sem;
int err;
- do
- {
- if (atomic_decrement_if_positive (futex) > 0)
- return 0;
+ if (atomic_decrement_if_positive (&isem->value) > 0)
+ return 0;
+ atomic_increment (&isem->nwaiters);
+
+ pthread_cleanup_push (__sem_wait_cleanup, isem);
+
+ while (1)
+ {
/* Enable asynchronous cancellation. Required by the standard. */
int oldtype = __pthread_enable_asynccancel ();
- err = lll_futex_wait (futex, 0);
+ err = lll_futex_wait (&isem->value, 0,
+ isem->private ^ FUTEX_PRIVATE_FLAG);
/* Disable asynchronous cancellation. */
__pthread_disable_asynccancel (oldtype);
+
+ if (err != 0 && err != -EWOULDBLOCK)
+ {
+ __set_errno (-err);
+ err = -1;
+ break;
+ }
+
+ if (atomic_decrement_if_positive (&isem->value) > 0)
+ {
+ err = 0;
+ break;
+ }
}
- while (err == 0 || err == -EWOULDBLOCK);
- __set_errno (-err);
- return -1;
+ pthread_cleanup_pop (0);
+
+ atomic_decrement (&isem->nwaiters);
+
+ return err;
}
weak_alias(__new_sem_wait, sem_wait)