summaryrefslogtreecommitdiff
path: root/lib/librthread/rthread_sem.c
diff options
context:
space:
mode:
authorPhilip Guenthe <guenther@cvs.openbsd.org>2012-01-17 02:34:19 +0000
committerPhilip Guenthe <guenther@cvs.openbsd.org>2012-01-17 02:34:19 +0000
commitb954f00c23f17debc35a7aa94bac39a336fc3359 (patch)
treeaec06661a73fe3843a229172ea9cbd95181c2a90 /lib/librthread/rthread_sem.c
parentc01d953b375c486f2bad253c49e4aed9a2f0938f (diff)
Reimplement mutexes, condvars, and rwlocks to eliminate bugs,
particularly the "consume the signal you just sent" hang, and putting the wait queues in userspace. Do cancellation handling in pthread_cond_*wait(), pthread_join(), and sem_wait(). Add __ prefix to thr{sleep,wakeup,exit,sigdivert}() syscalls; add 'abort" argument to thrsleep to close cancellation race; make thr{sleep,wakeup} return errno values via *retval to avoid touching userspace errno.
Diffstat (limited to 'lib/librthread/rthread_sem.c')
-rw-r--r--lib/librthread/rthread_sem.c97
1 files changed, 30 insertions, 67 deletions
diff --git a/lib/librthread/rthread_sem.c b/lib/librthread/rthread_sem.c
index 6c065cc4b78..66c22af4b9a 100644
--- a/lib/librthread/rthread_sem.c
+++ b/lib/librthread/rthread_sem.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: rthread_sem.c,v 1.3 2012/01/04 21:01:25 guenther Exp $ */
+/* $OpenBSD: rthread_sem.c,v 1.4 2012/01/17 02:34:18 guenther Exp $ */
/*
* Copyright (c) 2004,2005 Ted Unangst <tedu@openbsd.org>
* All Rights Reserved.
@@ -28,42 +28,29 @@
* Internal implementation of semaphores
*/
int
-_sem_wait(sem_t sem, int tryonly)
+_sem_wait(sem_t sem, int tryonly, int *delayed_cancel)
{
+ int r;
_spinlock(&sem->lock);
- return (_sem_waitl(sem, tryonly, 0, NULL));
-}
-
-int
-_sem_waitl(sem_t sem, int tryonly, clockid_t clock_id,
- const struct timespec *abstime)
-{
- int do_sleep;
-
-again:
- if (sem->value == 0) {
- if (tryonly) {
- _spinunlock(&sem->lock);
- return (0);
- }
- sem->waitcount++;
- do_sleep = 1;
- } else {
+ if (sem->value) {
sem->value--;
- do_sleep = 0;
- }
-
- if (do_sleep) {
- if (thrsleep(sem, clock_id, abstime, &sem->lock) == -1 &&
- errno == EWOULDBLOCK)
- return (0);
- _spinlock(&sem->lock);
+ r = 1;
+ } else if (tryonly) {
+ r = 0;
+ } else {
+ sem->waitcount++;
+ do {
+ r = __thrsleep(&sem->waitcount, 0, NULL, &sem->lock,
+ delayed_cancel) == 0;
+ _spinlock(&sem->lock);
+ } while (r && sem->value == 0);
sem->waitcount--;
- goto again;
+ if (r)
+ sem->value--;
}
_spinunlock(&sem->lock);
- return (1);
+ return (r);
}
/* always increment count */
@@ -75,44 +62,13 @@ _sem_post(sem_t sem)
_spinlock(&sem->lock);
sem->value++;
if (sem->waitcount) {
- thrwakeup(sem, 1);
+ __thrwakeup(&sem->waitcount, 1);
rv = 1;
}
_spinunlock(&sem->lock);
return (rv);
}
-/* only increment count if a waiter */
-int
-_sem_wakeup(sem_t sem)
-{
- int rv = 0;
-
- _spinlock(&sem->lock);
- if (sem->waitcount) {
- sem->value++;
- thrwakeup(sem, 1);
- rv = 1;
- }
- _spinunlock(&sem->lock);
- return (rv);
-}
-
-
-int
-_sem_wakeall(sem_t sem)
-{
- int rv;
-
- _spinlock(&sem->lock);
- rv = sem->waitcount;
- sem->value += rv;
- thrwakeup(sem, 0);
- _spinunlock(&sem->lock);
-
- return (rv);
-}
-
/*
* exported semaphores
*/
@@ -199,13 +155,17 @@ int
sem_wait(sem_t *semp)
{
sem_t sem = *semp;
+ pthread_t self = pthread_self();
+ int r;
if (!semp || !*semp) {
errno = EINVAL;
return (-1);
}
- _sem_wait(sem, 0);
+ _enter_delayed_cancel(self);
+ r = _sem_wait(sem, 0, &self->delayed_cancel);
+ _leave_delayed_cancel(self, !r);
return (0);
}
@@ -221,7 +181,7 @@ sem_trywait(sem_t *semp)
return (-1);
}
- rv = _sem_wait(sem, 1);
+ rv = _sem_wait(sem, 1, NULL);
if (!rv) {
errno = EAGAIN;
@@ -231,22 +191,25 @@ sem_trywait(sem_t *semp)
return (0);
}
+/* ARGSUSED */
sem_t *
-sem_open(const char *name, int oflag, ...)
+sem_open(const char *name __unused, int oflag __unused, ...)
{
errno = ENOSYS;
return (SEM_FAILED);
}
+/* ARGSUSED */
int
-sem_close(sem_t *sem)
+sem_close(sem_t *sem __unused)
{
errno = ENOSYS;
return (-1);
}
+/* ARGSUSED */
int
-sem_unlink(const char *name)
+sem_unlink(const char *name __unused)
{
errno = ENOSYS;
return (-1);