diff options
author | Philip Guenthe <guenther@cvs.openbsd.org> | 2012-03-03 10:02:27 +0000 |
---|---|---|
committer | Philip Guenthe <guenther@cvs.openbsd.org> | 2012-03-03 10:02:27 +0000 |
commit | c6639d6bd2cbd59523f2900c9ee02698933e817d (patch) | |
tree | 982d65927dc179d5335a3d8b92f156ec2b464b1b | |
parent | d3eb35cce401703fd2ae4cd22bfab4a2092ac3ee (diff) |
Add sem_timewait() and fix sem_wait()'s handling of signals, so
that it resumes waiting unless the thread was canceled. As part
of this, change the internal _sem_wait() function to return zero
on success and an errno value on failure instead of 1 on success
and zero on failure.
-rw-r--r-- | lib/libpthread/include/semaphore.h | 3 | ||||
-rw-r--r-- | lib/librthread/rthread.c | 11 | ||||
-rw-r--r-- | lib/librthread/rthread.h | 4 | ||||
-rw-r--r-- | lib/librthread/rthread_sem.c | 62 |
4 files changed, 58 insertions, 22 deletions
diff --git a/lib/libpthread/include/semaphore.h b/lib/libpthread/include/semaphore.h index 4735f9c29f9..08d659b3854 100644 --- a/lib/libpthread/include/semaphore.h +++ b/lib/libpthread/include/semaphore.h @@ -1,4 +1,4 @@ -/* $OpenBSD: semaphore.h,v 1.3 2002/02/16 21:27:25 millert Exp $ */ +/* $OpenBSD: semaphore.h,v 1.4 2012/03/03 10:02:26 guenther Exp $ */ /* semaphore.h: POSIX 1003.1b semaphores */ @@ -58,6 +58,7 @@ sem_t *sem_open(const char *, int, ...); int sem_close(sem_t *); int sem_unlink(const char *); int sem_wait(sem_t *); +int sem_timedwait(sem_t *, const struct timespec *); int sem_trywait(sem_t *); int sem_post(sem_t *); int sem_getvalue(sem_t *, int *); diff --git a/lib/librthread/rthread.c b/lib/librthread/rthread.c index a81645ee1fb..e2aaef74abd 100644 --- a/lib/librthread/rthread.c +++ b/lib/librthread/rthread.c @@ -1,4 +1,4 @@ -/* $OpenBSD: rthread.c,v 1.56 2012/03/02 17:49:58 fgsch Exp $ */ +/* $OpenBSD: rthread.c,v 1.57 2012/03/03 10:02:26 guenther Exp $ */ /* * Copyright (c) 2004,2005 Ted Unangst <tedu@openbsd.org> * All Rights Reserved. @@ -320,10 +320,10 @@ pthread_exit(void *retval) int pthread_join(pthread_t thread, void **retval) { - int e, r; + int e; pthread_t self = pthread_self(); - e = r = 0; + e = 0; _enter_delayed_cancel(self); if (thread == NULL) e = EINVAL; @@ -331,7 +331,8 @@ pthread_join(pthread_t thread, void **retval) e = EDEADLK; else if (thread->flags & THREAD_DETACHED) e = EINVAL; - else if ((r = _sem_wait(&thread->donesem, 0, &self->delayed_cancel))) { + else if ((e = _sem_wait(&thread->donesem, 0, NULL, + &self->delayed_cancel)) == 0) { if (retval) *retval = thread->retval; @@ -344,7 +345,7 @@ pthread_join(pthread_t thread, void **retval) _rthread_free(thread); } - _leave_delayed_cancel(self, !r); + _leave_delayed_cancel(self, e); _rthread_reaper(); return (e); } diff --git a/lib/librthread/rthread.h b/lib/librthread/rthread.h index d08819bd3ce..bf9748c4aa9 100644 --- a/lib/librthread/rthread.h +++ b/lib/librthread/rthread.h @@ -1,4 +1,4 @@ -/* $OpenBSD: rthread.h,v 1.35 2012/02/23 04:43:06 guenther Exp $ */ +/* $OpenBSD: rthread.h,v 1.36 2012/03/03 10:02:26 guenther Exp $ */ /* * Copyright (c) 2004,2005 Ted Unangst <tedu@openbsd.org> * All Rights Reserved. @@ -176,7 +176,7 @@ extern struct pthread_attr _rthread_attr_default; void _spinlock(_spinlock_lock_t *); void _spinunlock(_spinlock_lock_t *); -int _sem_wait(sem_t, int, int *); +int _sem_wait(sem_t, int, const struct timespec *, int *); int _sem_post(sem_t); int _rthread_init(void); 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); } |