summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPhilip Guenthe <guenther@cvs.openbsd.org>2012-03-03 10:02:27 +0000
committerPhilip Guenthe <guenther@cvs.openbsd.org>2012-03-03 10:02:27 +0000
commitc6639d6bd2cbd59523f2900c9ee02698933e817d (patch)
tree982d65927dc179d5335a3d8b92f156ec2b464b1b
parentd3eb35cce401703fd2ae4cd22bfab4a2092ac3ee (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.h3
-rw-r--r--lib/librthread/rthread.c11
-rw-r--r--lib/librthread/rthread.h4
-rw-r--r--lib/librthread/rthread_sem.c62
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);
}