19ef1f84bSDavid du Colombier #include <u.h>
29ef1f84bSDavid du Colombier #include "../port/lib.h"
39ef1f84bSDavid du Colombier #include "mem.h"
49ef1f84bSDavid du Colombier #include "dat.h"
59ef1f84bSDavid du Colombier #include "fns.h"
69ef1f84bSDavid du Colombier #include "../port/error.h"
79ef1f84bSDavid du Colombier
89ef1f84bSDavid du Colombier #include "../port/edf.h"
99ef1f84bSDavid du Colombier #include "errstr.h"
10d46407a3SDavid du Colombier #include <ptrace.h>
119ef1f84bSDavid du Colombier
129ef1f84bSDavid du Colombier int nrdy;
139ef1f84bSDavid du Colombier Ref noteidalloc;
149ef1f84bSDavid du Colombier
159ef1f84bSDavid du Colombier ulong delayedscheds; /* statistics */
169ef1f84bSDavid du Colombier long skipscheds;
179ef1f84bSDavid du Colombier long preempts;
189ef1f84bSDavid du Colombier
199ef1f84bSDavid du Colombier static Ref pidalloc;
209ef1f84bSDavid du Colombier
219ef1f84bSDavid du Colombier struct Procalloc procalloc;
229ef1f84bSDavid du Colombier
239ef1f84bSDavid du Colombier extern Proc* psalloc(void);
249ef1f84bSDavid du Colombier extern void pshash(Proc*);
259ef1f84bSDavid du Colombier extern void psrelease(Proc*);
269ef1f84bSDavid du Colombier extern void psunhash(Proc*);
279ef1f84bSDavid du Colombier
289ef1f84bSDavid du Colombier enum
299ef1f84bSDavid du Colombier {
309ef1f84bSDavid du Colombier Scaling=2,
319ef1f84bSDavid du Colombier };
329ef1f84bSDavid du Colombier
339ef1f84bSDavid du Colombier static int reprioritize(Proc*);
349ef1f84bSDavid du Colombier static void updatecpu(Proc*);
359ef1f84bSDavid du Colombier static int schedgain = 30; /* units in seconds */
369ef1f84bSDavid du Colombier
379ef1f84bSDavid du Colombier static void rebalance(void);
389ef1f84bSDavid du Colombier static ulong balancetime;
399ef1f84bSDavid du Colombier
409ef1f84bSDavid du Colombier Schedq runq[Nrq];
419ef1f84bSDavid du Colombier ulong runvec;
429ef1f84bSDavid du Colombier
439ef1f84bSDavid du Colombier char *statename[] =
449ef1f84bSDavid du Colombier { /* BUG: generate automatically */
459ef1f84bSDavid du Colombier "Dead",
469ef1f84bSDavid du Colombier "Moribund",
479ef1f84bSDavid du Colombier "Ready",
489ef1f84bSDavid du Colombier "Scheding",
499ef1f84bSDavid du Colombier "Running",
509ef1f84bSDavid du Colombier "Queueing",
519ef1f84bSDavid du Colombier "QueueingR",
529ef1f84bSDavid du Colombier "QueueingW",
539ef1f84bSDavid du Colombier "Wakeme",
549ef1f84bSDavid du Colombier "Broken",
559ef1f84bSDavid du Colombier "Stopped",
569ef1f84bSDavid du Colombier "Rendez",
579ef1f84bSDavid du Colombier "Waitrelease",
589ef1f84bSDavid du Colombier };
599ef1f84bSDavid du Colombier
609ef1f84bSDavid du Colombier /*
619ef1f84bSDavid du Colombier * Always splhi()'ed.
629ef1f84bSDavid du Colombier */
639ef1f84bSDavid du Colombier void
schedinit(void)649ef1f84bSDavid du Colombier schedinit(void) /* never returns */
659ef1f84bSDavid du Colombier {
669ef1f84bSDavid du Colombier Edf *e;
679ef1f84bSDavid du Colombier
689ef1f84bSDavid du Colombier setlabel(&m->sched);
699ef1f84bSDavid du Colombier if(up) {
709ef1f84bSDavid du Colombier if((e = up->edf) && (e->flags & Admitted))
719ef1f84bSDavid du Colombier edfrecord(up);
729ef1f84bSDavid du Colombier updatecpu(up);
73*4498a243SDavid du Colombier m->proc = nil;
749ef1f84bSDavid du Colombier switch(up->state) {
759ef1f84bSDavid du Colombier case Running:
769ef1f84bSDavid du Colombier ready(up);
779ef1f84bSDavid du Colombier break;
789ef1f84bSDavid du Colombier case Moribund:
799ef1f84bSDavid du Colombier up->state = Dead;
809ef1f84bSDavid du Colombier
819ef1f84bSDavid du Colombier /*
829ef1f84bSDavid du Colombier * Holding locks from pexit:
839ef1f84bSDavid du Colombier * procalloc
849ef1f84bSDavid du Colombier * palloc
859ef1f84bSDavid du Colombier */
869ef1f84bSDavid du Colombier mmurelease(up);
879ef1f84bSDavid du Colombier unlock(&palloc);
889ef1f84bSDavid du Colombier
899ef1f84bSDavid du Colombier psrelease(up);
909ef1f84bSDavid du Colombier unlock(&procalloc);
919ef1f84bSDavid du Colombier break;
929ef1f84bSDavid du Colombier }
939ef1f84bSDavid du Colombier up->mach = nil;
949ef1f84bSDavid du Colombier up = nil;
959ef1f84bSDavid du Colombier }
969ef1f84bSDavid du Colombier sched();
979ef1f84bSDavid du Colombier }
989ef1f84bSDavid du Colombier
999ef1f84bSDavid du Colombier /*
1009ef1f84bSDavid du Colombier * If changing this routine, look also at sleep(). It
1019ef1f84bSDavid du Colombier * contains a copy of the guts of sched().
1029ef1f84bSDavid du Colombier */
1039ef1f84bSDavid du Colombier void
sched(void)1049ef1f84bSDavid du Colombier sched(void)
1059ef1f84bSDavid du Colombier {
1069ef1f84bSDavid du Colombier Proc *p;
1079ef1f84bSDavid du Colombier
1089ef1f84bSDavid du Colombier if(m->ilockdepth)
1099ef1f84bSDavid du Colombier panic("cpu%d: ilockdepth %d, last lock %#p at %#p, sched called from %#p",
1109ef1f84bSDavid du Colombier m->machno,
1119ef1f84bSDavid du Colombier m->ilockdepth,
1129ef1f84bSDavid du Colombier up? up->lastilock: nil,
1139ef1f84bSDavid du Colombier (up && up->lastilock)? up->lastilock->pc: m->ilockpc,
1149ef1f84bSDavid du Colombier getcallerpc(&p+2));
1159ef1f84bSDavid du Colombier
1169ef1f84bSDavid du Colombier if(up){
1179ef1f84bSDavid du Colombier /*
1189ef1f84bSDavid du Colombier * Delay the sched until the process gives up the locks
1199ef1f84bSDavid du Colombier * it is holding. This avoids dumb lock loops.
1209ef1f84bSDavid du Colombier * Don't delay if the process is Moribund.
1219ef1f84bSDavid du Colombier * It called sched to die.
1229ef1f84bSDavid du Colombier * But do sched eventually. This avoids a missing unlock
1239ef1f84bSDavid du Colombier * from hanging the entire kernel.
1249ef1f84bSDavid du Colombier * But don't reschedule procs holding palloc or procalloc.
1259ef1f84bSDavid du Colombier * Those are far too important to be holding while asleep.
1269ef1f84bSDavid du Colombier *
1279ef1f84bSDavid du Colombier * This test is not exact. There can still be a few
1289ef1f84bSDavid du Colombier * instructions in the middle of taslock when a process
1299ef1f84bSDavid du Colombier * holds a lock but Lock.p has not yet been initialized.
1309ef1f84bSDavid du Colombier */
1319ef1f84bSDavid du Colombier if(up->nlocks)
1329ef1f84bSDavid du Colombier if(up->state != Moribund)
1339ef1f84bSDavid du Colombier if(up->delaysched < 20
1349ef1f84bSDavid du Colombier || palloc.Lock.p == up
1359ef1f84bSDavid du Colombier || procalloc.Lock.p == up){
1369ef1f84bSDavid du Colombier up->delaysched++;
1379ef1f84bSDavid du Colombier delayedscheds++;
1389ef1f84bSDavid du Colombier return;
1399ef1f84bSDavid du Colombier }
1409ef1f84bSDavid du Colombier up->delaysched = 0;
1419ef1f84bSDavid du Colombier
1429ef1f84bSDavid du Colombier splhi();
1439ef1f84bSDavid du Colombier
1449ef1f84bSDavid du Colombier /* statistics */
1459ef1f84bSDavid du Colombier m->cs++;
1469ef1f84bSDavid du Colombier
1479ef1f84bSDavid du Colombier procsave(up);
1489ef1f84bSDavid du Colombier if(setlabel(&up->sched)){
1499ef1f84bSDavid du Colombier procrestore(up);
1509ef1f84bSDavid du Colombier spllo();
1519ef1f84bSDavid du Colombier return;
1529ef1f84bSDavid du Colombier }
1539ef1f84bSDavid du Colombier gotolabel(&m->sched);
1549ef1f84bSDavid du Colombier }
1559ef1f84bSDavid du Colombier p = runproc();
1569ef1f84bSDavid du Colombier if(!p->edf){
1579ef1f84bSDavid du Colombier updatecpu(p);
1589ef1f84bSDavid du Colombier p->priority = reprioritize(p);
1599ef1f84bSDavid du Colombier }
1609ef1f84bSDavid du Colombier if(p != m->readied)
1619ef1f84bSDavid du Colombier m->schedticks = m->ticks + HZ/10;
162*4498a243SDavid du Colombier m->readied = nil;
1639ef1f84bSDavid du Colombier up = p;
1649ef1f84bSDavid du Colombier up->state = Running;
1659ef1f84bSDavid du Colombier up->mach = m;
1669ef1f84bSDavid du Colombier m->proc = up;
1679ef1f84bSDavid du Colombier mmuswitch(up);
1689ef1f84bSDavid du Colombier gotolabel(&up->sched);
1699ef1f84bSDavid du Colombier }
1709ef1f84bSDavid du Colombier
1719ef1f84bSDavid du Colombier int
anyready(void)1729ef1f84bSDavid du Colombier anyready(void)
1739ef1f84bSDavid du Colombier {
1749ef1f84bSDavid du Colombier return runvec;
1759ef1f84bSDavid du Colombier }
1769ef1f84bSDavid du Colombier
1779ef1f84bSDavid du Colombier int
anyhigher(void)1789ef1f84bSDavid du Colombier anyhigher(void)
1799ef1f84bSDavid du Colombier {
1809ef1f84bSDavid du Colombier return runvec & ~((1<<(up->priority+1))-1);
1819ef1f84bSDavid du Colombier }
1829ef1f84bSDavid du Colombier
1839ef1f84bSDavid du Colombier /*
1849ef1f84bSDavid du Colombier * here once per clock tick to see if we should resched
1859ef1f84bSDavid du Colombier */
1869ef1f84bSDavid du Colombier void
hzsched(void)1879ef1f84bSDavid du Colombier hzsched(void)
1889ef1f84bSDavid du Colombier {
1899ef1f84bSDavid du Colombier /* once a second, rebalance will reprioritize ready procs */
1909ef1f84bSDavid du Colombier if(m->machno == 0)
1919ef1f84bSDavid du Colombier rebalance();
1929ef1f84bSDavid du Colombier
1939ef1f84bSDavid du Colombier /* unless preempted, get to run for at least 100ms */
1949ef1f84bSDavid du Colombier if(anyhigher()
1959ef1f84bSDavid du Colombier || (!up->fixedpri && m->ticks > m->schedticks && anyready())){
1969ef1f84bSDavid du Colombier m->readied = nil; /* avoid cooperative scheduling */
1979ef1f84bSDavid du Colombier up->delaysched++;
1989ef1f84bSDavid du Colombier }
1999ef1f84bSDavid du Colombier }
2009ef1f84bSDavid du Colombier
2019ef1f84bSDavid du Colombier /*
2029ef1f84bSDavid du Colombier * here at the end of non-clock interrupts to see if we should preempt the
2039ef1f84bSDavid du Colombier * current process. Returns 1 if preempted, 0 otherwise.
2049ef1f84bSDavid du Colombier */
2059ef1f84bSDavid du Colombier int
preempted(void)2069ef1f84bSDavid du Colombier preempted(void)
2079ef1f84bSDavid du Colombier {
2089ef1f84bSDavid du Colombier if(up && up->state == Running)
2099ef1f84bSDavid du Colombier if(up->preempted == 0)
2109ef1f84bSDavid du Colombier if(anyhigher())
2119ef1f84bSDavid du Colombier if(!active.exiting){
2129ef1f84bSDavid du Colombier m->readied = nil; /* avoid cooperative scheduling */
2139ef1f84bSDavid du Colombier up->preempted = 1;
2149ef1f84bSDavid du Colombier sched();
2159ef1f84bSDavid du Colombier splhi();
2169ef1f84bSDavid du Colombier up->preempted = 0;
2179ef1f84bSDavid du Colombier return 1;
2189ef1f84bSDavid du Colombier }
2199ef1f84bSDavid du Colombier return 0;
2209ef1f84bSDavid du Colombier }
2219ef1f84bSDavid du Colombier
2229ef1f84bSDavid du Colombier /*
2239ef1f84bSDavid du Colombier * Update the cpu time average for this particular process,
2249ef1f84bSDavid du Colombier * which is about to change from up -> not up or vice versa.
2259ef1f84bSDavid du Colombier * p->lastupdate is the last time an updatecpu happened.
2269ef1f84bSDavid du Colombier *
2279ef1f84bSDavid du Colombier * The cpu time average is a decaying average that lasts
2289ef1f84bSDavid du Colombier * about D clock ticks. D is chosen to be approximately
2299ef1f84bSDavid du Colombier * the cpu time of a cpu-intensive "quick job". A job has to run
2309ef1f84bSDavid du Colombier * for approximately D clock ticks before we home in on its
2319ef1f84bSDavid du Colombier * actual cpu usage. Thus if you manage to get in and get out
2329ef1f84bSDavid du Colombier * quickly, you won't be penalized during your burst. Once you
2339ef1f84bSDavid du Colombier * start using your share of the cpu for more than about D
2349ef1f84bSDavid du Colombier * clock ticks though, your p->cpu hits 1000 (1.0) and you end up
2359ef1f84bSDavid du Colombier * below all the other quick jobs. Interactive tasks, because
2369ef1f84bSDavid du Colombier * they basically always use less than their fair share of cpu,
2379ef1f84bSDavid du Colombier * will be rewarded.
2389ef1f84bSDavid du Colombier *
2399ef1f84bSDavid du Colombier * If the process has not been running, then we want to
2409ef1f84bSDavid du Colombier * apply the filter
2419ef1f84bSDavid du Colombier *
2429ef1f84bSDavid du Colombier * cpu = cpu * (D-1)/D
2439ef1f84bSDavid du Colombier *
2449ef1f84bSDavid du Colombier * n times, yielding
2459ef1f84bSDavid du Colombier *
2469ef1f84bSDavid du Colombier * cpu = cpu * ((D-1)/D)^n
2479ef1f84bSDavid du Colombier *
2489ef1f84bSDavid du Colombier * but D is big enough that this is approximately
2499ef1f84bSDavid du Colombier *
2509ef1f84bSDavid du Colombier * cpu = cpu * (D-n)/D
2519ef1f84bSDavid du Colombier *
2529ef1f84bSDavid du Colombier * so we use that instead.
2539ef1f84bSDavid du Colombier *
2549ef1f84bSDavid du Colombier * If the process has been running, we apply the filter to
2559ef1f84bSDavid du Colombier * 1 - cpu, yielding a similar equation. Note that cpu is
2569ef1f84bSDavid du Colombier * stored in fixed point (* 1000).
2579ef1f84bSDavid du Colombier *
2589ef1f84bSDavid du Colombier * Updatecpu must be called before changing up, in order
2599ef1f84bSDavid du Colombier * to maintain accurate cpu usage statistics. It can be called
2609ef1f84bSDavid du Colombier * at any time to bring the stats for a given proc up-to-date.
2619ef1f84bSDavid du Colombier */
2629ef1f84bSDavid du Colombier static void
updatecpu(Proc * p)2639ef1f84bSDavid du Colombier updatecpu(Proc *p)
2649ef1f84bSDavid du Colombier {
2659ef1f84bSDavid du Colombier int D, n, t, ocpu;
2669ef1f84bSDavid du Colombier
2679ef1f84bSDavid du Colombier if(p->edf)
2689ef1f84bSDavid du Colombier return;
2699ef1f84bSDavid du Colombier
2709ef1f84bSDavid du Colombier t = sys->ticks*Scaling + Scaling/2;
2719ef1f84bSDavid du Colombier n = t - p->lastupdate;
2729ef1f84bSDavid du Colombier p->lastupdate = t;
2739ef1f84bSDavid du Colombier
2749ef1f84bSDavid du Colombier if(n == 0)
2759ef1f84bSDavid du Colombier return;
2769ef1f84bSDavid du Colombier D = schedgain*HZ*Scaling;
2779ef1f84bSDavid du Colombier if(n > D)
2789ef1f84bSDavid du Colombier n = D;
2799ef1f84bSDavid du Colombier
2809ef1f84bSDavid du Colombier ocpu = p->cpu;
2819ef1f84bSDavid du Colombier if(p != up)
2829ef1f84bSDavid du Colombier p->cpu = (ocpu*(D-n))/D;
2839ef1f84bSDavid du Colombier else{
2849ef1f84bSDavid du Colombier t = 1000 - ocpu;
2859ef1f84bSDavid du Colombier t = (t*(D-n))/D;
2869ef1f84bSDavid du Colombier p->cpu = 1000 - t;
2879ef1f84bSDavid du Colombier }
2889ef1f84bSDavid du Colombier
2899ef1f84bSDavid du Colombier //iprint("pid %d %s for %d cpu %d -> %d\n", p->pid,p==up?"active":"inactive",n, ocpu,p->cpu);
2909ef1f84bSDavid du Colombier }
2919ef1f84bSDavid du Colombier
2929ef1f84bSDavid du Colombier /*
2939ef1f84bSDavid du Colombier * On average, p has used p->cpu of a cpu recently.
2949ef1f84bSDavid du Colombier * Its fair share is sys.nonline/m->load of a cpu. If it has been getting
2959ef1f84bSDavid du Colombier * too much, penalize it. If it has been getting not enough, reward it.
2969ef1f84bSDavid du Colombier * I don't think you can get much more than your fair share that
2979ef1f84bSDavid du Colombier * often, so most of the queues are for using less. Having a priority
2989ef1f84bSDavid du Colombier * of 3 means you're just right. Having a higher priority (up to p->basepri)
2999ef1f84bSDavid du Colombier * means you're not using as much as you could.
3009ef1f84bSDavid du Colombier */
3019ef1f84bSDavid du Colombier static int
reprioritize(Proc * p)3029ef1f84bSDavid du Colombier reprioritize(Proc *p)
3039ef1f84bSDavid du Colombier {
3049ef1f84bSDavid du Colombier int fairshare, n, load, ratio;
3059ef1f84bSDavid du Colombier
3069ef1f84bSDavid du Colombier load = sys->machptr[0]->load;
3079ef1f84bSDavid du Colombier if(load == 0)
3089ef1f84bSDavid du Colombier return p->basepri;
3099ef1f84bSDavid du Colombier
3109ef1f84bSDavid du Colombier /*
3119ef1f84bSDavid du Colombier * fairshare = 1.000 * PROCMAX * 1.000/load,
3129ef1f84bSDavid du Colombier * except the decimal point is moved three places
3139ef1f84bSDavid du Colombier * on both load and fairshare.
3149ef1f84bSDavid du Colombier */
3159ef1f84bSDavid du Colombier fairshare = (sys->nonline*1000*1000)/load;
3169ef1f84bSDavid du Colombier n = p->cpu;
3179ef1f84bSDavid du Colombier if(n == 0)
3189ef1f84bSDavid du Colombier n = 1;
3199ef1f84bSDavid du Colombier ratio = (fairshare+n/2) / n;
3209ef1f84bSDavid du Colombier if(ratio > p->basepri)
3219ef1f84bSDavid du Colombier ratio = p->basepri;
3229ef1f84bSDavid du Colombier if(ratio < 0)
3239ef1f84bSDavid du Colombier panic("reprioritize");
3249ef1f84bSDavid du Colombier //iprint("pid %d cpu %d load %d fair %d pri %d\n", p->pid, p->cpu, load, fairshare, ratio);
3259ef1f84bSDavid du Colombier return ratio;
3269ef1f84bSDavid du Colombier }
3279ef1f84bSDavid du Colombier
3289ef1f84bSDavid du Colombier /*
3299ef1f84bSDavid du Colombier * add a process to a scheduling queue
3309ef1f84bSDavid du Colombier */
3319ef1f84bSDavid du Colombier void
queueproc(Schedq * rq,Proc * p)3329ef1f84bSDavid du Colombier queueproc(Schedq *rq, Proc *p)
3339ef1f84bSDavid du Colombier {
3349ef1f84bSDavid du Colombier int pri;
3359ef1f84bSDavid du Colombier
3369ef1f84bSDavid du Colombier pri = rq - runq;
3379ef1f84bSDavid du Colombier lock(runq);
3389ef1f84bSDavid du Colombier p->priority = pri;
3399ef1f84bSDavid du Colombier p->rnext = 0;
3409ef1f84bSDavid du Colombier if(rq->tail)
3419ef1f84bSDavid du Colombier rq->tail->rnext = p;
3429ef1f84bSDavid du Colombier else
3439ef1f84bSDavid du Colombier rq->head = p;
3449ef1f84bSDavid du Colombier rq->tail = p;
3459ef1f84bSDavid du Colombier rq->n++;
3469ef1f84bSDavid du Colombier nrdy++;
3479ef1f84bSDavid du Colombier runvec |= 1<<pri;
3489ef1f84bSDavid du Colombier unlock(runq);
3499ef1f84bSDavid du Colombier }
3509ef1f84bSDavid du Colombier
3519ef1f84bSDavid du Colombier /*
3529ef1f84bSDavid du Colombier * try to remove a process from a scheduling queue (called splhi)
3539ef1f84bSDavid du Colombier */
3549ef1f84bSDavid du Colombier Proc*
dequeueproc(Schedq * rq,Proc * tp)3559ef1f84bSDavid du Colombier dequeueproc(Schedq *rq, Proc *tp)
3569ef1f84bSDavid du Colombier {
3579ef1f84bSDavid du Colombier Proc *l, *p;
3589ef1f84bSDavid du Colombier
3599ef1f84bSDavid du Colombier if(!canlock(runq))
3609ef1f84bSDavid du Colombier return nil;
3619ef1f84bSDavid du Colombier
3629ef1f84bSDavid du Colombier /*
3639ef1f84bSDavid du Colombier * the queue may have changed before we locked runq,
3649ef1f84bSDavid du Colombier * refind the target process.
3659ef1f84bSDavid du Colombier */
3669ef1f84bSDavid du Colombier l = 0;
3679ef1f84bSDavid du Colombier for(p = rq->head; p; p = p->rnext){
3689ef1f84bSDavid du Colombier if(p == tp)
3699ef1f84bSDavid du Colombier break;
3709ef1f84bSDavid du Colombier l = p;
3719ef1f84bSDavid du Colombier }
3729ef1f84bSDavid du Colombier
3739ef1f84bSDavid du Colombier /*
3749ef1f84bSDavid du Colombier * p->mach==0 only when process state is saved
3759ef1f84bSDavid du Colombier */
376*4498a243SDavid du Colombier if(p == nil || p->mach){
3779ef1f84bSDavid du Colombier unlock(runq);
3789ef1f84bSDavid du Colombier return nil;
3799ef1f84bSDavid du Colombier }
380*4498a243SDavid du Colombier if(p->rnext == nil)
3819ef1f84bSDavid du Colombier rq->tail = l;
3829ef1f84bSDavid du Colombier if(l)
3839ef1f84bSDavid du Colombier l->rnext = p->rnext;
3849ef1f84bSDavid du Colombier else
3859ef1f84bSDavid du Colombier rq->head = p->rnext;
3869ef1f84bSDavid du Colombier if(rq->head == nil)
3879ef1f84bSDavid du Colombier runvec &= ~(1<<(rq-runq));
3889ef1f84bSDavid du Colombier rq->n--;
3899ef1f84bSDavid du Colombier nrdy--;
3909ef1f84bSDavid du Colombier if(p->state != Ready)
3919ef1f84bSDavid du Colombier print("dequeueproc %s %d %s\n", p->text, p->pid, statename[p->state]);
3929ef1f84bSDavid du Colombier
3939ef1f84bSDavid du Colombier unlock(runq);
3949ef1f84bSDavid du Colombier return p;
3959ef1f84bSDavid du Colombier }
3969ef1f84bSDavid du Colombier
3979ef1f84bSDavid du Colombier /*
3989ef1f84bSDavid du Colombier * ready(p) picks a new priority for a process and sticks it in the
3999ef1f84bSDavid du Colombier * runq for that priority.
4009ef1f84bSDavid du Colombier */
4019ef1f84bSDavid du Colombier void
ready(Proc * p)4029ef1f84bSDavid du Colombier ready(Proc *p)
4039ef1f84bSDavid du Colombier {
4049ef1f84bSDavid du Colombier Mreg s;
4059ef1f84bSDavid du Colombier int pri;
4069ef1f84bSDavid du Colombier Schedq *rq;
407d46407a3SDavid du Colombier void (*pt)(Proc*, int, vlong, vlong);
4089ef1f84bSDavid du Colombier
4099ef1f84bSDavid du Colombier s = splhi();
4109ef1f84bSDavid du Colombier if(edfready(p)){
4119ef1f84bSDavid du Colombier splx(s);
4129ef1f84bSDavid du Colombier return;
4139ef1f84bSDavid du Colombier }
4149ef1f84bSDavid du Colombier
4159ef1f84bSDavid du Colombier if(up != p && (p->wired == nil || p->wired == m))
4169ef1f84bSDavid du Colombier m->readied = p; /* group scheduling */
4179ef1f84bSDavid du Colombier
4189ef1f84bSDavid du Colombier updatecpu(p);
4199ef1f84bSDavid du Colombier pri = reprioritize(p);
4209ef1f84bSDavid du Colombier p->priority = pri;
4219ef1f84bSDavid du Colombier rq = &runq[pri];
4229ef1f84bSDavid du Colombier p->state = Ready;
4239ef1f84bSDavid du Colombier queueproc(rq, p);
4249ef1f84bSDavid du Colombier pt = proctrace;
4259ef1f84bSDavid du Colombier if(pt)
426d46407a3SDavid du Colombier pt(p, SReady, 0, 0);
4279ef1f84bSDavid du Colombier splx(s);
4289ef1f84bSDavid du Colombier }
4299ef1f84bSDavid du Colombier
4309ef1f84bSDavid du Colombier /*
4319ef1f84bSDavid du Colombier * yield the processor and drop our priority
4329ef1f84bSDavid du Colombier */
4339ef1f84bSDavid du Colombier void
yield(void)4349ef1f84bSDavid du Colombier yield(void)
4359ef1f84bSDavid du Colombier {
4369ef1f84bSDavid du Colombier if(anyready()){
4379ef1f84bSDavid du Colombier /* pretend we just used 1/2 tick */
4389ef1f84bSDavid du Colombier up->lastupdate -= Scaling/2;
4399ef1f84bSDavid du Colombier sched();
4409ef1f84bSDavid du Colombier }
4419ef1f84bSDavid du Colombier }
4429ef1f84bSDavid du Colombier
4439ef1f84bSDavid du Colombier /*
4449ef1f84bSDavid du Colombier * recalculate priorities once a second. We need to do this
4459ef1f84bSDavid du Colombier * since priorities will otherwise only be recalculated when
4469ef1f84bSDavid du Colombier * the running process blocks.
4479ef1f84bSDavid du Colombier */
4489ef1f84bSDavid du Colombier static void
rebalance(void)4499ef1f84bSDavid du Colombier rebalance(void)
4509ef1f84bSDavid du Colombier {
4519ef1f84bSDavid du Colombier Mreg s;
4529ef1f84bSDavid du Colombier int pri, npri, t;
4539ef1f84bSDavid du Colombier Schedq *rq;
4549ef1f84bSDavid du Colombier Proc *p;
4559ef1f84bSDavid du Colombier
4569ef1f84bSDavid du Colombier t = m->ticks;
4579ef1f84bSDavid du Colombier if(t - balancetime < HZ)
4589ef1f84bSDavid du Colombier return;
4599ef1f84bSDavid du Colombier balancetime = t;
4609ef1f84bSDavid du Colombier
4619ef1f84bSDavid du Colombier for(pri=0, rq=runq; pri<Npriq; pri++, rq++){
4629ef1f84bSDavid du Colombier another:
4639ef1f84bSDavid du Colombier p = rq->head;
4649ef1f84bSDavid du Colombier if(p == nil)
4659ef1f84bSDavid du Colombier continue;
4669ef1f84bSDavid du Colombier if(p->mp != m)
4679ef1f84bSDavid du Colombier continue;
4689ef1f84bSDavid du Colombier if(pri == p->basepri)
4699ef1f84bSDavid du Colombier continue;
4709ef1f84bSDavid du Colombier updatecpu(p);
4719ef1f84bSDavid du Colombier npri = reprioritize(p);
4729ef1f84bSDavid du Colombier if(npri != pri){
4739ef1f84bSDavid du Colombier s = splhi();
4749ef1f84bSDavid du Colombier p = dequeueproc(rq, p);
4759ef1f84bSDavid du Colombier if(p)
4769ef1f84bSDavid du Colombier queueproc(&runq[npri], p);
4779ef1f84bSDavid du Colombier splx(s);
4789ef1f84bSDavid du Colombier goto another;
4799ef1f84bSDavid du Colombier }
4809ef1f84bSDavid du Colombier }
4819ef1f84bSDavid du Colombier }
4829ef1f84bSDavid du Colombier
4839ef1f84bSDavid du Colombier
4849ef1f84bSDavid du Colombier /*
4859ef1f84bSDavid du Colombier * pick a process to run
4869ef1f84bSDavid du Colombier */
4879ef1f84bSDavid du Colombier Proc*
runproc(void)4889ef1f84bSDavid du Colombier runproc(void)
4899ef1f84bSDavid du Colombier {
4909ef1f84bSDavid du Colombier Schedq *rq;
4919ef1f84bSDavid du Colombier Proc *p;
4929ef1f84bSDavid du Colombier ulong start, now;
4939ef1f84bSDavid du Colombier int i;
494d46407a3SDavid du Colombier void (*pt)(Proc*, int, vlong, vlong);
4959ef1f84bSDavid du Colombier
4969ef1f84bSDavid du Colombier start = perfticks();
4979ef1f84bSDavid du Colombier
4989ef1f84bSDavid du Colombier /* cooperative scheduling until the clock ticks */
4999ef1f84bSDavid du Colombier if((p=m->readied) && p->mach==0 && p->state==Ready
5009ef1f84bSDavid du Colombier && (p->wired == nil || p->wired == m)
5019ef1f84bSDavid du Colombier && runq[Nrq-1].head == nil && runq[Nrq-2].head == nil){
5029ef1f84bSDavid du Colombier skipscheds++;
5039ef1f84bSDavid du Colombier rq = &runq[p->priority];
5049ef1f84bSDavid du Colombier goto found;
5059ef1f84bSDavid du Colombier }
5069ef1f84bSDavid du Colombier
5079ef1f84bSDavid du Colombier preempts++;
5089ef1f84bSDavid du Colombier
5099ef1f84bSDavid du Colombier loop:
5109ef1f84bSDavid du Colombier /*
5119ef1f84bSDavid du Colombier * find a process that last ran on this processor (affinity),
5129ef1f84bSDavid du Colombier * or one that hasn't moved in a while (load balancing). Every
5139ef1f84bSDavid du Colombier * time around the loop affinity goes down.
5149ef1f84bSDavid du Colombier */
5159ef1f84bSDavid du Colombier spllo();
5169ef1f84bSDavid du Colombier for(i = 0;; i++){
5179ef1f84bSDavid du Colombier /*
5189ef1f84bSDavid du Colombier * find the highest priority target process that this
5199ef1f84bSDavid du Colombier * processor can run given affinity constraints.
5209ef1f84bSDavid du Colombier *
5219ef1f84bSDavid du Colombier */
5229ef1f84bSDavid du Colombier for(rq = &runq[Nrq-1]; rq >= runq; rq--){
5239ef1f84bSDavid du Colombier for(p = rq->head; p; p = p->rnext){
5249ef1f84bSDavid du Colombier if(p->mp == nil || p->mp == m
5259ef1f84bSDavid du Colombier || (!p->wired && i > 0))
5269ef1f84bSDavid du Colombier goto found;
5279ef1f84bSDavid du Colombier }
5289ef1f84bSDavid du Colombier }
5299ef1f84bSDavid du Colombier
5309ef1f84bSDavid du Colombier /* waste time or halt the CPU */
5319ef1f84bSDavid du Colombier idlehands();
5329ef1f84bSDavid du Colombier
5339ef1f84bSDavid du Colombier /* remember how much time we're here */
5349ef1f84bSDavid du Colombier now = perfticks();
5359ef1f84bSDavid du Colombier m->perf.inidle += now-start;
5369ef1f84bSDavid du Colombier start = now;
5379ef1f84bSDavid du Colombier }
5389ef1f84bSDavid du Colombier
5399ef1f84bSDavid du Colombier found:
5409ef1f84bSDavid du Colombier splhi();
5419ef1f84bSDavid du Colombier p = dequeueproc(rq, p);
5429ef1f84bSDavid du Colombier if(p == nil)
5439ef1f84bSDavid du Colombier goto loop;
5449ef1f84bSDavid du Colombier
5459ef1f84bSDavid du Colombier p->state = Scheding;
5469ef1f84bSDavid du Colombier p->mp = m;
5479ef1f84bSDavid du Colombier
5489ef1f84bSDavid du Colombier if(edflock(p)){
5499ef1f84bSDavid du Colombier edfrun(p, rq == &runq[PriEdf]); /* start deadline timer and do admin */
5509ef1f84bSDavid du Colombier edfunlock();
5519ef1f84bSDavid du Colombier }
5529ef1f84bSDavid du Colombier pt = proctrace;
5539ef1f84bSDavid du Colombier if(pt)
554d46407a3SDavid du Colombier pt(p, SRun, 0, 0);
5559ef1f84bSDavid du Colombier return p;
5569ef1f84bSDavid du Colombier }
5579ef1f84bSDavid du Colombier
5589ef1f84bSDavid du Colombier int
canpage(Proc * p)5599ef1f84bSDavid du Colombier canpage(Proc *p)
5609ef1f84bSDavid du Colombier {
5619ef1f84bSDavid du Colombier int ok;
5629ef1f84bSDavid du Colombier
5639ef1f84bSDavid du Colombier splhi();
5649ef1f84bSDavid du Colombier lock(runq);
5659ef1f84bSDavid du Colombier /* Only reliable way to see if we are Running */
5669ef1f84bSDavid du Colombier if(p->mach == 0) {
5679ef1f84bSDavid du Colombier p->newtlb = 1;
5689ef1f84bSDavid du Colombier ok = 1;
5699ef1f84bSDavid du Colombier }
5709ef1f84bSDavid du Colombier else
5719ef1f84bSDavid du Colombier ok = 0;
5729ef1f84bSDavid du Colombier unlock(runq);
5739ef1f84bSDavid du Colombier spllo();
5749ef1f84bSDavid du Colombier
5759ef1f84bSDavid du Colombier return ok;
5769ef1f84bSDavid du Colombier }
5779ef1f84bSDavid du Colombier
5789ef1f84bSDavid du Colombier Proc*
newproc(void)5799ef1f84bSDavid du Colombier newproc(void)
5809ef1f84bSDavid du Colombier {
5819ef1f84bSDavid du Colombier Proc *p;
5829ef1f84bSDavid du Colombier
5839ef1f84bSDavid du Colombier p = psalloc();
5849ef1f84bSDavid du Colombier
5859ef1f84bSDavid du Colombier p->state = Scheding;
5869ef1f84bSDavid du Colombier p->psstate = "New";
587*4498a243SDavid du Colombier p->mach = nil;
588*4498a243SDavid du Colombier p->qnext = nil;
5899ef1f84bSDavid du Colombier p->nchild = 0;
5909ef1f84bSDavid du Colombier p->nwait = 0;
591*4498a243SDavid du Colombier p->waitq = nil;
592*4498a243SDavid du Colombier p->parent = nil;
593*4498a243SDavid du Colombier p->pgrp = nil;
594*4498a243SDavid du Colombier p->egrp = nil;
595*4498a243SDavid du Colombier p->fgrp = nil;
596*4498a243SDavid du Colombier p->rgrp = nil;
5979ef1f84bSDavid du Colombier p->pdbg = 0;
5989ef1f84bSDavid du Colombier p->kp = 0;
5999ef1f84bSDavid du Colombier if(up != nil && up->procctl == Proc_tracesyscall)
6009ef1f84bSDavid du Colombier p->procctl = Proc_tracesyscall;
6019ef1f84bSDavid du Colombier else
6029ef1f84bSDavid du Colombier p->procctl = 0;
6039ef1f84bSDavid du Colombier p->syscalltrace = nil;
6049ef1f84bSDavid du Colombier p->notepending = 0;
605*4498a243SDavid du Colombier p->ureg = nil;
6069ef1f84bSDavid du Colombier p->privatemem = 0;
6079ef1f84bSDavid du Colombier p->errstr = p->errbuf0;
6089ef1f84bSDavid du Colombier p->syserrstr = p->errbuf1;
6099ef1f84bSDavid du Colombier p->errbuf0[0] = '\0';
6109ef1f84bSDavid du Colombier p->errbuf1[0] = '\0';
6119ef1f84bSDavid du Colombier p->nlocks = 0;
6129ef1f84bSDavid du Colombier p->delaysched = 0;
6139ef1f84bSDavid du Colombier p->trace = 0;
6149ef1f84bSDavid du Colombier kstrdup(&p->user, "*nouser");
6159ef1f84bSDavid du Colombier kstrdup(&p->text, "*notext");
6169ef1f84bSDavid du Colombier kstrdup(&p->args, "");
6179ef1f84bSDavid du Colombier p->nargs = 0;
6189ef1f84bSDavid du Colombier p->setargs = 0;
6199ef1f84bSDavid du Colombier memset(p->seg, 0, sizeof p->seg);
6209ef1f84bSDavid du Colombier p->pid = incref(&pidalloc);
6219ef1f84bSDavid du Colombier pshash(p);
6229ef1f84bSDavid du Colombier p->noteid = incref(¬eidalloc);
6239ef1f84bSDavid du Colombier if(p->pid <= 0 || p->noteid <= 0)
6249ef1f84bSDavid du Colombier panic("pidalloc");
625*4498a243SDavid du Colombier if(p->kstack == nil)
6269ef1f84bSDavid du Colombier p->kstack = smalloc(KSTACK);
6279ef1f84bSDavid du Colombier
6289ef1f84bSDavid du Colombier /* sched params */
629*4498a243SDavid du Colombier p->mp = nil;
630*4498a243SDavid du Colombier p->wired = nil;
6319ef1f84bSDavid du Colombier procpriority(p, PriNormal, 0);
6329ef1f84bSDavid du Colombier p->cpu = 0;
6339ef1f84bSDavid du Colombier p->lastupdate = sys->ticks*Scaling;
6349ef1f84bSDavid du Colombier p->edf = nil;
6359ef1f84bSDavid du Colombier
6369ef1f84bSDavid du Colombier return p;
6379ef1f84bSDavid du Colombier }
6389ef1f84bSDavid du Colombier
6399ef1f84bSDavid du Colombier /*
6409ef1f84bSDavid du Colombier * wire this proc to a machine
6419ef1f84bSDavid du Colombier */
6429ef1f84bSDavid du Colombier void
procwired(Proc * p,int bm)6439ef1f84bSDavid du Colombier procwired(Proc *p, int bm)
6449ef1f84bSDavid du Colombier {
6459ef1f84bSDavid du Colombier Proc *pp;
6469ef1f84bSDavid du Colombier int i;
6479ef1f84bSDavid du Colombier char nwired[MACHMAX];
6489ef1f84bSDavid du Colombier Mach *wm, *mp;
6499ef1f84bSDavid du Colombier
6509ef1f84bSDavid du Colombier if(bm < 0){
6519ef1f84bSDavid du Colombier /* pick a machine to wire to */
6529ef1f84bSDavid du Colombier memset(nwired, 0, sizeof(nwired));
653*4498a243SDavid du Colombier p->wired = nil;
6549ef1f84bSDavid du Colombier for(i=0; (pp = psincref(i)) != nil; i++){
6559ef1f84bSDavid du Colombier wm = pp->wired;
6569ef1f84bSDavid du Colombier if(wm && pp->pid)
6579ef1f84bSDavid du Colombier nwired[wm->machno]++;
6589ef1f84bSDavid du Colombier psdecref(pp);
6599ef1f84bSDavid du Colombier }
6609ef1f84bSDavid du Colombier bm = 0;
6619ef1f84bSDavid du Colombier for(i=0; i<MACHMAX; i++){
6629ef1f84bSDavid du Colombier if((mp = sys->machptr[i]) == nil || !mp->online)
6639ef1f84bSDavid du Colombier continue;
6649ef1f84bSDavid du Colombier if(nwired[i] < nwired[bm])
6659ef1f84bSDavid du Colombier bm = i;
6669ef1f84bSDavid du Colombier }
6679ef1f84bSDavid du Colombier } else {
6689ef1f84bSDavid du Colombier /* use the virtual machine requested */
6699ef1f84bSDavid du Colombier bm = bm % MACHMAX;
6709ef1f84bSDavid du Colombier }
6719ef1f84bSDavid du Colombier
6729ef1f84bSDavid du Colombier p->wired = sys->machptr[bm];
6739ef1f84bSDavid du Colombier p->mp = p->wired;
6749ef1f84bSDavid du Colombier }
6759ef1f84bSDavid du Colombier
6769ef1f84bSDavid du Colombier void
procpriority(Proc * p,int pri,int fixed)6779ef1f84bSDavid du Colombier procpriority(Proc *p, int pri, int fixed)
6789ef1f84bSDavid du Colombier {
6799ef1f84bSDavid du Colombier if(pri >= Npriq)
6809ef1f84bSDavid du Colombier pri = Npriq - 1;
6819ef1f84bSDavid du Colombier else if(pri < 0)
6829ef1f84bSDavid du Colombier pri = 0;
6839ef1f84bSDavid du Colombier p->basepri = pri;
6849ef1f84bSDavid du Colombier p->priority = pri;
6859ef1f84bSDavid du Colombier if(fixed){
6869ef1f84bSDavid du Colombier p->fixedpri = 1;
6879ef1f84bSDavid du Colombier } else {
6889ef1f84bSDavid du Colombier p->fixedpri = 0;
6899ef1f84bSDavid du Colombier }
6909ef1f84bSDavid du Colombier }
6919ef1f84bSDavid du Colombier
6929ef1f84bSDavid du Colombier /*
6939ef1f84bSDavid du Colombier * sleep if a condition is not true. Another process will
6949ef1f84bSDavid du Colombier * awaken us after it sets the condition. When we awaken
6959ef1f84bSDavid du Colombier * the condition may no longer be true.
6969ef1f84bSDavid du Colombier *
6979ef1f84bSDavid du Colombier * we lock both the process and the rendezvous to keep r->p
6989ef1f84bSDavid du Colombier * and p->r synchronized.
6999ef1f84bSDavid du Colombier */
7009ef1f84bSDavid du Colombier void
sleep(Rendez * r,int (* f)(void *),void * arg)7019ef1f84bSDavid du Colombier sleep(Rendez *r, int (*f)(void*), void *arg)
7029ef1f84bSDavid du Colombier {
7039ef1f84bSDavid du Colombier Mreg s;
704d46407a3SDavid du Colombier void (*pt)(Proc*, int, vlong, vlong);
7059ef1f84bSDavid du Colombier
7069ef1f84bSDavid du Colombier s = splhi();
7079ef1f84bSDavid du Colombier
7089ef1f84bSDavid du Colombier if(up->nlocks)
7099ef1f84bSDavid du Colombier print("process %d sleeps with %d locks held, last lock %#p locked at pc %#p, sleep called from %#p\n",
7109ef1f84bSDavid du Colombier up->pid, up->nlocks, up->lastlock, up->lastlock->pc, getcallerpc(&r));
7119ef1f84bSDavid du Colombier lock(r);
7129ef1f84bSDavid du Colombier lock(&up->rlock);
7139ef1f84bSDavid du Colombier if(r->p){
7149ef1f84bSDavid du Colombier print("double sleep called from %#p, %d %d\n",
7159ef1f84bSDavid du Colombier getcallerpc(&r), r->p->pid, up->pid);
7169ef1f84bSDavid du Colombier dumpstack();
7179ef1f84bSDavid du Colombier }
7189ef1f84bSDavid du Colombier
7199ef1f84bSDavid du Colombier /*
7209ef1f84bSDavid du Colombier * Wakeup only knows there may be something to do by testing
7219ef1f84bSDavid du Colombier * r->p in order to get something to lock on.
7229ef1f84bSDavid du Colombier * Flush that information out to memory in case the sleep is
7239ef1f84bSDavid du Colombier * committed.
7249ef1f84bSDavid du Colombier */
7259ef1f84bSDavid du Colombier r->p = up;
7269ef1f84bSDavid du Colombier
7279ef1f84bSDavid du Colombier if((*f)(arg) || up->notepending){
7289ef1f84bSDavid du Colombier /*
7299ef1f84bSDavid du Colombier * if condition happened or a note is pending
7309ef1f84bSDavid du Colombier * never mind
7319ef1f84bSDavid du Colombier */
7329ef1f84bSDavid du Colombier r->p = nil;
7339ef1f84bSDavid du Colombier unlock(&up->rlock);
7349ef1f84bSDavid du Colombier unlock(r);
7359ef1f84bSDavid du Colombier } else {
7369ef1f84bSDavid du Colombier /*
7379ef1f84bSDavid du Colombier * now we are committed to
7389ef1f84bSDavid du Colombier * change state and call scheduler
7399ef1f84bSDavid du Colombier */
7409ef1f84bSDavid du Colombier pt = proctrace;
7419ef1f84bSDavid du Colombier if(pt)
742d46407a3SDavid du Colombier pt(up, SSleep, 0, 0);
7439ef1f84bSDavid du Colombier up->state = Wakeme;
7449ef1f84bSDavid du Colombier up->r = r;
7459ef1f84bSDavid du Colombier
7469ef1f84bSDavid du Colombier /* statistics */
7479ef1f84bSDavid du Colombier m->cs++;
7489ef1f84bSDavid du Colombier
7499ef1f84bSDavid du Colombier procsave(up);
7509ef1f84bSDavid du Colombier if(setlabel(&up->sched)) {
7519ef1f84bSDavid du Colombier /*
7529ef1f84bSDavid du Colombier * here when the process is awakened
7539ef1f84bSDavid du Colombier */
7549ef1f84bSDavid du Colombier procrestore(up);
7559ef1f84bSDavid du Colombier spllo();
7569ef1f84bSDavid du Colombier } else {
7579ef1f84bSDavid du Colombier /*
7589ef1f84bSDavid du Colombier * here to go to sleep (i.e. stop Running)
7599ef1f84bSDavid du Colombier */
7609ef1f84bSDavid du Colombier unlock(&up->rlock);
7619ef1f84bSDavid du Colombier unlock(r);
7629ef1f84bSDavid du Colombier gotolabel(&m->sched);
7639ef1f84bSDavid du Colombier }
7649ef1f84bSDavid du Colombier }
7659ef1f84bSDavid du Colombier
7669ef1f84bSDavid du Colombier if(up->notepending) {
7679ef1f84bSDavid du Colombier up->notepending = 0;
7689ef1f84bSDavid du Colombier splx(s);
7699ef1f84bSDavid du Colombier if(up->procctl == Proc_exitme && up->closingfgrp)
7709ef1f84bSDavid du Colombier forceclosefgrp();
7719ef1f84bSDavid du Colombier error(Eintr);
7729ef1f84bSDavid du Colombier }
7739ef1f84bSDavid du Colombier
7749ef1f84bSDavid du Colombier splx(s);
7759ef1f84bSDavid du Colombier }
7769ef1f84bSDavid du Colombier
7779ef1f84bSDavid du Colombier static int
tfn(void * arg)7789ef1f84bSDavid du Colombier tfn(void *arg)
7799ef1f84bSDavid du Colombier {
7809ef1f84bSDavid du Colombier return up->trend == nil || up->tfn(arg);
7819ef1f84bSDavid du Colombier }
7829ef1f84bSDavid du Colombier
7839ef1f84bSDavid du Colombier void
twakeup(Ureg *,Timer * t)7849ef1f84bSDavid du Colombier twakeup(Ureg*, Timer *t)
7859ef1f84bSDavid du Colombier {
7869ef1f84bSDavid du Colombier Proc *p;
7879ef1f84bSDavid du Colombier Rendez *trend;
7889ef1f84bSDavid du Colombier
7899ef1f84bSDavid du Colombier p = t->ta;
7909ef1f84bSDavid du Colombier trend = p->trend;
7919ef1f84bSDavid du Colombier p->trend = 0;
7929ef1f84bSDavid du Colombier if(trend)
7939ef1f84bSDavid du Colombier wakeup(trend);
7949ef1f84bSDavid du Colombier }
7959ef1f84bSDavid du Colombier
7969ef1f84bSDavid du Colombier void
tsleep(Rendez * r,int (* fn)(void *),void * arg,long ms)7979ef1f84bSDavid du Colombier tsleep(Rendez *r, int (*fn)(void*), void *arg, long ms)
7989ef1f84bSDavid du Colombier {
7999ef1f84bSDavid du Colombier if (up->tt){
8009ef1f84bSDavid du Colombier print("tsleep: timer active: mode %d, tf %#p\n",
8019ef1f84bSDavid du Colombier up->tmode, up->tf);
8029ef1f84bSDavid du Colombier timerdel(up);
8039ef1f84bSDavid du Colombier }
8049ef1f84bSDavid du Colombier up->tns = MS2NS(ms);
8059ef1f84bSDavid du Colombier up->tf = twakeup;
8069ef1f84bSDavid du Colombier up->tmode = Trelative;
8079ef1f84bSDavid du Colombier up->ta = up;
8089ef1f84bSDavid du Colombier up->trend = r;
8099ef1f84bSDavid du Colombier up->tfn = fn;
8109ef1f84bSDavid du Colombier timeradd(up);
8119ef1f84bSDavid du Colombier
8129ef1f84bSDavid du Colombier if(waserror()){
8139ef1f84bSDavid du Colombier timerdel(up);
8149ef1f84bSDavid du Colombier nexterror();
8159ef1f84bSDavid du Colombier }
8169ef1f84bSDavid du Colombier sleep(r, tfn, arg);
8179ef1f84bSDavid du Colombier if (up->tt)
8189ef1f84bSDavid du Colombier timerdel(up);
8199ef1f84bSDavid du Colombier up->twhen = 0;
8209ef1f84bSDavid du Colombier poperror();
8219ef1f84bSDavid du Colombier }
8229ef1f84bSDavid du Colombier
8239ef1f84bSDavid du Colombier /*
8249ef1f84bSDavid du Colombier * Expects that only one process can call wakeup for any given Rendez.
8259ef1f84bSDavid du Colombier * We hold both locks to ensure that r->p and p->r remain consistent.
8269ef1f84bSDavid du Colombier * Richard Miller has a better solution that doesn't require both to
8279ef1f84bSDavid du Colombier * be held simultaneously, but I'm a paranoid - presotto.
8289ef1f84bSDavid du Colombier */
8299ef1f84bSDavid du Colombier Proc*
wakeup(Rendez * r)8309ef1f84bSDavid du Colombier wakeup(Rendez *r)
8319ef1f84bSDavid du Colombier {
8329ef1f84bSDavid du Colombier Mreg s;
8339ef1f84bSDavid du Colombier Proc *p;
8349ef1f84bSDavid du Colombier
8359ef1f84bSDavid du Colombier s = splhi();
8369ef1f84bSDavid du Colombier
8379ef1f84bSDavid du Colombier lock(r);
8389ef1f84bSDavid du Colombier p = r->p;
8399ef1f84bSDavid du Colombier
8409ef1f84bSDavid du Colombier if(p != nil){
8419ef1f84bSDavid du Colombier lock(&p->rlock);
8429ef1f84bSDavid du Colombier if(p->state != Wakeme || p->r != r)
8439ef1f84bSDavid du Colombier panic("wakeup: state");
8449ef1f84bSDavid du Colombier r->p = nil;
8459ef1f84bSDavid du Colombier p->r = nil;
8469ef1f84bSDavid du Colombier ready(p);
8479ef1f84bSDavid du Colombier unlock(&p->rlock);
8489ef1f84bSDavid du Colombier }
8499ef1f84bSDavid du Colombier unlock(r);
8509ef1f84bSDavid du Colombier
8519ef1f84bSDavid du Colombier splx(s);
8529ef1f84bSDavid du Colombier
8539ef1f84bSDavid du Colombier return p;
8549ef1f84bSDavid du Colombier }
8559ef1f84bSDavid du Colombier
8569ef1f84bSDavid du Colombier /*
8579ef1f84bSDavid du Colombier * if waking a sleeping process, this routine must hold both
8589ef1f84bSDavid du Colombier * p->rlock and r->lock. However, it can't know them in
8599ef1f84bSDavid du Colombier * the same order as wakeup causing a possible lock ordering
8609ef1f84bSDavid du Colombier * deadlock. We break the deadlock by giving up the p->rlock
8619ef1f84bSDavid du Colombier * lock if we can't get the r->lock and retrying.
8629ef1f84bSDavid du Colombier */
8639ef1f84bSDavid du Colombier int
postnote(Proc * p,int dolock,char * n,int flag)8649ef1f84bSDavid du Colombier postnote(Proc *p, int dolock, char *n, int flag)
8659ef1f84bSDavid du Colombier {
8669ef1f84bSDavid du Colombier Mreg s;
8679ef1f84bSDavid du Colombier int ret;
8689ef1f84bSDavid du Colombier Rendez *r;
8699ef1f84bSDavid du Colombier Proc *d, **l;
8709ef1f84bSDavid du Colombier
8719ef1f84bSDavid du Colombier if(dolock && m->ilockdepth != 0)
8729ef1f84bSDavid du Colombier panic("postnote: caller %#p: ilockdepth %d note %s",
8739ef1f84bSDavid du Colombier getcallerpc(&p), m->ilockdepth, n);
8749ef1f84bSDavid du Colombier if(dolock)
8759ef1f84bSDavid du Colombier qlock(&p->debug);
8769ef1f84bSDavid du Colombier
877*4498a243SDavid du Colombier if(flag != NUser && (p->notify == nil || p->notified))
8789ef1f84bSDavid du Colombier p->nnote = 0;
8799ef1f84bSDavid du Colombier
8809ef1f84bSDavid du Colombier ret = 0;
8819ef1f84bSDavid du Colombier if(p->nnote < NNOTE) {
8829ef1f84bSDavid du Colombier strcpy(p->note[p->nnote].msg, n);
8839ef1f84bSDavid du Colombier p->note[p->nnote++].flag = flag;
8849ef1f84bSDavid du Colombier ret = 1;
8859ef1f84bSDavid du Colombier }
8869ef1f84bSDavid du Colombier p->notepending = 1;
8879ef1f84bSDavid du Colombier if(dolock)
8889ef1f84bSDavid du Colombier qunlock(&p->debug);
8899ef1f84bSDavid du Colombier
8909ef1f84bSDavid du Colombier /* this loop is to avoid lock ordering problems. */
8919ef1f84bSDavid du Colombier for(;;){
8929ef1f84bSDavid du Colombier s = splhi();
8939ef1f84bSDavid du Colombier lock(&p->rlock);
8949ef1f84bSDavid du Colombier r = p->r;
8959ef1f84bSDavid du Colombier
8969ef1f84bSDavid du Colombier /* waiting for a wakeup? */
8979ef1f84bSDavid du Colombier if(r == nil)
8989ef1f84bSDavid du Colombier break; /* no */
8999ef1f84bSDavid du Colombier
9009ef1f84bSDavid du Colombier /* try for the second lock */
9019ef1f84bSDavid du Colombier if(canlock(r)){
9029ef1f84bSDavid du Colombier if(p->state != Wakeme || r->p != p)
9039ef1f84bSDavid du Colombier panic("postnote: state %d %d %d", r->p != p, p->r != r, p->state);
9049ef1f84bSDavid du Colombier p->r = nil;
9059ef1f84bSDavid du Colombier r->p = nil;
9069ef1f84bSDavid du Colombier ready(p);
9079ef1f84bSDavid du Colombier unlock(r);
9089ef1f84bSDavid du Colombier break;
9099ef1f84bSDavid du Colombier }
9109ef1f84bSDavid du Colombier
9119ef1f84bSDavid du Colombier /* give other process time to get out of critical section and try again */
9129ef1f84bSDavid du Colombier unlock(&p->rlock);
9139ef1f84bSDavid du Colombier splx(s);
9149ef1f84bSDavid du Colombier sched();
9159ef1f84bSDavid du Colombier }
9169ef1f84bSDavid du Colombier unlock(&p->rlock);
9179ef1f84bSDavid du Colombier splx(s);
9189ef1f84bSDavid du Colombier
9199ef1f84bSDavid du Colombier if(p->state != Rendezvous)
9209ef1f84bSDavid du Colombier return ret;
9219ef1f84bSDavid du Colombier
9229ef1f84bSDavid du Colombier /* Try and pull out of a rendezvous */
9239ef1f84bSDavid du Colombier lock(p->rgrp);
9249ef1f84bSDavid du Colombier if(p->state == Rendezvous) {
9259ef1f84bSDavid du Colombier p->rendval = ~0;
9269ef1f84bSDavid du Colombier l = &REND(p->rgrp, p->rendtag);
9279ef1f84bSDavid du Colombier for(d = *l; d; d = d->rendhash) {
9289ef1f84bSDavid du Colombier if(d == p) {
9299ef1f84bSDavid du Colombier *l = p->rendhash;
9309ef1f84bSDavid du Colombier break;
9319ef1f84bSDavid du Colombier }
9329ef1f84bSDavid du Colombier l = &d->rendhash;
9339ef1f84bSDavid du Colombier }
9349ef1f84bSDavid du Colombier ready(p);
9359ef1f84bSDavid du Colombier }
9369ef1f84bSDavid du Colombier unlock(p->rgrp);
9379ef1f84bSDavid du Colombier return ret;
9389ef1f84bSDavid du Colombier }
9399ef1f84bSDavid du Colombier
9409ef1f84bSDavid du Colombier /*
9419ef1f84bSDavid du Colombier * weird thing: keep at most NBROKEN around
9429ef1f84bSDavid du Colombier */
9439ef1f84bSDavid du Colombier #define NBROKEN 4
9449ef1f84bSDavid du Colombier struct
9459ef1f84bSDavid du Colombier {
9469ef1f84bSDavid du Colombier QLock;
9479ef1f84bSDavid du Colombier int n;
9489ef1f84bSDavid du Colombier Proc *p[NBROKEN];
9499ef1f84bSDavid du Colombier }broken;
9509ef1f84bSDavid du Colombier
9519ef1f84bSDavid du Colombier void
addbroken(Proc * p)9529ef1f84bSDavid du Colombier addbroken(Proc *p)
9539ef1f84bSDavid du Colombier {
9549ef1f84bSDavid du Colombier qlock(&broken);
9559ef1f84bSDavid du Colombier if(broken.n == NBROKEN) {
9569ef1f84bSDavid du Colombier ready(broken.p[0]);
9579ef1f84bSDavid du Colombier memmove(&broken.p[0], &broken.p[1], sizeof(Proc*)*(NBROKEN-1));
9589ef1f84bSDavid du Colombier --broken.n;
9599ef1f84bSDavid du Colombier }
9609ef1f84bSDavid du Colombier broken.p[broken.n++] = p;
9619ef1f84bSDavid du Colombier qunlock(&broken);
9629ef1f84bSDavid du Colombier
9639ef1f84bSDavid du Colombier edfstop(up);
9649ef1f84bSDavid du Colombier p->state = Broken;
9659ef1f84bSDavid du Colombier p->psstate = 0;
9669ef1f84bSDavid du Colombier sched();
9679ef1f84bSDavid du Colombier }
9689ef1f84bSDavid du Colombier
9699ef1f84bSDavid du Colombier void
unbreak(Proc * p)9709ef1f84bSDavid du Colombier unbreak(Proc *p)
9719ef1f84bSDavid du Colombier {
9729ef1f84bSDavid du Colombier int b;
9739ef1f84bSDavid du Colombier
9749ef1f84bSDavid du Colombier qlock(&broken);
9759ef1f84bSDavid du Colombier for(b=0; b < broken.n; b++)
9769ef1f84bSDavid du Colombier if(broken.p[b] == p) {
9779ef1f84bSDavid du Colombier broken.n--;
9789ef1f84bSDavid du Colombier memmove(&broken.p[b], &broken.p[b+1],
9799ef1f84bSDavid du Colombier sizeof(Proc*)*(NBROKEN-(b+1)));
9809ef1f84bSDavid du Colombier ready(p);
9819ef1f84bSDavid du Colombier break;
9829ef1f84bSDavid du Colombier }
9839ef1f84bSDavid du Colombier qunlock(&broken);
9849ef1f84bSDavid du Colombier }
9859ef1f84bSDavid du Colombier
9869ef1f84bSDavid du Colombier int
freebroken(void)9879ef1f84bSDavid du Colombier freebroken(void)
9889ef1f84bSDavid du Colombier {
9899ef1f84bSDavid du Colombier int i, n;
9909ef1f84bSDavid du Colombier
9919ef1f84bSDavid du Colombier qlock(&broken);
9929ef1f84bSDavid du Colombier n = broken.n;
9939ef1f84bSDavid du Colombier for(i=0; i<n; i++) {
9949ef1f84bSDavid du Colombier ready(broken.p[i]);
9959ef1f84bSDavid du Colombier broken.p[i] = 0;
9969ef1f84bSDavid du Colombier }
9979ef1f84bSDavid du Colombier broken.n = 0;
9989ef1f84bSDavid du Colombier qunlock(&broken);
9999ef1f84bSDavid du Colombier return n;
10009ef1f84bSDavid du Colombier }
10019ef1f84bSDavid du Colombier
10029ef1f84bSDavid du Colombier void
pexit(char * exitstr,int freemem)10039ef1f84bSDavid du Colombier pexit(char *exitstr, int freemem)
10049ef1f84bSDavid du Colombier {
10059ef1f84bSDavid du Colombier Proc *p;
10069ef1f84bSDavid du Colombier Segment **s, **es;
10079ef1f84bSDavid du Colombier long utime, stime;
10089ef1f84bSDavid du Colombier Waitq *wq, *f, *next;
10099ef1f84bSDavid du Colombier Fgrp *fgrp;
10109ef1f84bSDavid du Colombier Egrp *egrp;
10119ef1f84bSDavid du Colombier Rgrp *rgrp;
10129ef1f84bSDavid du Colombier Pgrp *pgrp;
10139ef1f84bSDavid du Colombier Chan *dot;
1014d46407a3SDavid du Colombier void (*pt)(Proc*, int, vlong, vlong);
10159ef1f84bSDavid du Colombier
10169ef1f84bSDavid du Colombier if(up->syscalltrace != nil)
10179ef1f84bSDavid du Colombier free(up->syscalltrace);
10189ef1f84bSDavid du Colombier up->syscalltrace = nil;
10199ef1f84bSDavid du Colombier up->alarm = 0;
10209ef1f84bSDavid du Colombier if (up->tt)
10219ef1f84bSDavid du Colombier timerdel(up);
10229ef1f84bSDavid du Colombier pt = proctrace;
10239ef1f84bSDavid du Colombier if(pt)
1024d46407a3SDavid du Colombier pt(up, SDead, 0, 0);
10259ef1f84bSDavid du Colombier
10269ef1f84bSDavid du Colombier /* nil out all the resources under lock (free later) */
10279ef1f84bSDavid du Colombier qlock(&up->debug);
10289ef1f84bSDavid du Colombier fgrp = up->fgrp;
10299ef1f84bSDavid du Colombier up->fgrp = nil;
10309ef1f84bSDavid du Colombier egrp = up->egrp;
10319ef1f84bSDavid du Colombier up->egrp = nil;
10329ef1f84bSDavid du Colombier rgrp = up->rgrp;
10339ef1f84bSDavid du Colombier up->rgrp = nil;
10349ef1f84bSDavid du Colombier pgrp = up->pgrp;
10359ef1f84bSDavid du Colombier up->pgrp = nil;
10369ef1f84bSDavid du Colombier dot = up->dot;
10379ef1f84bSDavid du Colombier up->dot = nil;
10389ef1f84bSDavid du Colombier qunlock(&up->debug);
10399ef1f84bSDavid du Colombier
10409ef1f84bSDavid du Colombier if(fgrp)
10419ef1f84bSDavid du Colombier closefgrp(fgrp);
10429ef1f84bSDavid du Colombier if(egrp)
10439ef1f84bSDavid du Colombier closeegrp(egrp);
10449ef1f84bSDavid du Colombier if(rgrp)
10459ef1f84bSDavid du Colombier closergrp(rgrp);
10469ef1f84bSDavid du Colombier if(dot)
10479ef1f84bSDavid du Colombier cclose(dot);
10489ef1f84bSDavid du Colombier if(pgrp)
10499ef1f84bSDavid du Colombier closepgrp(pgrp);
10509ef1f84bSDavid du Colombier
10519ef1f84bSDavid du Colombier /*
10529ef1f84bSDavid du Colombier * if not a kernel process and have a parent,
10539ef1f84bSDavid du Colombier * do some housekeeping.
10549ef1f84bSDavid du Colombier */
10559ef1f84bSDavid du Colombier if(up->kp == 0) {
10569ef1f84bSDavid du Colombier p = up->parent;
1057*4498a243SDavid du Colombier if(p == nil) {
1058*4498a243SDavid du Colombier if(exitstr == nil)
10599ef1f84bSDavid du Colombier exitstr = "unknown";
10609ef1f84bSDavid du Colombier panic("boot process died: %s", exitstr);
10619ef1f84bSDavid du Colombier }
10629ef1f84bSDavid du Colombier
10639ef1f84bSDavid du Colombier while(waserror())
10649ef1f84bSDavid du Colombier ;
10659ef1f84bSDavid du Colombier
10669ef1f84bSDavid du Colombier wq = smalloc(sizeof(Waitq));
10679ef1f84bSDavid du Colombier poperror();
10689ef1f84bSDavid du Colombier
10699ef1f84bSDavid du Colombier wq->w.pid = up->pid;
10709ef1f84bSDavid du Colombier utime = up->time[TUser] + up->time[TCUser];
10719ef1f84bSDavid du Colombier stime = up->time[TSys] + up->time[TCSys];
10729ef1f84bSDavid du Colombier wq->w.time[TUser] = tk2ms(utime);
10739ef1f84bSDavid du Colombier wq->w.time[TSys] = tk2ms(stime);
10749ef1f84bSDavid du Colombier wq->w.time[TReal] = tk2ms(sys->ticks - up->time[TReal]);
10759ef1f84bSDavid du Colombier if(exitstr && exitstr[0])
10769ef1f84bSDavid du Colombier snprint(wq->w.msg, sizeof(wq->w.msg), "%s %d: %s",
10779ef1f84bSDavid du Colombier up->text, up->pid, exitstr);
10789ef1f84bSDavid du Colombier else
10799ef1f84bSDavid du Colombier wq->w.msg[0] = '\0';
10809ef1f84bSDavid du Colombier
10819ef1f84bSDavid du Colombier lock(&p->exl);
10829ef1f84bSDavid du Colombier /*
10839ef1f84bSDavid du Colombier * Check that parent is still alive.
10849ef1f84bSDavid du Colombier */
10859ef1f84bSDavid du Colombier if(p->pid == up->parentpid && p->state != Broken) {
10869ef1f84bSDavid du Colombier p->nchild--;
10879ef1f84bSDavid du Colombier p->time[TCUser] += utime;
10889ef1f84bSDavid du Colombier p->time[TCSys] += stime;
10899ef1f84bSDavid du Colombier /*
10909ef1f84bSDavid du Colombier * If there would be more than 128 wait records
10919ef1f84bSDavid du Colombier * processes for my parent, then don't leave a wait
10929ef1f84bSDavid du Colombier * record behind. This helps prevent badly written
10939ef1f84bSDavid du Colombier * daemon processes from accumulating lots of wait
10949ef1f84bSDavid du Colombier * records.
10959ef1f84bSDavid du Colombier */
10969ef1f84bSDavid du Colombier if(p->nwait < 128) {
10979ef1f84bSDavid du Colombier wq->next = p->waitq;
10989ef1f84bSDavid du Colombier p->waitq = wq;
10999ef1f84bSDavid du Colombier p->nwait++;
11009ef1f84bSDavid du Colombier wq = nil;
11019ef1f84bSDavid du Colombier wakeup(&p->waitr);
11029ef1f84bSDavid du Colombier }
11039ef1f84bSDavid du Colombier }
11049ef1f84bSDavid du Colombier unlock(&p->exl);
11059ef1f84bSDavid du Colombier if(wq)
11069ef1f84bSDavid du Colombier free(wq);
11079ef1f84bSDavid du Colombier }
11089ef1f84bSDavid du Colombier
11099ef1f84bSDavid du Colombier if(!freemem)
11109ef1f84bSDavid du Colombier addbroken(up);
11119ef1f84bSDavid du Colombier
11129ef1f84bSDavid du Colombier qlock(&up->seglock);
11139ef1f84bSDavid du Colombier es = &up->seg[NSEG];
11149ef1f84bSDavid du Colombier for(s = up->seg; s < es; s++) {
11159ef1f84bSDavid du Colombier if(*s) {
11169ef1f84bSDavid du Colombier putseg(*s);
11179ef1f84bSDavid du Colombier *s = 0;
11189ef1f84bSDavid du Colombier }
11199ef1f84bSDavid du Colombier }
11209ef1f84bSDavid du Colombier qunlock(&up->seglock);
11219ef1f84bSDavid du Colombier
11229ef1f84bSDavid du Colombier lock(&up->exl); /* Prevent my children from leaving waits */
11239ef1f84bSDavid du Colombier psunhash(up);
11249ef1f84bSDavid du Colombier up->pid = 0;
11259ef1f84bSDavid du Colombier wakeup(&up->waitr);
11269ef1f84bSDavid du Colombier unlock(&up->exl);
11279ef1f84bSDavid du Colombier
11289ef1f84bSDavid du Colombier for(f = up->waitq; f; f = next) {
11299ef1f84bSDavid du Colombier next = f->next;
11309ef1f84bSDavid du Colombier free(f);
11319ef1f84bSDavid du Colombier }
11329ef1f84bSDavid du Colombier
11339ef1f84bSDavid du Colombier /* release debuggers */
11349ef1f84bSDavid du Colombier qlock(&up->debug);
11359ef1f84bSDavid du Colombier if(up->pdbg) {
11369ef1f84bSDavid du Colombier wakeup(&up->pdbg->sleep);
11379ef1f84bSDavid du Colombier up->pdbg = 0;
11389ef1f84bSDavid du Colombier }
11399ef1f84bSDavid du Colombier qunlock(&up->debug);
11409ef1f84bSDavid du Colombier
11419ef1f84bSDavid du Colombier edfstop(up);
1142*4498a243SDavid du Colombier if(up->edf != nil){
11439ef1f84bSDavid du Colombier free(up->edf);
11449ef1f84bSDavid du Colombier up->edf = nil;
11459ef1f84bSDavid du Colombier }
11469ef1f84bSDavid du Colombier
11479ef1f84bSDavid du Colombier /* Sched must not loop for these locks */
11489ef1f84bSDavid du Colombier lock(&procalloc);
11499ef1f84bSDavid du Colombier lock(&palloc);
11509ef1f84bSDavid du Colombier
11519ef1f84bSDavid du Colombier up->state = Moribund;
11529ef1f84bSDavid du Colombier sched();
11539ef1f84bSDavid du Colombier panic("pexit");
11549ef1f84bSDavid du Colombier }
11559ef1f84bSDavid du Colombier
11569ef1f84bSDavid du Colombier int
haswaitq(void * x)11579ef1f84bSDavid du Colombier haswaitq(void *x)
11589ef1f84bSDavid du Colombier {
11599ef1f84bSDavid du Colombier Proc *p;
11609ef1f84bSDavid du Colombier
11619ef1f84bSDavid du Colombier p = (Proc *)x;
11629ef1f84bSDavid du Colombier return p->waitq != 0;
11639ef1f84bSDavid du Colombier }
11649ef1f84bSDavid du Colombier
11659ef1f84bSDavid du Colombier int
pwait(Waitmsg * w)11669ef1f84bSDavid du Colombier pwait(Waitmsg *w)
11679ef1f84bSDavid du Colombier {
11689ef1f84bSDavid du Colombier int cpid;
11699ef1f84bSDavid du Colombier Waitq *wq;
11709ef1f84bSDavid du Colombier
11719ef1f84bSDavid du Colombier if(!canqlock(&up->qwaitr))
11729ef1f84bSDavid du Colombier error(Einuse);
11739ef1f84bSDavid du Colombier
11749ef1f84bSDavid du Colombier if(waserror()) {
11759ef1f84bSDavid du Colombier qunlock(&up->qwaitr);
11769ef1f84bSDavid du Colombier nexterror();
11779ef1f84bSDavid du Colombier }
11789ef1f84bSDavid du Colombier
11799ef1f84bSDavid du Colombier lock(&up->exl);
1180*4498a243SDavid du Colombier if(up->nchild == 0 && up->waitq == nil) {
11819ef1f84bSDavid du Colombier unlock(&up->exl);
11829ef1f84bSDavid du Colombier error(Enochild);
11839ef1f84bSDavid du Colombier }
11849ef1f84bSDavid du Colombier unlock(&up->exl);
11859ef1f84bSDavid du Colombier
11869ef1f84bSDavid du Colombier sleep(&up->waitr, haswaitq, up);
11879ef1f84bSDavid du Colombier
11889ef1f84bSDavid du Colombier lock(&up->exl);
11899ef1f84bSDavid du Colombier wq = up->waitq;
11909ef1f84bSDavid du Colombier up->waitq = wq->next;
11919ef1f84bSDavid du Colombier up->nwait--;
11929ef1f84bSDavid du Colombier unlock(&up->exl);
11939ef1f84bSDavid du Colombier
11949ef1f84bSDavid du Colombier qunlock(&up->qwaitr);
11959ef1f84bSDavid du Colombier poperror();
11969ef1f84bSDavid du Colombier
11979ef1f84bSDavid du Colombier if(w)
11989ef1f84bSDavid du Colombier memmove(w, &wq->w, sizeof(Waitmsg));
11999ef1f84bSDavid du Colombier cpid = wq->w.pid;
12009ef1f84bSDavid du Colombier free(wq);
12019ef1f84bSDavid du Colombier
12029ef1f84bSDavid du Colombier return cpid;
12039ef1f84bSDavid du Colombier }
12049ef1f84bSDavid du Colombier
12059ef1f84bSDavid du Colombier void
dumpaproc(Proc * p)12069ef1f84bSDavid du Colombier dumpaproc(Proc *p)
12079ef1f84bSDavid du Colombier {
12089ef1f84bSDavid du Colombier uintptr bss;
12099ef1f84bSDavid du Colombier char *s;
12109ef1f84bSDavid du Colombier
1211*4498a243SDavid du Colombier if(p == nil)
12129ef1f84bSDavid du Colombier return;
12139ef1f84bSDavid du Colombier
12149ef1f84bSDavid du Colombier bss = 0;
12159ef1f84bSDavid du Colombier if(p->seg[BSEG])
12169ef1f84bSDavid du Colombier bss = p->seg[BSEG]->top;
12179ef1f84bSDavid du Colombier
12189ef1f84bSDavid du Colombier s = p->psstate;
1219*4498a243SDavid du Colombier if(s == nil)
12209ef1f84bSDavid du Colombier s = statename[p->state];
12219ef1f84bSDavid du Colombier print("%3d:%10s pc %#p dbgpc %#p %8s (%s) ut %ld st %ld bss %#p qpc %#p nl %d nd %lud lpc %#p pri %lud\n",
12229ef1f84bSDavid du Colombier p->pid, p->text, p->pc, dbgpc(p), s, statename[p->state],
12239ef1f84bSDavid du Colombier p->time[0], p->time[1], bss, p->qpc, p->nlocks,
12249ef1f84bSDavid du Colombier p->delaysched, p->lastlock ? p->lastlock->pc : 0, p->priority);
12259ef1f84bSDavid du Colombier }
12269ef1f84bSDavid du Colombier
12279ef1f84bSDavid du Colombier void
procdump(void)12289ef1f84bSDavid du Colombier procdump(void)
12299ef1f84bSDavid du Colombier {
12309ef1f84bSDavid du Colombier int i;
12319ef1f84bSDavid du Colombier Proc *p;
12329ef1f84bSDavid du Colombier
1233*4498a243SDavid du Colombier if(up != nil)
12349ef1f84bSDavid du Colombier print("up %d\n", up->pid);
12359ef1f84bSDavid du Colombier else
12369ef1f84bSDavid du Colombier print("no current process\n");
12379ef1f84bSDavid du Colombier for(i=0; (p = psincref(i)) != nil; i++) {
12389ef1f84bSDavid du Colombier if(p->state != Dead)
12399ef1f84bSDavid du Colombier dumpaproc(p);
12409ef1f84bSDavid du Colombier psdecref(p);
12419ef1f84bSDavid du Colombier }
12429ef1f84bSDavid du Colombier }
12439ef1f84bSDavid du Colombier
12449ef1f84bSDavid du Colombier /*
12459ef1f84bSDavid du Colombier * wait till all processes have flushed their mmu
12466cbc2fb8SDavid du Colombier * state about segment s
12479ef1f84bSDavid du Colombier */
12489ef1f84bSDavid du Colombier void
procflushseg(Segment * s)12499ef1f84bSDavid du Colombier procflushseg(Segment *s)
12509ef1f84bSDavid du Colombier {
12519ef1f84bSDavid du Colombier int i, ns, nm, nwait;
12529ef1f84bSDavid du Colombier Proc *p;
12539ef1f84bSDavid du Colombier Mach *mp;
12549ef1f84bSDavid du Colombier
12559ef1f84bSDavid du Colombier /*
12569ef1f84bSDavid du Colombier * tell all processes with this
12579ef1f84bSDavid du Colombier * segment to flush their mmu's
12589ef1f84bSDavid du Colombier */
12599ef1f84bSDavid du Colombier nwait = 0;
12609ef1f84bSDavid du Colombier for(i=0; (p = psincref(i)) != nil; i++) {
12619ef1f84bSDavid du Colombier if(p->state == Dead){
12629ef1f84bSDavid du Colombier psdecref(p);
12639ef1f84bSDavid du Colombier continue;
12649ef1f84bSDavid du Colombier }
12659ef1f84bSDavid du Colombier for(ns = 0; ns < NSEG; ns++){
12669ef1f84bSDavid du Colombier if(p->seg[ns] == s){
12679ef1f84bSDavid du Colombier p->newtlb = 1;
12689ef1f84bSDavid du Colombier for(nm = 0; nm < MACHMAX; nm++){
12699ef1f84bSDavid du Colombier if((mp = sys->machptr[nm]) == nil || !mp->online)
12709ef1f84bSDavid du Colombier continue;
12719ef1f84bSDavid du Colombier if(mp->proc == p){
12729ef1f84bSDavid du Colombier mp->mmuflush = 1;
12739ef1f84bSDavid du Colombier nwait++;
12749ef1f84bSDavid du Colombier }
12759ef1f84bSDavid du Colombier }
12769ef1f84bSDavid du Colombier break;
12779ef1f84bSDavid du Colombier }
12789ef1f84bSDavid du Colombier }
12799ef1f84bSDavid du Colombier psdecref(p);
12809ef1f84bSDavid du Colombier }
12819ef1f84bSDavid du Colombier
12829ef1f84bSDavid du Colombier if(nwait == 0)
12839ef1f84bSDavid du Colombier return;
12849ef1f84bSDavid du Colombier
12859ef1f84bSDavid du Colombier /*
12869ef1f84bSDavid du Colombier * wait for all processors to take a clock interrupt
12879ef1f84bSDavid du Colombier * and flush their mmu's
12889ef1f84bSDavid du Colombier */
12899ef1f84bSDavid du Colombier for(i = 0; i < MACHMAX; i++){
12909ef1f84bSDavid du Colombier if((mp = sys->machptr[i]) == nil || !mp->online || mp == m)
12919ef1f84bSDavid du Colombier continue;
12929ef1f84bSDavid du Colombier while(mp->mmuflush)
12939ef1f84bSDavid du Colombier sched();
12949ef1f84bSDavid du Colombier }
12959ef1f84bSDavid du Colombier }
12969ef1f84bSDavid du Colombier
12979ef1f84bSDavid du Colombier void
scheddump(void)12989ef1f84bSDavid du Colombier scheddump(void)
12999ef1f84bSDavid du Colombier {
13009ef1f84bSDavid du Colombier Proc *p;
13019ef1f84bSDavid du Colombier Schedq *rq;
13029ef1f84bSDavid du Colombier
13039ef1f84bSDavid du Colombier for(rq = &runq[Nrq-1]; rq >= runq; rq--){
13049ef1f84bSDavid du Colombier if(rq->head == 0)
13059ef1f84bSDavid du Colombier continue;
13069ef1f84bSDavid du Colombier print("rq%ld:", rq-runq);
13079ef1f84bSDavid du Colombier for(p = rq->head; p; p = p->rnext)
13089ef1f84bSDavid du Colombier print(" %d(%lud)", p->pid, m->ticks - p->readytime);
13099ef1f84bSDavid du Colombier print("\n");
13109ef1f84bSDavid du Colombier delay(150);
13119ef1f84bSDavid du Colombier }
13129ef1f84bSDavid du Colombier print("nrdy %d\n", nrdy);
13139ef1f84bSDavid du Colombier }
13149ef1f84bSDavid du Colombier
13159ef1f84bSDavid du Colombier void
kproc(char * name,void (* func)(void *),void * arg)13169ef1f84bSDavid du Colombier kproc(char *name, void (*func)(void *), void *arg)
13179ef1f84bSDavid du Colombier {
13189ef1f84bSDavid du Colombier Proc *p;
13199ef1f84bSDavid du Colombier static Pgrp *kpgrp;
13209ef1f84bSDavid du Colombier
13219ef1f84bSDavid du Colombier p = newproc();
13229ef1f84bSDavid du Colombier p->psstate = 0;
13239ef1f84bSDavid du Colombier p->procmode = 0640;
13249ef1f84bSDavid du Colombier p->kp = 1;
13259ef1f84bSDavid du Colombier
13269ef1f84bSDavid du Colombier p->scallnr = up->scallnr;
13279ef1f84bSDavid du Colombier memmove(p->arg, up->arg, sizeof(up->arg));
13289ef1f84bSDavid du Colombier p->nerrlab = 0;
13299ef1f84bSDavid du Colombier p->slash = up->slash;
13309ef1f84bSDavid du Colombier p->dot = up->dot;
13319ef1f84bSDavid du Colombier if(p->dot)
13329ef1f84bSDavid du Colombier incref(p->dot);
13339ef1f84bSDavid du Colombier
13349ef1f84bSDavid du Colombier memmove(p->note, up->note, sizeof(p->note));
13359ef1f84bSDavid du Colombier p->nnote = up->nnote;
13369ef1f84bSDavid du Colombier p->notified = 0;
13379ef1f84bSDavid du Colombier p->lastnote = up->lastnote;
13389ef1f84bSDavid du Colombier p->notify = up->notify;
1339*4498a243SDavid du Colombier p->ureg = nil;
1340*4498a243SDavid du Colombier p->dbgreg = nil;
13419ef1f84bSDavid du Colombier
13429ef1f84bSDavid du Colombier procpriority(p, PriKproc, 0);
13439ef1f84bSDavid du Colombier
13449ef1f84bSDavid du Colombier kprocchild(p, func, arg);
13459ef1f84bSDavid du Colombier
13469ef1f84bSDavid du Colombier kstrdup(&p->user, eve);
13479ef1f84bSDavid du Colombier kstrdup(&p->text, name);
1348*4498a243SDavid du Colombier if(kpgrp == nil)
13499ef1f84bSDavid du Colombier kpgrp = newpgrp();
13509ef1f84bSDavid du Colombier p->pgrp = kpgrp;
13519ef1f84bSDavid du Colombier incref(kpgrp);
13529ef1f84bSDavid du Colombier
13539ef1f84bSDavid du Colombier memset(p->time, 0, sizeof(p->time));
13549ef1f84bSDavid du Colombier p->time[TReal] = sys->ticks;
13559ef1f84bSDavid du Colombier ready(p);
13569ef1f84bSDavid du Colombier }
13579ef1f84bSDavid du Colombier
13589ef1f84bSDavid du Colombier /*
13599ef1f84bSDavid du Colombier * called splhi() by notify(). See comment in notify for the
13609ef1f84bSDavid du Colombier * reasoning.
13619ef1f84bSDavid du Colombier */
13629ef1f84bSDavid du Colombier void
procctl(Proc * p)13639ef1f84bSDavid du Colombier procctl(Proc *p)
13649ef1f84bSDavid du Colombier {
13659ef1f84bSDavid du Colombier Mreg s;
13669ef1f84bSDavid du Colombier char *state;
13679ef1f84bSDavid du Colombier
13689ef1f84bSDavid du Colombier switch(p->procctl) {
13699ef1f84bSDavid du Colombier case Proc_exitbig:
13709ef1f84bSDavid du Colombier spllo();
13719ef1f84bSDavid du Colombier pexit("Killed: Insufficient physical memory", 1);
13729ef1f84bSDavid du Colombier
13739ef1f84bSDavid du Colombier case Proc_exitme:
13749ef1f84bSDavid du Colombier spllo(); /* pexit has locks in it */
13759ef1f84bSDavid du Colombier pexit("Killed", 1);
13769ef1f84bSDavid du Colombier
13779ef1f84bSDavid du Colombier case Proc_traceme:
13789ef1f84bSDavid du Colombier if(p->nnote == 0)
13799ef1f84bSDavid du Colombier return;
13809ef1f84bSDavid du Colombier /* No break */
13819ef1f84bSDavid du Colombier
13829ef1f84bSDavid du Colombier case Proc_stopme:
13839ef1f84bSDavid du Colombier p->procctl = 0;
13849ef1f84bSDavid du Colombier state = p->psstate;
13859ef1f84bSDavid du Colombier p->psstate = "Stopped";
13869ef1f84bSDavid du Colombier /* free a waiting debugger */
13879ef1f84bSDavid du Colombier s = spllo();
13889ef1f84bSDavid du Colombier qlock(&p->debug);
13899ef1f84bSDavid du Colombier if(p->pdbg) {
13909ef1f84bSDavid du Colombier wakeup(&p->pdbg->sleep);
13919ef1f84bSDavid du Colombier p->pdbg = 0;
13929ef1f84bSDavid du Colombier }
13939ef1f84bSDavid du Colombier qunlock(&p->debug);
13949ef1f84bSDavid du Colombier splhi();
13959ef1f84bSDavid du Colombier p->state = Stopped;
13969ef1f84bSDavid du Colombier sched();
13979ef1f84bSDavid du Colombier p->psstate = state;
13989ef1f84bSDavid du Colombier splx(s);
13999ef1f84bSDavid du Colombier return;
14009ef1f84bSDavid du Colombier }
14019ef1f84bSDavid du Colombier }
14029ef1f84bSDavid du Colombier
14039ef1f84bSDavid du Colombier void
error(char * err)14049ef1f84bSDavid du Colombier error(char *err)
14059ef1f84bSDavid du Colombier {
14069ef1f84bSDavid du Colombier spllo();
14079ef1f84bSDavid du Colombier
14089ef1f84bSDavid du Colombier assert(up->nerrlab < NERR);
14099ef1f84bSDavid du Colombier kstrcpy(up->errstr, err, ERRMAX);
14109ef1f84bSDavid du Colombier setlabel(&up->errlab[NERR-1]);
14119ef1f84bSDavid du Colombier nexterror();
14129ef1f84bSDavid du Colombier }
14139ef1f84bSDavid du Colombier
14149ef1f84bSDavid du Colombier void
nexterror(void)14159ef1f84bSDavid du Colombier nexterror(void)
14169ef1f84bSDavid du Colombier {
14179ef1f84bSDavid du Colombier gotolabel(&up->errlab[--up->nerrlab]);
14189ef1f84bSDavid du Colombier }
14199ef1f84bSDavid du Colombier
14209ef1f84bSDavid du Colombier void
exhausted(char * resource)14219ef1f84bSDavid du Colombier exhausted(char *resource)
14229ef1f84bSDavid du Colombier {
14239ef1f84bSDavid du Colombier char buf[ERRMAX];
14249ef1f84bSDavid du Colombier
1425406c76faSDavid du Colombier snprint(buf, sizeof buf, "no free %s", resource);
14269ef1f84bSDavid du Colombier iprint("%s\n", buf);
14279ef1f84bSDavid du Colombier error(buf);
14289ef1f84bSDavid du Colombier }
14299ef1f84bSDavid du Colombier
14309ef1f84bSDavid du Colombier void
killbig(char * why)14319ef1f84bSDavid du Colombier killbig(char *why)
14329ef1f84bSDavid du Colombier {
14339ef1f84bSDavid du Colombier int i, x;
14349ef1f84bSDavid du Colombier Segment *s;
14359ef1f84bSDavid du Colombier ulong l, max;
14369ef1f84bSDavid du Colombier Proc *p, *kp;
14379ef1f84bSDavid du Colombier
14389ef1f84bSDavid du Colombier max = 0;
14399ef1f84bSDavid du Colombier kp = nil;
14409ef1f84bSDavid du Colombier for(x = 0; (p = psincref(x)) != nil; x++) {
14419ef1f84bSDavid du Colombier if(p->state == Dead || p->kp){
14429ef1f84bSDavid du Colombier psdecref(p);
14439ef1f84bSDavid du Colombier continue;
14449ef1f84bSDavid du Colombier }
14459ef1f84bSDavid du Colombier l = 0;
14469ef1f84bSDavid du Colombier for(i=1; i<NSEG; i++) {
14479ef1f84bSDavid du Colombier s = p->seg[i];
1448*4498a243SDavid du Colombier if(s != 0)
14499ef1f84bSDavid du Colombier l += s->top - s->base;
14509ef1f84bSDavid du Colombier }
14519ef1f84bSDavid du Colombier if(l > max && ((p->procmode&0222) || strcmp(eve, p->user)!=0)) {
14529ef1f84bSDavid du Colombier if(kp != nil)
14539ef1f84bSDavid du Colombier psdecref(kp);
14549ef1f84bSDavid du Colombier kp = p;
14559ef1f84bSDavid du Colombier max = l;
14569ef1f84bSDavid du Colombier }
14579ef1f84bSDavid du Colombier else
14589ef1f84bSDavid du Colombier psdecref(p);
14599ef1f84bSDavid du Colombier }
14609ef1f84bSDavid du Colombier if(kp == nil)
14619ef1f84bSDavid du Colombier return;
14629ef1f84bSDavid du Colombier
14639ef1f84bSDavid du Colombier print("%d: %s killed: %s\n", kp->pid, kp->text, why);
14649ef1f84bSDavid du Colombier for(x = 0; (p = psincref(x)) != nil; x++) {
14659ef1f84bSDavid du Colombier if(p->state == Dead || p->kp){
14669ef1f84bSDavid du Colombier psdecref(p);
14679ef1f84bSDavid du Colombier continue;
14689ef1f84bSDavid du Colombier }
14699ef1f84bSDavid du Colombier if(p != kp && p->seg[BSEG] && p->seg[BSEG] == kp->seg[BSEG])
14709ef1f84bSDavid du Colombier p->procctl = Proc_exitbig;
14719ef1f84bSDavid du Colombier psdecref(p);
14729ef1f84bSDavid du Colombier }
14739ef1f84bSDavid du Colombier
14749ef1f84bSDavid du Colombier kp->procctl = Proc_exitbig;
14759ef1f84bSDavid du Colombier for(i = 0; i < NSEG; i++) {
14769ef1f84bSDavid du Colombier s = kp->seg[i];
14779ef1f84bSDavid du Colombier if(s != nil && canqlock(&s->lk)) {
14789ef1f84bSDavid du Colombier mfreeseg(s, s->base, s->top);
14799ef1f84bSDavid du Colombier qunlock(&s->lk);
14809ef1f84bSDavid du Colombier }
14819ef1f84bSDavid du Colombier }
14829ef1f84bSDavid du Colombier psdecref(kp);
14839ef1f84bSDavid du Colombier }
14849ef1f84bSDavid du Colombier
14859ef1f84bSDavid du Colombier /*
14869ef1f84bSDavid du Colombier * change ownership to 'new' of all processes owned by 'old'. Used when
14879ef1f84bSDavid du Colombier * eve changes.
14889ef1f84bSDavid du Colombier */
14899ef1f84bSDavid du Colombier void
renameuser(char * old,char * new)14909ef1f84bSDavid du Colombier renameuser(char *old, char *new)
14919ef1f84bSDavid du Colombier {
14929ef1f84bSDavid du Colombier int i;
14939ef1f84bSDavid du Colombier Proc *p;
14949ef1f84bSDavid du Colombier
14959ef1f84bSDavid du Colombier for(i = 0; (p = psincref(i)) != nil; i++){
14969ef1f84bSDavid du Colombier if(p->user!=nil && strcmp(old, p->user)==0)
14979ef1f84bSDavid du Colombier kstrdup(&p->user, new);
14989ef1f84bSDavid du Colombier psdecref(p);
14999ef1f84bSDavid du Colombier }
15009ef1f84bSDavid du Colombier }
15019ef1f84bSDavid du Colombier
15029ef1f84bSDavid du Colombier /*
15039ef1f84bSDavid du Colombier * time accounting called by clock() splhi'd
15049ef1f84bSDavid du Colombier */
15059ef1f84bSDavid du Colombier void
accounttime(void)15069ef1f84bSDavid du Colombier accounttime(void)
15079ef1f84bSDavid du Colombier {
15089ef1f84bSDavid du Colombier Proc *p;
15099ef1f84bSDavid du Colombier ulong n, per;
15109ef1f84bSDavid du Colombier static ulong nrun;
15119ef1f84bSDavid du Colombier
15129ef1f84bSDavid du Colombier p = m->proc;
1513*4498a243SDavid du Colombier if(p != nil) {
15149ef1f84bSDavid du Colombier nrun++;
15159ef1f84bSDavid du Colombier p->time[p->insyscall]++;
15169ef1f84bSDavid du Colombier }
15179ef1f84bSDavid du Colombier
15189ef1f84bSDavid du Colombier /* calculate decaying duty cycles */
15199ef1f84bSDavid du Colombier n = perfticks();
15209ef1f84bSDavid du Colombier per = n - m->perf.last;
15219ef1f84bSDavid du Colombier m->perf.last = n;
15229ef1f84bSDavid du Colombier per = (m->perf.period*(HZ-1) + per)/HZ;
15239ef1f84bSDavid du Colombier if(per != 0)
15249ef1f84bSDavid du Colombier m->perf.period = per;
15259ef1f84bSDavid du Colombier
15269ef1f84bSDavid du Colombier m->perf.avg_inidle = (m->perf.avg_inidle*(HZ-1)+m->perf.inidle)/HZ;
15279ef1f84bSDavid du Colombier m->perf.inidle = 0;
15289ef1f84bSDavid du Colombier
15299ef1f84bSDavid du Colombier m->perf.avg_inintr = (m->perf.avg_inintr*(HZ-1)+m->perf.inintr)/HZ;
15309ef1f84bSDavid du Colombier m->perf.inintr = 0;
15319ef1f84bSDavid du Colombier
15329ef1f84bSDavid du Colombier /* only one processor gets to compute system load averages */
15339ef1f84bSDavid du Colombier if(m->machno != 0)
15349ef1f84bSDavid du Colombier return;
15359ef1f84bSDavid du Colombier
15369ef1f84bSDavid du Colombier /*
15379ef1f84bSDavid du Colombier * calculate decaying load average.
15389ef1f84bSDavid du Colombier * if we decay by (n-1)/n then it takes
15399ef1f84bSDavid du Colombier * n clock ticks to go from load L to .36 L once
15409ef1f84bSDavid du Colombier * things quiet down. it takes about 5 n clock
15419ef1f84bSDavid du Colombier * ticks to go to zero. so using HZ means this is
15429ef1f84bSDavid du Colombier * approximately the load over the last second,
15439ef1f84bSDavid du Colombier * with a tail lasting about 5 seconds.
15449ef1f84bSDavid du Colombier */
15459ef1f84bSDavid du Colombier n = nrun;
15469ef1f84bSDavid du Colombier nrun = 0;
15479ef1f84bSDavid du Colombier n = (nrdy+n)*1000;
15489ef1f84bSDavid du Colombier m->load = (m->load*(HZ-1)+n)/HZ;
15499ef1f84bSDavid du Colombier }
15509ef1f84bSDavid du Colombier
1551