diff options
author | Philip Guenthe <guenther@cvs.openbsd.org> | 2012-01-17 02:34:19 +0000 |
---|---|---|
committer | Philip Guenthe <guenther@cvs.openbsd.org> | 2012-01-17 02:34:19 +0000 |
commit | b954f00c23f17debc35a7aa94bac39a336fc3359 (patch) | |
tree | aec06661a73fe3843a229172ea9cbd95181c2a90 /lib/librthread/rthread_sem.c | |
parent | c01d953b375c486f2bad253c49e4aed9a2f0938f (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.c | 97 |
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); |