diff options
| author | ad <ad@NetBSD.org> | 2007-09-13 23:51:47 +0000 |
|---|---|---|
| committer | ad <ad@NetBSD.org> | 2007-09-13 23:51:47 +0000 |
| commit | 20e3392edc8d116aa42fc6fb3daa1456c090dd49 (patch) | |
| tree | a83f6a4f3f9a0f3a1f2e158f023ee09c9404c1b6 /lib/libpthread | |
| parent | aff14ee9c85d5f7ef3c66280a8dbf7056dd34b67 (diff) | |
Add a per-mutex deferred wakeup flag so that threads doing something like
the following do not wake other threads early:
pthread_mutex_lock(&mutex);
pthread_cond_broadcast(&cond);
foo = malloc(100); /* takes libc mutexes */
pthread_mutex_unlock(&mutex);
Diffstat (limited to 'lib/libpthread')
| -rw-r--r-- | lib/libpthread/pthread_cond.c | 10 | ||||
| -rw-r--r-- | lib/libpthread/pthread_int.h | 4 | ||||
| -rw-r--r-- | lib/libpthread/pthread_mutex.c | 6 | ||||
| -rw-r--r-- | lib/libpthread/pthread_mutex2.c | 37 |
4 files changed, 35 insertions, 22 deletions
diff --git a/lib/libpthread/pthread_cond.c b/lib/libpthread/pthread_cond.c index 2f8879c1dee..4266250ed72 100644 --- a/lib/libpthread/pthread_cond.c +++ b/lib/libpthread/pthread_cond.c @@ -1,4 +1,4 @@ -/* $NetBSD: pthread_cond.c,v 1.36 2007/09/08 22:49:50 ad Exp $ */ +/* $NetBSD: pthread_cond.c,v 1.37 2007/09/13 23:51:47 ad Exp $ */ /*- * Copyright (c) 2001, 2006, 2007 The NetBSD Foundation, Inc. @@ -37,7 +37,7 @@ */ #include <sys/cdefs.h> -__RCSID("$NetBSD: pthread_cond.c,v 1.36 2007/09/08 22:49:50 ad Exp $"); +__RCSID("$NetBSD: pthread_cond.c,v 1.37 2007/09/13 23:51:47 ad Exp $"); #include <errno.h> #include <sys/time.h> @@ -324,8 +324,8 @@ pthread_cond_signal(pthread_cond_t *cond) * deferred wakeup list. The waiter will be set running when the * caller (this thread) releases the mutex. */ - if (mutex != NULL && pthread__mutex_owned(self, mutex) && - self->pt_nwaiters < pthread__unpark_max) { + if (mutex != NULL && self->pt_nwaiters < pthread__unpark_max && + pthread__mutex_deferwake(self, mutex)) { signaled->pt_sleepobj = NULL; signaled->pt_sleeponq = 0; pthread_spinunlock(&cond->ptc_lock); @@ -363,7 +363,7 @@ pthread_cond_broadcast(pthread_cond_t *cond) * Try to defer waking threads (see pthread_cond_signal()). * Only transfer waiters for which there is no pending wakeup. */ - if (mutex != NULL && pthread__mutex_owned(self, mutex)) { + if (mutex != NULL && pthread__mutex_deferwake(self, mutex)) { for (signaled = PTQ_FIRST(&cond->ptc_waiters); signaled != NULL; signaled = next) { diff --git a/lib/libpthread/pthread_int.h b/lib/libpthread/pthread_int.h index 5ff010de00a..e0c91df8564 100644 --- a/lib/libpthread/pthread_int.h +++ b/lib/libpthread/pthread_int.h @@ -1,4 +1,4 @@ -/* $NetBSD: pthread_int.h,v 1.54 2007/09/11 18:11:29 ad Exp $ */ +/* $NetBSD: pthread_int.h,v 1.55 2007/09/13 23:51:47 ad Exp $ */ /*- * Copyright (c) 2001, 2002, 2003, 2006, 2007 The NetBSD Foundation, Inc. @@ -256,7 +256,7 @@ void pthread__membar_full(void); void pthread__membar_producer(void); void pthread__membar_consumer(void); -int pthread__mutex_owned(pthread_t, pthread_mutex_t *); +int pthread__mutex_deferwake(pthread_t, pthread_mutex_t *); int pthread__mutex_catchup(pthread_mutex_t *); #ifndef pthread__smt_pause diff --git a/lib/libpthread/pthread_mutex.c b/lib/libpthread/pthread_mutex.c index 9b306169de9..bb746da1c02 100644 --- a/lib/libpthread/pthread_mutex.c +++ b/lib/libpthread/pthread_mutex.c @@ -1,4 +1,4 @@ -/* $NetBSD: pthread_mutex.c,v 1.35 2007/09/11 10:27:44 ad Exp $ */ +/* $NetBSD: pthread_mutex.c,v 1.36 2007/09/13 23:51:47 ad Exp $ */ /*- * Copyright (c) 2001, 2003, 2006, 2007 The NetBSD Foundation, Inc. @@ -37,7 +37,7 @@ */ #include <sys/cdefs.h> -__RCSID("$NetBSD: pthread_mutex.c,v 1.35 2007/09/11 10:27:44 ad Exp $"); +__RCSID("$NetBSD: pthread_mutex.c,v 1.36 2007/09/13 23:51:47 ad Exp $"); #include <errno.h> #include <limits.h> @@ -469,7 +469,7 @@ pthread_once(pthread_once_t *once_control, void (*routine)(void)) } int -pthread__mutex_owned(pthread_t thread, pthread_mutex_t *mutex) +pthread__mutex_deferwake(pthread_t thread, pthread_mutex_t *mutex) { return mutex->ptm_owner == thread; diff --git a/lib/libpthread/pthread_mutex2.c b/lib/libpthread/pthread_mutex2.c index eed06934648..2a0b6d2d91d 100644 --- a/lib/libpthread/pthread_mutex2.c +++ b/lib/libpthread/pthread_mutex2.c @@ -1,4 +1,4 @@ -/* $NetBSD: pthread_mutex2.c,v 1.6 2007/09/11 18:11:29 ad Exp $ */ +/* $NetBSD: pthread_mutex2.c,v 1.7 2007/09/13 23:51:47 ad Exp $ */ /*- * Copyright (c) 2001, 2003, 2006, 2007 The NetBSD Foundation, Inc. @@ -37,7 +37,7 @@ */ #include <sys/cdefs.h> -__RCSID("$NetBSD: pthread_mutex2.c,v 1.6 2007/09/11 18:11:29 ad Exp $"); +__RCSID("$NetBSD: pthread_mutex2.c,v 1.7 2007/09/13 23:51:47 ad Exp $"); #include <errno.h> #include <limits.h> @@ -63,6 +63,8 @@ __RCSID("$NetBSD: pthread_mutex2.c,v 1.6 2007/09/11 18:11:29 ad Exp $"); #define MUTEX_RECURSIVE_BIT (0x02UL) #define MUTEX_THREAD (-16L) +#define MUTEX_DEFERRED(x) (*(char *)&(x)->ptm_lock) + #define MUTEX_HAS_WAITERS(x) ((uintptr_t)(x) & MUTEX_WAITERS_BIT) #define MUTEX_RECURSIVE(x) ((uintptr_t)(x) & MUTEX_RECURSIVE_BIT) #define MUTEX_OWNER(x) ((uintptr_t)(x) & MUTEX_THREAD) @@ -128,6 +130,7 @@ pthread_mutex_init(pthread_mutex_t *ptm, const pthread_mutexattr_t *attr) ptm->ptm_magic = _PT_MUTEX_MAGIC; ptm->ptm_waiters = NULL; ptm->ptm_private = NULL; + MUTEX_DEFERRED(ptm) = 0; return 0; } @@ -332,9 +335,12 @@ pthread_mutex_unlock(pthread_mutex_t *ptm) { void *owner; pthread_t self; + char deferred; self = pthread__self(); owner = self; + deferred = MUTEX_DEFERRED(ptm); + MUTEX_DEFERRED(ptm) = 0; if (__predict_false(!mutex_cas(&ptm->ptm_owner, &owner, NULL))) return pthread__mutex_unlock_slow(ptm); @@ -343,7 +349,7 @@ pthread_mutex_unlock(pthread_mutex_t *ptm) * There were no waiters, but we may have deferred waking * other threads until mutex unlock - we must wake them now. */ - if (self->pt_nwaiters != 0) + if (deferred) return pthread__mutex_catchup(ptm); return 0; @@ -353,6 +359,7 @@ NOINLINE static int pthread__mutex_unlock_slow(pthread_mutex_t *ptm) { pthread_t self, owner, new; + char deferred; int weown; pthread__error(EINVAL, "Invalid mutex", @@ -386,19 +393,22 @@ pthread__mutex_unlock_slow(pthread_mutex_t *ptm) * Release the mutex. If there appear to be waiters, then * wake them up. */ - if (new != owner) { - owner = pthread__atomic_swap_ptr(&ptm->ptm_owner, new); - if (MUTEX_HAS_WAITERS(owner) != 0) { - pthread__mutex_wakeup(self, ptm); - return 0; - } + if (new == owner) + return 0; + + deferred = MUTEX_DEFERRED(ptm); + MUTEX_DEFERRED(ptm) = 0; + owner = pthread__atomic_swap_ptr(&ptm->ptm_owner, new); + if (MUTEX_HAS_WAITERS(owner) != 0) { + pthread__mutex_wakeup(self, ptm); + return 0; } /* * There were no waiters, but we may have deferred waking * other threads until mutex unlock - we must wake them now. */ - if (self->pt_nwaiters != 0) + if (deferred) return pthread__mutex_catchup(ptm); return 0; @@ -543,10 +553,13 @@ pthread_once(pthread_once_t *once_control, void (*routine)(void)) } int -pthread__mutex_owned(pthread_t thread, pthread_mutex_t *ptm) +pthread__mutex_deferwake(pthread_t thread, pthread_mutex_t *ptm) { - return MUTEX_OWNER(ptm->ptm_owner) == (uintptr_t)thread; + if (MUTEX_OWNER(ptm->ptm_owner) != (uintptr_t)thread) + return 0; + MUTEX_DEFERRED(ptm) = 1; + return 1; } #endif /* PTHREAD__HAVE_ATOMIC */ |
