summaryrefslogtreecommitdiff
path: root/libpthread/nptl/sysdeps/unix/sysv/linux/sem_timedwait.c
diff options
context:
space:
mode:
Diffstat (limited to 'libpthread/nptl/sysdeps/unix/sysv/linux/sem_timedwait.c')
-rw-r--r--libpthread/nptl/sysdeps/unix/sysv/linux/sem_timedwait.c62
1 files changed, 38 insertions, 24 deletions
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sem_timedwait.c b/libpthread/nptl/sysdeps/unix/sysv/linux/sem_timedwait.c
index 79b11948c..3e5e6dcae 100644
--- a/libpthread/nptl/sysdeps/unix/sysv/linux/sem_timedwait.c
+++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sem_timedwait.c
@@ -1,5 +1,5 @@
/* sem_timedwait -- 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,38 +23,40 @@
#include <lowlevellock.h>
#include <internaltypes.h>
#include <semaphore.h>
+
#include <pthreadP.h>
+extern void __sem_wait_cleanup (void *arg) attribute_hidden;
+
+
int
sem_timedwait (sem_t *sem, const struct timespec *abstime)
{
- /* First check for cancellation. */
- CANCELLATION_P (THREAD_SELF);
-
- int *futex = (int *) sem;
- int val;
+ struct new_sem *isem = (struct new_sem *) sem;
int err;
- if (*futex > 0)
+ if (atomic_decrement_if_positive (&isem->value) > 0)
+ return 0;
+
+ if (abstime->tv_nsec < 0 || abstime->tv_nsec >= 1000000000)
{
- val = atomic_decrement_if_positive (futex);
- if (val > 0)
- return 0;
+ __set_errno (EINVAL);
+ return -1;
}
- err = -EINVAL;
- if (abstime->tv_nsec < 0 || abstime->tv_nsec >= 1000000000)
- goto error_return;
+ atomic_increment (&isem->nwaiters);
+
+ pthread_cleanup_push (__sem_wait_cleanup, isem);
- do
+ while (1)
{
struct timeval tv;
struct timespec rt;
int sec, nsec;
/* Get the current time. */
- gettimeofday (&tv, NULL);
+ __gettimeofday (&tv, NULL);
/* Compute relative timeout. */
sec = abstime->tv_sec - tv.tv_sec;
@@ -68,7 +70,11 @@ sem_timedwait (sem_t *sem, const struct timespec *abstime)
/* Already timed out? */
err = -ETIMEDOUT;
if (sec < 0)
- goto error_return;
+ {
+ __set_errno (ETIMEDOUT);
+ err = -1;
+ break;
+ }
/* Do wait. */
rt.tv_sec = sec;
@@ -77,21 +83,29 @@ sem_timedwait (sem_t *sem, const struct timespec *abstime)
/* Enable asynchronous cancellation. Required by the standard. */
int oldtype = __pthread_enable_asynccancel ();
- err = lll_futex_timed_wait (futex, 0, &rt);
+ err = lll_futex_timed_wait (&isem->value, 0, &rt,
+ isem->private ^ FUTEX_PRIVATE_FLAG);
/* Disable asynchronous cancellation. */
__pthread_disable_asynccancel (oldtype);
if (err != 0 && err != -EWOULDBLOCK)
- goto error_return;
+ {
+ __set_errno (-err);
+ err = -1;
+ break;
+ }
- val = atomic_decrement_if_positive (futex);
+ if (atomic_decrement_if_positive (&isem->value) > 0)
+ {
+ err = 0;
+ break;
+ }
}
- while (val <= 0);
- return 0;
+ pthread_cleanup_pop (0);
+
+ atomic_decrement (&isem->nwaiters);
- error_return:
- __set_errno (-err);
- return -1;
+ return err;
}