aboutsummaryrefslogtreecommitdiff
path: root/linuxthreads/condvar.c
diff options
context:
space:
mode:
Diffstat (limited to 'linuxthreads/condvar.c')
-rw-r--r--linuxthreads/condvar.c79
1 files changed, 24 insertions, 55 deletions
diff --git a/linuxthreads/condvar.c b/linuxthreads/condvar.c
index 6807522edc..91067d2d17 100644
--- a/linuxthreads/condvar.c
+++ b/linuxthreads/condvar.c
@@ -25,42 +25,36 @@
#include "queue.h"
#include "restart.h"
-static void remove_from_queue(pthread_queue * q, pthread_descr th);
-
int pthread_cond_init(pthread_cond_t *cond,
const pthread_condattr_t *cond_attr)
{
- cond->c_spinlock = 0;
- queue_init(&cond->c_waiting);
+ __pthread_init_lock(&cond->c_lock);
+ cond->c_waiting = NULL;
return 0;
}
int pthread_cond_destroy(pthread_cond_t *cond)
{
- pthread_descr head;
-
- acquire(&cond->c_spinlock);
- head = cond->c_waiting.head;
- release(&cond->c_spinlock);
- if (head != NULL) return EBUSY;
+ if (cond->c_waiting != NULL) return EBUSY;
return 0;
}
int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex)
{
volatile pthread_descr self = thread_self();
- acquire(&cond->c_spinlock);
+
+ __pthread_lock(&cond->c_lock);
enqueue(&cond->c_waiting, self);
- release(&cond->c_spinlock);
+ __pthread_unlock(&cond->c_lock);
pthread_mutex_unlock(mutex);
suspend_with_cancellation(self);
pthread_mutex_lock(mutex);
/* This is a cancellation point */
if (self->p_canceled && self->p_cancelstate == PTHREAD_CANCEL_ENABLE) {
/* Remove ourselves from the waiting queue if we're still on it */
- acquire(&cond->c_spinlock);
+ __pthread_lock(&cond->c_lock);
remove_from_queue(&cond->c_waiting, self);
- release(&cond->c_spinlock);
+ __pthread_unlock(&cond->c_lock);
pthread_exit(PTHREAD_CANCELED);
}
return 0;
@@ -77,15 +71,14 @@ pthread_cond_timedwait_relative(pthread_cond_t *cond,
sigjmp_buf jmpbuf;
/* Wait on the condition */
- acquire(&cond->c_spinlock);
+ __pthread_lock(&cond->c_lock);
enqueue(&cond->c_waiting, self);
- release(&cond->c_spinlock);
+ __pthread_unlock(&cond->c_lock);
pthread_mutex_unlock(mutex);
- /* Set up a longjmp handler for the restart signal */
- /* No need to save the signal mask, since PTHREAD_SIG_RESTART will be
- blocked when doing the siglongjmp, and we'll just leave it blocked. */
- if (sigsetjmp(jmpbuf, 0) == 0) {
+ /* Set up a longjmp handler for the restart and cancel signals */
+ if (sigsetjmp(jmpbuf, 1) == 0) {
self->p_signal_jmp = &jmpbuf;
+ self->p_cancel_jmp = &jmpbuf;
self->p_signal = 0;
/* Check for cancellation */
if (self->p_canceled && self->p_cancelstate == PTHREAD_CANCEL_ENABLE) {
@@ -104,28 +97,28 @@ pthread_cond_timedwait_relative(pthread_cond_t *cond,
retsleep = -1;
}
self->p_signal_jmp = NULL;
+ self->p_cancel_jmp = NULL;
/* Here, either the condition was signaled (self->p_signal != 0)
or we got canceled (self->p_canceled != 0)
or the timeout occurred (retsleep == 0)
or another interrupt occurred (retsleep == -1) */
- /* Re-acquire the spinlock */
- acquire(&cond->c_spinlock);
/* This is a cancellation point */
if (self->p_canceled && self->p_cancelstate == PTHREAD_CANCEL_ENABLE) {
+ __pthread_lock(&cond->c_lock);
remove_from_queue(&cond->c_waiting, self);
- release(&cond->c_spinlock);
+ __pthread_unlock(&cond->c_lock);
pthread_mutex_lock(mutex);
pthread_exit(PTHREAD_CANCELED);
}
/* If not signaled: also remove ourselves and return an error code */
if (self->p_signal == 0) {
+ __pthread_lock(&cond->c_lock);
remove_from_queue(&cond->c_waiting, self);
- release(&cond->c_spinlock);
+ __pthread_unlock(&cond->c_lock);
pthread_mutex_lock(mutex);
return retsleep == 0 ? ETIMEDOUT : EINTR;
}
/* Otherwise, return normally */
- release(&cond->c_spinlock);
pthread_mutex_lock(mutex);
return 0;
}
@@ -151,23 +144,22 @@ int pthread_cond_signal(pthread_cond_t *cond)
{
pthread_descr th;
- acquire(&cond->c_spinlock);
+ __pthread_lock(&cond->c_lock);
th = dequeue(&cond->c_waiting);
- release(&cond->c_spinlock);
+ __pthread_unlock(&cond->c_lock);
if (th != NULL) restart(th);
return 0;
}
int pthread_cond_broadcast(pthread_cond_t *cond)
{
- pthread_queue tosignal;
- pthread_descr th;
+ pthread_descr tosignal, th;
- acquire(&cond->c_spinlock);
+ __pthread_lock(&cond->c_lock);
/* Copy the current state of the waiting queue and empty it */
tosignal = cond->c_waiting;
- queue_init(&cond->c_waiting);
- release(&cond->c_spinlock);
+ cond->c_waiting = NULL;
+ __pthread_unlock(&cond->c_lock);
/* Now signal each process in the queue */
while ((th = dequeue(&tosignal)) != NULL) restart(th);
return 0;
@@ -182,26 +174,3 @@ int pthread_condattr_destroy(pthread_condattr_t *attr)
{
return 0;
}
-
-/* Auxiliary function on queues */
-
-static void remove_from_queue(pthread_queue * q, pthread_descr th)
-{
- pthread_descr t;
-
- if (q->head == NULL) return;
- if (q->head == th) {
- q->head = th->p_nextwaiting;
- if (q->head == NULL) q->tail = NULL;
- th->p_nextwaiting = NULL;
- return;
- }
- for (t = q->head; t->p_nextwaiting != NULL; t = t->p_nextwaiting) {
- if (t->p_nextwaiting == th) {
- t->p_nextwaiting = th->p_nextwaiting;
- if (th->p_nextwaiting == NULL) q->tail = t;
- th->p_nextwaiting = NULL;
- return;
- }
- }
-}