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);
This commit is contained in:
parent
aff14ee9c8
commit
20e3392edc
@ -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.
|
* Copyright (c) 2001, 2006, 2007 The NetBSD Foundation, Inc.
|
||||||
@ -37,7 +37,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include <sys/cdefs.h>
|
#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 <errno.h>
|
||||||
#include <sys/time.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
|
* deferred wakeup list. The waiter will be set running when the
|
||||||
* caller (this thread) releases the mutex.
|
* caller (this thread) releases the mutex.
|
||||||
*/
|
*/
|
||||||
if (mutex != NULL && pthread__mutex_owned(self, mutex) &&
|
if (mutex != NULL && self->pt_nwaiters < pthread__unpark_max &&
|
||||||
self->pt_nwaiters < pthread__unpark_max) {
|
pthread__mutex_deferwake(self, mutex)) {
|
||||||
signaled->pt_sleepobj = NULL;
|
signaled->pt_sleepobj = NULL;
|
||||||
signaled->pt_sleeponq = 0;
|
signaled->pt_sleeponq = 0;
|
||||||
pthread_spinunlock(&cond->ptc_lock);
|
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()).
|
* Try to defer waking threads (see pthread_cond_signal()).
|
||||||
* Only transfer waiters for which there is no pending wakeup.
|
* 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);
|
for (signaled = PTQ_FIRST(&cond->ptc_waiters);
|
||||||
signaled != NULL;
|
signaled != NULL;
|
||||||
signaled = next) {
|
signaled = next) {
|
||||||
|
@ -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.
|
* 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_producer(void);
|
||||||
void pthread__membar_consumer(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 *);
|
int pthread__mutex_catchup(pthread_mutex_t *);
|
||||||
|
|
||||||
#ifndef pthread__smt_pause
|
#ifndef pthread__smt_pause
|
||||||
|
@ -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.
|
* Copyright (c) 2001, 2003, 2006, 2007 The NetBSD Foundation, Inc.
|
||||||
@ -37,7 +37,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include <sys/cdefs.h>
|
#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 <errno.h>
|
||||||
#include <limits.h>
|
#include <limits.h>
|
||||||
@ -469,7 +469,7 @@ pthread_once(pthread_once_t *once_control, void (*routine)(void))
|
|||||||
}
|
}
|
||||||
|
|
||||||
int
|
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;
|
return mutex->ptm_owner == thread;
|
||||||
|
@ -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.
|
* Copyright (c) 2001, 2003, 2006, 2007 The NetBSD Foundation, Inc.
|
||||||
@ -37,7 +37,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include <sys/cdefs.h>
|
#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 <errno.h>
|
||||||
#include <limits.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_RECURSIVE_BIT (0x02UL)
|
||||||
#define MUTEX_THREAD (-16L)
|
#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_HAS_WAITERS(x) ((uintptr_t)(x) & MUTEX_WAITERS_BIT)
|
||||||
#define MUTEX_RECURSIVE(x) ((uintptr_t)(x) & MUTEX_RECURSIVE_BIT)
|
#define MUTEX_RECURSIVE(x) ((uintptr_t)(x) & MUTEX_RECURSIVE_BIT)
|
||||||
#define MUTEX_OWNER(x) ((uintptr_t)(x) & MUTEX_THREAD)
|
#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_magic = _PT_MUTEX_MAGIC;
|
||||||
ptm->ptm_waiters = NULL;
|
ptm->ptm_waiters = NULL;
|
||||||
ptm->ptm_private = NULL;
|
ptm->ptm_private = NULL;
|
||||||
|
MUTEX_DEFERRED(ptm) = 0;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -332,9 +335,12 @@ pthread_mutex_unlock(pthread_mutex_t *ptm)
|
|||||||
{
|
{
|
||||||
void *owner;
|
void *owner;
|
||||||
pthread_t self;
|
pthread_t self;
|
||||||
|
char deferred;
|
||||||
|
|
||||||
self = pthread__self();
|
self = pthread__self();
|
||||||
owner = self;
|
owner = self;
|
||||||
|
deferred = MUTEX_DEFERRED(ptm);
|
||||||
|
MUTEX_DEFERRED(ptm) = 0;
|
||||||
|
|
||||||
if (__predict_false(!mutex_cas(&ptm->ptm_owner, &owner, NULL)))
|
if (__predict_false(!mutex_cas(&ptm->ptm_owner, &owner, NULL)))
|
||||||
return pthread__mutex_unlock_slow(ptm);
|
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
|
* There were no waiters, but we may have deferred waking
|
||||||
* other threads until mutex unlock - we must wake them now.
|
* other threads until mutex unlock - we must wake them now.
|
||||||
*/
|
*/
|
||||||
if (self->pt_nwaiters != 0)
|
if (deferred)
|
||||||
return pthread__mutex_catchup(ptm);
|
return pthread__mutex_catchup(ptm);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@ -353,6 +359,7 @@ NOINLINE static int
|
|||||||
pthread__mutex_unlock_slow(pthread_mutex_t *ptm)
|
pthread__mutex_unlock_slow(pthread_mutex_t *ptm)
|
||||||
{
|
{
|
||||||
pthread_t self, owner, new;
|
pthread_t self, owner, new;
|
||||||
|
char deferred;
|
||||||
int weown;
|
int weown;
|
||||||
|
|
||||||
pthread__error(EINVAL, "Invalid mutex",
|
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
|
* Release the mutex. If there appear to be waiters, then
|
||||||
* wake them up.
|
* wake them up.
|
||||||
*/
|
*/
|
||||||
if (new != owner) {
|
if (new == owner)
|
||||||
owner = pthread__atomic_swap_ptr(&ptm->ptm_owner, new);
|
return 0;
|
||||||
if (MUTEX_HAS_WAITERS(owner) != 0) {
|
|
||||||
pthread__mutex_wakeup(self, ptm);
|
deferred = MUTEX_DEFERRED(ptm);
|
||||||
return 0;
|
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
|
* There were no waiters, but we may have deferred waking
|
||||||
* other threads until mutex unlock - we must wake them now.
|
* other threads until mutex unlock - we must wake them now.
|
||||||
*/
|
*/
|
||||||
if (self->pt_nwaiters != 0)
|
if (deferred)
|
||||||
return pthread__mutex_catchup(ptm);
|
return pthread__mutex_catchup(ptm);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@ -543,10 +553,13 @@ pthread_once(pthread_once_t *once_control, void (*routine)(void))
|
|||||||
}
|
}
|
||||||
|
|
||||||
int
|
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 */
|
#endif /* PTHREAD__HAVE_ATOMIC */
|
||||||
|
Loading…
Reference in New Issue
Block a user