xref: /plan9/sys/src/9/port/proc.c (revision 8ccc32ef0b9b7222ff49b683668eb07a18989e02)
1e288d156SDavid du Colombier #include	<u.h>
23e12c5d1SDavid du Colombier #include	"../port/lib.h"
33e12c5d1SDavid du Colombier #include	"mem.h"
43e12c5d1SDavid du Colombier #include	"dat.h"
53e12c5d1SDavid du Colombier #include	"fns.h"
63e12c5d1SDavid du Colombier #include	"../port/error.h"
7696c1e60SDavid du Colombier #include	"../port/edf.h"
8e288d156SDavid du Colombier #include	<trace.h>
93e12c5d1SDavid du Colombier 
1095a264b3SDavid du Colombier int	schedgain = 30;	/* units in seconds */
119a747e4fSDavid du Colombier int	nrdy;
123e12c5d1SDavid du Colombier Ref	noteidalloc;
133e12c5d1SDavid du Colombier 
1459c21d95SDavid du Colombier void updatecpu(Proc*);
1559c21d95SDavid du Colombier int reprioritize(Proc*);
1659c21d95SDavid du Colombier 
17061a3f44SDavid du Colombier ulong	delayedscheds;	/* statistics */
1859c21d95SDavid du Colombier long skipscheds;
1959c21d95SDavid du Colombier long preempts;
2059c21d95SDavid du Colombier ulong load;
219a747e4fSDavid du Colombier 
229a747e4fSDavid du Colombier static Ref	pidalloc;
239a747e4fSDavid du Colombier 
249a747e4fSDavid du Colombier static struct Procalloc
253e12c5d1SDavid du Colombier {
263e12c5d1SDavid du Colombier 	Lock;
279a747e4fSDavid du Colombier 	Proc*	ht[128];
283e12c5d1SDavid du Colombier 	Proc*	arena;
293e12c5d1SDavid du Colombier 	Proc*	free;
303e12c5d1SDavid du Colombier } procalloc;
313e12c5d1SDavid du Colombier 
32a6a9e072SDavid du Colombier enum
33a6a9e072SDavid du Colombier {
3459c21d95SDavid du Colombier 	Q=10,
3559c21d95SDavid du Colombier 	DQ=4,
3695a264b3SDavid du Colombier 	Scaling=2,
37a6a9e072SDavid du Colombier };
38a6a9e072SDavid du Colombier 
39e288d156SDavid du Colombier Schedq	runq[Nrq];
40e288d156SDavid du Colombier ulong	runvec;
413e12c5d1SDavid du Colombier 
423e12c5d1SDavid du Colombier char *statename[] =
433e12c5d1SDavid du Colombier {	/* BUG: generate automatically */
443e12c5d1SDavid du Colombier 	"Dead",
453e12c5d1SDavid du Colombier 	"Moribund",
463e12c5d1SDavid du Colombier 	"Ready",
473e12c5d1SDavid du Colombier 	"Scheding",
483e12c5d1SDavid du Colombier 	"Running",
493e12c5d1SDavid du Colombier 	"Queueing",
507dd7cddfSDavid du Colombier 	"QueueingR",
517dd7cddfSDavid du Colombier 	"QueueingW",
523e12c5d1SDavid du Colombier 	"Wakeme",
533e12c5d1SDavid du Colombier 	"Broken",
543e12c5d1SDavid du Colombier 	"Stopped",
553e12c5d1SDavid du Colombier 	"Rendez",
56e288d156SDavid du Colombier 	"Waitrelease",
573e12c5d1SDavid du Colombier };
583e12c5d1SDavid du Colombier 
599a747e4fSDavid du Colombier static void pidhash(Proc*);
609a747e4fSDavid du Colombier static void pidunhash(Proc*);
6159c21d95SDavid du Colombier static void rebalance(void);
629a747e4fSDavid du Colombier 
633e12c5d1SDavid du Colombier /*
643e12c5d1SDavid du Colombier  * Always splhi()'ed.
653e12c5d1SDavid du Colombier  */
663e12c5d1SDavid du Colombier void
schedinit(void)673e12c5d1SDavid du Colombier schedinit(void)		/* never returns */
683e12c5d1SDavid du Colombier {
69e288d156SDavid du Colombier 	Edf *e;
70e288d156SDavid du Colombier 
713e12c5d1SDavid du Colombier 	setlabel(&m->sched);
727dd7cddfSDavid du Colombier 	if(up) {
73e288d156SDavid du Colombier 		if((e = up->edf) && (e->flags & Admitted))
74e288d156SDavid du Colombier 			edfrecord(up);
753e12c5d1SDavid du Colombier 		m->proc = 0;
767dd7cddfSDavid du Colombier 		switch(up->state) {
777dd7cddfSDavid du Colombier 		case Running:
787dd7cddfSDavid du Colombier 			ready(up);
797dd7cddfSDavid du Colombier 			break;
807dd7cddfSDavid du Colombier 		case Moribund:
817dd7cddfSDavid du Colombier 			up->state = Dead;
82e288d156SDavid du Colombier 			edfstop(up);
83e288d156SDavid du Colombier 			if (up->edf)
84e288d156SDavid du Colombier 				free(up->edf);
85e288d156SDavid du Colombier 			up->edf = nil;
869a747e4fSDavid du Colombier 
873e12c5d1SDavid du Colombier 			/*
883e12c5d1SDavid du Colombier 			 * Holding locks from pexit:
897dd7cddfSDavid du Colombier 			 * 	procalloc
907dd7cddfSDavid du Colombier 			 *	palloc
913e12c5d1SDavid du Colombier 			 */
927dd7cddfSDavid du Colombier 			mmurelease(up);
933e12c5d1SDavid du Colombier 
947dd7cddfSDavid du Colombier 			up->qnext = procalloc.free;
957dd7cddfSDavid du Colombier 			procalloc.free = up;
963e12c5d1SDavid du Colombier 
973e12c5d1SDavid du Colombier 			unlock(&palloc);
983e12c5d1SDavid du Colombier 			unlock(&procalloc);
997dd7cddfSDavid du Colombier 			break;
1003e12c5d1SDavid du Colombier 		}
10159c21d95SDavid du Colombier 		up->mach = nil;
10259c21d95SDavid du Colombier 		updatecpu(up);
1039a747e4fSDavid du Colombier 		up = nil;
1043e12c5d1SDavid du Colombier 	}
1053e12c5d1SDavid du Colombier 	sched();
1063e12c5d1SDavid du Colombier }
1073e12c5d1SDavid du Colombier 
1087dd7cddfSDavid du Colombier /*
1097dd7cddfSDavid du Colombier  *  If changing this routine, look also at sleep().  It
1107dd7cddfSDavid du Colombier  *  contains a copy of the guts of sched().
1117dd7cddfSDavid du Colombier  */
1123e12c5d1SDavid du Colombier void
sched(void)1133e12c5d1SDavid du Colombier sched(void)
1143e12c5d1SDavid du Colombier {
11559c21d95SDavid du Colombier 	Proc *p;
116d9306527SDavid du Colombier 
1179a747e4fSDavid du Colombier 	if(m->ilockdepth)
1185f7495c3SDavid du Colombier 		panic("cpu%d: ilockdepth %d, last lock %#p at %#p, sched called from %#p",
1195f7495c3SDavid du Colombier 			m->machno,
1205f7495c3SDavid du Colombier 			m->ilockdepth,
1215f7495c3SDavid du Colombier 			up? up->lastilock: nil,
1224de34a7eSDavid du Colombier 			(up && up->lastilock)? up->lastilock->pc: 0,
1234de34a7eSDavid du Colombier 			getcallerpc(&p+2));
1247dd7cddfSDavid du Colombier 	if(up){
1255437ee90SDavid du Colombier 		/*
1265437ee90SDavid du Colombier 		 * Delay the sched until the process gives up the locks
1275437ee90SDavid du Colombier 		 * it is holding.  This avoids dumb lock loops.
1285437ee90SDavid du Colombier 		 * Don't delay if the process is Moribund.
1295437ee90SDavid du Colombier 		 * It called sched to die.
1305437ee90SDavid du Colombier 		 * But do sched eventually.  This avoids a missing unlock
1315437ee90SDavid du Colombier 		 * from hanging the entire kernel.
1325437ee90SDavid du Colombier 		 * But don't reschedule procs holding palloc or procalloc.
1335437ee90SDavid du Colombier 		 * Those are far too important to be holding while asleep.
1345437ee90SDavid du Colombier 		 *
1355437ee90SDavid du Colombier 		 * This test is not exact.  There can still be a few instructions
1365437ee90SDavid du Colombier 		 * in the middle of taslock when a process holds a lock
1375437ee90SDavid du Colombier 		 * but Lock.p has not yet been initialized.
1385437ee90SDavid du Colombier 		 */
1395437ee90SDavid du Colombier 		if(up->nlocks.ref)
1405437ee90SDavid du Colombier 		if(up->state != Moribund)
1415437ee90SDavid du Colombier 		if(up->delaysched < 20
1425437ee90SDavid du Colombier 		|| palloc.Lock.p == up
1435437ee90SDavid du Colombier 		|| procalloc.Lock.p == up){
144e288d156SDavid du Colombier 			up->delaysched++;
1459a747e4fSDavid du Colombier  			delayedscheds++;
1469a747e4fSDavid du Colombier 			return;
1479a747e4fSDavid du Colombier 		}
148e288d156SDavid du Colombier 		up->delaysched = 0;
1499a747e4fSDavid du Colombier 
1503e12c5d1SDavid du Colombier 		splhi();
1517dd7cddfSDavid du Colombier 
1527dd7cddfSDavid du Colombier 		/* statistics */
1533e12c5d1SDavid du Colombier 		m->cs++;
1547dd7cddfSDavid du Colombier 
1557dd7cddfSDavid du Colombier 		procsave(up);
1567dd7cddfSDavid du Colombier 		if(setlabel(&up->sched)){
1577dd7cddfSDavid du Colombier 			procrestore(up);
1583e12c5d1SDavid du Colombier 			spllo();
1593e12c5d1SDavid du Colombier 			return;
1603e12c5d1SDavid du Colombier 		}
1613e12c5d1SDavid du Colombier 		gotolabel(&m->sched);
1623e12c5d1SDavid du Colombier 	}
16359c21d95SDavid du Colombier 	p = runproc();
16459c21d95SDavid du Colombier 	if(!p->edf){
16559c21d95SDavid du Colombier 		updatecpu(p);
16659c21d95SDavid du Colombier 		p->priority = reprioritize(p);
16759c21d95SDavid du Colombier 	}
16859c21d95SDavid du Colombier 	if(p != m->readied)
16959c21d95SDavid du Colombier 		m->schedticks = m->ticks + HZ/10;
17095a264b3SDavid du Colombier 	m->readied = 0;
17159c21d95SDavid du Colombier 	up = p;
1727dd7cddfSDavid du Colombier 	up->state = Running;
1737dd7cddfSDavid du Colombier 	up->mach = MACHP(m->machno);
1747dd7cddfSDavid du Colombier 	m->proc = up;
1757dd7cddfSDavid du Colombier 	mmuswitch(up);
1767dd7cddfSDavid du Colombier 	gotolabel(&up->sched);
1773e12c5d1SDavid du Colombier }
1783e12c5d1SDavid du Colombier 
1793e12c5d1SDavid du Colombier int
anyready(void)1803e12c5d1SDavid du Colombier anyready(void)
1813e12c5d1SDavid du Colombier {
182e288d156SDavid du Colombier 	return runvec;
1833e12c5d1SDavid du Colombier }
1843e12c5d1SDavid du Colombier 
185219b2ee8SDavid du Colombier int
anyhigher(void)186219b2ee8SDavid du Colombier anyhigher(void)
187219b2ee8SDavid du Colombier {
188a6a9e072SDavid du Colombier 	return runvec & ~((1<<(up->priority+1))-1);
189a6a9e072SDavid du Colombier }
190219b2ee8SDavid du Colombier 
191a6a9e072SDavid du Colombier /*
192a6a9e072SDavid du Colombier  *  here once per clock tick to see if we should resched
193a6a9e072SDavid du Colombier  */
194a6a9e072SDavid du Colombier void
hzsched(void)195a6a9e072SDavid du Colombier hzsched(void)
196a6a9e072SDavid du Colombier {
19759c21d95SDavid du Colombier 	/* once a second, rebalance will reprioritize ready procs */
19859c21d95SDavid du Colombier 	if(m->machno == 0)
19959c21d95SDavid du Colombier 		rebalance();
2007dd7cddfSDavid du Colombier 
20159c21d95SDavid du Colombier 	/* unless preempted, get to run for at least 100ms */
20259c21d95SDavid du Colombier 	if(anyhigher()
20359c21d95SDavid du Colombier 	|| (!up->fixedpri && m->ticks > m->schedticks && anyready())){
20459c21d95SDavid du Colombier 		m->readied = nil;	/* avoid cooperative scheduling */
205da51d93aSDavid du Colombier 		up->delaysched++;
206a6a9e072SDavid du Colombier 	}
207a6a9e072SDavid du Colombier }
208a6a9e072SDavid du Colombier 
209a6a9e072SDavid du Colombier /*
210a6a9e072SDavid du Colombier  *  here at the end of non-clock interrupts to see if we should preempt the
211a6a9e072SDavid du Colombier  *  current process.  Returns 1 if preempted, 0 otherwise.
212a6a9e072SDavid du Colombier  */
213a6a9e072SDavid du Colombier int
preempted(void)214a6a9e072SDavid du Colombier preempted(void)
215a6a9e072SDavid du Colombier {
216a6a9e072SDavid du Colombier 	if(up && up->state == Running)
217a6a9e072SDavid du Colombier 	if(up->preempted == 0)
218a6a9e072SDavid du Colombier 	if(anyhigher())
219a6a9e072SDavid du Colombier 	if(!active.exiting){
22059c21d95SDavid du Colombier 		m->readied = nil;	/* avoid cooperative scheduling */
221a6a9e072SDavid du Colombier 		up->preempted = 1;
222a6a9e072SDavid du Colombier 		sched();
223a6a9e072SDavid du Colombier 		splhi();
224a6a9e072SDavid du Colombier 		up->preempted = 0;
2257dd7cddfSDavid du Colombier 		return 1;
226a6a9e072SDavid du Colombier 	}
2277dd7cddfSDavid du Colombier 	return 0;
228219b2ee8SDavid du Colombier }
229219b2ee8SDavid du Colombier 
230a6a9e072SDavid du Colombier /*
23159c21d95SDavid du Colombier  * Update the cpu time average for this particular process,
23259c21d95SDavid du Colombier  * which is about to change from up -> not up or vice versa.
23359c21d95SDavid du Colombier  * p->lastupdate is the last time an updatecpu happened.
234a6a9e072SDavid du Colombier  *
23559c21d95SDavid du Colombier  * The cpu time average is a decaying average that lasts
23659c21d95SDavid du Colombier  * about D clock ticks.  D is chosen to be approximately
23759c21d95SDavid du Colombier  * the cpu time of a cpu-intensive "quick job".  A job has to run
23859c21d95SDavid du Colombier  * for approximately D clock ticks before we home in on its
23959c21d95SDavid du Colombier  * actual cpu usage.  Thus if you manage to get in and get out
24059c21d95SDavid du Colombier  * quickly, you won't be penalized during your burst.  Once you
24159c21d95SDavid du Colombier  * start using your share of the cpu for more than about D
24259c21d95SDavid du Colombier  * clock ticks though, your p->cpu hits 1000 (1.0) and you end up
24359c21d95SDavid du Colombier  * below all the other quick jobs.  Interactive tasks, because
24459c21d95SDavid du Colombier  * they basically always use less than their fair share of cpu,
24559c21d95SDavid du Colombier  * will be rewarded.
246a6a9e072SDavid du Colombier  *
24759c21d95SDavid du Colombier  * If the process has not been running, then we want to
24859c21d95SDavid du Colombier  * apply the filter
24959c21d95SDavid du Colombier  *
25059c21d95SDavid du Colombier  *	cpu = cpu * (D-1)/D
25159c21d95SDavid du Colombier  *
25259c21d95SDavid du Colombier  * n times, yielding
25359c21d95SDavid du Colombier  *
25459c21d95SDavid du Colombier  *	cpu = cpu * ((D-1)/D)^n
25559c21d95SDavid du Colombier  *
25659c21d95SDavid du Colombier  * but D is big enough that this is approximately
25759c21d95SDavid du Colombier  *
25859c21d95SDavid du Colombier  * 	cpu = cpu * (D-n)/D
25959c21d95SDavid du Colombier  *
26059c21d95SDavid du Colombier  * so we use that instead.
26159c21d95SDavid du Colombier  *
26259c21d95SDavid du Colombier  * If the process has been running, we apply the filter to
26359c21d95SDavid du Colombier  * 1 - cpu, yielding a similar equation.  Note that cpu is
26459c21d95SDavid du Colombier  * stored in fixed point (* 1000).
26559c21d95SDavid du Colombier  *
26659c21d95SDavid du Colombier  * Updatecpu must be called before changing up, in order
26759c21d95SDavid du Colombier  * to maintain accurate cpu usage statistics.  It can be called
26859c21d95SDavid du Colombier  * at any time to bring the stats for a given proc up-to-date.
269a6a9e072SDavid du Colombier  */
2703e12c5d1SDavid du Colombier void
updatecpu(Proc * p)27159c21d95SDavid du Colombier updatecpu(Proc *p)
2723e12c5d1SDavid du Colombier {
27359c21d95SDavid du Colombier 	int n, t, ocpu;
27495a264b3SDavid du Colombier 	int D = schedgain*HZ*Scaling;
2753e12c5d1SDavid du Colombier 
27659c21d95SDavid du Colombier 	if(p->edf)
2779a747e4fSDavid du Colombier 		return;
27859c21d95SDavid du Colombier 
27995a264b3SDavid du Colombier 	t = MACHP(0)->ticks*Scaling + Scaling/2;
28059c21d95SDavid du Colombier 	n = t - p->lastupdate;
28159c21d95SDavid du Colombier 	p->lastupdate = t;
28259c21d95SDavid du Colombier 
28359c21d95SDavid du Colombier 	if(n == 0)
28459c21d95SDavid du Colombier 		return;
28559c21d95SDavid du Colombier 	if(n > D)
28659c21d95SDavid du Colombier 		n = D;
28759c21d95SDavid du Colombier 
28859c21d95SDavid du Colombier 	ocpu = p->cpu;
28959c21d95SDavid du Colombier 	if(p != up)
29059c21d95SDavid du Colombier 		p->cpu = (ocpu*(D-n))/D;
29159c21d95SDavid du Colombier 	else{
29259c21d95SDavid du Colombier 		t = 1000 - ocpu;
29359c21d95SDavid du Colombier 		t = (t*(D-n))/D;
29459c21d95SDavid du Colombier 		p->cpu = 1000 - t;
2959a747e4fSDavid du Colombier 	}
296a6a9e072SDavid du Colombier 
29759c21d95SDavid du Colombier //iprint("pid %d %s for %d cpu %d -> %d\n", p->pid,p==up?"active":"inactive",n, ocpu,p->cpu);
29880ee5cbfSDavid du Colombier }
2997dd7cddfSDavid du Colombier 
30059c21d95SDavid du Colombier /*
30159c21d95SDavid du Colombier  * On average, p has used p->cpu of a cpu recently.
30259c21d95SDavid du Colombier  * Its fair share is conf.nmach/m->load of a cpu.  If it has been getting
30359c21d95SDavid du Colombier  * too much, penalize it.  If it has been getting not enough, reward it.
30459c21d95SDavid du Colombier  * I don't think you can get much more than your fair share that
30559c21d95SDavid du Colombier  * often, so most of the queues are for using less.  Having a priority
30659c21d95SDavid du Colombier  * of 3 means you're just right.  Having a higher priority (up to p->basepri)
30759c21d95SDavid du Colombier  * means you're not using as much as you could.
30859c21d95SDavid du Colombier  */
30959c21d95SDavid du Colombier int
reprioritize(Proc * p)31059c21d95SDavid du Colombier reprioritize(Proc *p)
31159c21d95SDavid du Colombier {
31259c21d95SDavid du Colombier 	int fairshare, n, load, ratio;
31359c21d95SDavid du Colombier 
31459c21d95SDavid du Colombier 	load = MACHP(0)->load;
31559c21d95SDavid du Colombier 	if(load == 0)
31659c21d95SDavid du Colombier 		return p->basepri;
31759c21d95SDavid du Colombier 
31859c21d95SDavid du Colombier 	/*
31959c21d95SDavid du Colombier 	 *  fairshare = 1.000 * conf.nproc * 1.000/load,
32059c21d95SDavid du Colombier 	 * except the decimal point is moved three places
32159c21d95SDavid du Colombier 	 * on both load and fairshare.
32259c21d95SDavid du Colombier 	 */
32359c21d95SDavid du Colombier 	fairshare = (conf.nmach*1000*1000)/load;
32459c21d95SDavid du Colombier 	n = p->cpu;
32559c21d95SDavid du Colombier 	if(n == 0)
32659c21d95SDavid du Colombier 		n = 1;
32759c21d95SDavid du Colombier 	ratio = (fairshare+n/2) / n;
32859c21d95SDavid du Colombier 	if(ratio > p->basepri)
32959c21d95SDavid du Colombier 		ratio = p->basepri;
33059c21d95SDavid du Colombier 	if(ratio < 0)
33159c21d95SDavid du Colombier 		panic("reprioritize");
33259c21d95SDavid du Colombier //iprint("pid %d cpu %d load %d fair %d pri %d\n", p->pid, p->cpu, load, fairshare, ratio);
33359c21d95SDavid du Colombier 	return ratio;
33459c21d95SDavid du Colombier }
33559c21d95SDavid du Colombier 
33659c21d95SDavid du Colombier /*
33759c21d95SDavid du Colombier  * add a process to a scheduling queue
33859c21d95SDavid du Colombier  */
33959c21d95SDavid du Colombier void
queueproc(Schedq * rq,Proc * p)34059c21d95SDavid du Colombier queueproc(Schedq *rq, Proc *p)
34159c21d95SDavid du Colombier {
34259c21d95SDavid du Colombier 	int pri;
34359c21d95SDavid du Colombier 
34459c21d95SDavid du Colombier 	pri = rq - runq;
345219b2ee8SDavid du Colombier 	lock(runq);
34659c21d95SDavid du Colombier 	p->priority = pri;
3473e12c5d1SDavid du Colombier 	p->rnext = 0;
3483e12c5d1SDavid du Colombier 	if(rq->tail)
3493e12c5d1SDavid du Colombier 		rq->tail->rnext = p;
3503e12c5d1SDavid du Colombier 	else
3513e12c5d1SDavid du Colombier 		rq->head = p;
3523e12c5d1SDavid du Colombier 	rq->tail = p;
353219b2ee8SDavid du Colombier 	rq->n++;
3543e12c5d1SDavid du Colombier 	nrdy++;
355a6a9e072SDavid du Colombier 	runvec |= 1<<pri;
356219b2ee8SDavid du Colombier 	unlock(runq);
3573e12c5d1SDavid du Colombier }
3583e12c5d1SDavid du Colombier 
35904b73bddSDavid du Colombier /*
36059c21d95SDavid du Colombier  *  try to remove a process from a scheduling queue (called splhi)
36104b73bddSDavid du Colombier  */
362e288d156SDavid du Colombier Proc*
dequeueproc(Schedq * rq,Proc * tp)36304b73bddSDavid du Colombier dequeueproc(Schedq *rq, Proc *tp)
3643e12c5d1SDavid du Colombier {
36504b73bddSDavid du Colombier 	Proc *l, *p;
3663e12c5d1SDavid du Colombier 
3677dd7cddfSDavid du Colombier 	if(!canlock(runq))
36804b73bddSDavid du Colombier 		return nil;
369219b2ee8SDavid du Colombier 
370a6a9e072SDavid du Colombier 	/*
371a6a9e072SDavid du Colombier 	 *  the queue may have changed before we locked runq,
372a6a9e072SDavid du Colombier 	 *  refind the target process.
373a6a9e072SDavid du Colombier 	 */
374219b2ee8SDavid du Colombier 	l = 0;
375219b2ee8SDavid du Colombier 	for(p = rq->head; p; p = p->rnext){
376a6a9e072SDavid du Colombier 		if(p == tp)
377219b2ee8SDavid du Colombier 			break;
378219b2ee8SDavid du Colombier 		l = p;
379219b2ee8SDavid du Colombier 	}
380219b2ee8SDavid du Colombier 
381219b2ee8SDavid du Colombier 	/*
382219b2ee8SDavid du Colombier 	 *  p->mach==0 only when process state is saved
383219b2ee8SDavid du Colombier 	 */
384219b2ee8SDavid du Colombier 	if(p == 0 || p->mach){
385219b2ee8SDavid du Colombier 		unlock(runq);
38604b73bddSDavid du Colombier 		return nil;
3873e12c5d1SDavid du Colombier 	}
3883e12c5d1SDavid du Colombier 	if(p->rnext == 0)
389219b2ee8SDavid du Colombier 		rq->tail = l;
390219b2ee8SDavid du Colombier 	if(l)
391219b2ee8SDavid du Colombier 		l->rnext = p->rnext;
392219b2ee8SDavid du Colombier 	else
3933e12c5d1SDavid du Colombier 		rq->head = p->rnext;
394a6a9e072SDavid du Colombier 	if(rq->head == nil)
395a6a9e072SDavid du Colombier 		runvec &= ~(1<<(rq-runq));
396219b2ee8SDavid du Colombier 	rq->n--;
3973e12c5d1SDavid du Colombier 	nrdy--;
3983e12c5d1SDavid du Colombier 	if(p->state != Ready)
39904b73bddSDavid du Colombier 		print("dequeueproc %s %lud %s\n", p->text, p->pid, statename[p->state]);
40004b73bddSDavid du Colombier 
401219b2ee8SDavid du Colombier 	unlock(runq);
40204b73bddSDavid du Colombier 	return p;
40304b73bddSDavid du Colombier }
40404b73bddSDavid du Colombier 
40504b73bddSDavid du Colombier /*
40659c21d95SDavid du Colombier  *  ready(p) picks a new priority for a process and sticks it in the
40759c21d95SDavid du Colombier  *  runq for that priority.
40859c21d95SDavid du Colombier  */
40959c21d95SDavid du Colombier void
ready(Proc * p)41059c21d95SDavid du Colombier ready(Proc *p)
41159c21d95SDavid du Colombier {
41259c21d95SDavid du Colombier 	int s, pri;
41359c21d95SDavid du Colombier 	Schedq *rq;
41459c21d95SDavid du Colombier 	void (*pt)(Proc*, int, vlong);
41559c21d95SDavid du Colombier 
41659c21d95SDavid du Colombier 	s = splhi();
41759c21d95SDavid du Colombier 	if(edfready(p)){
41859c21d95SDavid du Colombier 		splx(s);
41959c21d95SDavid du Colombier 		return;
42059c21d95SDavid du Colombier 	}
42159c21d95SDavid du Colombier 
4226fb99756SDavid du Colombier 	if(up != p && (p->wired == nil || p->wired == m))
42359c21d95SDavid du Colombier 		m->readied = p;	/* group scheduling */
42459c21d95SDavid du Colombier 
42559c21d95SDavid du Colombier 	updatecpu(p);
42659c21d95SDavid du Colombier 	pri = reprioritize(p);
42759c21d95SDavid du Colombier 	p->priority = pri;
42859c21d95SDavid du Colombier 	rq = &runq[pri];
42959c21d95SDavid du Colombier 	p->state = Ready;
43059c21d95SDavid du Colombier 	queueproc(rq, p);
43159c21d95SDavid du Colombier 	pt = proctrace;
43259c21d95SDavid du Colombier 	if(pt)
43359c21d95SDavid du Colombier 		pt(p, SReady, 0);
43459c21d95SDavid du Colombier 	splx(s);
43559c21d95SDavid du Colombier }
43659c21d95SDavid du Colombier 
43759c21d95SDavid du Colombier /*
43804b73bddSDavid du Colombier  *  yield the processor and drop our priority
43904b73bddSDavid du Colombier  */
44004b73bddSDavid du Colombier void
yield(void)44104b73bddSDavid du Colombier yield(void)
44204b73bddSDavid du Colombier {
44304b73bddSDavid du Colombier 	if(anyready()){
44495a264b3SDavid du Colombier 		/* pretend we just used 1/2 tick */
44595a264b3SDavid du Colombier 		up->lastupdate -= Scaling/2;
44604b73bddSDavid du Colombier 		sched();
44704b73bddSDavid du Colombier 	}
44804b73bddSDavid du Colombier }
44904b73bddSDavid du Colombier 
45004b73bddSDavid du Colombier /*
45195a264b3SDavid du Colombier  *  recalculate priorities once a second.  We need to do this
45295a264b3SDavid du Colombier  *  since priorities will otherwise only be recalculated when
45395a264b3SDavid du Colombier  *  the running process blocks.
45404b73bddSDavid du Colombier  */
45559c21d95SDavid du Colombier ulong balancetime;
45659c21d95SDavid du Colombier 
45704b73bddSDavid du Colombier static void
rebalance(void)45804b73bddSDavid du Colombier rebalance(void)
45904b73bddSDavid du Colombier {
460da51d93aSDavid du Colombier 	int pri, npri, t, x;
46104b73bddSDavid du Colombier 	Schedq *rq;
46204b73bddSDavid du Colombier 	Proc *p;
46304b73bddSDavid du Colombier 
46459c21d95SDavid du Colombier 	t = m->ticks;
46559c21d95SDavid du Colombier 	if(t - balancetime < HZ)
46659c21d95SDavid du Colombier 		return;
46759c21d95SDavid du Colombier 	balancetime = t;
46859c21d95SDavid du Colombier 
46959c21d95SDavid du Colombier 	for(pri=0, rq=runq; pri<Npriq; pri++, rq++){
47059c21d95SDavid du Colombier another:
47104b73bddSDavid du Colombier 		p = rq->head;
47204b73bddSDavid du Colombier 		if(p == nil)
47304b73bddSDavid du Colombier 			continue;
47404b73bddSDavid du Colombier 		if(p->mp != MACHP(m->machno))
47504b73bddSDavid du Colombier 			continue;
47659c21d95SDavid du Colombier 		if(pri == p->basepri)
47704b73bddSDavid du Colombier 			continue;
47859c21d95SDavid du Colombier 		updatecpu(p);
47959c21d95SDavid du Colombier 		npri = reprioritize(p);
48059c21d95SDavid du Colombier 		if(npri != pri){
481da51d93aSDavid du Colombier 			x = splhi();
48204b73bddSDavid du Colombier 			p = dequeueproc(rq, p);
48359c21d95SDavid du Colombier 			if(p)
48459c21d95SDavid du Colombier 				queueproc(&runq[npri], p);
485da51d93aSDavid du Colombier 			splx(x);
48659c21d95SDavid du Colombier 			goto another;
48704b73bddSDavid du Colombier 		}
48804b73bddSDavid du Colombier 	}
48959c21d95SDavid du Colombier }
49059c21d95SDavid du Colombier 
49104b73bddSDavid du Colombier 
49204b73bddSDavid du Colombier /*
49304b73bddSDavid du Colombier  *  pick a process to run
49404b73bddSDavid du Colombier  */
49504b73bddSDavid du Colombier Proc*
runproc(void)49604b73bddSDavid du Colombier runproc(void)
49704b73bddSDavid du Colombier {
49804b73bddSDavid du Colombier 	Schedq *rq;
49904b73bddSDavid du Colombier 	Proc *p;
50004b73bddSDavid du Colombier 	ulong start, now;
50104b73bddSDavid du Colombier 	int i;
5020701b922SDavid du Colombier 	void (*pt)(Proc*, int, vlong);
50304b73bddSDavid du Colombier 
50404b73bddSDavid du Colombier 	start = perfticks();
50504b73bddSDavid du Colombier 
50659c21d95SDavid du Colombier 	/* cooperative scheduling until the clock ticks */
507adc470c1SDavid du Colombier 	if((p=m->readied) && p->mach==0 && p->state==Ready
5086fb99756SDavid du Colombier 	&& (p->wired == nil || p->wired == m)
50959c21d95SDavid du Colombier 	&& runq[Nrq-1].head == nil && runq[Nrq-2].head == nil){
51059c21d95SDavid du Colombier 		skipscheds++;
51159c21d95SDavid du Colombier 		rq = &runq[p->priority];
51259c21d95SDavid du Colombier 		goto found;
51304b73bddSDavid du Colombier 	}
51404b73bddSDavid du Colombier 
51559c21d95SDavid du Colombier 	preempts++;
51659c21d95SDavid du Colombier 
51704b73bddSDavid du Colombier loop:
51804b73bddSDavid du Colombier 	/*
51904b73bddSDavid du Colombier 	 *  find a process that last ran on this processor (affinity),
52004b73bddSDavid du Colombier 	 *  or one that hasn't moved in a while (load balancing).  Every
52104b73bddSDavid du Colombier 	 *  time around the loop affinity goes down.
52204b73bddSDavid du Colombier 	 */
52304b73bddSDavid du Colombier 	spllo();
52404b73bddSDavid du Colombier 	for(i = 0;; i++){
52504b73bddSDavid du Colombier 		/*
52604b73bddSDavid du Colombier 		 *  find the highest priority target process that this
52704b73bddSDavid du Colombier 		 *  processor can run given affinity constraints.
52804b73bddSDavid du Colombier 		 *
52904b73bddSDavid du Colombier 		 */
53004b73bddSDavid du Colombier 		for(rq = &runq[Nrq-1]; rq >= runq; rq--){
53104b73bddSDavid du Colombier 			for(p = rq->head; p; p = p->rnext){
53204b73bddSDavid du Colombier 				if(p->mp == nil || p->mp == MACHP(m->machno)
53304b73bddSDavid du Colombier 				|| (!p->wired && i > 0))
53404b73bddSDavid du Colombier 					goto found;
53504b73bddSDavid du Colombier 			}
53604b73bddSDavid du Colombier 		}
53704b73bddSDavid du Colombier 
53804b73bddSDavid du Colombier 		/* waste time or halt the CPU */
53904b73bddSDavid du Colombier 		idlehands();
54004b73bddSDavid du Colombier 
54104b73bddSDavid du Colombier 		/* remember how much time we're here */
54204b73bddSDavid du Colombier 		now = perfticks();
54304b73bddSDavid du Colombier 		m->perf.inidle += now-start;
54404b73bddSDavid du Colombier 		start = now;
54504b73bddSDavid du Colombier 	}
54604b73bddSDavid du Colombier 
54704b73bddSDavid du Colombier found:
54804b73bddSDavid du Colombier 	splhi();
54904b73bddSDavid du Colombier 	p = dequeueproc(rq, p);
55004b73bddSDavid du Colombier 	if(p == nil)
55104b73bddSDavid du Colombier 		goto loop;
552219b2ee8SDavid du Colombier 
5533e12c5d1SDavid du Colombier 	p->state = Scheding;
5547dd7cddfSDavid du Colombier 	p->mp = MACHP(m->machno);
5559a747e4fSDavid du Colombier 
556da51d93aSDavid du Colombier 	if(edflock(p)){
557e288d156SDavid du Colombier 		edfrun(p, rq == &runq[PriEdf]);	/* start deadline timer and do admin */
558e288d156SDavid du Colombier 		edfunlock();
559e288d156SDavid du Colombier 	}
560e288d156SDavid du Colombier 	pt = proctrace;
5610701b922SDavid du Colombier 	if(pt)
5620701b922SDavid du Colombier 		pt(p, SRun, 0);
5633e12c5d1SDavid du Colombier 	return p;
5643e12c5d1SDavid du Colombier }
5653e12c5d1SDavid du Colombier 
5663e12c5d1SDavid du Colombier int
canpage(Proc * p)5673e12c5d1SDavid du Colombier canpage(Proc *p)
5683e12c5d1SDavid du Colombier {
5693e12c5d1SDavid du Colombier 	int ok = 0;
5703e12c5d1SDavid du Colombier 
5713e12c5d1SDavid du Colombier 	splhi();
5727dd7cddfSDavid du Colombier 	lock(runq);
5733e12c5d1SDavid du Colombier 	/* Only reliable way to see if we are Running */
5743e12c5d1SDavid du Colombier 	if(p->mach == 0) {
5753e12c5d1SDavid du Colombier 		p->newtlb = 1;
5763e12c5d1SDavid du Colombier 		ok = 1;
5773e12c5d1SDavid du Colombier 	}
5787dd7cddfSDavid du Colombier 	unlock(runq);
5793e12c5d1SDavid du Colombier 	spllo();
5803e12c5d1SDavid du Colombier 
5813e12c5d1SDavid du Colombier 	return ok;
5823e12c5d1SDavid du Colombier }
5833e12c5d1SDavid du Colombier 
584*8ccc32efSDavid du Colombier void
noprocpanic(char * msg)585*8ccc32efSDavid du Colombier noprocpanic(char *msg)
586*8ccc32efSDavid du Colombier {
587*8ccc32efSDavid du Colombier 	/*
588*8ccc32efSDavid du Colombier 	 * setting exiting will make hzclock() on each processor call exit(0).
589*8ccc32efSDavid du Colombier 	 * clearing our bit in machs avoids calling exit(0) from hzclock()
590*8ccc32efSDavid du Colombier 	 * on this processor.
591*8ccc32efSDavid du Colombier 	 */
592*8ccc32efSDavid du Colombier 	lock(&active);
593*8ccc32efSDavid du Colombier 	active.machs &= ~(1<<m->machno);
594*8ccc32efSDavid du Colombier 	active.exiting = 1;
595*8ccc32efSDavid du Colombier 	unlock(&active);
596*8ccc32efSDavid du Colombier 
597*8ccc32efSDavid du Colombier 	procdump();
598*8ccc32efSDavid du Colombier 	delay(1000);
599*8ccc32efSDavid du Colombier 	panic(msg);
600*8ccc32efSDavid du Colombier }
601*8ccc32efSDavid du Colombier 
6023e12c5d1SDavid du Colombier Proc*
newproc(void)6033e12c5d1SDavid du Colombier newproc(void)
6043e12c5d1SDavid du Colombier {
60514cc0f53SDavid du Colombier 	char msg[64];
6063e12c5d1SDavid du Colombier 	Proc *p;
6073e12c5d1SDavid du Colombier 
6083e12c5d1SDavid du Colombier 	lock(&procalloc);
609*8ccc32efSDavid du Colombier 	while((p = procalloc.free) == nil) {
610*8ccc32efSDavid du Colombier 		unlock(&procalloc);
6117dd7cddfSDavid du Colombier 
61214cc0f53SDavid du Colombier 		snprint(msg, sizeof msg, "no procs; %s forking",
61314cc0f53SDavid du Colombier 			up? up->text: "kernel");
614*8ccc32efSDavid du Colombier 		/*
615*8ccc32efSDavid du Colombier 		 * the situation is unlikely to heal itself.
616*8ccc32efSDavid du Colombier 		 * dump the proc table and restart by default.
617*8ccc32efSDavid du Colombier 		 * *noprocspersist in plan9.ini will yield the old
618*8ccc32efSDavid du Colombier 		 * behaviour of trying forever.
619*8ccc32efSDavid du Colombier 		 */
620*8ccc32efSDavid du Colombier 		if(getconf("*noprocspersist") == nil)
621*8ccc32efSDavid du Colombier 			noprocpanic(msg);
62214cc0f53SDavid du Colombier 		resrcwait(msg);
6237dd7cddfSDavid du Colombier 		lock(&procalloc);
6247dd7cddfSDavid du Colombier 	}
6253e12c5d1SDavid du Colombier 	procalloc.free = p->qnext;
6267dd7cddfSDavid du Colombier 	unlock(&procalloc);
6277dd7cddfSDavid du Colombier 
6283e12c5d1SDavid du Colombier 	p->state = Scheding;
6293e12c5d1SDavid du Colombier 	p->psstate = "New";
6303e12c5d1SDavid du Colombier 	p->mach = 0;
6313e12c5d1SDavid du Colombier 	p->qnext = 0;
6323e12c5d1SDavid du Colombier 	p->nchild = 0;
6333e12c5d1SDavid du Colombier 	p->nwait = 0;
6343e12c5d1SDavid du Colombier 	p->waitq = 0;
6359a747e4fSDavid du Colombier 	p->parent = 0;
6363e12c5d1SDavid du Colombier 	p->pgrp = 0;
6373e12c5d1SDavid du Colombier 	p->egrp = 0;
6383e12c5d1SDavid du Colombier 	p->fgrp = 0;
6397dd7cddfSDavid du Colombier 	p->rgrp = 0;
6403e12c5d1SDavid du Colombier 	p->pdbg = 0;
6413e12c5d1SDavid du Colombier 	p->fpstate = FPinit;
6423e12c5d1SDavid du Colombier 	p->kp = 0;
643d1be6b08SDavid du Colombier 	if(up && up->procctl == Proc_tracesyscall)
644d1be6b08SDavid du Colombier 		p->procctl = Proc_tracesyscall;
645d1be6b08SDavid du Colombier 	else
6463e12c5d1SDavid du Colombier 		p->procctl = 0;
647d1be6b08SDavid du Colombier 	p->syscalltrace = 0;
6483e12c5d1SDavid du Colombier 	p->notepending = 0;
6497dd7cddfSDavid du Colombier 	p->ureg = 0;
6509a747e4fSDavid du Colombier 	p->privatemem = 0;
651b7b24591SDavid du Colombier 	p->noswap = 0;
6529a747e4fSDavid du Colombier 	p->errstr = p->errbuf0;
6539a747e4fSDavid du Colombier 	p->syserrstr = p->errbuf1;
6549a747e4fSDavid du Colombier 	p->errbuf0[0] = '\0';
6559a747e4fSDavid du Colombier 	p->errbuf1[0] = '\0';
656e288d156SDavid du Colombier 	p->nlocks.ref = 0;
6579a747e4fSDavid du Colombier 	p->delaysched = 0;
658220e960cSDavid du Colombier 	p->trace = 0;
6599a747e4fSDavid du Colombier 	kstrdup(&p->user, "*nouser");
6609a747e4fSDavid du Colombier 	kstrdup(&p->text, "*notext");
6619a747e4fSDavid du Colombier 	kstrdup(&p->args, "");
6629a747e4fSDavid du Colombier 	p->nargs = 0;
663d9306527SDavid du Colombier 	p->setargs = 0;
6643e12c5d1SDavid du Colombier 	memset(p->seg, 0, sizeof p->seg);
6653e12c5d1SDavid du Colombier 	p->pid = incref(&pidalloc);
6669a747e4fSDavid du Colombier 	pidhash(p);
6673e12c5d1SDavid du Colombier 	p->noteid = incref(&noteidalloc);
6683e12c5d1SDavid du Colombier 	if(p->pid==0 || p->noteid==0)
6693e12c5d1SDavid du Colombier 		panic("pidalloc");
6707dd7cddfSDavid du Colombier 	if(p->kstack == 0)
6717dd7cddfSDavid du Colombier 		p->kstack = smalloc(KSTACK);
6727dd7cddfSDavid du Colombier 
673a6a9e072SDavid du Colombier 	/* sched params */
674a6a9e072SDavid du Colombier 	p->mp = 0;
675a6a9e072SDavid du Colombier 	p->wired = 0;
676a6a9e072SDavid du Colombier 	procpriority(p, PriNormal, 0);
67795a264b3SDavid du Colombier 	p->cpu = 0;
67895a264b3SDavid du Colombier 	p->lastupdate = MACHP(0)->ticks*Scaling;
679e288d156SDavid du Colombier 	p->edf = nil;
6809a747e4fSDavid du Colombier 
6813e12c5d1SDavid du Colombier 	return p;
6823e12c5d1SDavid du Colombier }
6837dd7cddfSDavid du Colombier 
6847dd7cddfSDavid du Colombier /*
6857dd7cddfSDavid du Colombier  * wire this proc to a machine
6867dd7cddfSDavid du Colombier  */
6877dd7cddfSDavid du Colombier void
procwired(Proc * p,int bm)6887dd7cddfSDavid du Colombier procwired(Proc *p, int bm)
6897dd7cddfSDavid du Colombier {
6907dd7cddfSDavid du Colombier 	Proc *pp;
6917dd7cddfSDavid du Colombier 	int i;
6927dd7cddfSDavid du Colombier 	char nwired[MAXMACH];
6937dd7cddfSDavid du Colombier 	Mach *wm;
6947dd7cddfSDavid du Colombier 
6957dd7cddfSDavid du Colombier 	if(bm < 0){
6967dd7cddfSDavid du Colombier 		/* pick a machine to wire to */
6977dd7cddfSDavid du Colombier 		memset(nwired, 0, sizeof(nwired));
6987dd7cddfSDavid du Colombier 		p->wired = 0;
6997dd7cddfSDavid du Colombier 		pp = proctab(0);
7007dd7cddfSDavid du Colombier 		for(i=0; i<conf.nproc; i++, pp++){
7017dd7cddfSDavid du Colombier 			wm = pp->wired;
7027dd7cddfSDavid du Colombier 			if(wm && pp->pid)
7037dd7cddfSDavid du Colombier 				nwired[wm->machno]++;
7043e12c5d1SDavid du Colombier 		}
7057dd7cddfSDavid du Colombier 		bm = 0;
7067dd7cddfSDavid du Colombier 		for(i=0; i<conf.nmach; i++)
7077dd7cddfSDavid du Colombier 			if(nwired[i] < nwired[bm])
7087dd7cddfSDavid du Colombier 				bm = i;
7097dd7cddfSDavid du Colombier 	} else {
7107dd7cddfSDavid du Colombier 		/* use the virtual machine requested */
7117dd7cddfSDavid du Colombier 		bm = bm % conf.nmach;
7127dd7cddfSDavid du Colombier 	}
7137dd7cddfSDavid du Colombier 
7147dd7cddfSDavid du Colombier 	p->wired = MACHP(bm);
7157dd7cddfSDavid du Colombier 	p->mp = p->wired;
7163e12c5d1SDavid du Colombier }
7173e12c5d1SDavid du Colombier 
7183e12c5d1SDavid du Colombier void
procpriority(Proc * p,int pri,int fixed)719a6a9e072SDavid du Colombier procpriority(Proc *p, int pri, int fixed)
720a6a9e072SDavid du Colombier {
721e288d156SDavid du Colombier 	if(pri >= Npriq)
722e288d156SDavid du Colombier 		pri = Npriq - 1;
723a6a9e072SDavid du Colombier 	else if(pri < 0)
724a6a9e072SDavid du Colombier 		pri = 0;
725a6a9e072SDavid du Colombier 	p->basepri = pri;
726a6a9e072SDavid du Colombier 	p->priority = pri;
727a6a9e072SDavid du Colombier 	if(fixed){
728a6a9e072SDavid du Colombier 		p->fixedpri = 1;
729a6a9e072SDavid du Colombier 	} else {
730a6a9e072SDavid du Colombier 		p->fixedpri = 0;
731a6a9e072SDavid du Colombier 	}
732a6a9e072SDavid du Colombier }
733a6a9e072SDavid du Colombier 
734a6a9e072SDavid du Colombier void
procinit0(void)7353e12c5d1SDavid du Colombier procinit0(void)		/* bad planning - clashes with devproc.c */
7363e12c5d1SDavid du Colombier {
7373e12c5d1SDavid du Colombier 	Proc *p;
7383e12c5d1SDavid du Colombier 	int i;
7393e12c5d1SDavid du Colombier 
7403e12c5d1SDavid du Colombier 	procalloc.free = xalloc(conf.nproc*sizeof(Proc));
7414de34a7eSDavid du Colombier 	if(procalloc.free == nil){
7424de34a7eSDavid du Colombier 		xsummary();
7434de34a7eSDavid du Colombier 		panic("cannot allocate %lud procs (%ludMB)\n", conf.nproc, conf.nproc*sizeof(Proc)/(1024*1024));
7444de34a7eSDavid du Colombier 	}
7453e12c5d1SDavid du Colombier 	procalloc.arena = procalloc.free;
7463e12c5d1SDavid du Colombier 
7473e12c5d1SDavid du Colombier 	p = procalloc.free;
7483e12c5d1SDavid du Colombier 	for(i=0; i<conf.nproc-1; i++,p++)
7493e12c5d1SDavid du Colombier 		p->qnext = p+1;
7503e12c5d1SDavid du Colombier 	p->qnext = 0;
7513e12c5d1SDavid du Colombier }
7523e12c5d1SDavid du Colombier 
7537dd7cddfSDavid du Colombier /*
75459cc4ca5SDavid du Colombier  *  sleep if a condition is not true.  Another process will
75559cc4ca5SDavid du Colombier  *  awaken us after it sets the condition.  When we awaken
75659cc4ca5SDavid du Colombier  *  the condition may no longer be true.
7577dd7cddfSDavid du Colombier  *
75859cc4ca5SDavid du Colombier  *  we lock both the process and the rendezvous to keep r->p
75959cc4ca5SDavid du Colombier  *  and p->r synchronized.
7607dd7cddfSDavid du Colombier  */
7613e12c5d1SDavid du Colombier void
sleep(Rendez * r,int (* f)(void *),void * arg)7627dd7cddfSDavid du Colombier sleep(Rendez *r, int (*f)(void*), void *arg)
7633e12c5d1SDavid du Colombier {
7643e12c5d1SDavid du Colombier 	int s;
7650701b922SDavid du Colombier 	void (*pt)(Proc*, int, vlong);
7663e12c5d1SDavid du Colombier 
7673e12c5d1SDavid du Colombier 	s = splhi();
7683e12c5d1SDavid du Colombier 
769e288d156SDavid du Colombier 	if(up->nlocks.ref)
770567483c8SDavid du Colombier 		print("process %lud sleeps with %lud locks held, last lock %#p locked at pc %#lux, sleep called from %#p\n",
771da51d93aSDavid du Colombier 			up->pid, up->nlocks.ref, up->lastlock, up->lastlock->pc, getcallerpc(&r));
77259cc4ca5SDavid du Colombier 	lock(r);
7737dd7cddfSDavid du Colombier 	lock(&up->rlock);
7747dd7cddfSDavid du Colombier 	if(r->p){
775567483c8SDavid du Colombier 		print("double sleep called from %#p, %lud %lud\n", getcallerpc(&r), r->p->pid, up->pid);
7767dd7cddfSDavid du Colombier 		dumpstack();
7773e12c5d1SDavid du Colombier 	}
7783e12c5d1SDavid du Colombier 
7793e12c5d1SDavid du Colombier 	/*
7807dd7cddfSDavid du Colombier 	 *  Wakeup only knows there may be something to do by testing
7817dd7cddfSDavid du Colombier 	 *  r->p in order to get something to lock on.
7827dd7cddfSDavid du Colombier 	 *  Flush that information out to memory in case the sleep is
7837dd7cddfSDavid du Colombier 	 *  committed.
7847dd7cddfSDavid du Colombier 	 */
7857dd7cddfSDavid du Colombier 	r->p = up;
7867dd7cddfSDavid du Colombier 
7877dd7cddfSDavid du Colombier 	if((*f)(arg) || up->notepending){
7887dd7cddfSDavid du Colombier 		/*
7897dd7cddfSDavid du Colombier 		 *  if condition happened or a note is pending
7907dd7cddfSDavid du Colombier 		 *  never mind
7917dd7cddfSDavid du Colombier 		 */
7927dd7cddfSDavid du Colombier 		r->p = nil;
7937dd7cddfSDavid du Colombier 		unlock(&up->rlock);
79459cc4ca5SDavid du Colombier 		unlock(r);
7957dd7cddfSDavid du Colombier 	} else {
7967dd7cddfSDavid du Colombier 		/*
7973e12c5d1SDavid du Colombier 		 *  now we are committed to
7983e12c5d1SDavid du Colombier 		 *  change state and call scheduler
7993e12c5d1SDavid du Colombier 		 */
800e288d156SDavid du Colombier 		pt = proctrace;
8010701b922SDavid du Colombier 		if(pt)
8020701b922SDavid du Colombier 			pt(up, SSleep, 0);
8037dd7cddfSDavid du Colombier 		up->state = Wakeme;
8047dd7cddfSDavid du Colombier 		up->r = r;
8057dd7cddfSDavid du Colombier 
8067dd7cddfSDavid du Colombier 		/* statistics */
8077dd7cddfSDavid du Colombier 		m->cs++;
8087dd7cddfSDavid du Colombier 
8097dd7cddfSDavid du Colombier 		procsave(up);
8107dd7cddfSDavid du Colombier 		if(setlabel(&up->sched)) {
8117dd7cddfSDavid du Colombier 			/*
8127dd7cddfSDavid du Colombier 			 *  here when the process is awakened
8137dd7cddfSDavid du Colombier 			 */
8147dd7cddfSDavid du Colombier 			procrestore(up);
8157dd7cddfSDavid du Colombier 			spllo();
8167dd7cddfSDavid du Colombier 		} else {
8177dd7cddfSDavid du Colombier 			/*
8187dd7cddfSDavid du Colombier 			 *  here to go to sleep (i.e. stop Running)
8197dd7cddfSDavid du Colombier 			 */
8207dd7cddfSDavid du Colombier 			unlock(&up->rlock);
82159cc4ca5SDavid du Colombier 			unlock(r);
8227dd7cddfSDavid du Colombier 			gotolabel(&m->sched);
8233e12c5d1SDavid du Colombier 		}
8243e12c5d1SDavid du Colombier 	}
8253e12c5d1SDavid du Colombier 
8267dd7cddfSDavid du Colombier 	if(up->notepending) {
8277dd7cddfSDavid du Colombier 		up->notepending = 0;
8283e12c5d1SDavid du Colombier 		splx(s);
8292cca75a1SDavid du Colombier 		if(up->procctl == Proc_exitme && up->closingfgrp)
8302cca75a1SDavid du Colombier 			forceclosefgrp();
8313e12c5d1SDavid du Colombier 		error(Eintr);
8323e12c5d1SDavid du Colombier 	}
8337dd7cddfSDavid du Colombier 
8347dd7cddfSDavid du Colombier 	splx(s);
8353e12c5d1SDavid du Colombier }
8363e12c5d1SDavid du Colombier 
83715174232SDavid du Colombier static int
tfn(void * arg)8383e12c5d1SDavid du Colombier tfn(void *arg)
8393e12c5d1SDavid du Colombier {
840da51d93aSDavid du Colombier 	return up->trend == nil || up->tfn(arg);
8413e12c5d1SDavid du Colombier }
8423e12c5d1SDavid du Colombier 
8433e12c5d1SDavid du Colombier void
twakeup(Ureg *,Timer * t)844e288d156SDavid du Colombier twakeup(Ureg*, Timer *t)
8453e12c5d1SDavid du Colombier {
846e288d156SDavid du Colombier 	Proc *p;
8478280c5dcSDavid du Colombier 	Rendez *trend;
8483e12c5d1SDavid du Colombier 
849e288d156SDavid du Colombier 	p = t->ta;
8508280c5dcSDavid du Colombier 	trend = p->trend;
851e288d156SDavid du Colombier 	p->trend = 0;
8528280c5dcSDavid du Colombier 	if(trend)
8538280c5dcSDavid du Colombier 		wakeup(trend);
854e288d156SDavid du Colombier }
8553e12c5d1SDavid du Colombier 
856e288d156SDavid du Colombier void
tsleep(Rendez * r,int (* fn)(void *),void * arg,ulong ms)857e288d156SDavid du Colombier tsleep(Rendez *r, int (*fn)(void*), void *arg, ulong ms)
858e288d156SDavid du Colombier {
859da51d93aSDavid du Colombier 	if (up->tt){
860567483c8SDavid du Colombier 		print("tsleep: timer active: mode %d, tf %#p\n", up->tmode, up->tf);
861e288d156SDavid du Colombier 		timerdel(up);
862da51d93aSDavid du Colombier 	}
863e288d156SDavid du Colombier 	up->tns = MS2NS(ms);
864e288d156SDavid du Colombier 	up->tf = twakeup;
865e288d156SDavid du Colombier 	up->tmode = Trelative;
866e288d156SDavid du Colombier 	up->ta = up;
867e288d156SDavid du Colombier 	up->trend = r;
868e288d156SDavid du Colombier 	up->tfn = fn;
869e288d156SDavid du Colombier 	timeradd(up);
870e288d156SDavid du Colombier 
871e288d156SDavid du Colombier 	if(waserror()){
872e288d156SDavid du Colombier 		timerdel(up);
873e288d156SDavid du Colombier 		nexterror();
874e288d156SDavid du Colombier 	}
875e288d156SDavid du Colombier 	sleep(r, tfn, arg);
876e288d156SDavid du Colombier 	if(up->tt)
877e288d156SDavid du Colombier 		timerdel(up);
8787dd7cddfSDavid du Colombier 	up->twhen = 0;
8797dd7cddfSDavid du Colombier 	poperror();
8803e12c5d1SDavid du Colombier }
8813e12c5d1SDavid du Colombier 
8823e12c5d1SDavid du Colombier /*
88359cc4ca5SDavid du Colombier  *  Expects that only one process can call wakeup for any given Rendez.
88459cc4ca5SDavid du Colombier  *  We hold both locks to ensure that r->p and p->r remain consistent.
88559cc4ca5SDavid du Colombier  *  Richard Miller has a better solution that doesn't require both to
88659cc4ca5SDavid du Colombier  *  be held simultaneously, but I'm a paranoid - presotto.
8873e12c5d1SDavid du Colombier  */
88880ee5cbfSDavid du Colombier Proc*
wakeup(Rendez * r)8893e12c5d1SDavid du Colombier wakeup(Rendez *r)
8903e12c5d1SDavid du Colombier {
8919a747e4fSDavid du Colombier 	Proc *p;
89280ee5cbfSDavid du Colombier 	int s;
8937dd7cddfSDavid du Colombier 
8943e12c5d1SDavid du Colombier 	s = splhi();
8957dd7cddfSDavid du Colombier 
89659cc4ca5SDavid du Colombier 	lock(r);
89759cc4ca5SDavid du Colombier 	p = r->p;
89859cc4ca5SDavid du Colombier 
89959cc4ca5SDavid du Colombier 	if(p != nil){
90059cc4ca5SDavid du Colombier 		lock(&p->rlock);
901017579bfSDavid du Colombier 		if(p->state != Wakeme || p->r != r){
902017579bfSDavid du Colombier 			iprint("%p %p %d\n", p->r, r, p->state);
9033e12c5d1SDavid du Colombier 			panic("wakeup: state");
904017579bfSDavid du Colombier 		}
90559cc4ca5SDavid du Colombier 		r->p = nil;
90659cc4ca5SDavid du Colombier 		p->r = nil;
9073e12c5d1SDavid du Colombier 		ready(p);
90859cc4ca5SDavid du Colombier 		unlock(&p->rlock);
9093e12c5d1SDavid du Colombier 	}
91059cc4ca5SDavid du Colombier 	unlock(r);
91159cc4ca5SDavid du Colombier 
9123e12c5d1SDavid du Colombier 	splx(s);
9137dd7cddfSDavid du Colombier 
9149a747e4fSDavid du Colombier 	return p;
9153e12c5d1SDavid du Colombier }
9163e12c5d1SDavid du Colombier 
91759cc4ca5SDavid du Colombier /*
91859cc4ca5SDavid du Colombier  *  if waking a sleeping process, this routine must hold both
91959cc4ca5SDavid du Colombier  *  p->rlock and r->lock.  However, it can't know them in
92059cc4ca5SDavid du Colombier  *  the same order as wakeup causing a possible lock ordering
92159cc4ca5SDavid du Colombier  *  deadlock.  We break the deadlock by giving up the p->rlock
92259cc4ca5SDavid du Colombier  *  lock if we can't get the r->lock and retrying.
92359cc4ca5SDavid du Colombier  */
9243e12c5d1SDavid du Colombier int
postnote(Proc * p,int dolock,char * n,int flag)9253e12c5d1SDavid du Colombier postnote(Proc *p, int dolock, char *n, int flag)
9263e12c5d1SDavid du Colombier {
9273e12c5d1SDavid du Colombier 	int s, ret;
9283e12c5d1SDavid du Colombier 	Rendez *r;
9293e12c5d1SDavid du Colombier 	Proc *d, **l;
9303e12c5d1SDavid du Colombier 
9313e12c5d1SDavid du Colombier 	if(dolock)
9323e12c5d1SDavid du Colombier 		qlock(&p->debug);
9333e12c5d1SDavid du Colombier 
9347dd7cddfSDavid du Colombier 	if(flag != NUser && (p->notify == 0 || p->notified))
9357dd7cddfSDavid du Colombier 		p->nnote = 0;
9363e12c5d1SDavid du Colombier 
9373e12c5d1SDavid du Colombier 	ret = 0;
9387dd7cddfSDavid du Colombier 	if(p->nnote < NNOTE) {
9397dd7cddfSDavid du Colombier 		strcpy(p->note[p->nnote].msg, n);
9407dd7cddfSDavid du Colombier 		p->note[p->nnote++].flag = flag;
9413e12c5d1SDavid du Colombier 		ret = 1;
9423e12c5d1SDavid du Colombier 	}
9433e12c5d1SDavid du Colombier 	p->notepending = 1;
9443e12c5d1SDavid du Colombier 	if(dolock)
9453e12c5d1SDavid du Colombier 		qunlock(&p->debug);
9463e12c5d1SDavid du Colombier 
94759cc4ca5SDavid du Colombier 	/* this loop is to avoid lock ordering problems. */
94859cc4ca5SDavid du Colombier 	for(;;){
9493e12c5d1SDavid du Colombier 		s = splhi();
9507dd7cddfSDavid du Colombier 		lock(&p->rlock);
9517dd7cddfSDavid du Colombier 		r = p->r;
95259cc4ca5SDavid du Colombier 
95359cc4ca5SDavid du Colombier 		/* waiting for a wakeup? */
95459cc4ca5SDavid du Colombier 		if(r == nil)
95559cc4ca5SDavid du Colombier 			break;	/* no */
95659cc4ca5SDavid du Colombier 
95759cc4ca5SDavid du Colombier 		/* try for the second lock */
95859cc4ca5SDavid du Colombier 		if(canlock(r)){
95959cc4ca5SDavid du Colombier 			if(p->state != Wakeme || r->p != p)
9607dd7cddfSDavid du Colombier 				panic("postnote: state %d %d %d", r->p != p, p->r != r, p->state);
96159cc4ca5SDavid du Colombier 			p->r = nil;
96259cc4ca5SDavid du Colombier 			r->p = nil;
9633e12c5d1SDavid du Colombier 			ready(p);
96459cc4ca5SDavid du Colombier 			unlock(r);
96559cc4ca5SDavid du Colombier 			break;
96659cc4ca5SDavid du Colombier 		}
96759cc4ca5SDavid du Colombier 
96859cc4ca5SDavid du Colombier 		/* give other process time to get out of critical section and try again */
96959cc4ca5SDavid du Colombier 		unlock(&p->rlock);
97059cc4ca5SDavid du Colombier 		splx(s);
97159cc4ca5SDavid du Colombier 		sched();
9723e12c5d1SDavid du Colombier 	}
9737dd7cddfSDavid du Colombier 	unlock(&p->rlock);
9743e12c5d1SDavid du Colombier 	splx(s);
9753e12c5d1SDavid du Colombier 
976bd389b36SDavid du Colombier 	if(p->state != Rendezvous)
977bd389b36SDavid du Colombier 		return ret;
978bd389b36SDavid du Colombier 
979bd389b36SDavid du Colombier 	/* Try and pull out of a rendezvous */
9807dd7cddfSDavid du Colombier 	lock(p->rgrp);
9813e12c5d1SDavid du Colombier 	if(p->state == Rendezvous) {
9823e12c5d1SDavid du Colombier 		p->rendval = ~0;
9837dd7cddfSDavid du Colombier 		l = &REND(p->rgrp, p->rendtag);
9843e12c5d1SDavid du Colombier 		for(d = *l; d; d = d->rendhash) {
9853e12c5d1SDavid du Colombier 			if(d == p) {
9863e12c5d1SDavid du Colombier 				*l = p->rendhash;
9873e12c5d1SDavid du Colombier 				break;
9883e12c5d1SDavid du Colombier 			}
9893e12c5d1SDavid du Colombier 			l = &d->rendhash;
9903e12c5d1SDavid du Colombier 		}
9917dd7cddfSDavid du Colombier 		ready(p);
9923e12c5d1SDavid du Colombier 	}
9937dd7cddfSDavid du Colombier 	unlock(p->rgrp);
9943e12c5d1SDavid du Colombier 	return ret;
9953e12c5d1SDavid du Colombier }
9963e12c5d1SDavid du Colombier 
9973e12c5d1SDavid du Colombier /*
9983e12c5d1SDavid du Colombier  * weird thing: keep at most NBROKEN around
9993e12c5d1SDavid du Colombier  */
10003e12c5d1SDavid du Colombier #define	NBROKEN 4
1001bd389b36SDavid du Colombier struct
1002bd389b36SDavid du Colombier {
1003bd389b36SDavid du Colombier 	QLock;
10043e12c5d1SDavid du Colombier 	int	n;
10053e12c5d1SDavid du Colombier 	Proc	*p[NBROKEN];
10063e12c5d1SDavid du Colombier }broken;
10073e12c5d1SDavid du Colombier 
10083e12c5d1SDavid du Colombier void
addbroken(Proc * p)1009bd389b36SDavid du Colombier addbroken(Proc *p)
10103e12c5d1SDavid du Colombier {
1011bd389b36SDavid du Colombier 	qlock(&broken);
10123e12c5d1SDavid du Colombier 	if(broken.n == NBROKEN) {
10133e12c5d1SDavid du Colombier 		ready(broken.p[0]);
10143e12c5d1SDavid du Colombier 		memmove(&broken.p[0], &broken.p[1], sizeof(Proc*)*(NBROKEN-1));
10153e12c5d1SDavid du Colombier 		--broken.n;
10163e12c5d1SDavid du Colombier 	}
1017bd389b36SDavid du Colombier 	broken.p[broken.n++] = p;
1018bd389b36SDavid du Colombier 	qunlock(&broken);
1019bd389b36SDavid du Colombier 
1020e288d156SDavid du Colombier 	edfstop(up);
1021bd389b36SDavid du Colombier 	p->state = Broken;
1022bd389b36SDavid du Colombier 	p->psstate = 0;
1023bd389b36SDavid du Colombier 	sched();
1024bd389b36SDavid du Colombier }
1025bd389b36SDavid du Colombier 
1026bd389b36SDavid du Colombier void
unbreak(Proc * p)1027bd389b36SDavid du Colombier unbreak(Proc *p)
1028bd389b36SDavid du Colombier {
1029bd389b36SDavid du Colombier 	int b;
1030bd389b36SDavid du Colombier 
1031bd389b36SDavid du Colombier 	qlock(&broken);
1032bd389b36SDavid du Colombier 	for(b=0; b < broken.n; b++)
1033bd389b36SDavid du Colombier 		if(broken.p[b] == p) {
10343e12c5d1SDavid du Colombier 			broken.n--;
1035bd389b36SDavid du Colombier 			memmove(&broken.p[b], &broken.p[b+1],
1036bd389b36SDavid du Colombier 					sizeof(Proc*)*(NBROKEN-(b+1)));
1037bd389b36SDavid du Colombier 			ready(p);
10383e12c5d1SDavid du Colombier 			break;
10393e12c5d1SDavid du Colombier 		}
1040bd389b36SDavid du Colombier 	qunlock(&broken);
10413e12c5d1SDavid du Colombier }
10423e12c5d1SDavid du Colombier 
10433e12c5d1SDavid du Colombier int
freebroken(void)10443e12c5d1SDavid du Colombier freebroken(void)
10453e12c5d1SDavid du Colombier {
10463e12c5d1SDavid du Colombier 	int i, n;
10473e12c5d1SDavid du Colombier 
1048bd389b36SDavid du Colombier 	qlock(&broken);
10493e12c5d1SDavid du Colombier 	n = broken.n;
1050bd389b36SDavid du Colombier 	for(i=0; i<n; i++) {
10513e12c5d1SDavid du Colombier 		ready(broken.p[i]);
1052bd389b36SDavid du Colombier 		broken.p[i] = 0;
1053bd389b36SDavid du Colombier 	}
10543e12c5d1SDavid du Colombier 	broken.n = 0;
1055bd389b36SDavid du Colombier 	qunlock(&broken);
10563e12c5d1SDavid du Colombier 	return n;
10573e12c5d1SDavid du Colombier }
10583e12c5d1SDavid du Colombier 
10593e12c5d1SDavid du Colombier void
pexit(char * exitstr,int freemem)10603e12c5d1SDavid du Colombier pexit(char *exitstr, int freemem)
10613e12c5d1SDavid du Colombier {
10627dd7cddfSDavid du Colombier 	Proc *p;
1063bd389b36SDavid du Colombier 	Segment **s, **es;
10647dd7cddfSDavid du Colombier 	long utime, stime;
10653e12c5d1SDavid du Colombier 	Waitq *wq, *f, *next;
10667dd7cddfSDavid du Colombier 	Fgrp *fgrp;
10677dd7cddfSDavid du Colombier 	Egrp *egrp;
10687dd7cddfSDavid du Colombier 	Rgrp *rgrp;
10697dd7cddfSDavid du Colombier 	Pgrp *pgrp;
10707dd7cddfSDavid du Colombier 	Chan *dot;
10710701b922SDavid du Colombier 	void (*pt)(Proc*, int, vlong);
10723e12c5d1SDavid du Colombier 
1073d1be6b08SDavid du Colombier 	if(up->syscalltrace)
1074d1be6b08SDavid du Colombier 		free(up->syscalltrace);
10757dd7cddfSDavid du Colombier 	up->alarm = 0;
1076e288d156SDavid du Colombier 	if (up->tt)
1077e288d156SDavid du Colombier 		timerdel(up);
1078e288d156SDavid du Colombier 	pt = proctrace;
10790701b922SDavid du Colombier 	if(pt)
10800701b922SDavid du Colombier 		pt(up, SDead, 0);
10813e12c5d1SDavid du Colombier 
10827dd7cddfSDavid du Colombier 	/* nil out all the resources under lock (free later) */
10837dd7cddfSDavid du Colombier 	qlock(&up->debug);
10847dd7cddfSDavid du Colombier 	fgrp = up->fgrp;
10857dd7cddfSDavid du Colombier 	up->fgrp = nil;
10867dd7cddfSDavid du Colombier 	egrp = up->egrp;
10877dd7cddfSDavid du Colombier 	up->egrp = nil;
10887dd7cddfSDavid du Colombier 	rgrp = up->rgrp;
10897dd7cddfSDavid du Colombier 	up->rgrp = nil;
10907dd7cddfSDavid du Colombier 	pgrp = up->pgrp;
10917dd7cddfSDavid du Colombier 	up->pgrp = nil;
10927dd7cddfSDavid du Colombier 	dot = up->dot;
10937dd7cddfSDavid du Colombier 	up->dot = nil;
10947dd7cddfSDavid du Colombier 	qunlock(&up->debug);
10957dd7cddfSDavid du Colombier 
10967dd7cddfSDavid du Colombier 	if(fgrp)
10977dd7cddfSDavid du Colombier 		closefgrp(fgrp);
10987dd7cddfSDavid du Colombier 	if(egrp)
10997dd7cddfSDavid du Colombier 		closeegrp(egrp);
11007dd7cddfSDavid du Colombier 	if(rgrp)
11017dd7cddfSDavid du Colombier 		closergrp(rgrp);
11027dd7cddfSDavid du Colombier 	if(dot)
11037dd7cddfSDavid du Colombier 		cclose(dot);
11047dd7cddfSDavid du Colombier 	if(pgrp)
11057dd7cddfSDavid du Colombier 		closepgrp(pgrp);
11063e12c5d1SDavid du Colombier 
11073e12c5d1SDavid du Colombier 	/*
11083e12c5d1SDavid du Colombier 	 * if not a kernel process and have a parent,
11093e12c5d1SDavid du Colombier 	 * do some housekeeping.
11103e12c5d1SDavid du Colombier 	 */
11117dd7cddfSDavid du Colombier 	if(up->kp == 0) {
11127dd7cddfSDavid du Colombier 		p = up->parent;
1113bd389b36SDavid du Colombier 		if(p == 0) {
11143e12c5d1SDavid du Colombier 			if(exitstr == 0)
11153e12c5d1SDavid du Colombier 				exitstr = "unknown";
11163e12c5d1SDavid du Colombier 			panic("boot process died: %s", exitstr);
11173e12c5d1SDavid du Colombier 		}
11183e12c5d1SDavid du Colombier 
11193e12c5d1SDavid du Colombier 		while(waserror())
11203e12c5d1SDavid du Colombier 			;
11217dd7cddfSDavid du Colombier 
11223e12c5d1SDavid du Colombier 		wq = smalloc(sizeof(Waitq));
11233e12c5d1SDavid du Colombier 		poperror();
11243e12c5d1SDavid du Colombier 
11259a747e4fSDavid du Colombier 		wq->w.pid = up->pid;
1126b7b24591SDavid du Colombier 		utime = up->time[TUser] + up->time[TCUser];
1127b7b24591SDavid du Colombier 		stime = up->time[TSys] + up->time[TCSys];
11283ff48bf5SDavid du Colombier 		wq->w.time[TUser] = tk2ms(utime);
11293ff48bf5SDavid du Colombier 		wq->w.time[TSys] = tk2ms(stime);
11303ff48bf5SDavid du Colombier 		wq->w.time[TReal] = tk2ms(MACHP(0)->ticks - up->time[TReal]);
11319a747e4fSDavid du Colombier 		if(exitstr && exitstr[0])
11329a747e4fSDavid du Colombier 			snprint(wq->w.msg, sizeof(wq->w.msg), "%s %lud: %s", up->text, up->pid, exitstr);
1133bd389b36SDavid du Colombier 		else
11343e12c5d1SDavid du Colombier 			wq->w.msg[0] = '\0';
11353e12c5d1SDavid du Colombier 
11363e12c5d1SDavid du Colombier 		lock(&p->exl);
11377dd7cddfSDavid du Colombier 		/*
1138017579bfSDavid du Colombier 		 * Check that parent is still alive.
11393e12c5d1SDavid du Colombier 		 */
1140017579bfSDavid du Colombier 		if(p->pid == up->parentpid && p->state != Broken) {
11413e12c5d1SDavid du Colombier 			p->nchild--;
11423e12c5d1SDavid du Colombier 			p->time[TCUser] += utime;
11433e12c5d1SDavid du Colombier 			p->time[TCSys] += stime;
1144017579bfSDavid du Colombier 			/*
1145017579bfSDavid du Colombier 			 * If there would be more than 128 wait records
1146017579bfSDavid du Colombier 			 * processes for my parent, then don't leave a wait
1147017579bfSDavid du Colombier 			 * record behind.  This helps prevent badly written
1148017579bfSDavid du Colombier 			 * daemon processes from accumulating lots of wait
1149017579bfSDavid du Colombier 			 * records.
1150017579bfSDavid du Colombier 		 	 */
1151017579bfSDavid du Colombier 			if(p->nwait < 128) {
11523e12c5d1SDavid du Colombier 				wq->next = p->waitq;
11533e12c5d1SDavid du Colombier 				p->waitq = wq;
11543e12c5d1SDavid du Colombier 				p->nwait++;
1155017579bfSDavid du Colombier 				wq = nil;
11563e12c5d1SDavid du Colombier 				wakeup(&p->waitr);
11573e12c5d1SDavid du Colombier 			}
1158017579bfSDavid du Colombier 		}
11593e12c5d1SDavid du Colombier 		unlock(&p->exl);
1160017579bfSDavid du Colombier 		if(wq)
11613e12c5d1SDavid du Colombier 			free(wq);
11623e12c5d1SDavid du Colombier 	}
11633e12c5d1SDavid du Colombier 
11643e12c5d1SDavid du Colombier 	if(!freemem)
11657dd7cddfSDavid du Colombier 		addbroken(up);
11663e12c5d1SDavid du Colombier 
11677dd7cddfSDavid du Colombier 	qlock(&up->seglock);
11687dd7cddfSDavid du Colombier 	es = &up->seg[NSEG];
11697dd7cddfSDavid du Colombier 	for(s = up->seg; s < es; s++) {
11707dd7cddfSDavid du Colombier 		if(*s) {
1171bd389b36SDavid du Colombier 			putseg(*s);
11727dd7cddfSDavid du Colombier 			*s = 0;
11737dd7cddfSDavid du Colombier 		}
11747dd7cddfSDavid du Colombier 	}
11757dd7cddfSDavid du Colombier 	qunlock(&up->seglock);
11763e12c5d1SDavid du Colombier 
11777dd7cddfSDavid du Colombier 	lock(&up->exl);		/* Prevent my children from leaving waits */
11789a747e4fSDavid du Colombier 	pidunhash(up);
11797dd7cddfSDavid du Colombier 	up->pid = 0;
11807dd7cddfSDavid du Colombier 	wakeup(&up->waitr);
11817dd7cddfSDavid du Colombier 	unlock(&up->exl);
11823e12c5d1SDavid du Colombier 
11837dd7cddfSDavid du Colombier 	for(f = up->waitq; f; f = next) {
11843e12c5d1SDavid du Colombier 		next = f->next;
11853e12c5d1SDavid du Colombier 		free(f);
11863e12c5d1SDavid du Colombier 	}
11873e12c5d1SDavid du Colombier 
11883e12c5d1SDavid du Colombier 	/* release debuggers */
11897dd7cddfSDavid du Colombier 	qlock(&up->debug);
11907dd7cddfSDavid du Colombier 	if(up->pdbg) {
11917dd7cddfSDavid du Colombier 		wakeup(&up->pdbg->sleep);
11927dd7cddfSDavid du Colombier 		up->pdbg = 0;
11933e12c5d1SDavid du Colombier 	}
11947dd7cddfSDavid du Colombier 	qunlock(&up->debug);
11953e12c5d1SDavid du Colombier 
11967dd7cddfSDavid du Colombier 	/* Sched must not loop for these locks */
11973e12c5d1SDavid du Colombier 	lock(&procalloc);
11983e12c5d1SDavid du Colombier 	lock(&palloc);
11993e12c5d1SDavid du Colombier 
1200e288d156SDavid du Colombier 	edfstop(up);
12017dd7cddfSDavid du Colombier 	up->state = Moribund;
12023e12c5d1SDavid du Colombier 	sched();
12033e12c5d1SDavid du Colombier 	panic("pexit");
12043e12c5d1SDavid du Colombier }
12053e12c5d1SDavid du Colombier 
12063e12c5d1SDavid du Colombier int
haswaitq(void * x)12073e12c5d1SDavid du Colombier haswaitq(void *x)
12083e12c5d1SDavid du Colombier {
12093e12c5d1SDavid du Colombier 	Proc *p;
12103e12c5d1SDavid du Colombier 
12113e12c5d1SDavid du Colombier 	p = (Proc *)x;
12123e12c5d1SDavid du Colombier 	return p->waitq != 0;
12133e12c5d1SDavid du Colombier }
12143e12c5d1SDavid du Colombier 
12153e12c5d1SDavid du Colombier ulong
pwait(Waitmsg * w)12163e12c5d1SDavid du Colombier pwait(Waitmsg *w)
12173e12c5d1SDavid du Colombier {
12183e12c5d1SDavid du Colombier 	ulong cpid;
12193e12c5d1SDavid du Colombier 	Waitq *wq;
12203e12c5d1SDavid du Colombier 
12217dd7cddfSDavid du Colombier 	if(!canqlock(&up->qwaitr))
1222219b2ee8SDavid du Colombier 		error(Einuse);
1223219b2ee8SDavid du Colombier 
1224219b2ee8SDavid du Colombier 	if(waserror()) {
12257dd7cddfSDavid du Colombier 		qunlock(&up->qwaitr);
1226219b2ee8SDavid du Colombier 		nexterror();
1227219b2ee8SDavid du Colombier 	}
1228219b2ee8SDavid du Colombier 
12297dd7cddfSDavid du Colombier 	lock(&up->exl);
12307dd7cddfSDavid du Colombier 	if(up->nchild == 0 && up->waitq == 0) {
12317dd7cddfSDavid du Colombier 		unlock(&up->exl);
12323e12c5d1SDavid du Colombier 		error(Enochild);
12333e12c5d1SDavid du Colombier 	}
12347dd7cddfSDavid du Colombier 	unlock(&up->exl);
12353e12c5d1SDavid du Colombier 
12367dd7cddfSDavid du Colombier 	sleep(&up->waitr, haswaitq, up);
12373e12c5d1SDavid du Colombier 
12387dd7cddfSDavid du Colombier 	lock(&up->exl);
12397dd7cddfSDavid du Colombier 	wq = up->waitq;
12407dd7cddfSDavid du Colombier 	up->waitq = wq->next;
12417dd7cddfSDavid du Colombier 	up->nwait--;
12427dd7cddfSDavid du Colombier 	unlock(&up->exl);
12433e12c5d1SDavid du Colombier 
12447dd7cddfSDavid du Colombier 	qunlock(&up->qwaitr);
1245219b2ee8SDavid du Colombier 	poperror();
1246219b2ee8SDavid du Colombier 
12473e12c5d1SDavid du Colombier 	if(w)
12483e12c5d1SDavid du Colombier 		memmove(w, &wq->w, sizeof(Waitmsg));
12499a747e4fSDavid du Colombier 	cpid = wq->w.pid;
12503e12c5d1SDavid du Colombier 	free(wq);
12513e12c5d1SDavid du Colombier 	return cpid;
12523e12c5d1SDavid du Colombier }
12533e12c5d1SDavid du Colombier 
12543e12c5d1SDavid du Colombier Proc*
proctab(int i)12553e12c5d1SDavid du Colombier proctab(int i)
12563e12c5d1SDavid du Colombier {
12573e12c5d1SDavid du Colombier 	return &procalloc.arena[i];
12583e12c5d1SDavid du Colombier }
12593e12c5d1SDavid du Colombier 
12603e12c5d1SDavid du Colombier void
dumpaproc(Proc * p)12617dd7cddfSDavid du Colombier dumpaproc(Proc *p)
12623e12c5d1SDavid du Colombier {
12633e12c5d1SDavid du Colombier 	ulong bss;
12647dd7cddfSDavid du Colombier 	char *s;
12653e12c5d1SDavid du Colombier 
12667dd7cddfSDavid du Colombier 	if(p == 0)
12677dd7cddfSDavid du Colombier 		return;
12687dd7cddfSDavid du Colombier 
12693e12c5d1SDavid du Colombier 	bss = 0;
12703e12c5d1SDavid du Colombier 	if(p->seg[BSEG])
12713e12c5d1SDavid du Colombier 		bss = p->seg[BSEG]->top;
12723e12c5d1SDavid du Colombier 
12733e12c5d1SDavid du Colombier 	s = p->psstate;
12743e12c5d1SDavid du Colombier 	if(s == 0)
127580ee5cbfSDavid du Colombier 		s = statename[p->state];
1276a6a9e072SDavid du Colombier 	print("%3lud:%10s pc %8lux dbgpc %8lux  %8s (%s) ut %ld st %ld bss %lux qpc %lux nl %lud nd %lud lpc %lux pri %lud\n",
12777dd7cddfSDavid du Colombier 		p->pid, p->text, p->pc, dbgpc(p),  s, statename[p->state],
1278e288d156SDavid du Colombier 		p->time[0], p->time[1], bss, p->qpc, p->nlocks.ref, p->delaysched, p->lastlock ? p->lastlock->pc : 0, p->priority);
12797dd7cddfSDavid du Colombier }
12807dd7cddfSDavid du Colombier 
12817dd7cddfSDavid du Colombier void
procdump(void)12827dd7cddfSDavid du Colombier procdump(void)
12837dd7cddfSDavid du Colombier {
12847dd7cddfSDavid du Colombier 	int i;
12857dd7cddfSDavid du Colombier 	Proc *p;
12867dd7cddfSDavid du Colombier 
12877dd7cddfSDavid du Colombier 	if(up)
12887dd7cddfSDavid du Colombier 		print("up %lud\n", up->pid);
12897dd7cddfSDavid du Colombier 	else
12907dd7cddfSDavid du Colombier 		print("no current process\n");
12917dd7cddfSDavid du Colombier 	for(i=0; i<conf.nproc; i++) {
12927dd7cddfSDavid du Colombier 		p = &procalloc.arena[i];
12937dd7cddfSDavid du Colombier 		if(p->state == Dead)
12947dd7cddfSDavid du Colombier 			continue;
12957dd7cddfSDavid du Colombier 
12967dd7cddfSDavid du Colombier 		dumpaproc(p);
12973e12c5d1SDavid du Colombier 	}
12983e12c5d1SDavid du Colombier }
12997dd7cddfSDavid du Colombier 
13007dd7cddfSDavid du Colombier /*
13017dd7cddfSDavid du Colombier  *  wait till all processes have flushed their mmu
13027dd7cddfSDavid du Colombier  *  state about segement s
13037dd7cddfSDavid du Colombier  */
13047dd7cddfSDavid du Colombier void
procflushseg(Segment * s)13057dd7cddfSDavid du Colombier procflushseg(Segment *s)
13067dd7cddfSDavid du Colombier {
13077dd7cddfSDavid du Colombier 	int i, ns, nm, nwait;
13087dd7cddfSDavid du Colombier 	Proc *p;
13097dd7cddfSDavid du Colombier 
13107dd7cddfSDavid du Colombier 	/*
13117dd7cddfSDavid du Colombier 	 *  tell all processes with this
13127dd7cddfSDavid du Colombier 	 *  segment to flush their mmu's
13137dd7cddfSDavid du Colombier 	 */
13147dd7cddfSDavid du Colombier 	nwait = 0;
13157dd7cddfSDavid du Colombier 	for(i=0; i<conf.nproc; i++) {
13167dd7cddfSDavid du Colombier 		p = &procalloc.arena[i];
13177dd7cddfSDavid du Colombier 		if(p->state == Dead)
13187dd7cddfSDavid du Colombier 			continue;
13197dd7cddfSDavid du Colombier 		for(ns = 0; ns < NSEG; ns++)
13207dd7cddfSDavid du Colombier 			if(p->seg[ns] == s){
13217dd7cddfSDavid du Colombier 				p->newtlb = 1;
13227dd7cddfSDavid du Colombier 				for(nm = 0; nm < conf.nmach; nm++){
13237dd7cddfSDavid du Colombier 					if(MACHP(nm)->proc == p){
13247dd7cddfSDavid du Colombier 						MACHP(nm)->flushmmu = 1;
13257dd7cddfSDavid du Colombier 						nwait++;
13267dd7cddfSDavid du Colombier 					}
13277dd7cddfSDavid du Colombier 				}
13287dd7cddfSDavid du Colombier 				break;
13297dd7cddfSDavid du Colombier 			}
13307dd7cddfSDavid du Colombier 	}
13317dd7cddfSDavid du Colombier 
13327dd7cddfSDavid du Colombier 	if(nwait == 0)
13337dd7cddfSDavid du Colombier 		return;
13347dd7cddfSDavid du Colombier 
13357dd7cddfSDavid du Colombier 	/*
13367dd7cddfSDavid du Colombier 	 *  wait for all processors to take a clock interrupt
13377dd7cddfSDavid du Colombier 	 *  and flush their mmu's
13387dd7cddfSDavid du Colombier 	 */
13397dd7cddfSDavid du Colombier 	for(nm = 0; nm < conf.nmach; nm++)
13407dd7cddfSDavid du Colombier 		if(MACHP(nm) != m)
13417dd7cddfSDavid du Colombier 			while(MACHP(nm)->flushmmu)
13427dd7cddfSDavid du Colombier 				sched();
13437dd7cddfSDavid du Colombier }
13447dd7cddfSDavid du Colombier 
13457dd7cddfSDavid du Colombier void
scheddump(void)13467dd7cddfSDavid du Colombier scheddump(void)
13477dd7cddfSDavid du Colombier {
13487dd7cddfSDavid du Colombier 	Proc *p;
13497dd7cddfSDavid du Colombier 	Schedq *rq;
13507dd7cddfSDavid du Colombier 
13517dd7cddfSDavid du Colombier 	for(rq = &runq[Nrq-1]; rq >= runq; rq--){
1352219b2ee8SDavid du Colombier 		if(rq->head == 0)
1353219b2ee8SDavid du Colombier 			continue;
13547dd7cddfSDavid du Colombier 		print("rq%ld:", rq-runq);
1355219b2ee8SDavid du Colombier 		for(p = rq->head; p; p = p->rnext)
1356a6a9e072SDavid du Colombier 			print(" %lud(%lud)", p->pid, m->ticks - p->readytime);
1357219b2ee8SDavid du Colombier 		print("\n");
13587dd7cddfSDavid du Colombier 		delay(150);
1359219b2ee8SDavid du Colombier 	}
1360219b2ee8SDavid du Colombier 	print("nrdy %d\n", nrdy);
13613e12c5d1SDavid du Colombier }
13623e12c5d1SDavid du Colombier 
13633e12c5d1SDavid du Colombier void
kproc(char * name,void (* func)(void *),void * arg)13643e12c5d1SDavid du Colombier kproc(char *name, void (*func)(void *), void *arg)
13653e12c5d1SDavid du Colombier {
13663e12c5d1SDavid du Colombier 	Proc *p;
13673e12c5d1SDavid du Colombier 	static Pgrp *kpgrp;
13683e12c5d1SDavid du Colombier 
13693e12c5d1SDavid du Colombier 	p = newproc();
13709a747e4fSDavid du Colombier 	p->psstate = 0;
13719a747e4fSDavid du Colombier 	p->procmode = 0640;
13723e12c5d1SDavid du Colombier 	p->kp = 1;
1373b7b24591SDavid du Colombier 	p->noswap = 1;
13743e12c5d1SDavid du Colombier 
13757dd7cddfSDavid du Colombier 	p->fpsave = up->fpsave;
13767dd7cddfSDavid du Colombier 	p->scallnr = up->scallnr;
13777dd7cddfSDavid du Colombier 	p->s = up->s;
13787dd7cddfSDavid du Colombier 	p->nerrlab = 0;
13797dd7cddfSDavid du Colombier 	p->slash = up->slash;
13807dd7cddfSDavid du Colombier 	p->dot = up->dot;
13812cca75a1SDavid du Colombier 	if(p->dot)
13827dd7cddfSDavid du Colombier 		incref(p->dot);
13837dd7cddfSDavid du Colombier 
13847dd7cddfSDavid du Colombier 	memmove(p->note, up->note, sizeof(p->note));
13857dd7cddfSDavid du Colombier 	p->nnote = up->nnote;
13867dd7cddfSDavid du Colombier 	p->notified = 0;
13877dd7cddfSDavid du Colombier 	p->lastnote = up->lastnote;
13887dd7cddfSDavid du Colombier 	p->notify = up->notify;
13897dd7cddfSDavid du Colombier 	p->ureg = 0;
13907dd7cddfSDavid du Colombier 	p->dbgreg = 0;
13913e12c5d1SDavid du Colombier 
1392a6a9e072SDavid du Colombier 	procpriority(p, PriKproc, 0);
1393219b2ee8SDavid du Colombier 
13947dd7cddfSDavid du Colombier 	kprocchild(p, func, arg);
13953e12c5d1SDavid du Colombier 
13969a747e4fSDavid du Colombier 	kstrdup(&p->user, eve);
13979a747e4fSDavid du Colombier 	kstrdup(&p->text, name);
13987dd7cddfSDavid du Colombier 	if(kpgrp == 0)
13993e12c5d1SDavid du Colombier 		kpgrp = newpgrp();
14003e12c5d1SDavid du Colombier 	p->pgrp = kpgrp;
14013e12c5d1SDavid du Colombier 	incref(kpgrp);
14023e12c5d1SDavid du Colombier 
14033e12c5d1SDavid du Colombier 	memset(p->time, 0, sizeof(p->time));
14043e12c5d1SDavid du Colombier 	p->time[TReal] = MACHP(0)->ticks;
14053e12c5d1SDavid du Colombier 	ready(p);
14063e12c5d1SDavid du Colombier }
14073e12c5d1SDavid du Colombier 
14083e12c5d1SDavid du Colombier /*
14093e12c5d1SDavid du Colombier  *  called splhi() by notify().  See comment in notify for the
14103e12c5d1SDavid du Colombier  *  reasoning.
14113e12c5d1SDavid du Colombier  */
14123e12c5d1SDavid du Colombier void
procctl(Proc * p)14133e12c5d1SDavid du Colombier procctl(Proc *p)
14143e12c5d1SDavid du Colombier {
14153e12c5d1SDavid du Colombier 	char *state;
1416219b2ee8SDavid du Colombier 	ulong s;
14173e12c5d1SDavid du Colombier 
14183e12c5d1SDavid du Colombier 	switch(p->procctl) {
14197dd7cddfSDavid du Colombier 	case Proc_exitbig:
14207dd7cddfSDavid du Colombier 		spllo();
14217dd7cddfSDavid du Colombier 		pexit("Killed: Insufficient physical memory", 1);
14227dd7cddfSDavid du Colombier 
14233e12c5d1SDavid du Colombier 	case Proc_exitme:
14243e12c5d1SDavid du Colombier 		spllo();		/* pexit has locks in it */
14253e12c5d1SDavid du Colombier 		pexit("Killed", 1);
14263e12c5d1SDavid du Colombier 
14273e12c5d1SDavid du Colombier 	case Proc_traceme:
14287dd7cddfSDavid du Colombier 		if(p->nnote == 0)
14293e12c5d1SDavid du Colombier 			return;
14303e12c5d1SDavid du Colombier 		/* No break */
14313e12c5d1SDavid du Colombier 
14323e12c5d1SDavid du Colombier 	case Proc_stopme:
14333e12c5d1SDavid du Colombier 		p->procctl = 0;
14343e12c5d1SDavid du Colombier 		state = p->psstate;
14353e12c5d1SDavid du Colombier 		p->psstate = "Stopped";
14363e12c5d1SDavid du Colombier 		/* free a waiting debugger */
1437219b2ee8SDavid du Colombier 		s = spllo();
14383e12c5d1SDavid du Colombier 		qlock(&p->debug);
14393e12c5d1SDavid du Colombier 		if(p->pdbg) {
14403e12c5d1SDavid du Colombier 			wakeup(&p->pdbg->sleep);
14413e12c5d1SDavid du Colombier 			p->pdbg = 0;
14423e12c5d1SDavid du Colombier 		}
14433e12c5d1SDavid du Colombier 		qunlock(&p->debug);
14443e12c5d1SDavid du Colombier 		splhi();
1445219b2ee8SDavid du Colombier 		p->state = Stopped;
1446219b2ee8SDavid du Colombier 		sched();
14473e12c5d1SDavid du Colombier 		p->psstate = state;
1448219b2ee8SDavid du Colombier 		splx(s);
14493e12c5d1SDavid du Colombier 		return;
14503e12c5d1SDavid du Colombier 	}
14513e12c5d1SDavid du Colombier }
14523e12c5d1SDavid du Colombier 
14533e12c5d1SDavid du Colombier #include "errstr.h"
14543e12c5d1SDavid du Colombier 
14553e12c5d1SDavid du Colombier void
error(char * err)14563e12c5d1SDavid du Colombier error(char *err)
14573e12c5d1SDavid du Colombier {
1458219b2ee8SDavid du Colombier 	spllo();
1459dc5a79c1SDavid du Colombier 
1460dc5a79c1SDavid du Colombier 	assert(up->nerrlab < NERR);
14619a747e4fSDavid du Colombier 	kstrcpy(up->errstr, err, ERRMAX);
14629a747e4fSDavid du Colombier 	setlabel(&up->errlab[NERR-1]);
14633e12c5d1SDavid du Colombier 	nexterror();
14643e12c5d1SDavid du Colombier }
14653e12c5d1SDavid du Colombier 
14663e12c5d1SDavid du Colombier void
nexterror(void)14673e12c5d1SDavid du Colombier nexterror(void)
14683e12c5d1SDavid du Colombier {
14697dd7cddfSDavid du Colombier 	gotolabel(&up->errlab[--up->nerrlab]);
14703e12c5d1SDavid du Colombier }
14713e12c5d1SDavid du Colombier 
14723e12c5d1SDavid du Colombier void
exhausted(char * resource)14733e12c5d1SDavid du Colombier exhausted(char *resource)
14743e12c5d1SDavid du Colombier {
14759a747e4fSDavid du Colombier 	char buf[ERRMAX];
14763e12c5d1SDavid du Colombier 
1477f755faa2SDavid du Colombier 	snprint(buf, sizeof buf, "no free %s", resource);
14787dd7cddfSDavid du Colombier 	iprint("%s\n", buf);
14793e12c5d1SDavid du Colombier 	error(buf);
14803e12c5d1SDavid du Colombier }
14817dd7cddfSDavid du Colombier 
14827dd7cddfSDavid du Colombier void
killbig(char * why)1483cd42b314SDavid du Colombier killbig(char *why)
14847dd7cddfSDavid du Colombier {
14857dd7cddfSDavid du Colombier 	int i;
14867dd7cddfSDavid du Colombier 	Segment *s;
14877dd7cddfSDavid du Colombier 	ulong l, max;
14887dd7cddfSDavid du Colombier 	Proc *p, *ep, *kp;
14897dd7cddfSDavid du Colombier 
14907dd7cddfSDavid du Colombier 	max = 0;
14917dd7cddfSDavid du Colombier 	kp = 0;
14927dd7cddfSDavid du Colombier 	ep = procalloc.arena+conf.nproc;
14937dd7cddfSDavid du Colombier 	for(p = procalloc.arena; p < ep; p++) {
14947dd7cddfSDavid du Colombier 		if(p->state == Dead || p->kp)
14957dd7cddfSDavid du Colombier 			continue;
14967dd7cddfSDavid du Colombier 		l = 0;
14977dd7cddfSDavid du Colombier 		for(i=1; i<NSEG; i++) {
14987dd7cddfSDavid du Colombier 			s = p->seg[i];
14997dd7cddfSDavid du Colombier 			if(s != 0)
15007dd7cddfSDavid du Colombier 				l += s->top - s->base;
15017dd7cddfSDavid du Colombier 		}
1502cd42b314SDavid du Colombier 		if(l > max && ((p->procmode&0222) || strcmp(eve, p->user)!=0)) {
15037dd7cddfSDavid du Colombier 			kp = p;
15047dd7cddfSDavid du Colombier 			max = l;
15057dd7cddfSDavid du Colombier 		}
15067dd7cddfSDavid du Colombier 	}
1507cd42b314SDavid du Colombier 
1508cd42b314SDavid du Colombier 	print("%lud: %s killed: %s\n", kp->pid, kp->text, why);
1509cd42b314SDavid du Colombier 	for(p = procalloc.arena; p < ep; p++) {
1510cd42b314SDavid du Colombier 		if(p->state == Dead || p->kp)
1511cd42b314SDavid du Colombier 			continue;
1512cd42b314SDavid du Colombier 		if(p != kp && p->seg[BSEG] && p->seg[BSEG] == kp->seg[BSEG])
1513cd42b314SDavid du Colombier 			p->procctl = Proc_exitbig;
1514cd42b314SDavid du Colombier 	}
15157dd7cddfSDavid du Colombier 	kp->procctl = Proc_exitbig;
15167dd7cddfSDavid du Colombier 	for(i = 0; i < NSEG; i++) {
15177dd7cddfSDavid du Colombier 		s = kp->seg[i];
15187dd7cddfSDavid du Colombier 		if(s != 0 && canqlock(&s->lk)) {
15197dd7cddfSDavid du Colombier 			mfreeseg(s, s->base, (s->top - s->base)/BY2PG);
15207dd7cddfSDavid du Colombier 			qunlock(&s->lk);
15217dd7cddfSDavid du Colombier 		}
15227dd7cddfSDavid du Colombier 	}
15237dd7cddfSDavid du Colombier }
15247dd7cddfSDavid du Colombier 
15257dd7cddfSDavid du Colombier /*
15267dd7cddfSDavid du Colombier  *  change ownership to 'new' of all processes owned by 'old'.  Used when
15277dd7cddfSDavid du Colombier  *  eve changes.
15287dd7cddfSDavid du Colombier  */
15297dd7cddfSDavid du Colombier void
renameuser(char * old,char * new)15307dd7cddfSDavid du Colombier renameuser(char *old, char *new)
15317dd7cddfSDavid du Colombier {
15327dd7cddfSDavid du Colombier 	Proc *p, *ep;
15337dd7cddfSDavid du Colombier 
15347dd7cddfSDavid du Colombier 	ep = procalloc.arena+conf.nproc;
15357dd7cddfSDavid du Colombier 	for(p = procalloc.arena; p < ep; p++)
15369a747e4fSDavid du Colombier 		if(p->user!=nil && strcmp(old, p->user)==0)
15379a747e4fSDavid du Colombier 			kstrdup(&p->user, new);
15387dd7cddfSDavid du Colombier }
15397dd7cddfSDavid du Colombier 
15407dd7cddfSDavid du Colombier /*
15417dd7cddfSDavid du Colombier  *  time accounting called by clock() splhi'd
15427dd7cddfSDavid du Colombier  */
15437dd7cddfSDavid du Colombier void
accounttime(void)15447dd7cddfSDavid du Colombier accounttime(void)
15457dd7cddfSDavid du Colombier {
15467dd7cddfSDavid du Colombier 	Proc *p;
15473ff48bf5SDavid du Colombier 	ulong n, per;
15483ff48bf5SDavid du Colombier 	static ulong nrun;
15497dd7cddfSDavid du Colombier 
15507dd7cddfSDavid du Colombier 	p = m->proc;
15517dd7cddfSDavid du Colombier 	if(p) {
15527dd7cddfSDavid du Colombier 		nrun++;
15537dd7cddfSDavid du Colombier 		p->time[p->insyscall]++;
15547dd7cddfSDavid du Colombier 	}
15557dd7cddfSDavid du Colombier 
15563ff48bf5SDavid du Colombier 	/* calculate decaying duty cycles */
15573ff48bf5SDavid du Colombier 	n = perfticks();
15583ff48bf5SDavid du Colombier 	per = n - m->perf.last;
15593ff48bf5SDavid du Colombier 	m->perf.last = n;
1560d9306527SDavid du Colombier 	per = (m->perf.period*(HZ-1) + per)/HZ;
1561d9306527SDavid du Colombier 	if(per != 0)
1562d9306527SDavid du Colombier 		m->perf.period = per;
15633ff48bf5SDavid du Colombier 
15643ff48bf5SDavid du Colombier 	m->perf.avg_inidle = (m->perf.avg_inidle*(HZ-1)+m->perf.inidle)/HZ;
15653ff48bf5SDavid du Colombier 	m->perf.inidle = 0;
15663ff48bf5SDavid du Colombier 
15673ff48bf5SDavid du Colombier 	m->perf.avg_inintr = (m->perf.avg_inintr*(HZ-1)+m->perf.inintr)/HZ;
15683ff48bf5SDavid du Colombier 	m->perf.inintr = 0;
15693ff48bf5SDavid du Colombier 
15707dd7cddfSDavid du Colombier 	/* only one processor gets to compute system load averages */
15717dd7cddfSDavid du Colombier 	if(m->machno != 0)
15727dd7cddfSDavid du Colombier 		return;
15737dd7cddfSDavid du Colombier 
157459c21d95SDavid du Colombier 	/*
157559c21d95SDavid du Colombier 	 * calculate decaying load average.
157659c21d95SDavid du Colombier 	 * if we decay by (n-1)/n then it takes
157759c21d95SDavid du Colombier 	 * n clock ticks to go from load L to .36 L once
157859c21d95SDavid du Colombier 	 * things quiet down.  it takes about 5 n clock
157959c21d95SDavid du Colombier 	 * ticks to go to zero.  so using HZ means this is
158059c21d95SDavid du Colombier 	 * approximately the load over the last second,
158159c21d95SDavid du Colombier 	 * with a tail lasting about 5 seconds.
158259c21d95SDavid du Colombier 	 */
15837dd7cddfSDavid du Colombier 	n = nrun;
15847dd7cddfSDavid du Colombier 	nrun = 0;
15857dd7cddfSDavid du Colombier 	n = (nrdy+n)*1000;
158659c21d95SDavid du Colombier 	m->load = (m->load*(HZ-1)+n)/HZ;
15877dd7cddfSDavid du Colombier }
15889a747e4fSDavid du Colombier 
15899a747e4fSDavid du Colombier static void
pidhash(Proc * p)15909a747e4fSDavid du Colombier pidhash(Proc *p)
15919a747e4fSDavid du Colombier {
15929a747e4fSDavid du Colombier 	int h;
15939a747e4fSDavid du Colombier 
15949a747e4fSDavid du Colombier 	h = p->pid % nelem(procalloc.ht);
15959a747e4fSDavid du Colombier 	lock(&procalloc);
15969a747e4fSDavid du Colombier 	p->pidhash = procalloc.ht[h];
15979a747e4fSDavid du Colombier 	procalloc.ht[h] = p;
15989a747e4fSDavid du Colombier 	unlock(&procalloc);
15999a747e4fSDavid du Colombier }
16009a747e4fSDavid du Colombier 
16019a747e4fSDavid du Colombier static void
pidunhash(Proc * p)16029a747e4fSDavid du Colombier pidunhash(Proc *p)
16039a747e4fSDavid du Colombier {
16049a747e4fSDavid du Colombier 	int h;
16059a747e4fSDavid du Colombier 	Proc **l;
16069a747e4fSDavid du Colombier 
16079a747e4fSDavid du Colombier 	h = p->pid % nelem(procalloc.ht);
16089a747e4fSDavid du Colombier 	lock(&procalloc);
16099a747e4fSDavid du Colombier 	for(l = &procalloc.ht[h]; *l != nil; l = &(*l)->pidhash)
16109a747e4fSDavid du Colombier 		if(*l == p){
16119a747e4fSDavid du Colombier 			*l = p->pidhash;
16129a747e4fSDavid du Colombier 			break;
16139a747e4fSDavid du Colombier 		}
16149a747e4fSDavid du Colombier 	unlock(&procalloc);
16159a747e4fSDavid du Colombier }
16169a747e4fSDavid du Colombier 
16179a747e4fSDavid du Colombier int
procindex(ulong pid)16189a747e4fSDavid du Colombier procindex(ulong pid)
16199a747e4fSDavid du Colombier {
16209a747e4fSDavid du Colombier 	Proc *p;
16219a747e4fSDavid du Colombier 	int h;
16229a747e4fSDavid du Colombier 	int s;
16239a747e4fSDavid du Colombier 
16249a747e4fSDavid du Colombier 	s = -1;
16259a747e4fSDavid du Colombier 	h = pid % nelem(procalloc.ht);
16269a747e4fSDavid du Colombier 	lock(&procalloc);
16279a747e4fSDavid du Colombier 	for(p = procalloc.ht[h]; p != nil; p = p->pidhash)
16289a747e4fSDavid du Colombier 		if(p->pid == pid){
16299a747e4fSDavid du Colombier 			s = p - procalloc.arena;
16309a747e4fSDavid du Colombier 			break;
16319a747e4fSDavid du Colombier 		}
16329a747e4fSDavid du Colombier 	unlock(&procalloc);
16339a747e4fSDavid du Colombier 	return s;
16349a747e4fSDavid du Colombier }
1635