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
422c2c68342SDavid du Colombier /*
423c2c68342SDavid du Colombier * since the 386 is short of registers, m always contains the constant
424c2c68342SDavid du Colombier * MACHADDR, not MACHP(m->machno); see ../pc/dat.h. so we can't just
425c2c68342SDavid du Colombier * compare addresses with m.
426c2c68342SDavid du Colombier */
427c2c68342SDavid du Colombier if(up != p && (p->wired == nil || p->wired == MACHP(m->machno)))
42859c21d95SDavid du Colombier m->readied = p; /* group scheduling */
42959c21d95SDavid du Colombier
43059c21d95SDavid du Colombier updatecpu(p);
43159c21d95SDavid du Colombier pri = reprioritize(p);
43259c21d95SDavid du Colombier p->priority = pri;
43359c21d95SDavid du Colombier rq = &runq[pri];
43459c21d95SDavid du Colombier p->state = Ready;
43559c21d95SDavid du Colombier queueproc(rq, p);
43659c21d95SDavid du Colombier pt = proctrace;
43759c21d95SDavid du Colombier if(pt)
43859c21d95SDavid du Colombier pt(p, SReady, 0);
43959c21d95SDavid du Colombier splx(s);
44059c21d95SDavid du Colombier }
44159c21d95SDavid du Colombier
44259c21d95SDavid du Colombier /*
44304b73bddSDavid du Colombier * yield the processor and drop our priority
44404b73bddSDavid du Colombier */
44504b73bddSDavid du Colombier void
yield(void)44604b73bddSDavid du Colombier yield(void)
44704b73bddSDavid du Colombier {
44804b73bddSDavid du Colombier if(anyready()){
44995a264b3SDavid du Colombier /* pretend we just used 1/2 tick */
45095a264b3SDavid du Colombier up->lastupdate -= Scaling/2;
45104b73bddSDavid du Colombier sched();
45204b73bddSDavid du Colombier }
45304b73bddSDavid du Colombier }
45404b73bddSDavid du Colombier
45504b73bddSDavid du Colombier /*
45695a264b3SDavid du Colombier * recalculate priorities once a second. We need to do this
45795a264b3SDavid du Colombier * since priorities will otherwise only be recalculated when
45895a264b3SDavid du Colombier * the running process blocks.
45904b73bddSDavid du Colombier */
46059c21d95SDavid du Colombier ulong balancetime;
46159c21d95SDavid du Colombier
46204b73bddSDavid du Colombier static void
rebalance(void)46304b73bddSDavid du Colombier rebalance(void)
46404b73bddSDavid du Colombier {
465da51d93aSDavid du Colombier int pri, npri, t, x;
46604b73bddSDavid du Colombier Schedq *rq;
46704b73bddSDavid du Colombier Proc *p;
46804b73bddSDavid du Colombier
46959c21d95SDavid du Colombier t = m->ticks;
47059c21d95SDavid du Colombier if(t - balancetime < HZ)
47159c21d95SDavid du Colombier return;
47259c21d95SDavid du Colombier balancetime = t;
47359c21d95SDavid du Colombier
47459c21d95SDavid du Colombier for(pri=0, rq=runq; pri<Npriq; pri++, rq++){
47559c21d95SDavid du Colombier another:
47604b73bddSDavid du Colombier p = rq->head;
47704b73bddSDavid du Colombier if(p == nil)
47804b73bddSDavid du Colombier continue;
47959c21d95SDavid du Colombier if(pri == p->basepri)
48004b73bddSDavid du Colombier continue;
48159c21d95SDavid du Colombier updatecpu(p);
48259c21d95SDavid du Colombier npri = reprioritize(p);
48359c21d95SDavid du Colombier if(npri != pri){
484da51d93aSDavid du Colombier x = splhi();
48504b73bddSDavid du Colombier p = dequeueproc(rq, p);
48659c21d95SDavid du Colombier if(p)
48759c21d95SDavid du Colombier queueproc(&runq[npri], p);
488da51d93aSDavid du Colombier splx(x);
48959c21d95SDavid du Colombier goto another;
49004b73bddSDavid du Colombier }
49104b73bddSDavid du Colombier }
49259c21d95SDavid du Colombier }
49359c21d95SDavid du Colombier
49404b73bddSDavid du Colombier
49504b73bddSDavid du Colombier /*
49604b73bddSDavid du Colombier * pick a process to run
49704b73bddSDavid du Colombier */
49804b73bddSDavid du Colombier Proc*
runproc(void)49904b73bddSDavid du Colombier runproc(void)
50004b73bddSDavid du Colombier {
50104b73bddSDavid du Colombier Schedq *rq;
50204b73bddSDavid du Colombier Proc *p;
50304b73bddSDavid du Colombier ulong start, now;
50404b73bddSDavid du Colombier int i;
5050701b922SDavid du Colombier void (*pt)(Proc*, int, vlong);
50604b73bddSDavid du Colombier
50704b73bddSDavid du Colombier start = perfticks();
50804b73bddSDavid du Colombier
50959c21d95SDavid du Colombier /* cooperative scheduling until the clock ticks */
510c2c68342SDavid du Colombier /*
511c2c68342SDavid du Colombier * since the 386 is short of registers, m always contains the constant
512c2c68342SDavid du Colombier * MACHADDR, not MACHP(m->machno); see ../pc/dat.h. so we can't just
513c2c68342SDavid du Colombier * compare addresses with m.
514c2c68342SDavid du Colombier */
515adc470c1SDavid du Colombier if((p=m->readied) && p->mach==0 && p->state==Ready
516c2c68342SDavid du Colombier && (p->wired == nil || p->wired == MACHP(m->machno))
51759c21d95SDavid du Colombier && runq[Nrq-1].head == nil && runq[Nrq-2].head == nil){
51859c21d95SDavid du Colombier skipscheds++;
51959c21d95SDavid du Colombier rq = &runq[p->priority];
52059c21d95SDavid du Colombier goto found;
52104b73bddSDavid du Colombier }
52204b73bddSDavid du Colombier
52359c21d95SDavid du Colombier preempts++;
52459c21d95SDavid du Colombier
52504b73bddSDavid du Colombier loop:
52604b73bddSDavid du Colombier /*
52704b73bddSDavid du Colombier * find a process that last ran on this processor (affinity),
52804b73bddSDavid du Colombier * or one that hasn't moved in a while (load balancing). Every
52904b73bddSDavid du Colombier * time around the loop affinity goes down.
53004b73bddSDavid du Colombier */
53104b73bddSDavid du Colombier spllo();
53204b73bddSDavid du Colombier for(i = 0;; i++){
53304b73bddSDavid du Colombier /*
53404b73bddSDavid du Colombier * find the highest priority target process that this
53504b73bddSDavid du Colombier * processor can run given affinity constraints.
53604b73bddSDavid du Colombier *
53704b73bddSDavid du Colombier */
53804b73bddSDavid du Colombier for(rq = &runq[Nrq-1]; rq >= runq; rq--){
53904b73bddSDavid du Colombier for(p = rq->head; p; p = p->rnext){
54004b73bddSDavid du Colombier if(p->mp == nil || p->mp == MACHP(m->machno)
54104b73bddSDavid du Colombier || (!p->wired && i > 0))
54204b73bddSDavid du Colombier goto found;
54304b73bddSDavid du Colombier }
54404b73bddSDavid du Colombier }
54504b73bddSDavid du Colombier
54604b73bddSDavid du Colombier /* waste time or halt the CPU */
54704b73bddSDavid du Colombier idlehands();
54804b73bddSDavid du Colombier
54904b73bddSDavid du Colombier /* remember how much time we're here */
55004b73bddSDavid du Colombier now = perfticks();
55104b73bddSDavid du Colombier m->perf.inidle += now-start;
55204b73bddSDavid du Colombier start = now;
55304b73bddSDavid du Colombier }
55404b73bddSDavid du Colombier
55504b73bddSDavid du Colombier found:
55604b73bddSDavid du Colombier splhi();
55704b73bddSDavid du Colombier p = dequeueproc(rq, p);
55804b73bddSDavid du Colombier if(p == nil)
55904b73bddSDavid du Colombier goto loop;
560219b2ee8SDavid du Colombier
5613e12c5d1SDavid du Colombier p->state = Scheding;
5627dd7cddfSDavid du Colombier p->mp = MACHP(m->machno);
5639a747e4fSDavid du Colombier
564da51d93aSDavid du Colombier if(edflock(p)){
565e288d156SDavid du Colombier edfrun(p, rq == &runq[PriEdf]); /* start deadline timer and do admin */
566e288d156SDavid du Colombier edfunlock();
567e288d156SDavid du Colombier }
568e288d156SDavid du Colombier pt = proctrace;
5690701b922SDavid du Colombier if(pt)
5700701b922SDavid du Colombier pt(p, SRun, 0);
5713e12c5d1SDavid du Colombier return p;
5723e12c5d1SDavid du Colombier }
5733e12c5d1SDavid du Colombier
5743e12c5d1SDavid du Colombier int
canpage(Proc * p)5753e12c5d1SDavid du Colombier canpage(Proc *p)
5763e12c5d1SDavid du Colombier {
5773e12c5d1SDavid du Colombier int ok = 0;
5783e12c5d1SDavid du Colombier
5793e12c5d1SDavid du Colombier splhi();
5807dd7cddfSDavid du Colombier lock(runq);
5813e12c5d1SDavid du Colombier /* Only reliable way to see if we are Running */
5823e12c5d1SDavid du Colombier if(p->mach == 0) {
5833e12c5d1SDavid du Colombier p->newtlb = 1;
5843e12c5d1SDavid du Colombier ok = 1;
5853e12c5d1SDavid du Colombier }
5867dd7cddfSDavid du Colombier unlock(runq);
5873e12c5d1SDavid du Colombier spllo();
5883e12c5d1SDavid du Colombier
5893e12c5d1SDavid du Colombier return ok;
5903e12c5d1SDavid du Colombier }
5913e12c5d1SDavid du Colombier
592*405829f1SDavid du Colombier /*
593*405829f1SDavid du Colombier * these assume that active.Lock is held when needed.
594*405829f1SDavid du Colombier */
595*405829f1SDavid du Colombier
596*405829f1SDavid du Colombier void
cpuactive(uint cpu)597*405829f1SDavid du Colombier cpuactive(uint cpu)
598*405829f1SDavid du Colombier {
599*405829f1SDavid du Colombier #ifdef MACHS_BITMAP
600*405829f1SDavid du Colombier active.machsmap[cpu / BI2WD] |= 1ULL << (cpu % BI2WD);
601*405829f1SDavid du Colombier active.nmachs++;
602*405829f1SDavid du Colombier #else
603*405829f1SDavid du Colombier active.machs |= 1ULL << cpu;
604*405829f1SDavid du Colombier #endif
605*405829f1SDavid du Colombier }
606*405829f1SDavid du Colombier
607*405829f1SDavid du Colombier void
cpuinactive(uint cpu)608*405829f1SDavid du Colombier cpuinactive(uint cpu)
609*405829f1SDavid du Colombier {
610*405829f1SDavid du Colombier #ifdef MACHS_BITMAP
611*405829f1SDavid du Colombier active.machsmap[cpu / BI2WD] &= ~(1ULL << (cpu % BI2WD));
612*405829f1SDavid du Colombier active.nmachs--;
613*405829f1SDavid du Colombier #else
614*405829f1SDavid du Colombier active.machs &= ~(1ULL << cpu);
615*405829f1SDavid du Colombier #endif
616*405829f1SDavid du Colombier }
617*405829f1SDavid du Colombier
618*405829f1SDavid du Colombier int
iscpuactive(uint cpu)619*405829f1SDavid du Colombier iscpuactive(uint cpu)
620*405829f1SDavid du Colombier {
621*405829f1SDavid du Colombier #ifdef MACHS_BITMAP
622*405829f1SDavid du Colombier return (active.machsmap[cpu / BI2WD] & (1ULL << (cpu % BI2WD))) != 0;
623*405829f1SDavid du Colombier #else
624*405829f1SDavid du Colombier return (active.machs & (1ULL << cpu)) != 0;
625*405829f1SDavid du Colombier #endif
626*405829f1SDavid du Colombier }
627*405829f1SDavid du Colombier
628*405829f1SDavid du Colombier
6298ccc32efSDavid du Colombier void
noprocpanic(char * msg)6308ccc32efSDavid du Colombier noprocpanic(char *msg)
6318ccc32efSDavid du Colombier {
6328ccc32efSDavid du Colombier /*
6338ccc32efSDavid du Colombier * setting exiting will make hzclock() on each processor call exit(0).
6348ccc32efSDavid du Colombier * clearing our bit in machs avoids calling exit(0) from hzclock()
6358ccc32efSDavid du Colombier * on this processor.
6368ccc32efSDavid du Colombier */
6378ccc32efSDavid du Colombier lock(&active);
638*405829f1SDavid du Colombier cpuinactive(m->machno);
6398ccc32efSDavid du Colombier active.exiting = 1;
6408ccc32efSDavid du Colombier unlock(&active);
6418ccc32efSDavid du Colombier
6428ccc32efSDavid du Colombier procdump();
6438ccc32efSDavid du Colombier delay(1000);
6448ccc32efSDavid du Colombier panic(msg);
6458ccc32efSDavid du Colombier }
6468ccc32efSDavid du Colombier
6473e12c5d1SDavid du Colombier Proc*
newproc(void)6483e12c5d1SDavid du Colombier newproc(void)
6493e12c5d1SDavid du Colombier {
65014cc0f53SDavid du Colombier char msg[64];
6513e12c5d1SDavid du Colombier Proc *p;
6523e12c5d1SDavid du Colombier
6533e12c5d1SDavid du Colombier lock(&procalloc);
6548ccc32efSDavid du Colombier while((p = procalloc.free) == nil) {
6558ccc32efSDavid du Colombier unlock(&procalloc);
6567dd7cddfSDavid du Colombier
65714cc0f53SDavid du Colombier snprint(msg, sizeof msg, "no procs; %s forking",
65814cc0f53SDavid du Colombier up? up->text: "kernel");
6598ccc32efSDavid du Colombier /*
6608ccc32efSDavid du Colombier * the situation is unlikely to heal itself.
6618ccc32efSDavid du Colombier * dump the proc table and restart by default.
6628ccc32efSDavid du Colombier * *noprocspersist in plan9.ini will yield the old
6638ccc32efSDavid du Colombier * behaviour of trying forever.
6648ccc32efSDavid du Colombier */
6658ccc32efSDavid du Colombier if(getconf("*noprocspersist") == nil)
6668ccc32efSDavid du Colombier noprocpanic(msg);
66714cc0f53SDavid du Colombier resrcwait(msg);
6687dd7cddfSDavid du Colombier lock(&procalloc);
6697dd7cddfSDavid du Colombier }
6703e12c5d1SDavid du Colombier procalloc.free = p->qnext;
6717dd7cddfSDavid du Colombier unlock(&procalloc);
6727dd7cddfSDavid du Colombier
6733e12c5d1SDavid du Colombier p->state = Scheding;
6743e12c5d1SDavid du Colombier p->psstate = "New";
6753e12c5d1SDavid du Colombier p->mach = 0;
6763e12c5d1SDavid du Colombier p->qnext = 0;
6773e12c5d1SDavid du Colombier p->nchild = 0;
6783e12c5d1SDavid du Colombier p->nwait = 0;
6793e12c5d1SDavid du Colombier p->waitq = 0;
6809a747e4fSDavid du Colombier p->parent = 0;
6813e12c5d1SDavid du Colombier p->pgrp = 0;
6823e12c5d1SDavid du Colombier p->egrp = 0;
6833e12c5d1SDavid du Colombier p->fgrp = 0;
6847dd7cddfSDavid du Colombier p->rgrp = 0;
6853e12c5d1SDavid du Colombier p->pdbg = 0;
6863e12c5d1SDavid du Colombier p->fpstate = FPinit;
6873e12c5d1SDavid du Colombier p->kp = 0;
688d1be6b08SDavid du Colombier if(up && up->procctl == Proc_tracesyscall)
689d1be6b08SDavid du Colombier p->procctl = Proc_tracesyscall;
690d1be6b08SDavid du Colombier else
6913e12c5d1SDavid du Colombier p->procctl = 0;
692d1be6b08SDavid du Colombier p->syscalltrace = 0;
6933e12c5d1SDavid du Colombier p->notepending = 0;
6947dd7cddfSDavid du Colombier p->ureg = 0;
6959a747e4fSDavid du Colombier p->privatemem = 0;
696b7b24591SDavid du Colombier p->noswap = 0;
6979a747e4fSDavid du Colombier p->errstr = p->errbuf0;
6989a747e4fSDavid du Colombier p->syserrstr = p->errbuf1;
6999a747e4fSDavid du Colombier p->errbuf0[0] = '\0';
7009a747e4fSDavid du Colombier p->errbuf1[0] = '\0';
701e288d156SDavid du Colombier p->nlocks.ref = 0;
7029a747e4fSDavid du Colombier p->delaysched = 0;
703220e960cSDavid du Colombier p->trace = 0;
7049a747e4fSDavid du Colombier kstrdup(&p->user, "*nouser");
7059a747e4fSDavid du Colombier kstrdup(&p->text, "*notext");
7069a747e4fSDavid du Colombier kstrdup(&p->args, "");
7079a747e4fSDavid du Colombier p->nargs = 0;
708d9306527SDavid du Colombier p->setargs = 0;
7093e12c5d1SDavid du Colombier memset(p->seg, 0, sizeof p->seg);
7103e12c5d1SDavid du Colombier p->pid = incref(&pidalloc);
7119a747e4fSDavid du Colombier pidhash(p);
7123e12c5d1SDavid du Colombier p->noteid = incref(¬eidalloc);
7133e12c5d1SDavid du Colombier if(p->pid==0 || p->noteid==0)
7143e12c5d1SDavid du Colombier panic("pidalloc");
7157dd7cddfSDavid du Colombier if(p->kstack == 0)
7167dd7cddfSDavid du Colombier p->kstack = smalloc(KSTACK);
7177dd7cddfSDavid du Colombier
718a6a9e072SDavid du Colombier /* sched params */
719a6a9e072SDavid du Colombier p->mp = 0;
720a6a9e072SDavid du Colombier p->wired = 0;
721a6a9e072SDavid du Colombier procpriority(p, PriNormal, 0);
72295a264b3SDavid du Colombier p->cpu = 0;
72395a264b3SDavid du Colombier p->lastupdate = MACHP(0)->ticks*Scaling;
724e288d156SDavid du Colombier p->edf = nil;
7259a747e4fSDavid du Colombier
7263e12c5d1SDavid du Colombier return p;
7273e12c5d1SDavid du Colombier }
7287dd7cddfSDavid du Colombier
7297dd7cddfSDavid du Colombier /*
7307dd7cddfSDavid du Colombier * wire this proc to a machine
7317dd7cddfSDavid du Colombier */
7327dd7cddfSDavid du Colombier void
procwired(Proc * p,int bm)7337dd7cddfSDavid du Colombier procwired(Proc *p, int bm)
7347dd7cddfSDavid du Colombier {
7357dd7cddfSDavid du Colombier Proc *pp;
7367dd7cddfSDavid du Colombier int i;
7377dd7cddfSDavid du Colombier char nwired[MAXMACH];
7387dd7cddfSDavid du Colombier Mach *wm;
7397dd7cddfSDavid du Colombier
7407dd7cddfSDavid du Colombier if(bm < 0){
7417dd7cddfSDavid du Colombier /* pick a machine to wire to */
7427dd7cddfSDavid du Colombier memset(nwired, 0, sizeof(nwired));
7437dd7cddfSDavid du Colombier p->wired = 0;
7447dd7cddfSDavid du Colombier pp = proctab(0);
7457dd7cddfSDavid du Colombier for(i=0; i<conf.nproc; i++, pp++){
7467dd7cddfSDavid du Colombier wm = pp->wired;
7477dd7cddfSDavid du Colombier if(wm && pp->pid)
7487dd7cddfSDavid du Colombier nwired[wm->machno]++;
7493e12c5d1SDavid du Colombier }
7507dd7cddfSDavid du Colombier bm = 0;
7517dd7cddfSDavid du Colombier for(i=0; i<conf.nmach; i++)
7527dd7cddfSDavid du Colombier if(nwired[i] < nwired[bm])
7537dd7cddfSDavid du Colombier bm = i;
7547dd7cddfSDavid du Colombier } else {
7557dd7cddfSDavid du Colombier /* use the virtual machine requested */
7567dd7cddfSDavid du Colombier bm = bm % conf.nmach;
7577dd7cddfSDavid du Colombier }
7587dd7cddfSDavid du Colombier
7597dd7cddfSDavid du Colombier p->wired = MACHP(bm);
7607dd7cddfSDavid du Colombier p->mp = p->wired;
7613e12c5d1SDavid du Colombier }
7623e12c5d1SDavid du Colombier
7633e12c5d1SDavid du Colombier void
procpriority(Proc * p,int pri,int fixed)764a6a9e072SDavid du Colombier procpriority(Proc *p, int pri, int fixed)
765a6a9e072SDavid du Colombier {
766e288d156SDavid du Colombier if(pri >= Npriq)
767e288d156SDavid du Colombier pri = Npriq - 1;
768a6a9e072SDavid du Colombier else if(pri < 0)
769a6a9e072SDavid du Colombier pri = 0;
770a6a9e072SDavid du Colombier p->basepri = pri;
771a6a9e072SDavid du Colombier p->priority = pri;
772a6a9e072SDavid du Colombier if(fixed){
773a6a9e072SDavid du Colombier p->fixedpri = 1;
774a6a9e072SDavid du Colombier } else {
775a6a9e072SDavid du Colombier p->fixedpri = 0;
776a6a9e072SDavid du Colombier }
777a6a9e072SDavid du Colombier }
778a6a9e072SDavid du Colombier
779a6a9e072SDavid du Colombier void
procinit0(void)7803e12c5d1SDavid du Colombier procinit0(void) /* bad planning - clashes with devproc.c */
7813e12c5d1SDavid du Colombier {
7823e12c5d1SDavid du Colombier Proc *p;
7833e12c5d1SDavid du Colombier int i;
7843e12c5d1SDavid du Colombier
7853e12c5d1SDavid du Colombier procalloc.free = xalloc(conf.nproc*sizeof(Proc));
7864de34a7eSDavid du Colombier if(procalloc.free == nil){
7874de34a7eSDavid du Colombier xsummary();
7884de34a7eSDavid du Colombier panic("cannot allocate %lud procs (%ludMB)\n", conf.nproc, conf.nproc*sizeof(Proc)/(1024*1024));
7894de34a7eSDavid du Colombier }
7903e12c5d1SDavid du Colombier procalloc.arena = procalloc.free;
7913e12c5d1SDavid du Colombier
7923e12c5d1SDavid du Colombier p = procalloc.free;
7933e12c5d1SDavid du Colombier for(i=0; i<conf.nproc-1; i++,p++)
7943e12c5d1SDavid du Colombier p->qnext = p+1;
7953e12c5d1SDavid du Colombier p->qnext = 0;
7963e12c5d1SDavid du Colombier }
7973e12c5d1SDavid du Colombier
7987dd7cddfSDavid du Colombier /*
79959cc4ca5SDavid du Colombier * sleep if a condition is not true. Another process will
80059cc4ca5SDavid du Colombier * awaken us after it sets the condition. When we awaken
80159cc4ca5SDavid du Colombier * the condition may no longer be true.
8027dd7cddfSDavid du Colombier *
80359cc4ca5SDavid du Colombier * we lock both the process and the rendezvous to keep r->p
80459cc4ca5SDavid du Colombier * and p->r synchronized.
8057dd7cddfSDavid du Colombier */
8063e12c5d1SDavid du Colombier void
sleep(Rendez * r,int (* f)(void *),void * arg)8077dd7cddfSDavid du Colombier sleep(Rendez *r, int (*f)(void*), void *arg)
8083e12c5d1SDavid du Colombier {
8093e12c5d1SDavid du Colombier int s;
8100701b922SDavid du Colombier void (*pt)(Proc*, int, vlong);
8113e12c5d1SDavid du Colombier
8123e12c5d1SDavid du Colombier s = splhi();
8133e12c5d1SDavid du Colombier
814e288d156SDavid du Colombier if(up->nlocks.ref)
815567483c8SDavid du Colombier print("process %lud sleeps with %lud locks held, last lock %#p locked at pc %#lux, sleep called from %#p\n",
816da51d93aSDavid du Colombier up->pid, up->nlocks.ref, up->lastlock, up->lastlock->pc, getcallerpc(&r));
81759cc4ca5SDavid du Colombier lock(r);
8187dd7cddfSDavid du Colombier lock(&up->rlock);
8197dd7cddfSDavid du Colombier if(r->p){
820567483c8SDavid du Colombier print("double sleep called from %#p, %lud %lud\n", getcallerpc(&r), r->p->pid, up->pid);
8217dd7cddfSDavid du Colombier dumpstack();
8223e12c5d1SDavid du Colombier }
8233e12c5d1SDavid du Colombier
8243e12c5d1SDavid du Colombier /*
8257dd7cddfSDavid du Colombier * Wakeup only knows there may be something to do by testing
8267dd7cddfSDavid du Colombier * r->p in order to get something to lock on.
8277dd7cddfSDavid du Colombier * Flush that information out to memory in case the sleep is
8287dd7cddfSDavid du Colombier * committed.
8297dd7cddfSDavid du Colombier */
8307dd7cddfSDavid du Colombier r->p = up;
8317dd7cddfSDavid du Colombier
8327dd7cddfSDavid du Colombier if((*f)(arg) || up->notepending){
8337dd7cddfSDavid du Colombier /*
8347dd7cddfSDavid du Colombier * if condition happened or a note is pending
8357dd7cddfSDavid du Colombier * never mind
8367dd7cddfSDavid du Colombier */
8377dd7cddfSDavid du Colombier r->p = nil;
8387dd7cddfSDavid du Colombier unlock(&up->rlock);
83959cc4ca5SDavid du Colombier unlock(r);
8407dd7cddfSDavid du Colombier } else {
8417dd7cddfSDavid du Colombier /*
8423e12c5d1SDavid du Colombier * now we are committed to
8433e12c5d1SDavid du Colombier * change state and call scheduler
8443e12c5d1SDavid du Colombier */
845e288d156SDavid du Colombier pt = proctrace;
8460701b922SDavid du Colombier if(pt)
8470701b922SDavid du Colombier pt(up, SSleep, 0);
8487dd7cddfSDavid du Colombier up->state = Wakeme;
8497dd7cddfSDavid du Colombier up->r = r;
8507dd7cddfSDavid du Colombier
8517dd7cddfSDavid du Colombier /* statistics */
8527dd7cddfSDavid du Colombier m->cs++;
8537dd7cddfSDavid du Colombier
8547dd7cddfSDavid du Colombier procsave(up);
8557dd7cddfSDavid du Colombier if(setlabel(&up->sched)) {
8567dd7cddfSDavid du Colombier /*
8577dd7cddfSDavid du Colombier * here when the process is awakened
8587dd7cddfSDavid du Colombier */
8597dd7cddfSDavid du Colombier procrestore(up);
8607dd7cddfSDavid du Colombier spllo();
8617dd7cddfSDavid du Colombier } else {
8627dd7cddfSDavid du Colombier /*
8637dd7cddfSDavid du Colombier * here to go to sleep (i.e. stop Running)
8647dd7cddfSDavid du Colombier */
8657dd7cddfSDavid du Colombier unlock(&up->rlock);
86659cc4ca5SDavid du Colombier unlock(r);
8677dd7cddfSDavid du Colombier gotolabel(&m->sched);
8683e12c5d1SDavid du Colombier }
8693e12c5d1SDavid du Colombier }
8703e12c5d1SDavid du Colombier
8717dd7cddfSDavid du Colombier if(up->notepending) {
8727dd7cddfSDavid du Colombier up->notepending = 0;
8733e12c5d1SDavid du Colombier splx(s);
8742cca75a1SDavid du Colombier if(up->procctl == Proc_exitme && up->closingfgrp)
8752cca75a1SDavid du Colombier forceclosefgrp();
8763e12c5d1SDavid du Colombier error(Eintr);
8773e12c5d1SDavid du Colombier }
8787dd7cddfSDavid du Colombier
8797dd7cddfSDavid du Colombier splx(s);
8803e12c5d1SDavid du Colombier }
8813e12c5d1SDavid du Colombier
88215174232SDavid du Colombier static int
tfn(void * arg)8833e12c5d1SDavid du Colombier tfn(void *arg)
8843e12c5d1SDavid du Colombier {
885da51d93aSDavid du Colombier return up->trend == nil || up->tfn(arg);
8863e12c5d1SDavid du Colombier }
8873e12c5d1SDavid du Colombier
8883e12c5d1SDavid du Colombier void
twakeup(Ureg *,Timer * t)889e288d156SDavid du Colombier twakeup(Ureg*, Timer *t)
8903e12c5d1SDavid du Colombier {
891e288d156SDavid du Colombier Proc *p;
8928280c5dcSDavid du Colombier Rendez *trend;
8933e12c5d1SDavid du Colombier
894e288d156SDavid du Colombier p = t->ta;
8958280c5dcSDavid du Colombier trend = p->trend;
896e288d156SDavid du Colombier p->trend = 0;
8978280c5dcSDavid du Colombier if(trend)
8988280c5dcSDavid du Colombier wakeup(trend);
899e288d156SDavid du Colombier }
9003e12c5d1SDavid du Colombier
901e288d156SDavid du Colombier void
tsleep(Rendez * r,int (* fn)(void *),void * arg,ulong ms)902e288d156SDavid du Colombier tsleep(Rendez *r, int (*fn)(void*), void *arg, ulong ms)
903e288d156SDavid du Colombier {
904da51d93aSDavid du Colombier if (up->tt){
905567483c8SDavid du Colombier print("tsleep: timer active: mode %d, tf %#p\n", up->tmode, up->tf);
906e288d156SDavid du Colombier timerdel(up);
907da51d93aSDavid du Colombier }
908e288d156SDavid du Colombier up->tns = MS2NS(ms);
909e288d156SDavid du Colombier up->tf = twakeup;
910e288d156SDavid du Colombier up->tmode = Trelative;
911e288d156SDavid du Colombier up->ta = up;
912e288d156SDavid du Colombier up->trend = r;
913e288d156SDavid du Colombier up->tfn = fn;
914e288d156SDavid du Colombier timeradd(up);
915e288d156SDavid du Colombier
916e288d156SDavid du Colombier if(waserror()){
917e288d156SDavid du Colombier timerdel(up);
918e288d156SDavid du Colombier nexterror();
919e288d156SDavid du Colombier }
920e288d156SDavid du Colombier sleep(r, tfn, arg);
921e288d156SDavid du Colombier if(up->tt)
922e288d156SDavid du Colombier timerdel(up);
9237dd7cddfSDavid du Colombier up->twhen = 0;
9247dd7cddfSDavid du Colombier poperror();
9253e12c5d1SDavid du Colombier }
9263e12c5d1SDavid du Colombier
9273e12c5d1SDavid du Colombier /*
92859cc4ca5SDavid du Colombier * Expects that only one process can call wakeup for any given Rendez.
92959cc4ca5SDavid du Colombier * We hold both locks to ensure that r->p and p->r remain consistent.
93059cc4ca5SDavid du Colombier * Richard Miller has a better solution that doesn't require both to
93159cc4ca5SDavid du Colombier * be held simultaneously, but I'm a paranoid - presotto.
9323e12c5d1SDavid du Colombier */
93380ee5cbfSDavid du Colombier Proc*
wakeup(Rendez * r)9343e12c5d1SDavid du Colombier wakeup(Rendez *r)
9353e12c5d1SDavid du Colombier {
9369a747e4fSDavid du Colombier Proc *p;
93780ee5cbfSDavid du Colombier int s;
9387dd7cddfSDavid du Colombier
9393e12c5d1SDavid du Colombier s = splhi();
9407dd7cddfSDavid du Colombier
94159cc4ca5SDavid du Colombier lock(r);
94259cc4ca5SDavid du Colombier p = r->p;
94359cc4ca5SDavid du Colombier
94459cc4ca5SDavid du Colombier if(p != nil){
94559cc4ca5SDavid du Colombier lock(&p->rlock);
946017579bfSDavid du Colombier if(p->state != Wakeme || p->r != r){
947017579bfSDavid du Colombier iprint("%p %p %d\n", p->r, r, p->state);
9483e12c5d1SDavid du Colombier panic("wakeup: state");
949017579bfSDavid du Colombier }
95059cc4ca5SDavid du Colombier r->p = nil;
95159cc4ca5SDavid du Colombier p->r = nil;
9523e12c5d1SDavid du Colombier ready(p);
95359cc4ca5SDavid du Colombier unlock(&p->rlock);
9543e12c5d1SDavid du Colombier }
95559cc4ca5SDavid du Colombier unlock(r);
95659cc4ca5SDavid du Colombier
9573e12c5d1SDavid du Colombier splx(s);
9587dd7cddfSDavid du Colombier
9599a747e4fSDavid du Colombier return p;
9603e12c5d1SDavid du Colombier }
9613e12c5d1SDavid du Colombier
96259cc4ca5SDavid du Colombier /*
96359cc4ca5SDavid du Colombier * if waking a sleeping process, this routine must hold both
96459cc4ca5SDavid du Colombier * p->rlock and r->lock. However, it can't know them in
96559cc4ca5SDavid du Colombier * the same order as wakeup causing a possible lock ordering
96659cc4ca5SDavid du Colombier * deadlock. We break the deadlock by giving up the p->rlock
96759cc4ca5SDavid du Colombier * lock if we can't get the r->lock and retrying.
96859cc4ca5SDavid du Colombier */
9693e12c5d1SDavid du Colombier int
postnote(Proc * p,int dolock,char * n,int flag)9703e12c5d1SDavid du Colombier postnote(Proc *p, int dolock, char *n, int flag)
9713e12c5d1SDavid du Colombier {
9723e12c5d1SDavid du Colombier int s, ret;
9733e12c5d1SDavid du Colombier Rendez *r;
9743e12c5d1SDavid du Colombier Proc *d, **l;
9753e12c5d1SDavid du Colombier
9763e12c5d1SDavid du Colombier if(dolock)
9773e12c5d1SDavid du Colombier qlock(&p->debug);
9783e12c5d1SDavid du Colombier
9797dd7cddfSDavid du Colombier if(flag != NUser && (p->notify == 0 || p->notified))
9807dd7cddfSDavid du Colombier p->nnote = 0;
9813e12c5d1SDavid du Colombier
9823e12c5d1SDavid du Colombier ret = 0;
9837dd7cddfSDavid du Colombier if(p->nnote < NNOTE) {
9847dd7cddfSDavid du Colombier strcpy(p->note[p->nnote].msg, n);
9857dd7cddfSDavid du Colombier p->note[p->nnote++].flag = flag;
9863e12c5d1SDavid du Colombier ret = 1;
9873e12c5d1SDavid du Colombier }
9883e12c5d1SDavid du Colombier p->notepending = 1;
9893e12c5d1SDavid du Colombier if(dolock)
9903e12c5d1SDavid du Colombier qunlock(&p->debug);
9913e12c5d1SDavid du Colombier
99259cc4ca5SDavid du Colombier /* this loop is to avoid lock ordering problems. */
99359cc4ca5SDavid du Colombier for(;;){
9943e12c5d1SDavid du Colombier s = splhi();
9957dd7cddfSDavid du Colombier lock(&p->rlock);
9967dd7cddfSDavid du Colombier r = p->r;
99759cc4ca5SDavid du Colombier
99859cc4ca5SDavid du Colombier /* waiting for a wakeup? */
99959cc4ca5SDavid du Colombier if(r == nil)
100059cc4ca5SDavid du Colombier break; /* no */
100159cc4ca5SDavid du Colombier
100259cc4ca5SDavid du Colombier /* try for the second lock */
100359cc4ca5SDavid du Colombier if(canlock(r)){
100459cc4ca5SDavid du Colombier if(p->state != Wakeme || r->p != p)
10057dd7cddfSDavid du Colombier panic("postnote: state %d %d %d", r->p != p, p->r != r, p->state);
100659cc4ca5SDavid du Colombier p->r = nil;
100759cc4ca5SDavid du Colombier r->p = nil;
10083e12c5d1SDavid du Colombier ready(p);
100959cc4ca5SDavid du Colombier unlock(r);
101059cc4ca5SDavid du Colombier break;
101159cc4ca5SDavid du Colombier }
101259cc4ca5SDavid du Colombier
101359cc4ca5SDavid du Colombier /* give other process time to get out of critical section and try again */
101459cc4ca5SDavid du Colombier unlock(&p->rlock);
101559cc4ca5SDavid du Colombier splx(s);
101659cc4ca5SDavid du Colombier sched();
10173e12c5d1SDavid du Colombier }
10187dd7cddfSDavid du Colombier unlock(&p->rlock);
10193e12c5d1SDavid du Colombier splx(s);
10203e12c5d1SDavid du Colombier
1021bd389b36SDavid du Colombier if(p->state != Rendezvous)
1022bd389b36SDavid du Colombier return ret;
1023bd389b36SDavid du Colombier
1024bd389b36SDavid du Colombier /* Try and pull out of a rendezvous */
10257dd7cddfSDavid du Colombier lock(p->rgrp);
10263e12c5d1SDavid du Colombier if(p->state == Rendezvous) {
10273e12c5d1SDavid du Colombier p->rendval = ~0;
10287dd7cddfSDavid du Colombier l = &REND(p->rgrp, p->rendtag);
10293e12c5d1SDavid du Colombier for(d = *l; d; d = d->rendhash) {
10303e12c5d1SDavid du Colombier if(d == p) {
10313e12c5d1SDavid du Colombier *l = p->rendhash;
10323e12c5d1SDavid du Colombier break;
10333e12c5d1SDavid du Colombier }
10343e12c5d1SDavid du Colombier l = &d->rendhash;
10353e12c5d1SDavid du Colombier }
10367dd7cddfSDavid du Colombier ready(p);
10373e12c5d1SDavid du Colombier }
10387dd7cddfSDavid du Colombier unlock(p->rgrp);
10393e12c5d1SDavid du Colombier return ret;
10403e12c5d1SDavid du Colombier }
10413e12c5d1SDavid du Colombier
10423e12c5d1SDavid du Colombier /*
10433e12c5d1SDavid du Colombier * weird thing: keep at most NBROKEN around
10443e12c5d1SDavid du Colombier */
10453e12c5d1SDavid du Colombier #define NBROKEN 4
1046bd389b36SDavid du Colombier struct
1047bd389b36SDavid du Colombier {
1048bd389b36SDavid du Colombier QLock;
10493e12c5d1SDavid du Colombier int n;
10503e12c5d1SDavid du Colombier Proc *p[NBROKEN];
10513e12c5d1SDavid du Colombier }broken;
10523e12c5d1SDavid du Colombier
10533e12c5d1SDavid du Colombier void
addbroken(Proc * p)1054bd389b36SDavid du Colombier addbroken(Proc *p)
10553e12c5d1SDavid du Colombier {
1056bd389b36SDavid du Colombier qlock(&broken);
10573e12c5d1SDavid du Colombier if(broken.n == NBROKEN) {
10583e12c5d1SDavid du Colombier ready(broken.p[0]);
10593e12c5d1SDavid du Colombier memmove(&broken.p[0], &broken.p[1], sizeof(Proc*)*(NBROKEN-1));
10603e12c5d1SDavid du Colombier --broken.n;
10613e12c5d1SDavid du Colombier }
1062bd389b36SDavid du Colombier broken.p[broken.n++] = p;
1063bd389b36SDavid du Colombier qunlock(&broken);
1064bd389b36SDavid du Colombier
1065e288d156SDavid du Colombier edfstop(up);
1066bd389b36SDavid du Colombier p->state = Broken;
1067bd389b36SDavid du Colombier p->psstate = 0;
1068bd389b36SDavid du Colombier sched();
1069bd389b36SDavid du Colombier }
1070bd389b36SDavid du Colombier
1071bd389b36SDavid du Colombier void
unbreak(Proc * p)1072bd389b36SDavid du Colombier unbreak(Proc *p)
1073bd389b36SDavid du Colombier {
1074bd389b36SDavid du Colombier int b;
1075bd389b36SDavid du Colombier
1076bd389b36SDavid du Colombier qlock(&broken);
1077bd389b36SDavid du Colombier for(b=0; b < broken.n; b++)
1078bd389b36SDavid du Colombier if(broken.p[b] == p) {
10793e12c5d1SDavid du Colombier broken.n--;
1080bd389b36SDavid du Colombier memmove(&broken.p[b], &broken.p[b+1],
1081bd389b36SDavid du Colombier sizeof(Proc*)*(NBROKEN-(b+1)));
1082bd389b36SDavid du Colombier ready(p);
10833e12c5d1SDavid du Colombier break;
10843e12c5d1SDavid du Colombier }
1085bd389b36SDavid du Colombier qunlock(&broken);
10863e12c5d1SDavid du Colombier }
10873e12c5d1SDavid du Colombier
10883e12c5d1SDavid du Colombier int
freebroken(void)10893e12c5d1SDavid du Colombier freebroken(void)
10903e12c5d1SDavid du Colombier {
10913e12c5d1SDavid du Colombier int i, n;
10923e12c5d1SDavid du Colombier
1093bd389b36SDavid du Colombier qlock(&broken);
10943e12c5d1SDavid du Colombier n = broken.n;
1095bd389b36SDavid du Colombier for(i=0; i<n; i++) {
10963e12c5d1SDavid du Colombier ready(broken.p[i]);
1097bd389b36SDavid du Colombier broken.p[i] = 0;
1098bd389b36SDavid du Colombier }
10993e12c5d1SDavid du Colombier broken.n = 0;
1100bd389b36SDavid du Colombier qunlock(&broken);
11013e12c5d1SDavid du Colombier return n;
11023e12c5d1SDavid du Colombier }
11033e12c5d1SDavid du Colombier
11043e12c5d1SDavid du Colombier void
pexit(char * exitstr,int freemem)11053e12c5d1SDavid du Colombier pexit(char *exitstr, int freemem)
11063e12c5d1SDavid du Colombier {
11077dd7cddfSDavid du Colombier Proc *p;
1108bd389b36SDavid du Colombier Segment **s, **es;
11097dd7cddfSDavid du Colombier long utime, stime;
11103e12c5d1SDavid du Colombier Waitq *wq, *f, *next;
11117dd7cddfSDavid du Colombier Fgrp *fgrp;
11127dd7cddfSDavid du Colombier Egrp *egrp;
11137dd7cddfSDavid du Colombier Rgrp *rgrp;
11147dd7cddfSDavid du Colombier Pgrp *pgrp;
11157dd7cddfSDavid du Colombier Chan *dot;
11160701b922SDavid du Colombier void (*pt)(Proc*, int, vlong);
11173e12c5d1SDavid du Colombier
1118d1be6b08SDavid du Colombier if(up->syscalltrace)
1119d1be6b08SDavid du Colombier free(up->syscalltrace);
11207dd7cddfSDavid du Colombier up->alarm = 0;
1121e288d156SDavid du Colombier if (up->tt)
1122e288d156SDavid du Colombier timerdel(up);
1123e288d156SDavid du Colombier pt = proctrace;
11240701b922SDavid du Colombier if(pt)
11250701b922SDavid du Colombier pt(up, SDead, 0);
11263e12c5d1SDavid du Colombier
11277dd7cddfSDavid du Colombier /* nil out all the resources under lock (free later) */
11287dd7cddfSDavid du Colombier qlock(&up->debug);
11297dd7cddfSDavid du Colombier fgrp = up->fgrp;
11307dd7cddfSDavid du Colombier up->fgrp = nil;
11317dd7cddfSDavid du Colombier egrp = up->egrp;
11327dd7cddfSDavid du Colombier up->egrp = nil;
11337dd7cddfSDavid du Colombier rgrp = up->rgrp;
11347dd7cddfSDavid du Colombier up->rgrp = nil;
11357dd7cddfSDavid du Colombier pgrp = up->pgrp;
11367dd7cddfSDavid du Colombier up->pgrp = nil;
11377dd7cddfSDavid du Colombier dot = up->dot;
11387dd7cddfSDavid du Colombier up->dot = nil;
11397dd7cddfSDavid du Colombier qunlock(&up->debug);
11407dd7cddfSDavid du Colombier
11417dd7cddfSDavid du Colombier if(fgrp)
11427dd7cddfSDavid du Colombier closefgrp(fgrp);
11437dd7cddfSDavid du Colombier if(egrp)
11447dd7cddfSDavid du Colombier closeegrp(egrp);
11457dd7cddfSDavid du Colombier if(rgrp)
11467dd7cddfSDavid du Colombier closergrp(rgrp);
11477dd7cddfSDavid du Colombier if(dot)
11487dd7cddfSDavid du Colombier cclose(dot);
11497dd7cddfSDavid du Colombier if(pgrp)
11507dd7cddfSDavid du Colombier closepgrp(pgrp);
11513e12c5d1SDavid du Colombier
11523e12c5d1SDavid du Colombier /*
11533e12c5d1SDavid du Colombier * if not a kernel process and have a parent,
11543e12c5d1SDavid du Colombier * do some housekeeping.
11553e12c5d1SDavid du Colombier */
11562fb4ea66SDavid du Colombier if(up->kp == 0 && up->parentpid != 0) {
11577dd7cddfSDavid du Colombier p = up->parent;
1158bd389b36SDavid du Colombier if(p == 0) {
11593e12c5d1SDavid du Colombier if(exitstr == 0)
11603e12c5d1SDavid du Colombier exitstr = "unknown";
11613e12c5d1SDavid du Colombier panic("boot process died: %s", exitstr);
11623e12c5d1SDavid du Colombier }
11633e12c5d1SDavid du Colombier
11643e12c5d1SDavid du Colombier while(waserror())
11653e12c5d1SDavid du Colombier ;
11667dd7cddfSDavid du Colombier
11673e12c5d1SDavid du Colombier wq = smalloc(sizeof(Waitq));
11683e12c5d1SDavid du Colombier poperror();
11693e12c5d1SDavid du Colombier
11709a747e4fSDavid du Colombier wq->w.pid = up->pid;
1171b7b24591SDavid du Colombier utime = up->time[TUser] + up->time[TCUser];
1172b7b24591SDavid du Colombier stime = up->time[TSys] + up->time[TCSys];
11733ff48bf5SDavid du Colombier wq->w.time[TUser] = tk2ms(utime);
11743ff48bf5SDavid du Colombier wq->w.time[TSys] = tk2ms(stime);
11753ff48bf5SDavid du Colombier wq->w.time[TReal] = tk2ms(MACHP(0)->ticks - up->time[TReal]);
11769a747e4fSDavid du Colombier if(exitstr && exitstr[0])
11779a747e4fSDavid du Colombier snprint(wq->w.msg, sizeof(wq->w.msg), "%s %lud: %s", up->text, up->pid, exitstr);
1178bd389b36SDavid du Colombier else
11793e12c5d1SDavid du Colombier wq->w.msg[0] = '\0';
11803e12c5d1SDavid du Colombier
11813e12c5d1SDavid du Colombier lock(&p->exl);
11827dd7cddfSDavid du Colombier /*
1183017579bfSDavid du Colombier * Check that parent is still alive.
11843e12c5d1SDavid du Colombier */
1185017579bfSDavid du Colombier if(p->pid == up->parentpid && p->state != Broken) {
11863e12c5d1SDavid du Colombier p->nchild--;
11873e12c5d1SDavid du Colombier p->time[TCUser] += utime;
11883e12c5d1SDavid du Colombier p->time[TCSys] += stime;
1189017579bfSDavid du Colombier /*
1190e3bac0bdSDavid du Colombier * If there would be more than 2000 wait records
1191017579bfSDavid du Colombier * processes for my parent, then don't leave a wait
1192017579bfSDavid du Colombier * record behind. This helps prevent badly written
1193017579bfSDavid du Colombier * daemon processes from accumulating lots of wait
1194017579bfSDavid du Colombier * records.
1195017579bfSDavid du Colombier */
1196e3bac0bdSDavid du Colombier if(p->nwait < 2000) {
11973e12c5d1SDavid du Colombier wq->next = p->waitq;
11983e12c5d1SDavid du Colombier p->waitq = wq;
11993e12c5d1SDavid du Colombier p->nwait++;
1200017579bfSDavid du Colombier wq = nil;
12013e12c5d1SDavid du Colombier wakeup(&p->waitr);
12023e12c5d1SDavid du Colombier }
1203017579bfSDavid du Colombier }
12043e12c5d1SDavid du Colombier unlock(&p->exl);
1205017579bfSDavid du Colombier if(wq)
12063e12c5d1SDavid du Colombier free(wq);
12073e12c5d1SDavid du Colombier }
12083e12c5d1SDavid du Colombier
12093e12c5d1SDavid du Colombier if(!freemem)
12107dd7cddfSDavid du Colombier addbroken(up);
12113e12c5d1SDavid du Colombier
12127dd7cddfSDavid du Colombier qlock(&up->seglock);
12137dd7cddfSDavid du Colombier es = &up->seg[NSEG];
12147dd7cddfSDavid du Colombier for(s = up->seg; s < es; s++) {
12157dd7cddfSDavid du Colombier if(*s) {
1216bd389b36SDavid du Colombier putseg(*s);
12177dd7cddfSDavid du Colombier *s = 0;
12187dd7cddfSDavid du Colombier }
12197dd7cddfSDavid du Colombier }
12207dd7cddfSDavid du Colombier qunlock(&up->seglock);
12213e12c5d1SDavid du Colombier
12227dd7cddfSDavid du Colombier lock(&up->exl); /* Prevent my children from leaving waits */
12239a747e4fSDavid du Colombier pidunhash(up);
12247dd7cddfSDavid du Colombier up->pid = 0;
12257dd7cddfSDavid du Colombier wakeup(&up->waitr);
12267dd7cddfSDavid du Colombier unlock(&up->exl);
12273e12c5d1SDavid du Colombier
12287dd7cddfSDavid du Colombier for(f = up->waitq; f; f = next) {
12293e12c5d1SDavid du Colombier next = f->next;
12303e12c5d1SDavid du Colombier free(f);
12313e12c5d1SDavid du Colombier }
12323e12c5d1SDavid du Colombier
12333e12c5d1SDavid du Colombier /* release debuggers */
12347dd7cddfSDavid du Colombier qlock(&up->debug);
12357dd7cddfSDavid du Colombier if(up->pdbg) {
12367dd7cddfSDavid du Colombier wakeup(&up->pdbg->sleep);
12377dd7cddfSDavid du Colombier up->pdbg = 0;
12383e12c5d1SDavid du Colombier }
12397dd7cddfSDavid du Colombier qunlock(&up->debug);
12403e12c5d1SDavid du Colombier
12417dd7cddfSDavid du Colombier /* Sched must not loop for these locks */
12423e12c5d1SDavid du Colombier lock(&procalloc);
12433e12c5d1SDavid du Colombier lock(&palloc);
12443e12c5d1SDavid du Colombier
1245e288d156SDavid du Colombier edfstop(up);
12467dd7cddfSDavid du Colombier up->state = Moribund;
12473e12c5d1SDavid du Colombier sched();
12483e12c5d1SDavid du Colombier panic("pexit");
12493e12c5d1SDavid du Colombier }
12503e12c5d1SDavid du Colombier
12513e12c5d1SDavid du Colombier int
haswaitq(void * x)12523e12c5d1SDavid du Colombier haswaitq(void *x)
12533e12c5d1SDavid du Colombier {
12543e12c5d1SDavid du Colombier Proc *p;
12553e12c5d1SDavid du Colombier
12563e12c5d1SDavid du Colombier p = (Proc *)x;
12573e12c5d1SDavid du Colombier return p->waitq != 0;
12583e12c5d1SDavid du Colombier }
12593e12c5d1SDavid du Colombier
12603e12c5d1SDavid du Colombier ulong
pwait(Waitmsg * w)12613e12c5d1SDavid du Colombier pwait(Waitmsg *w)
12623e12c5d1SDavid du Colombier {
12633e12c5d1SDavid du Colombier ulong cpid;
12643e12c5d1SDavid du Colombier Waitq *wq;
12653e12c5d1SDavid du Colombier
12667dd7cddfSDavid du Colombier if(!canqlock(&up->qwaitr))
1267219b2ee8SDavid du Colombier error(Einuse);
1268219b2ee8SDavid du Colombier
1269219b2ee8SDavid du Colombier if(waserror()) {
12707dd7cddfSDavid du Colombier qunlock(&up->qwaitr);
1271219b2ee8SDavid du Colombier nexterror();
1272219b2ee8SDavid du Colombier }
1273219b2ee8SDavid du Colombier
12747dd7cddfSDavid du Colombier lock(&up->exl);
12757dd7cddfSDavid du Colombier if(up->nchild == 0 && up->waitq == 0) {
12767dd7cddfSDavid du Colombier unlock(&up->exl);
12773e12c5d1SDavid du Colombier error(Enochild);
12783e12c5d1SDavid du Colombier }
12797dd7cddfSDavid du Colombier unlock(&up->exl);
12803e12c5d1SDavid du Colombier
12817dd7cddfSDavid du Colombier sleep(&up->waitr, haswaitq, up);
12823e12c5d1SDavid du Colombier
12837dd7cddfSDavid du Colombier lock(&up->exl);
12847dd7cddfSDavid du Colombier wq = up->waitq;
12857dd7cddfSDavid du Colombier up->waitq = wq->next;
12867dd7cddfSDavid du Colombier up->nwait--;
12877dd7cddfSDavid du Colombier unlock(&up->exl);
12883e12c5d1SDavid du Colombier
12897dd7cddfSDavid du Colombier qunlock(&up->qwaitr);
1290219b2ee8SDavid du Colombier poperror();
1291219b2ee8SDavid du Colombier
12923e12c5d1SDavid du Colombier if(w)
12933e12c5d1SDavid du Colombier memmove(w, &wq->w, sizeof(Waitmsg));
12949a747e4fSDavid du Colombier cpid = wq->w.pid;
12953e12c5d1SDavid du Colombier free(wq);
12963e12c5d1SDavid du Colombier return cpid;
12973e12c5d1SDavid du Colombier }
12983e12c5d1SDavid du Colombier
12993e12c5d1SDavid du Colombier Proc*
proctab(int i)13003e12c5d1SDavid du Colombier proctab(int i)
13013e12c5d1SDavid du Colombier {
13023e12c5d1SDavid du Colombier return &procalloc.arena[i];
13033e12c5d1SDavid du Colombier }
13043e12c5d1SDavid du Colombier
13053e12c5d1SDavid du Colombier void
dumpaproc(Proc * p)13067dd7cddfSDavid du Colombier dumpaproc(Proc *p)
13073e12c5d1SDavid du Colombier {
13083e12c5d1SDavid du Colombier ulong bss;
13097dd7cddfSDavid du Colombier char *s;
13103e12c5d1SDavid du Colombier
13117dd7cddfSDavid du Colombier if(p == 0)
13127dd7cddfSDavid du Colombier return;
13137dd7cddfSDavid du Colombier
13143e12c5d1SDavid du Colombier bss = 0;
13153e12c5d1SDavid du Colombier if(p->seg[BSEG])
13163e12c5d1SDavid du Colombier bss = p->seg[BSEG]->top;
13173e12c5d1SDavid du Colombier
13183e12c5d1SDavid du Colombier s = p->psstate;
13193e12c5d1SDavid du Colombier if(s == 0)
132080ee5cbfSDavid du Colombier s = statename[p->state];
1321a6a9e072SDavid 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",
13227dd7cddfSDavid du Colombier p->pid, p->text, p->pc, dbgpc(p), s, statename[p->state],
1323e288d156SDavid du Colombier p->time[0], p->time[1], bss, p->qpc, p->nlocks.ref, p->delaysched, p->lastlock ? p->lastlock->pc : 0, p->priority);
13247dd7cddfSDavid du Colombier }
13257dd7cddfSDavid du Colombier
13267dd7cddfSDavid du Colombier void
procdump(void)13277dd7cddfSDavid du Colombier procdump(void)
13287dd7cddfSDavid du Colombier {
13297dd7cddfSDavid du Colombier int i;
13307dd7cddfSDavid du Colombier Proc *p;
13317dd7cddfSDavid du Colombier
13327dd7cddfSDavid du Colombier if(up)
13337dd7cddfSDavid du Colombier print("up %lud\n", up->pid);
13347dd7cddfSDavid du Colombier else
13357dd7cddfSDavid du Colombier print("no current process\n");
13367dd7cddfSDavid du Colombier for(i=0; i<conf.nproc; i++) {
13377dd7cddfSDavid du Colombier p = &procalloc.arena[i];
13387dd7cddfSDavid du Colombier if(p->state == Dead)
13397dd7cddfSDavid du Colombier continue;
13407dd7cddfSDavid du Colombier
13417dd7cddfSDavid du Colombier dumpaproc(p);
13423e12c5d1SDavid du Colombier }
13433e12c5d1SDavid du Colombier }
13447dd7cddfSDavid du Colombier
13457dd7cddfSDavid du Colombier /*
13467dd7cddfSDavid du Colombier * wait till all processes have flushed their mmu
1347278a30f0SDavid du Colombier * state about segment s
13487dd7cddfSDavid du Colombier */
13497dd7cddfSDavid du Colombier void
procflushseg(Segment * s)13507dd7cddfSDavid du Colombier procflushseg(Segment *s)
13517dd7cddfSDavid du Colombier {
13527dd7cddfSDavid du Colombier int i, ns, nm, nwait;
13537dd7cddfSDavid du Colombier Proc *p;
13547dd7cddfSDavid du Colombier
13557dd7cddfSDavid du Colombier /*
13567dd7cddfSDavid du Colombier * tell all processes with this
13577dd7cddfSDavid du Colombier * segment to flush their mmu's
13587dd7cddfSDavid du Colombier */
13597dd7cddfSDavid du Colombier nwait = 0;
13607dd7cddfSDavid du Colombier for(i=0; i<conf.nproc; i++) {
13617dd7cddfSDavid du Colombier p = &procalloc.arena[i];
13627dd7cddfSDavid du Colombier if(p->state == Dead)
13637dd7cddfSDavid du Colombier continue;
13647dd7cddfSDavid du Colombier for(ns = 0; ns < NSEG; ns++)
13657dd7cddfSDavid du Colombier if(p->seg[ns] == s){
13667dd7cddfSDavid du Colombier p->newtlb = 1;
13677dd7cddfSDavid du Colombier for(nm = 0; nm < conf.nmach; nm++){
13687dd7cddfSDavid du Colombier if(MACHP(nm)->proc == p){
13697dd7cddfSDavid du Colombier MACHP(nm)->flushmmu = 1;
13707dd7cddfSDavid du Colombier nwait++;
13717dd7cddfSDavid du Colombier }
13727dd7cddfSDavid du Colombier }
13737dd7cddfSDavid du Colombier break;
13747dd7cddfSDavid du Colombier }
13757dd7cddfSDavid du Colombier }
13767dd7cddfSDavid du Colombier
13777dd7cddfSDavid du Colombier if(nwait == 0)
13787dd7cddfSDavid du Colombier return;
13797dd7cddfSDavid du Colombier
13807dd7cddfSDavid du Colombier /*
13817dd7cddfSDavid du Colombier * wait for all processors to take a clock interrupt
13827dd7cddfSDavid du Colombier * and flush their mmu's
13837dd7cddfSDavid du Colombier */
1384278a30f0SDavid du Colombier again:
1385278a30f0SDavid du Colombier for(nm = 0; nm < conf.nmach; nm++){
1386278a30f0SDavid du Colombier if(nm != m->machno && MACHP(nm)->flushmmu){
13877dd7cddfSDavid du Colombier sched();
1388278a30f0SDavid du Colombier goto again;
1389278a30f0SDavid du Colombier }
1390278a30f0SDavid du Colombier }
13917dd7cddfSDavid du Colombier }
13927dd7cddfSDavid du Colombier
13937dd7cddfSDavid du Colombier void
scheddump(void)13947dd7cddfSDavid du Colombier scheddump(void)
13957dd7cddfSDavid du Colombier {
13967dd7cddfSDavid du Colombier Proc *p;
13977dd7cddfSDavid du Colombier Schedq *rq;
13987dd7cddfSDavid du Colombier
13997dd7cddfSDavid du Colombier for(rq = &runq[Nrq-1]; rq >= runq; rq--){
1400219b2ee8SDavid du Colombier if(rq->head == 0)
1401219b2ee8SDavid du Colombier continue;
14027dd7cddfSDavid du Colombier print("rq%ld:", rq-runq);
1403219b2ee8SDavid du Colombier for(p = rq->head; p; p = p->rnext)
1404a6a9e072SDavid du Colombier print(" %lud(%lud)", p->pid, m->ticks - p->readytime);
1405219b2ee8SDavid du Colombier print("\n");
14067dd7cddfSDavid du Colombier delay(150);
1407219b2ee8SDavid du Colombier }
1408219b2ee8SDavid du Colombier print("nrdy %d\n", nrdy);
14093e12c5d1SDavid du Colombier }
14103e12c5d1SDavid du Colombier
14113e12c5d1SDavid du Colombier void
kproc(char * name,void (* func)(void *),void * arg)14123e12c5d1SDavid du Colombier kproc(char *name, void (*func)(void *), void *arg)
14133e12c5d1SDavid du Colombier {
14143e12c5d1SDavid du Colombier Proc *p;
14153e12c5d1SDavid du Colombier static Pgrp *kpgrp;
14163e12c5d1SDavid du Colombier
14173e12c5d1SDavid du Colombier p = newproc();
14189a747e4fSDavid du Colombier p->psstate = 0;
14199a747e4fSDavid du Colombier p->procmode = 0640;
14203e12c5d1SDavid du Colombier p->kp = 1;
1421b7b24591SDavid du Colombier p->noswap = 1;
14223e12c5d1SDavid du Colombier
14237dd7cddfSDavid du Colombier p->fpsave = up->fpsave;
14247dd7cddfSDavid du Colombier p->scallnr = up->scallnr;
14257dd7cddfSDavid du Colombier p->s = up->s;
14267dd7cddfSDavid du Colombier p->nerrlab = 0;
14277dd7cddfSDavid du Colombier p->slash = up->slash;
14287dd7cddfSDavid du Colombier p->dot = up->dot;
14292cca75a1SDavid du Colombier if(p->dot)
14307dd7cddfSDavid du Colombier incref(p->dot);
14317dd7cddfSDavid du Colombier
14327dd7cddfSDavid du Colombier memmove(p->note, up->note, sizeof(p->note));
14337dd7cddfSDavid du Colombier p->nnote = up->nnote;
14347dd7cddfSDavid du Colombier p->notified = 0;
14357dd7cddfSDavid du Colombier p->lastnote = up->lastnote;
14367dd7cddfSDavid du Colombier p->notify = up->notify;
14377dd7cddfSDavid du Colombier p->ureg = 0;
14387dd7cddfSDavid du Colombier p->dbgreg = 0;
14393e12c5d1SDavid du Colombier
1440a6a9e072SDavid du Colombier procpriority(p, PriKproc, 0);
1441219b2ee8SDavid du Colombier
14427dd7cddfSDavid du Colombier kprocchild(p, func, arg);
14433e12c5d1SDavid du Colombier
14449a747e4fSDavid du Colombier kstrdup(&p->user, eve);
14459a747e4fSDavid du Colombier kstrdup(&p->text, name);
14467dd7cddfSDavid du Colombier if(kpgrp == 0)
14473e12c5d1SDavid du Colombier kpgrp = newpgrp();
14483e12c5d1SDavid du Colombier p->pgrp = kpgrp;
14493e12c5d1SDavid du Colombier incref(kpgrp);
14503e12c5d1SDavid du Colombier
14513e12c5d1SDavid du Colombier memset(p->time, 0, sizeof(p->time));
14523e12c5d1SDavid du Colombier p->time[TReal] = MACHP(0)->ticks;
14533e12c5d1SDavid du Colombier ready(p);
14543e12c5d1SDavid du Colombier }
14553e12c5d1SDavid du Colombier
14563e12c5d1SDavid du Colombier /*
14573e12c5d1SDavid du Colombier * called splhi() by notify(). See comment in notify for the
14583e12c5d1SDavid du Colombier * reasoning.
14593e12c5d1SDavid du Colombier */
14603e12c5d1SDavid du Colombier void
procctl(Proc * p)14613e12c5d1SDavid du Colombier procctl(Proc *p)
14623e12c5d1SDavid du Colombier {
14633e12c5d1SDavid du Colombier char *state;
1464219b2ee8SDavid du Colombier ulong s;
14653e12c5d1SDavid du Colombier
14663e12c5d1SDavid du Colombier switch(p->procctl) {
14677dd7cddfSDavid du Colombier case Proc_exitbig:
14687dd7cddfSDavid du Colombier spllo();
14697dd7cddfSDavid du Colombier pexit("Killed: Insufficient physical memory", 1);
14707dd7cddfSDavid du Colombier
14713e12c5d1SDavid du Colombier case Proc_exitme:
14723e12c5d1SDavid du Colombier spllo(); /* pexit has locks in it */
14733e12c5d1SDavid du Colombier pexit("Killed", 1);
14743e12c5d1SDavid du Colombier
14753e12c5d1SDavid du Colombier case Proc_traceme:
14767dd7cddfSDavid du Colombier if(p->nnote == 0)
14773e12c5d1SDavid du Colombier return;
14783e12c5d1SDavid du Colombier /* No break */
14793e12c5d1SDavid du Colombier
14803e12c5d1SDavid du Colombier case Proc_stopme:
14813e12c5d1SDavid du Colombier p->procctl = 0;
14823e12c5d1SDavid du Colombier state = p->psstate;
14833e12c5d1SDavid du Colombier p->psstate = "Stopped";
14843e12c5d1SDavid du Colombier /* free a waiting debugger */
1485219b2ee8SDavid du Colombier s = spllo();
14863e12c5d1SDavid du Colombier qlock(&p->debug);
14873e12c5d1SDavid du Colombier if(p->pdbg) {
14883e12c5d1SDavid du Colombier wakeup(&p->pdbg->sleep);
14893e12c5d1SDavid du Colombier p->pdbg = 0;
14903e12c5d1SDavid du Colombier }
14913e12c5d1SDavid du Colombier qunlock(&p->debug);
14923e12c5d1SDavid du Colombier splhi();
1493219b2ee8SDavid du Colombier p->state = Stopped;
1494219b2ee8SDavid du Colombier sched();
14953e12c5d1SDavid du Colombier p->psstate = state;
1496219b2ee8SDavid du Colombier splx(s);
14973e12c5d1SDavid du Colombier return;
14983e12c5d1SDavid du Colombier }
14993e12c5d1SDavid du Colombier }
15003e12c5d1SDavid du Colombier
15013e12c5d1SDavid du Colombier #include "errstr.h"
15023e12c5d1SDavid du Colombier
15033e12c5d1SDavid du Colombier void
error(char * err)15043e12c5d1SDavid du Colombier error(char *err)
15053e12c5d1SDavid du Colombier {
1506219b2ee8SDavid du Colombier spllo();
1507dc5a79c1SDavid du Colombier
1508dc5a79c1SDavid du Colombier assert(up->nerrlab < NERR);
15099a747e4fSDavid du Colombier kstrcpy(up->errstr, err, ERRMAX);
15109a747e4fSDavid du Colombier setlabel(&up->errlab[NERR-1]);
15113e12c5d1SDavid du Colombier nexterror();
15123e12c5d1SDavid du Colombier }
15133e12c5d1SDavid du Colombier
15143e12c5d1SDavid du Colombier void
nexterror(void)15153e12c5d1SDavid du Colombier nexterror(void)
15163e12c5d1SDavid du Colombier {
15177dd7cddfSDavid du Colombier gotolabel(&up->errlab[--up->nerrlab]);
15183e12c5d1SDavid du Colombier }
15193e12c5d1SDavid du Colombier
15203e12c5d1SDavid du Colombier void
exhausted(char * resource)15213e12c5d1SDavid du Colombier exhausted(char *resource)
15223e12c5d1SDavid du Colombier {
15239a747e4fSDavid du Colombier char buf[ERRMAX];
15243e12c5d1SDavid du Colombier
1525f755faa2SDavid du Colombier snprint(buf, sizeof buf, "no free %s", resource);
15267dd7cddfSDavid du Colombier iprint("%s\n", buf);
15273e12c5d1SDavid du Colombier error(buf);
15283e12c5d1SDavid du Colombier }
15297dd7cddfSDavid du Colombier
15307dd7cddfSDavid du Colombier void
killbig(char * why)1531cd42b314SDavid du Colombier killbig(char *why)
15327dd7cddfSDavid du Colombier {
15337dd7cddfSDavid du Colombier int i;
15347dd7cddfSDavid du Colombier Segment *s;
15357dd7cddfSDavid du Colombier ulong l, max;
15367dd7cddfSDavid du Colombier Proc *p, *ep, *kp;
15377dd7cddfSDavid du Colombier
15387dd7cddfSDavid du Colombier max = 0;
15397dd7cddfSDavid du Colombier kp = 0;
15407dd7cddfSDavid du Colombier ep = procalloc.arena+conf.nproc;
15417dd7cddfSDavid du Colombier for(p = procalloc.arena; p < ep; p++) {
15427dd7cddfSDavid du Colombier if(p->state == Dead || p->kp)
15437dd7cddfSDavid du Colombier continue;
15447dd7cddfSDavid du Colombier l = 0;
15457dd7cddfSDavid du Colombier for(i=1; i<NSEG; i++) {
15467dd7cddfSDavid du Colombier s = p->seg[i];
15477dd7cddfSDavid du Colombier if(s != 0)
15487dd7cddfSDavid du Colombier l += s->top - s->base;
15497dd7cddfSDavid du Colombier }
1550cd42b314SDavid du Colombier if(l > max && ((p->procmode&0222) || strcmp(eve, p->user)!=0)) {
15517dd7cddfSDavid du Colombier kp = p;
15527dd7cddfSDavid du Colombier max = l;
15537dd7cddfSDavid du Colombier }
15547dd7cddfSDavid du Colombier }
1555cd42b314SDavid du Colombier
1556cd42b314SDavid du Colombier print("%lud: %s killed: %s\n", kp->pid, kp->text, why);
1557cd42b314SDavid du Colombier for(p = procalloc.arena; p < ep; p++) {
1558cd42b314SDavid du Colombier if(p->state == Dead || p->kp)
1559cd42b314SDavid du Colombier continue;
1560cd42b314SDavid du Colombier if(p != kp && p->seg[BSEG] && p->seg[BSEG] == kp->seg[BSEG])
1561cd42b314SDavid du Colombier p->procctl = Proc_exitbig;
1562cd42b314SDavid du Colombier }
15637dd7cddfSDavid du Colombier kp->procctl = Proc_exitbig;
15647dd7cddfSDavid du Colombier for(i = 0; i < NSEG; i++) {
15657dd7cddfSDavid du Colombier s = kp->seg[i];
15667dd7cddfSDavid du Colombier if(s != 0 && canqlock(&s->lk)) {
15677dd7cddfSDavid du Colombier mfreeseg(s, s->base, (s->top - s->base)/BY2PG);
15687dd7cddfSDavid du Colombier qunlock(&s->lk);
15697dd7cddfSDavid du Colombier }
15707dd7cddfSDavid du Colombier }
15717dd7cddfSDavid du Colombier }
15727dd7cddfSDavid du Colombier
15737dd7cddfSDavid du Colombier /*
15747dd7cddfSDavid du Colombier * change ownership to 'new' of all processes owned by 'old'. Used when
15757dd7cddfSDavid du Colombier * eve changes.
15767dd7cddfSDavid du Colombier */
15777dd7cddfSDavid du Colombier void
renameuser(char * old,char * new)15787dd7cddfSDavid du Colombier renameuser(char *old, char *new)
15797dd7cddfSDavid du Colombier {
15807dd7cddfSDavid du Colombier Proc *p, *ep;
15817dd7cddfSDavid du Colombier
15827dd7cddfSDavid du Colombier ep = procalloc.arena+conf.nproc;
15837dd7cddfSDavid du Colombier for(p = procalloc.arena; p < ep; p++)
15849a747e4fSDavid du Colombier if(p->user!=nil && strcmp(old, p->user)==0)
15859a747e4fSDavid du Colombier kstrdup(&p->user, new);
15867dd7cddfSDavid du Colombier }
15877dd7cddfSDavid du Colombier
15887dd7cddfSDavid du Colombier /*
15897dd7cddfSDavid du Colombier * time accounting called by clock() splhi'd
15907dd7cddfSDavid du Colombier */
15917dd7cddfSDavid du Colombier void
accounttime(void)15927dd7cddfSDavid du Colombier accounttime(void)
15937dd7cddfSDavid du Colombier {
15947dd7cddfSDavid du Colombier Proc *p;
15953ff48bf5SDavid du Colombier ulong n, per;
15963ff48bf5SDavid du Colombier static ulong nrun;
15977dd7cddfSDavid du Colombier
15987dd7cddfSDavid du Colombier p = m->proc;
15997dd7cddfSDavid du Colombier if(p) {
16007dd7cddfSDavid du Colombier nrun++;
16017dd7cddfSDavid du Colombier p->time[p->insyscall]++;
16027dd7cddfSDavid du Colombier }
16037dd7cddfSDavid du Colombier
16043ff48bf5SDavid du Colombier /* calculate decaying duty cycles */
16053ff48bf5SDavid du Colombier n = perfticks();
16063ff48bf5SDavid du Colombier per = n - m->perf.last;
16073ff48bf5SDavid du Colombier m->perf.last = n;
1608d9306527SDavid du Colombier per = (m->perf.period*(HZ-1) + per)/HZ;
1609d9306527SDavid du Colombier if(per != 0)
1610d9306527SDavid du Colombier m->perf.period = per;
16113ff48bf5SDavid du Colombier
16123ff48bf5SDavid du Colombier m->perf.avg_inidle = (m->perf.avg_inidle*(HZ-1)+m->perf.inidle)/HZ;
16133ff48bf5SDavid du Colombier m->perf.inidle = 0;
16143ff48bf5SDavid du Colombier
16153ff48bf5SDavid du Colombier m->perf.avg_inintr = (m->perf.avg_inintr*(HZ-1)+m->perf.inintr)/HZ;
16163ff48bf5SDavid du Colombier m->perf.inintr = 0;
16173ff48bf5SDavid du Colombier
16187dd7cddfSDavid du Colombier /* only one processor gets to compute system load averages */
16197dd7cddfSDavid du Colombier if(m->machno != 0)
16207dd7cddfSDavid du Colombier return;
16217dd7cddfSDavid du Colombier
162259c21d95SDavid du Colombier /*
162359c21d95SDavid du Colombier * calculate decaying load average.
162459c21d95SDavid du Colombier * if we decay by (n-1)/n then it takes
162559c21d95SDavid du Colombier * n clock ticks to go from load L to .36 L once
162659c21d95SDavid du Colombier * things quiet down. it takes about 5 n clock
162759c21d95SDavid du Colombier * ticks to go to zero. so using HZ means this is
162859c21d95SDavid du Colombier * approximately the load over the last second,
162959c21d95SDavid du Colombier * with a tail lasting about 5 seconds.
163059c21d95SDavid du Colombier */
16317dd7cddfSDavid du Colombier n = nrun;
16327dd7cddfSDavid du Colombier nrun = 0;
16337dd7cddfSDavid du Colombier n = (nrdy+n)*1000;
163459c21d95SDavid du Colombier m->load = (m->load*(HZ-1)+n)/HZ;
16357dd7cddfSDavid du Colombier }
16369a747e4fSDavid du Colombier
16379a747e4fSDavid du Colombier static void
pidhash(Proc * p)16389a747e4fSDavid du Colombier pidhash(Proc *p)
16399a747e4fSDavid du Colombier {
16409a747e4fSDavid du Colombier int h;
16419a747e4fSDavid du Colombier
16429a747e4fSDavid du Colombier h = p->pid % nelem(procalloc.ht);
16439a747e4fSDavid du Colombier lock(&procalloc);
16449a747e4fSDavid du Colombier p->pidhash = procalloc.ht[h];
16459a747e4fSDavid du Colombier procalloc.ht[h] = p;
16469a747e4fSDavid du Colombier unlock(&procalloc);
16479a747e4fSDavid du Colombier }
16489a747e4fSDavid du Colombier
16499a747e4fSDavid du Colombier static void
pidunhash(Proc * p)16509a747e4fSDavid du Colombier pidunhash(Proc *p)
16519a747e4fSDavid du Colombier {
16529a747e4fSDavid du Colombier int h;
16539a747e4fSDavid du Colombier Proc **l;
16549a747e4fSDavid du Colombier
16559a747e4fSDavid du Colombier h = p->pid % nelem(procalloc.ht);
16569a747e4fSDavid du Colombier lock(&procalloc);
16579a747e4fSDavid du Colombier for(l = &procalloc.ht[h]; *l != nil; l = &(*l)->pidhash)
16589a747e4fSDavid du Colombier if(*l == p){
16599a747e4fSDavid du Colombier *l = p->pidhash;
16609a747e4fSDavid du Colombier break;
16619a747e4fSDavid du Colombier }
16629a747e4fSDavid du Colombier unlock(&procalloc);
16639a747e4fSDavid du Colombier }
16649a747e4fSDavid du Colombier
16659a747e4fSDavid du Colombier int
procindex(ulong pid)16669a747e4fSDavid du Colombier procindex(ulong pid)
16679a747e4fSDavid du Colombier {
16689a747e4fSDavid du Colombier Proc *p;
16699a747e4fSDavid du Colombier int h;
16709a747e4fSDavid du Colombier int s;
16719a747e4fSDavid du Colombier
16729a747e4fSDavid du Colombier s = -1;
16739a747e4fSDavid du Colombier h = pid % nelem(procalloc.ht);
16749a747e4fSDavid du Colombier lock(&procalloc);
16759a747e4fSDavid du Colombier for(p = procalloc.ht[h]; p != nil; p = p->pidhash)
16769a747e4fSDavid du Colombier if(p->pid == pid){
16779a747e4fSDavid du Colombier s = p - procalloc.arena;
16789a747e4fSDavid du Colombier break;
16799a747e4fSDavid du Colombier }
16809a747e4fSDavid du Colombier unlock(&procalloc);
16819a747e4fSDavid du Colombier return s;
16829a747e4fSDavid du Colombier }
1683