implement priority inheritance.

This commit is contained in:
yamt 2007-02-26 09:20:52 +00:00
parent 1458eba0f6
commit e781af39bd
15 changed files with 363 additions and 84 deletions

View File

@ -1,4 +1,4 @@
/* $NetBSD: kern_condvar.c,v 1.3 2007/02/11 15:41:53 yamt Exp $ */
/* $NetBSD: kern_condvar.c,v 1.4 2007/02/26 09:20:52 yamt Exp $ */
/*-
* Copyright (c) 2006, 2007 The NetBSD Foundation, Inc.
@ -45,7 +45,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: kern_condvar.c,v 1.3 2007/02/11 15:41:53 yamt Exp $");
__KERNEL_RCSID(0, "$NetBSD: kern_condvar.c,v 1.4 2007/02/26 09:20:52 yamt Exp $");
#include <sys/param.h>
#include <sys/proc.h>
@ -61,6 +61,8 @@ syncobj_t cv_syncobj = {
SOBJ_SLEEPQ_SORTED,
cv_unsleep,
cv_changepri,
sleepq_lendpri,
syncobj_noowner,
};
/*
@ -149,13 +151,13 @@ cv_changepri(struct lwp *l, int pri)
KASSERT(lwp_locked(l, sq->sq_mutex));
opri = l->l_priority;
opri = lwp_eprio(l);
l->l_usrpri = pri;
l->l_priority = sched_kpri(l);
if (l->l_priority != opri) {
if (lwp_eprio(l) != opri) {
TAILQ_REMOVE(&sq->sq_queue, l, l_sleepchain);
sleepq_insert(sq, l, pri, l->l_syncobj);
sleepq_insert(sq, l, l->l_syncobj);
}
}

View File

@ -1,4 +1,4 @@
/* $NetBSD: kern_ktrace.c,v 1.116 2007/02/22 06:34:43 thorpej Exp $ */
/* $NetBSD: kern_ktrace.c,v 1.117 2007/02/26 09:20:53 yamt Exp $ */
/*
* Copyright (c) 1989, 1993
@ -32,7 +32,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: kern_ktrace.c,v 1.116 2007/02/22 06:34:43 thorpej Exp $");
__KERNEL_RCSID(0, "$NetBSD: kern_ktrace.c,v 1.117 2007/02/26 09:20:53 yamt Exp $");
#include "opt_ktrace.h"
#include "opt_compat_mach.h"
@ -688,7 +688,7 @@ ktrcsw(struct lwp *l, int out, int user)
* Don't record context switches resulting from blocking on
* locks; it's too easy to get duff results.
*/
if (l->l_syncobj == &turnstile_syncobj)
if (l->l_syncobj == &mutex_syncobj || l->l_syncobj == &rw_syncobj)
return;
/*

View File

@ -1,4 +1,4 @@
/* $NetBSD: kern_lwp.c,v 1.59 2007/02/21 23:48:13 thorpej Exp $ */
/* $NetBSD: kern_lwp.c,v 1.60 2007/02/26 09:20:53 yamt Exp $ */
/*-
* Copyright (c) 2001, 2006, 2007 The NetBSD Foundation, Inc.
@ -204,7 +204,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: kern_lwp.c,v 1.59 2007/02/21 23:48:13 thorpej Exp $");
__KERNEL_RCSID(0, "$NetBSD: kern_lwp.c,v 1.60 2007/02/26 09:20:53 yamt Exp $");
#include "opt_multiprocessor.h"
#include "opt_lockdebug.h"
@ -504,9 +504,12 @@ newlwp(struct lwp *l1, struct proc *p2, vaddr_t uaddr, bool inmem,
l2 = pool_get(&lwp_pool, PR_WAITOK);
memset(l2, 0, sizeof(*l2));
l2->l_ts = pool_cache_get(&turnstile_cache, PR_WAITOK);
SLIST_INIT(&l2->l_pi_lenders);
} else {
l2 = isfree;
ts = l2->l_ts;
KASSERT(l2->l_inheritedprio == MAXPRI);
KASSERT(SLIST_EMPTY(&l2->l_pi_lenders));
memset(l2, 0, sizeof(*l2));
l2->l_ts = ts;
}
@ -516,6 +519,7 @@ newlwp(struct lwp *l1, struct proc *p2, vaddr_t uaddr, bool inmem,
l2->l_refcnt = 1;
l2->l_priority = l1->l_priority;
l2->l_usrpri = l1->l_usrpri;
l2->l_inheritedprio = MAXPRI;
l2->l_mutex = &sched_mutex;
l2->l_cpu = l1->l_cpu;
l2->l_flag = inmem ? LW_INMEM : 0;
@ -782,6 +786,8 @@ lwp_free(struct lwp *l, int recycle, int last)
cpu_lwp_free2(l);
#endif
uvm_lwp_exit(l);
KASSERT(SLIST_EMPTY(&l->l_pi_lenders));
KASSERT(l->l_inheritedprio == MAXPRI);
if (!recycle)
pool_put(&lwp_pool, l);
KERNEL_UNLOCK_ONE(curlwp); /* XXXSMP */
@ -1065,6 +1071,24 @@ lwp_relock(struct lwp *l, kmutex_t *new)
#endif
}
int
lwp_trylock(struct lwp *l)
{
#if defined(MULTIPROCESSOR) || defined(LOCKDEBUG)
kmutex_t *old;
for (;;) {
if (!mutex_tryenter(old = l->l_mutex))
return 0;
if (__predict_true(l->l_mutex == old))
return 1;
mutex_spin_exit(old);
}
#else
return mutex_tryenter(l->l_mutex);
#endif
}
/*
* Handle exceptions for mi_userret(). Called if a member of LW_USERRET is
* set.

View File

@ -1,4 +1,4 @@
/* $NetBSD: kern_mutex.c,v 1.4 2007/02/15 15:49:27 ad Exp $ */
/* $NetBSD: kern_mutex.c,v 1.5 2007/02/26 09:20:53 yamt Exp $ */
/*-
* Copyright (c) 2002, 2006, 2007 The NetBSD Foundation, Inc.
@ -49,7 +49,7 @@
#define __MUTEX_PRIVATE
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: kern_mutex.c,v 1.4 2007/02/15 15:49:27 ad Exp $");
__KERNEL_RCSID(0, "$NetBSD: kern_mutex.c,v 1.5 2007/02/26 09:20:53 yamt Exp $");
#include <sys/param.h>
#include <sys/proc.h>
@ -236,6 +236,7 @@ __strong_alias(mutex_spin_exit, mutex_vector_exit);
void mutex_abort(kmutex_t *, const char *, const char *);
void mutex_dump(volatile void *);
int mutex_onproc(uintptr_t, struct cpu_info **);
static struct lwp *mutex_getowner(wchan_t); /* XXX naming conflict */
lockops_t mutex_spin_lockops = {
"Mutex",
@ -249,6 +250,14 @@ lockops_t mutex_adaptive_lockops = {
mutex_dump
};
syncobj_t mutex_syncobj = {
SOBJ_SLEEPQ_SORTED,
turnstile_unsleep,
turnstile_changepri,
sleepq_lendpri,
mutex_getowner,
};
/*
* mutex_dump:
*
@ -637,7 +646,7 @@ mutex_vector_enter(kmutex_t *mtx)
LOCKSTAT_START_TIMER(lsflag, slptime);
turnstile_block(ts, TS_WRITER_Q, mtx);
turnstile_block(ts, TS_WRITER_Q, mtx, &mutex_syncobj);
LOCKSTAT_STOP_TIMER(lsflag, slptime);
LOCKSTAT_COUNT(slpcnt, 1);
@ -761,6 +770,14 @@ mutex_owner(kmutex_t *mtx)
return (struct lwp *)MUTEX_OWNER(mtx->mtx_owner);
}
static struct lwp *
mutex_getowner(wchan_t obj)
{
kmutex_t *mtx = (void *)(uintptr_t)obj; /* discard qualifiers */
return mutex_owner(mtx);
}
/*
* mutex_tryenter:
*

View File

@ -1,4 +1,4 @@
/* $NetBSD: kern_proc.c,v 1.104 2007/02/21 23:48:14 thorpej Exp $ */
/* $NetBSD: kern_proc.c,v 1.105 2007/02/26 09:20:53 yamt Exp $ */
/*-
* Copyright (c) 1999, 2006, 2007 The NetBSD Foundation, Inc.
@ -69,7 +69,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: kern_proc.c,v 1.104 2007/02/21 23:48:14 thorpej Exp $");
__KERNEL_RCSID(0, "$NetBSD: kern_proc.c,v 1.105 2007/02/26 09:20:53 yamt Exp $");
#include "opt_kstack.h"
#include "opt_maxuprc.h"
@ -355,6 +355,8 @@ proc0_init(void)
l->l_cpu = curcpu();
l->l_priority = PRIBIO;
l->l_usrpri = PRIBIO;
l->l_inheritedprio = MAXPRI;
SLIST_INIT(&l->l_pi_lenders);
callout_init(&l->l_tsleep_ch);
cv_init(&l->l_sigcv, "sigwait");

View File

@ -1,4 +1,4 @@
/* $NetBSD: kern_rwlock.c,v 1.3 2007/02/10 21:07:52 ad Exp $ */
/* $NetBSD: kern_rwlock.c,v 1.4 2007/02/26 09:20:53 yamt Exp $ */
/*-
* Copyright (c) 2002, 2006, 2007 The NetBSD Foundation, Inc.
@ -47,7 +47,7 @@
#include "opt_multiprocessor.h"
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: kern_rwlock.c,v 1.3 2007/02/10 21:07:52 ad Exp $");
__KERNEL_RCSID(0, "$NetBSD: kern_rwlock.c,v 1.4 2007/02/26 09:20:53 yamt Exp $");
#define __RWLOCK_PRIVATE
@ -145,6 +145,7 @@ __strong_alias(rw_exit, rw_vector_exit);
#endif
void rw_dump(volatile void *);
static struct lwp *rw_owner(wchan_t);
lockops_t rwlock_lockops = {
"Reader / writer lock",
@ -152,6 +153,14 @@ lockops_t rwlock_lockops = {
rw_dump
};
syncobj_t rw_syncobj = {
SOBJ_SLEEPQ_SORTED,
turnstile_unsleep,
turnstile_changepri,
sleepq_lendpri,
rw_owner,
};
/*
* rw_dump:
*
@ -299,7 +308,7 @@ rw_vector_enter(krwlock_t *rw, const krw_t op)
LOCKSTAT_START_TIMER(lsflag, slptime);
turnstile_block(ts, queue, rw);
turnstile_block(ts, queue, rw, &rw_syncobj);
/* If we wake up and arrive here, we've been handed the lock. */
RW_RECEIVE(rw);
@ -670,3 +679,15 @@ rw_lock_held(krwlock_t *rw)
return (rw->rw_owner & RW_THREAD) != 0;
}
static struct lwp *
rw_owner(wchan_t obj)
{
krwlock_t *rw = (void *)(uintptr_t)obj; /* discard qualifiers */
uintptr_t owner = rw->rw_owner;
if ((owner & RW_WRITE_LOCKED) == 0)
return NULL;
return (void *)(owner & RW_THREAD);
}

