Implement wakeup_one(), which wakes up the highest priority process

first in line for the specified identifier.  For use in places where
you don't want a Thundering Herd.

While here, add an optimization to wakeup() suggested by Ross Harvey.
This commit is contained in:
thorpej 1999-07-26 23:00:58 +00:00
parent 8fa3d8be55
commit 1bd7bb28ea
2 changed files with 130 additions and 19 deletions

View File

@ -1,4 +1,41 @@
/* $NetBSD: kern_synch.c,v 1.62 1999/07/25 06:30:35 thorpej Exp $ */ /* $NetBSD: kern_synch.c,v 1.63 1999/07/26 23:00:59 thorpej Exp $ */
/*-
* Copyright (c) 1999 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
* NASA Ames Research Center.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the NetBSD
* Foundation, Inc. and its contributors.
* 4. Neither the name of The NetBSD Foundation nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
/*- /*-
* Copyright (c) 1982, 1986, 1990, 1991, 1993 * Copyright (c) 1982, 1986, 1990, 1991, 1993
@ -74,6 +111,8 @@ void schedcpu __P((void *));
void updatepri __P((struct proc *)); void updatepri __P((struct proc *));
void endtsleep __P((void *)); void endtsleep __P((void *));
__inline void awaken __P((struct proc *));
/* /*
* Force switch among equal priority processes every 100ms. * Force switch among equal priority processes every 100ms.
*/ */
@ -519,6 +558,29 @@ unsleep(p)
splx(s); splx(s);
} }
/*
* Optimized-for-wakeup() version of setrunnable().
*/
__inline void
awaken(p)
struct proc *p;
{
if (p->p_slptime > 1)
updatepri(p);
p->p_slptime = 0;
p->p_stat = SRUN;
/*
* Since curpriority is a user priority, p->p_priority
* is always better than curpriority.
*/
if (p->p_flag & P_INMEM) {
setrunqueue(p);
need_resched();
} else
wakeup((caddr_t)&proc0);
}
/* /*
* Make all processes sleeping on the specified identifier runnable. * Make all processes sleeping on the specified identifier runnable.
*/ */
@ -544,23 +606,7 @@ restart:
if (qp->sq_tailp == &p->p_forw) if (qp->sq_tailp == &p->p_forw)
qp->sq_tailp = q; qp->sq_tailp = q;
if (p->p_stat == SSLEEP) { if (p->p_stat == SSLEEP) {
/* OPTIMIZED EXPANSION OF setrunnable(p); */ awaken(p);
if (p->p_slptime > 1)
updatepri(p);
p->p_slptime = 0;
p->p_stat = SRUN;
if (p->p_flag & P_INMEM)
setrunqueue(p);
/*
* Since curpriority is a user priority,
* p->p_priority is always better than
* curpriority.
*/
if ((p->p_flag & P_INMEM) == 0)
wakeup((caddr_t)&proc0);
else
need_resched();
/* END INLINE EXPANSION */
goto restart; goto restart;
} }
} else } else
@ -569,6 +615,70 @@ restart:
splx(s); splx(s);
} }
/*
* Make the highest priority process first in line on the specified
* identifier runnable.
*/
void
wakeup_one(ident)
void *ident;
{
struct slpque *qp;
struct proc *p, **q;
struct proc *best_sleepp, **best_sleepq;
struct proc *best_stopp, **best_stopq;
int s;
best_sleepp = best_stopp = NULL;
best_sleepq = best_stopq = NULL;
s = splhigh();
qp = &slpque[LOOKUP(ident)];
for (q = &qp->sq_head; (p = *q) != NULL; q = &p->p_forw) {
#ifdef DIAGNOSTIC
if (p->p_back || (p->p_stat != SSLEEP && p->p_stat != SSTOP))
panic("wakeup_one");
#endif
if (p->p_wchan == ident) {
if (p->p_stat == SSLEEP) {
if (best_sleepp == NULL ||
p->p_priority < best_sleepp->p_priority) {
best_sleepp = p;
best_sleepq = q;
}
} else {
if (best_stopp == NULL ||
p->p_priority < best_stopp->p_priority) {
best_stopp = p;
best_stopq = q;
}
}
}
}
/*
* Consider any SSLEEP process higher than the highest priority SSTOP
* process.
*/
if (best_sleepp != NULL) {
p = best_sleepp;
q = best_sleepq;
} else {
p = best_stopp;
q = best_stopq;
}
if (p != NULL) {
p->p_wchan = 0;
*q = p->p_forw;
if (qp->sq_tailp == &p->p_forw)
qp->sq_tailp = q;
if (p->p_stat == SSLEEP)
awaken(p);
}
splx(s);
}
/* /*
* The machine independent parts of mi_switch(). * The machine independent parts of mi_switch().
* Must be called at splstatclock() or higher. * Must be called at splstatclock() or higher.

View File

@ -1,4 +1,4 @@
/* $NetBSD: proc.h,v 1.81 1999/07/25 06:30:33 thorpej Exp $ */ /* $NetBSD: proc.h,v 1.82 1999/07/26 23:00:58 thorpej Exp $ */
/*- /*-
* Copyright (c) 1986, 1989, 1991, 1993 * Copyright (c) 1986, 1989, 1991, 1993
@ -362,6 +362,7 @@ void uvm_swapin __P((struct proc *)); /* XXX: uvm_extern.h? */
int tsleep __P((void *chan, int pri, const char *wmesg, int timo)); int tsleep __P((void *chan, int pri, const char *wmesg, int timo));
void unsleep __P((struct proc *)); void unsleep __P((struct proc *));
void wakeup __P((void *chan)); void wakeup __P((void *chan));
void wakeup_one __P((void *chan));
void reaper __P((void)); void reaper __P((void));
void exit1 __P((struct proc *, int)); void exit1 __P((struct proc *, int));
void exit2 __P((struct proc *)); void exit2 __P((struct proc *));