Don't grab the state lock to check for cancellation around condition

variables, as _lwp_wakeup/lwp_park provide the necessary barrier.
This commit is contained in:
ad 2007-03-02 17:47:40 +00:00
parent 948e7684e3
commit dba14ef0a0
2 changed files with 64 additions and 38 deletions

View File

@ -1,4 +1,4 @@
$NetBSD: TODO,v 1.6 2007/02/15 15:39:33 yamt Exp $
$NetBSD: TODO,v 1.7 2007/03/02 17:47:40 ad Exp $
Bugs to fix, mostly with SA:
@ -108,10 +108,6 @@ Future work for 1:1 threads:
that does something similar. Again, lots of thought and benchmarking
required. (Original idea from matt@)
- It's possible that we don't need to take so many spinlocks around
cancellation points like pthread_cond_wait() given that _lwp_wakeup()
and _lwp_unpark() need to synchronise anyway.
- Need to give consideration to the order in which threads enter and exit
synchronisation objects, both in the pthread library and in the kernel.
Commonly locks are acquired/released in order (a, b, c -> c, b, a). The

View File

@ -1,4 +1,4 @@
/* $NetBSD: pthread_cond.c,v 1.20 2006/12/24 18:39:46 ad Exp $ */
/* $NetBSD: pthread_cond.c,v 1.21 2007/03/02 17:47:40 ad Exp $ */
/*-
* Copyright (c) 2001 The NetBSD Foundation, Inc.
@ -37,7 +37,7 @@
*/
#include <sys/cdefs.h>
__RCSID("$NetBSD: pthread_cond.c,v 1.20 2006/12/24 18:39:46 ad Exp $");
__RCSID("$NetBSD: pthread_cond.c,v 1.21 2007/03/02 17:47:40 ad Exp $");
#include <errno.h>
#include <sys/time.h>
@ -119,15 +119,11 @@ pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex)
if (__predict_false(pthread__started == 0))
return pthread_cond_wait_nothread(self, mutex, NULL);
#ifdef PTHREAD_SA
pthread_spinlock(self, &cond->ptc_lock);
SDPRINTF(("(cond wait %p) Waiting on %p, mutex %p\n",
self, cond, mutex));
pthread_spinlock(self, &self->pt_statelock);
if (__predict_false(self->pt_cancel)) {
pthread_spinunlock(self, &self->pt_statelock);
pthread_spinunlock(self, &cond->ptc_lock);
pthread_exit(PTHREAD_CANCELED);
}
#ifdef ERRORCHECK
if (cond->ptc_mutex == NULL)
cond->ptc_mutex = mutex;
@ -137,7 +133,13 @@ pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex)
cond->ptc_mutex == mutex);
#endif
#ifdef PTHREAD_SA
pthread_spinlock(self, &self->pt_statelock);
if (__predict_false(self->pt_cancel)) {
pthread_spinunlock(self, &self->pt_statelock);
pthread_spinunlock(self, &cond->ptc_lock);
pthread_exit(PTHREAD_CANCELED);
}
self->pt_sleepobj = cond;
self->pt_state = PT_STATE_BLOCKED_QUEUE;
self->pt_sleepq = &cond->ptc_waiters;
@ -149,8 +151,20 @@ pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex)
pthread__block(self, &cond->ptc_lock);
/* Spinlock is unlocked on return */
#else /* PTHREAD_SA */
SDPRINTF(("(cond wait %p) Waiting on %p, mutex %p\n",
self, cond, mutex));
if (__predict_false(self->pt_cancel))
pthread_exit(PTHREAD_CANCELED);
pthread_spinlock(self, &cond->ptc_lock);
#ifdef ERRORCHECK
if (cond->ptc_mutex == NULL)
cond->ptc_mutex = mutex;
else
pthread__error(EINVAL,
"Multiple mutexes used for condition wait",
cond->ptc_mutex == mutex);
#endif
pthread_mutex_unlock(mutex);
pthread_spinunlock(self, &self->pt_statelock);
(void)pthread__park(self, &cond->ptc_lock, cond,
&cond->ptc_waiters, NULL, 0, 1);
pthread_spinunlock(self, &cond->ptc_lock);
@ -206,10 +220,12 @@ pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex,
if (__predict_false(pthread__started == 0))
return pthread_cond_wait_nothread(self, mutex, abstime);
pthread_spinlock(self, &cond->ptc_lock);
wait.ptw_thread = self;
wait.ptw_cond = cond;
retval = 0;
#ifdef PTHREAD_SA
pthread_spinlock(self, &cond->ptc_lock);
SDPRINTF(("(cond timed wait %p) Waiting on %p until %d.%06ld\n",
self, cond, abstime->tv_sec, abstime->tv_nsec/1000));
@ -228,7 +244,6 @@ pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex,
cond->ptc_mutex == mutex);
#endif
#ifdef PTHREAD_SA
pthread__alarm_add(self, &alarm, abstime, pthread_cond_wait__callback,
&wait);
self->pt_state = PT_STATE_BLOCKED_QUEUE;
@ -246,8 +261,21 @@ pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex,
if (pthread__alarm_fired(&alarm))
retval = ETIMEDOUT;
#else /* PTHREAD_SA */
SDPRINTF(("(cond timed wait %p) Waiting on %p until %d.%06ld\n",
self, cond, abstime->tv_sec, abstime->tv_nsec/1000));
if (__predict_false(self->pt_cancel))
pthread_exit(PTHREAD_CANCELED);
pthread_spinlock(self, &cond->ptc_lock);
#ifdef ERRORCHECK
if (cond->ptc_mutex == NULL)
cond->ptc_mutex = mutex;
else
pthread__error(EINVAL,
"Multiple mutexes used for condition wait",
cond->ptc_mutex == mutex);
#endif
pthread_mutex_unlock(mutex);
pthread_spinunlock(self, &self->pt_statelock);
retval = pthread__park(self, &cond->ptc_lock, cond,
&cond->ptc_waiters, abstime, 0, 1);
pthread_spinunlock(self, &cond->ptc_lock);
@ -328,18 +356,26 @@ pthread_cond_signal(pthread_cond_t *cond)
pthread_spinunlock(self, &cond->ptc_lock);
}
#else /* PTHREAD_SA */
self = pthread__self();
pthread_spinlock(self, &cond->ptc_lock);
if ((signaled = PTQ_FIRST(&cond->ptc_waiters)) != NULL) {
PTQ_REMOVE(&cond->ptc_waiters, signaled, pt_sleep);
PTHREADD_ADD(PTHREADD_COND_WOKEUP);
if (!PTQ_EMPTY(&cond->ptc_waiters)) {
self = pthread__self();
pthread_spinlock(self, &cond->ptc_lock);
signaled = PTQ_FIRST(&cond->ptc_waiters);
if (signaled != NULL) {
PTQ_REMOVE(&cond->ptc_waiters, signaled, pt_sleep);
#ifdef ERRORCHECK
if (PTQ_EMPTY(&cond->ptc_waiters))
cond->ptc_mutex = NULL;
#endif
pthread__unpark(self, &cond->ptc_lock, cond, signaled);
PTHREADD_ADD(PTHREADD_COND_WOKEUP);
} else {
#ifdef ERRORCHECK
if (PTQ_EMPTY(&cond->ptc_waiters))
cond->ptc_mutex = NULL;
#endif
pthread_spinunlock(self, &cond->ptc_lock);
}
}
pthread__unpark(self, &cond->ptc_lock, cond, signaled);
#endif /* PTHREAD_SA */
#endif
return 0;
}
@ -358,29 +394,23 @@ pthread_cond_broadcast(pthread_cond_t *cond)
SDPRINTF(("(cond signal %p) Broadcasting %p\n",
pthread__self(), cond));
#ifdef PTHREAD_SA
if (!PTQ_EMPTY(&cond->ptc_waiters)) {
self = pthread__self();
pthread_spinlock(self, &cond->ptc_lock);
blockedq = cond->ptc_waiters;
PTQ_INIT(&cond->ptc_waiters);
#ifdef ERRORCHECK
cond->ptc_mutex = NULL;
#endif
#ifdef PTHREAD_SA
blockedq = cond->ptc_waiters;
PTQ_INIT(&cond->ptc_waiters);
pthread__sched_sleepers(self, &blockedq);
PTHREADD_ADD(PTHREADD_COND_WOKEUP);
pthread_spinunlock(self, &cond->ptc_lock);
}
#else /* PTHREAD_SA */
self = pthread__self();
pthread_spinlock(self, &cond->ptc_lock);
#ifdef ERRORCHECK
if (!PTQ_EMPTY(&cond->ptc_waiters))
cond->ptc_mutex = NULL;
#endif
pthread__unpark_all(self, &cond->ptc_lock, cond, &cond->ptc_waiters);
PTHREADD_ADD(PTHREADD_COND_WOKEUP);
pthread__unpark_all(self, &cond->ptc_lock, cond, &cond->ptc_waiters);
PTHREADD_ADD(PTHREADD_COND_WOKEUP);
#endif /* PTHREAD_SA */
}
return 0;