View File

@ -1,4 +1,4 @@
/* $NetBSD: kern_sleepq.c,v 1.5 2007/02/17 22:31:43 pavel Exp $ */
/* $NetBSD: kern_sleepq.c,v 1.6 2007/02/26 09:20:53 yamt Exp $ */
/*-
* Copyright (c) 2006, 2007 The NetBSD Foundation, Inc.
@ -42,7 +42,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: kern_sleepq.c,v 1.5 2007/02/17 22:31:43 pavel Exp $");
__KERNEL_RCSID(0, "$NetBSD: kern_sleepq.c,v 1.6 2007/02/26 09:20:53 yamt Exp $");
#include "opt_multiprocessor.h"
#include "opt_lockdebug.h"
@ -177,7 +177,7 @@ sleepq_remove(sleepq_t *sq, struct lwp *l)
l->l_slptime = 0;
if ((l->l_flag & LW_INMEM) != 0) {
setrunqueue(l);
if (l->l_priority < ci->ci_schedstate.spc_curpriority)
if (lwp_eprio(l) < ci->ci_schedstate.spc_curpriority)
cpu_need_resched(ci);
sched_unlock(1);
return 0;
@ -193,13 +193,14 @@ sleepq_remove(sleepq_t *sq, struct lwp *l)
* Insert an LWP into the sleep queue, optionally sorting by priority.
*/
inline void
sleepq_insert(sleepq_t *sq, struct lwp *l, int pri, syncobj_t *sobj)
sleepq_insert(sleepq_t *sq, struct lwp *l, syncobj_t *sobj)
{
struct lwp *l2;
const int pri = lwp_eprio(l);
if ((sobj->sobj_flag & SOBJ_SLEEPQ_SORTED) != 0) {
TAILQ_FOREACH(l2, &sq->sq_queue, l_sleepchain) {
if (l2->l_priority > pri) {
if (lwp_eprio(l2) > pri) {
TAILQ_INSERT_BEFORE(l2, l, l_sleepchain);
return;
}
@ -209,19 +210,9 @@ sleepq_insert(sleepq_t *sq, struct lwp *l, int pri, syncobj_t *sobj)
TAILQ_INSERT_TAIL(&sq->sq_queue, l, l_sleepchain);
}
/*
* sleepq_block:
*
* Enter an LWP into the sleep queue and prepare for sleep. The sleep
* queue must already be locked, and any interlock (such as the kernel
* lock) must have be released (see sleeptab_lookup(), sleepq_enter()).
*
* sleepq_block() may return early under exceptional conditions, for
* example if the LWP's containing process is exiting.
*/
void
sleepq_block(sleepq_t *sq, int pri, wchan_t wchan, const char *wmesg, int timo,
int catch, syncobj_t *sobj)
sleepq_enqueue(sleepq_t *sq, int pri, wchan_t wchan, const char *wmesg,
syncobj_t *sobj)
{
struct lwp *l = curlwp;
@ -240,7 +231,13 @@ sleepq_block(sleepq_t *sq, int pri, wchan_t wchan, const char *wmesg, int timo,
l->l_nvcsw++;
sq->sq_waiters++;
sleepq_insert(sq, l, pri, sobj);
sleepq_insert(sq, l, sobj);
}
void
sleepq_switch(int timo, int catch)
{
struct lwp *l = curlwp;
#ifdef KTRACE
if (KTRPOINT(l->l_proc, KTR_CSW))
@ -280,6 +277,25 @@ sleepq_block(sleepq_t *sq, int pri, wchan_t wchan, const char *wmesg, int timo,
KASSERT(l->l_wchan == NULL && l->l_sleepq == NULL);
}
/*
* sleepq_block:
*
* Enter an LWP into the sleep queue and prepare for sleep. The sleep
* queue must already be locked, and any interlock (such as the kernel
* lock) must have be released (see sleeptab_lookup(), sleepq_enter()).
*
* sleepq_block() may return early under exceptional conditions, for
* example if the LWP's containing process is exiting.
*/
void
sleepq_block(sleepq_t *sq, int pri, wchan_t wchan, const char *wmesg, int timo,
int catch, syncobj_t *sobj)
{
sleepq_enqueue(sq, pri, wchan, wmesg, sobj);
sleepq_switch(timo, catch);
}
/*
* sleepq_unblock:
*
@ -484,3 +500,21 @@ sleepq_changepri(struct lwp *l, int pri)
KASSERT(lwp_locked(l, l->l_sleepq->sq_mutex));
l->l_usrpri = pri;
}
void
sleepq_lendpri(struct lwp *l, int pri)
{
sleepq_t *sq = l->l_sleepq;
int opri;
KASSERT(lwp_locked(l, sq->sq_mutex));
opri = lwp_eprio(l);
l->l_inheritedprio = pri;
if (lwp_eprio(l) != opri &&
(l->l_syncobj->sobj_flag & SOBJ_SLEEPQ_SORTED) != 0) {
TAILQ_REMOVE(&sq->sq_queue, l, l_sleepchain);
sleepq_insert(sq, l, l->l_syncobj);
}
}

View File

@ -1,4 +1,4 @@
/* $NetBSD: kern_synch.c,v 1.183 2007/02/23 16:51:47 ad Exp $ */
/* $NetBSD: kern_synch.c,v 1.184 2007/02/26 09:20:53 yamt Exp $ */
/*-
* Copyright (c) 1999, 2000, 2004, 2006, 2007 The NetBSD Foundation, Inc.
@ -74,7 +74,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: kern_synch.c,v 1.183 2007/02/23 16:51:47 ad Exp $");
__KERNEL_RCSID(0, "$NetBSD: kern_synch.c,v 1.184 2007/02/26 09:20:53 yamt Exp $");
#include "opt_ddb.h"
#include "opt_kstack.h"
@ -120,6 +120,7 @@ void updatepri(struct lwp *);
void sched_unsleep(struct lwp *);
void sched_changepri(struct lwp *, int);
void sched_lendpri(struct lwp *, int);
struct callout schedcpu_ch = CALLOUT_INITIALIZER_SETFUNC(schedcpu, NULL);
static unsigned int schedcpu_ticks;
@ -127,13 +128,17 @@ static unsigned int schedcpu_ticks;
syncobj_t sleep_syncobj = {
SOBJ_SLEEPQ_SORTED,
sleepq_unsleep,
sleepq_changepri
sleepq_changepri,
sleepq_lendpri,
syncobj_noowner,
};
syncobj_t sched_syncobj = {
SOBJ_SLEEPQ_SORTED,
sched_unsleep,
sched_changepri
sched_changepri,
sched_lendpri,
syncobj_noowner,
};
/*
@ -743,9 +748,10 @@ rqinit()
}
static inline void
resched_lwp(struct lwp *l, u_char pri)
resched_lwp(struct lwp *l)
{
struct cpu_info *ci;
const int pri = lwp_eprio(l);
/*
* XXXSMP
@ -857,7 +863,7 @@ setrunnable(struct lwp *l)
if (l->l_flag & LW_INMEM) {
setrunqueue(l);
resched_lwp(l, l->l_priority);
resched_lwp(l);
lwp_unlock(l);
} else {
lwp_unlock(l);
@ -1108,11 +1114,10 @@ sched_changepri(struct lwp *l, int pri)
LOCK_ASSERT(lwp_locked(l, &sched_mutex));
l->l_usrpri = pri;
if (l->l_priority < PUSER)
return;
if (l->l_stat != LSRUN || (l->l_flag & LW_INMEM) == 0 ||
(l->l_priority / PPQ) == (pri / PPQ)) {
if (l->l_stat != LSRUN || (l->l_flag & LW_INMEM) == 0) {
l->l_priority = pri;
return;
}
@ -1120,7 +1125,31 @@ sched_changepri(struct lwp *l, int pri)
remrunqueue(l);
l->l_priority = pri;
setrunqueue(l);
resched_lwp(l, pri);
resched_lwp(l);
}
void
sched_lendpri(struct lwp *l, int pri)
{
LOCK_ASSERT(lwp_locked(l, &sched_mutex));
if (l->l_stat != LSRUN || (l->l_flag & LW_INMEM) == 0) {
l->l_inheritedprio = pri;
return;
}
remrunqueue(l);
l->l_inheritedprio = pri;
setrunqueue(l);
resched_lwp(l);
}
struct lwp *
syncobj_noowner(wchan_t wchan)
{
return NULL;
}
/*
@ -1212,7 +1241,7 @@ setrunqueue(struct lwp *l)
{
struct prochd *rq;
struct lwp *prev;
const int whichq = l->l_priority / PPQ;
const int whichq = lwp_eprio(l) / PPQ;
LOCK_ASSERT(lwp_locked(l, &sched_mutex));
@ -1245,7 +1274,7 @@ void
remrunqueue(struct lwp *l)
{
struct lwp *prev, *next;
const int whichq = l->l_priority / PPQ;
const int whichq = lwp_eprio(l) / PPQ;
LOCK_ASSERT(lwp_locked(l, &sched_mutex));

View File

@ -1,4 +1,4 @@
/* $NetBSD: kern_turnstile.c,v 1.3 2007/02/15 20:21:13 ad Exp $ */
/* $NetBSD: kern_turnstile.c,v 1.4 2007/02/26 09:20:53 yamt Exp $ */
/*-
* Copyright (c) 2002, 2006, 2007 The NetBSD Foundation, Inc.
@ -63,12 +63,11 @@
* grabs a free turnstile off the free list. Otherwise, it can take back
* the active turnstile from the lock (thus deactivating the turnstile).
*
* Turnstiles are the place to do priority inheritence. However, we do
* not currently implement that.
* Turnstiles are the place to do priority inheritence.
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: kern_turnstile.c,v 1.3 2007/02/15 20:21:13 ad Exp $");
__KERNEL_RCSID(0, "$NetBSD: kern_turnstile.c,v 1.4 2007/02/26 09:20:53 yamt Exp $");
#include "opt_lockdebug.h"
#include "opt_multiprocessor.h"
@ -77,6 +76,7 @@ __KERNEL_RCSID(0, "$NetBSD: kern_turnstile.c,v 1.3 2007/02/15 20:21:13 ad Exp $"
#include <sys/param.h>
#include <sys/lock.h>
#include <sys/lockdebug.h>
#include <sys/pool.h>
#include <sys/proc.h>
#include <sys/sleepq.h>
@ -94,17 +94,9 @@ struct pool turnstile_pool;
struct pool_cache turnstile_cache;
int turnstile_ctor(void *, void *, int);
void turnstile_unsleep(struct lwp *);
void turnstile_changepri(struct lwp *, int);
extern turnstile_t turnstile0;
syncobj_t turnstile_syncobj = {
SOBJ_SLEEPQ_FIFO,
turnstile_unsleep,
turnstile_changepri
};
/*
* turnstile_init:
*
@ -231,15 +223,18 @@ turnstile_exit(wchan_t obj)
* LWP for sleep.
*/
void
turnstile_block(turnstile_t *ts, int q, wchan_t obj)
turnstile_block(turnstile_t *ts, int q, wchan_t obj, syncobj_t *sobj)
{
struct lwp *l;
struct lwp *cur; /* cached curlwp */
struct lwp *owner;
turnstile_t *ots;
tschain_t *tc;
sleepq_t *sq;
u_char prio;
tc = &turnstile_tab[TS_HASH(obj)];
l = curlwp;
l = cur = curlwp;
KASSERT(q == TS_READER_Q || q == TS_WRITER_Q);
KASSERT(mutex_owned(tc->tc_mutex));
@ -255,6 +250,7 @@ turnstile_block(turnstile_t *ts, int q, wchan_t obj)
KASSERT(TAILQ_EMPTY(&ts->ts_sleepq[TS_READER_Q].sq_queue) &&
TAILQ_EMPTY(&ts->ts_sleepq[TS_WRITER_Q].sq_queue));
ts->ts_obj = obj;
ts->ts_inheritor = NULL;
ts->ts_sleepq[TS_READER_Q].sq_mutex = tc->tc_mutex;
ts->ts_sleepq[TS_WRITER_Q].sq_mutex = tc->tc_mutex;
LIST_INSERT_HEAD(&tc->tc_chain, ts, ts_chain);
@ -269,6 +265,7 @@ turnstile_block(turnstile_t *ts, int q, wchan_t obj)
ts->ts_free = ots;
l->l_ts = ts;
KASSERT(ts->ts_obj == obj);
KASSERT(TS_ALL_WAITERS(ts) != 0);
KASSERT(!TAILQ_EMPTY(&ts->ts_sleepq[TS_READER_Q].sq_queue) ||
!TAILQ_EMPTY(&ts->ts_sleepq[TS_WRITER_Q].sq_queue));
@ -276,8 +273,69 @@ turnstile_block(turnstile_t *ts, int q, wchan_t obj)
sq = &ts->ts_sleepq[q];
sleepq_enter(sq, l);
sleepq_block(sq, sched_kpri(l), obj, "tstile", 0, 0,
&turnstile_syncobj);
LOCKDEBUG_BARRIER(tc->tc_mutex, 1);
prio = lwp_eprio(l);
sleepq_enqueue(sq, prio, obj, "tstile", sobj);
/*
* lend our priority to lwps on the blocking chain.
*/
for (;;) {
bool dolock;
if (l->l_wchan == NULL)
break;
owner = (*l->l_syncobj->sobj_owner)(l->l_wchan);
if (owner == NULL)
break;
KASSERT(l != owner);
KASSERT(cur != owner);
if (l->l_mutex != owner->l_mutex)
dolock = true;
else
dolock = false;
if (dolock && !lwp_trylock(owner)) {
/*
* restart from curlwp.
*/
lwp_unlock(l);
l = cur;
lwp_lock(l);
prio = lwp_eprio(l);
continue;
}
if (prio >= lwp_eprio(owner)) {
if (dolock)
lwp_unlock(owner);
break;
}
ts = l->l_ts;
KASSERT(ts->ts_inheritor == owner || ts->ts_inheritor == NULL);
if (ts->ts_inheritor == NULL) {
ts->ts_inheritor = owner;
ts->ts_eprio = prio;
SLIST_INSERT_HEAD(&owner->l_pi_lenders, ts, ts_pichain);
lwp_lendpri(owner, prio);
} else if (prio < ts->ts_eprio) {
ts->ts_eprio = prio;
lwp_lendpri(owner, prio);
}
if (dolock)
lwp_unlock(l);
l = owner;
}
LOCKDEBUG_BARRIER(l->l_mutex, 1);
if (cur->l_mutex != l->l_mutex) {
lwp_unlock(l);
lwp_lock(cur);
}
LOCKDEBUG_BARRIER(cur->l_mutex, 1);
sleepq_switch(0, 0);
}
/*
@ -301,6 +359,52 @@ turnstile_wakeup(turnstile_t *ts, int q, int count, struct lwp *nl)
KASSERT(q == TS_READER_Q || q == TS_WRITER_Q);
KASSERT(count > 0 && count <= TS_WAITERS(ts, q));
KASSERT(mutex_owned(tc->tc_mutex) && sq->sq_mutex == tc->tc_mutex);
KASSERT(ts->ts_inheritor == curlwp || ts->ts_inheritor == NULL);
/*
* restore inherited priority if necessary.
*/
if (ts->ts_inheritor != NULL) {
turnstile_t *iter;
turnstile_t *next;
turnstile_t *prev = NULL;
u_char prio;
ts->ts_inheritor = NULL;
l = curlwp;
lwp_lock(l);
/*
* the following loop does two things.
*
* - remove ts from the list.
*
* - from the rest of the list, find the highest priority.
*/
prio = MAXPRI;
KASSERT(!SLIST_EMPTY(&l->l_pi_lenders));
for (iter = SLIST_FIRST(&l->l_pi_lenders);
iter != NULL; iter = next) {
KASSERT(lwp_eprio(l) <= ts->ts_eprio);
next = SLIST_NEXT(iter, ts_pichain);
if (iter == ts) {
if (prev == NULL) {
SLIST_REMOVE_HEAD(&l->l_pi_lenders,
ts_pichain);
} else {
SLIST_REMOVE_AFTER(prev, ts_pichain);
}
} else if (prio > iter->ts_eprio) {
prio = iter->ts_eprio;
}
prev = iter;
}
lwp_lendpri(l, prio);
lwp_unlock(l);
}
if (nl != NULL) {
#if defined(DEBUG) || defined(LOCKDEBUG)
@ -348,16 +452,14 @@ turnstile_unsleep(struct lwp *l)
/*
* turnstile_changepri:
*
* Adjust the priority of an LWP residing on a turnstile. Since we do
* not yet do priority inheritance, we mostly ignore this action.
* Adjust the priority of an LWP residing on a turnstile.
*/
void
turnstile_changepri(struct lwp *l, int pri)
{
/* LWPs on turnstiles always have kernel priority. */
l->l_usrpri = pri;
l->l_priority = sched_kpri(l);
/* XXX priority inheritance */
sleepq_changepri(l, pri);
}
#if defined(LOCKDEBUG)

View File

@ -1,4 +1,4 @@
/* $NetBSD: sys_lwp.c,v 1.6 2007/02/21 23:48:15 thorpej Exp $ */
/* $NetBSD: sys_lwp.c,v 1.7 2007/02/26 09:20:54 yamt Exp $ */
/*-
* Copyright (c) 2001, 2006, 2007 The NetBSD Foundation, Inc.
@ -42,7 +42,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: sys_lwp.c,v 1.6 2007/02/21 23:48:15 thorpej Exp $");
__KERNEL_RCSID(0, "$NetBSD: sys_lwp.c,v 1.7 2007/02/26 09:20:54 yamt Exp $");
#include <sys/param.h>
#include <sys/systm.h>
@ -61,7 +61,9 @@ __KERNEL_RCSID(0, "$NetBSD: sys_lwp.c,v 1.6 2007/02/21 23:48:15 thorpej Exp $");
syncobj_t lwp_park_sobj = {
SOBJ_SLEEPQ_SORTED,
sleepq_unsleep,
sleepq_changepri
sleepq_changepri,
sleepq_lendpri,
syncobj_noowner,
};
sleeptab_t lwp_park_tab;

View File

@ -1,4 +1,4 @@
/* $NetBSD: lwp.h,v 1.51 2007/02/22 04:38:03 matt Exp $ */
/* $NetBSD: lwp.h,v 1.52 2007/02/26 09:20:52 yamt Exp $ */
/*-
* Copyright (c) 2001, 2006, 2007 The NetBSD Foundation, Inc.
@ -83,8 +83,10 @@ struct lwp {
u_int l_swtime; /* l: time swapped in or out */
int l_holdcnt; /* l: if non-zero, don't swap */
int l_biglocks; /* l: biglock count before sleep */
u_char l_priority; /* l: process priority */
u_char l_usrpri; /* l: user-priority */
int l_priority; /* l: process priority */
int l_usrpri; /* l: user-priority */
int l_inheritedprio;/* l: inherited priority */
SLIST_HEAD(, turnstile) l_pi_lenders; /* l: ts lending us priority */
long l_nvcsw; /* l: voluntary context switches */
long l_nivcsw; /* l: involuntary context switches */
@ -250,6 +252,7 @@ void lwp_setlock(struct lwp *, kmutex_t *);
void lwp_unlock_to(struct lwp *, kmutex_t *);
void lwp_lock_retry(struct lwp *, kmutex_t *);
void lwp_relock(struct lwp *, kmutex_t *);
int lwp_trylock(struct lwp *);
void lwp_addref(struct lwp *);
void lwp_delref(struct lwp *);
void lwp_drainrefs(struct lwp *);
@ -322,9 +325,23 @@ lwp_changepri(struct lwp *l, int pri)
{
LOCK_ASSERT(mutex_owned(l->l_mutex));
if (l->l_priority == pri)
return;
(*l->l_syncobj->sobj_changepri)(l, pri);
}
static inline void
lwp_lendpri(struct lwp *l, int pri)
{
LOCK_ASSERT(mutex_owned(l->l_mutex));
if (l->l_inheritedprio == pri)
return;
(*l->l_syncobj->sobj_lendpri)(l, pri);
}
static inline void
lwp_unsleep(struct lwp *l)
{
@ -333,6 +350,13 @@ lwp_unsleep(struct lwp *l)
(*l->l_syncobj->sobj_unsleep)(l);
}
static inline int
lwp_eprio(struct lwp *l)
{
return MIN(l->l_inheritedprio, l->l_priority);
}
int newlwp(struct lwp *, struct proc *, vaddr_t, bool, int,
void *, size_t, void (*)(void *), void *, struct lwp **);

View File

@ -1,4 +1,4 @@
/* $NetBSD: queue.h,v 1.45 2006/03/07 17:56:00 pooka Exp $ */
/* $NetBSD: queue.h,v 1.46 2007/02/26 09:20:52 yamt Exp $ */
/*
* Copyright (c) 1991, 1993
@ -222,6 +222,11 @@ struct { \
} \
} while (/*CONSTCOND*/0)
#define SLIST_REMOVE_AFTER(slistelm, field) do { \
(slistelm)->field.sle_next = \
SLIST_NEXT(SLIST_NEXT((slistelm), field), field); \
} while (/*CONSTCOND*/0)
#define SLIST_FOREACH(var, head, field) \
for((var) = (head)->slh_first; (var); (var) = (var)->field.sle_next)

View File

@ -1,4 +1,4 @@
/* $NetBSD: sched.h,v 1.30 2007/02/15 15:09:16 ad Exp $ */
/* $NetBSD: sched.h,v 1.31 2007/02/26 09:20:52 yamt Exp $ */
/*-
* Copyright (c) 1999, 2000, 2001, 2002, 2007 The NetBSD Foundation, Inc.
@ -195,13 +195,18 @@ typedef struct syncobj {
u_int sobj_flag;
void (*sobj_unsleep)(struct lwp *);
void (*sobj_changepri)(struct lwp *, int);
void (*sobj_lendpri)(struct lwp *, int);
struct lwp *(*sobj_owner)(volatile const void *); /* XXX wchan_t */
} syncobj_t;
struct lwp *syncobj_noowner(volatile const void *); /* XXX wchan_t */
#define SOBJ_SLEEPQ_SORTED 0x01
#define SOBJ_SLEEPQ_FIFO 0x02
extern syncobj_t sched_syncobj;
extern syncobj_t turnstile_syncobj;
extern syncobj_t mutex_syncobj;
extern syncobj_t rw_syncobj;
#endif /* _KERNEL */
#endif /* _SYS_SCHED_H_ */

View File

@ -1,4 +1,4 @@
/* $NetBSD: sleepq.h,v 1.2 2007/02/09 21:55:37 ad Exp $ */
/* $NetBSD: sleepq.h,v 1.3 2007/02/26 09:20:52 yamt Exp $ */
/*-
* Copyright (c) 2002, 2006, 2007 The NetBSD Foundation, Inc.
@ -95,8 +95,12 @@ void sleepq_timeout(void *);
void sleepq_wake(sleepq_t *, wchan_t, u_int);
int sleepq_abort(kmutex_t *, int);
void sleepq_changepri(struct lwp *, int);
void sleepq_lendpri(struct lwp *, int);
int sleepq_unblock(int, int);
void sleepq_insert(sleepq_t *, struct lwp *, int, syncobj_t *);
void sleepq_insert(sleepq_t *, struct lwp *, syncobj_t *);
void sleepq_enqueue(sleepq_t *, int, wchan_t, const char *, syncobj_t *);
void sleepq_switch(int, int);
void sleeptab_init(sleeptab_t *);
@ -189,6 +193,11 @@ typedef struct turnstile {
struct turnstile *ts_free; /* turnstile free list */
wchan_t ts_obj; /* lock object */
sleepq_t ts_sleepq[2]; /* sleep queues */
/* priority inheritance */
u_char ts_eprio;
struct lwp *ts_inheritor;
SLIST_ENTRY(turnstile) ts_pichain;
} turnstile_t;
#if defined(MULTIPROCESSOR) || defined(LOCKDEBUG)
@ -222,7 +231,7 @@ typedef struct tschain {
void turnstile_init(void);
turnstile_t *turnstile_lookup(wchan_t);
void turnstile_exit(wchan_t);
void turnstile_block(turnstile_t *, int, wchan_t);
void turnstile_block(turnstile_t *, int, wchan_t, syncobj_t *);
void turnstile_wakeup(turnstile_t *, int, int, struct lwp *);
void turnstile_print(volatile void *, void (*)(const char *, ...));
@ -232,6 +241,9 @@ turnstile_unblock(void)
(void)sleepq_unblock(0, 0);
}
void turnstile_unsleep(struct lwp *);
void turnstile_changepri(struct lwp *, int);
extern struct pool_cache turnstile_cache;
extern struct turnstile turnstile0;

View File

@ -1,4 +1,4 @@
/* $NetBSD: uvm_meter.c,v 1.46 2007/02/17 22:31:45 pavel Exp $ */
/* $NetBSD: uvm_meter.c,v 1.47 2007/02/26 09:20:54 yamt Exp $ */
/*
* Copyright (c) 1997 Charles D. Cranor and Washington University.
@ -41,7 +41,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: uvm_meter.c,v 1.46 2007/02/17 22:31:45 pavel Exp $");
__KERNEL_RCSID(0, "$NetBSD: uvm_meter.c,v 1.47 2007/02/26 09:20:54 yamt Exp $");
#include <sys/param.h>
#include <sys/proc.h>
@ -378,7 +378,7 @@ uvm_total(struct vmtotal *totalp)
case LSSLEEP:
case LSSTOP:
if (l->l_flag & LW_INMEM) {
if (l->l_priority <= PZERO)
if (lwp_eprio(l) <= PZERO)
totalp->t_dw++;
else if (l->l_slptime < maxslp)
totalp->t_sl++;