summaryrefslogtreecommitdiff
path: root/lib/librthread/rthread_sem.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/librthread/rthread_sem.c')
-rw-r--r--lib/librthread/rthread_sem.c62
1 files changed, 48 insertions, 14 deletions
diff --git a/lib/librthread/rthread_sem.c b/lib/librthread/rthread_sem.c
index 3a410b62155..39eb4a0f684 100644
--- a/lib/librthread/rthread_sem.c
+++ b/lib/librthread/rthread_sem.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: rthread_sem.c,v 1.5 2012/03/02 08:07:43 guenther Exp $ */
+/* $OpenBSD: rthread_sem.c,v 1.6 2012/03/03 10:02:26 guenther Exp $ */
/*
* Copyright (c) 2004,2005 Ted Unangst <tedu@openbsd.org>
* All Rights Reserved.
@@ -28,25 +28,30 @@
* Internal implementation of semaphores
*/
int
-_sem_wait(sem_t sem, int tryonly, int *delayed_cancel)
+_sem_wait(sem_t sem, int tryonly, const struct timespec *abstime,
+ int *delayed_cancel)
{
int r;
_spinlock(&sem->lock);
if (sem->value) {
sem->value--;
- r = 1;
- } else if (tryonly) {
r = 0;
+ } else if (tryonly) {
+ r = EAGAIN;
} else {
sem->waitcount++;
do {
- r = __thrsleep(&sem->waitcount, 0, NULL, &sem->lock,
- delayed_cancel) == 0;
+ r = __thrsleep(&sem->waitcount, CLOCK_REALTIME,
+ abstime, &sem->lock, delayed_cancel);
_spinlock(&sem->lock);
- } while (r && sem->value == 0);
+ /* ignore interruptions other than cancelation */
+ if (r == EINTR && (delayed_cancel == NULL ||
+ *delayed_cancel == 0))
+ r = 0;
+ } while (r == 0 && sem->value == 0);
sem->waitcount--;
- if (r)
+ if (r == 0)
sem->value--;
}
_spinunlock(&sem->lock);
@@ -165,8 +170,37 @@ sem_wait(sem_t *semp)
}
_enter_delayed_cancel(self);
- r = _sem_wait(sem, 0, &self->delayed_cancel);
- _leave_delayed_cancel(self, !r);
+ r = _sem_wait(sem, 0, NULL, &self->delayed_cancel);
+ _leave_delayed_cancel(self, r);
+
+ if (r) {
+ errno = r;
+ return (-1);
+ }
+
+ return (0);
+}
+
+int
+sem_timedwait(sem_t *semp, const struct timespec *abstime)
+{
+ sem_t sem = *semp;
+ pthread_t self = pthread_self();
+ int r;
+
+ if (!semp || !*semp) {
+ errno = EINVAL;
+ return (-1);
+ }
+
+ _enter_delayed_cancel(self);
+ r = _sem_wait(sem, 0, abstime, &self->delayed_cancel);
+ _leave_delayed_cancel(self, r);
+
+ if (r) {
+ errno = r;
+ return (-1);
+ }
return (0);
}
@@ -175,17 +209,17 @@ int
sem_trywait(sem_t *semp)
{
sem_t sem = *semp;
- int rv;
+ int r;
if (!semp || !*semp) {
errno = EINVAL;
return (-1);
}
- rv = _sem_wait(sem, 1, NULL);
+ r = _sem_wait(sem, 1, NULL, NULL);
- if (!rv) {
- errno = EAGAIN;
+ if (r) {
+ errno = r;
return (-1);
}