From a91755ae5e6333bd3f690820f086645cd122ec7f Mon Sep 17 00:00:00 2001 From: David du Colombier <0intro@gmail.com> Date: Fri, 28 Feb 2003 00:00:00 +0000 Subject: [PATCH] Plan 9 from Bell Labs 2003-02-28 --- pc/trap.c | 21 +---- port/devproc.c | 29 ++----- port/portclock.c | 24 +----- port/portdat.h | 5 +- port/portfns.h | 3 + port/proc.c | 215 +++++++++++++++++++++++++++-------------------- 6 files changed, 145 insertions(+), 152 deletions(-) diff --git a/pc/trap.c b/pc/trap.c index d8645ac90793f9ec560045ac683d6e9ad08120d6..0b0ef1aaae52be0533a2de0eb6b6ba8214a84993 100644 --- a/pc/trap.c +++ b/pc/trap.c @@ -310,26 +310,11 @@ trap(Ureg* ureg) if(ctl->eoi) ctl->eoi(vno); - /* - * preemptive scheduling. to limit stack depth, - * make sure process has a chance to return from - * the current interrupt before being preempted a - * second time. - */ - if(ctl->isintr && ctl->irq != IrqTIMER && ctl->irq != IrqCLOCK) - if(up && up->state == Running) - if(anyhigher()) - if(up->preempted == 0) - if(!active.exiting){ - up->preempted = 1; + if(ctl->isintr){ intrtime(m, vno); - sched(); - splhi(); - up->preempted = 0; - return; + if(up && ctl->irq != IrqTIMER && ctl->irq != IrqCLOCK) + preempted(); } - if(ctl->isintr) - intrtime(m, vno); } else if(vno <= nelem(excname) && user){ spllo(); diff --git a/port/devproc.c b/port/devproc.c index 124d3be2be78388c8ca1ade7700020a577fe13a0..7db88b29ad0c6f8057f68955f6cbac5b4aca8167 100644 --- a/port/devproc.c +++ b/port/devproc.c @@ -1094,7 +1094,7 @@ void procctlreq(Proc *p, char *va, int n) { Segment *s; - int i, npc; + int npc, pri; Cmdbuf *cb; Cmdtab *ct; @@ -1116,17 +1116,6 @@ procctlreq(Proc *p, char *va, int n) case CMclosefiles: procctlclosefiles(p, 1, 0); break; - case CMfixedpri: - i = atoi(cb->f[1]); - if(i < 0) - i = 0; - if(i >= Nrq) - i = Nrq - 1; - if(i > p->basepri && !iseve()) - error(Eperm); - p->basepri = i; - p->fixedpri = 1; - break; case CMhang: p->hang = 1; break; @@ -1152,15 +1141,15 @@ procctlreq(Proc *p, char *va, int n) p->noswap = 1; break; case CMpri: - i = atoi(cb->f[1]); - if(i < 0) - i = 0; - if(i >= Nrq) - i = Nrq - 1; - if(i > p->basepri && !iseve()) + pri = atoi(cb->f[1]); + if(pri > PriNormal && !iseve()) + error(Eperm); + procpriority(p, pri, 0); + break; + case CMfixedpri: + if(!iseve()) error(Eperm); - p->basepri = i; - p->fixedpri = 0; + procpriority(p, atoi(cb->f[1]), 1); break; case CMprivate: p->privatemem = 1; diff --git a/port/portclock.c b/port/portclock.c index 9da9eeda5c3c9f56bd07d0bb318f2cdf617dc4a7..8ab90955cbf219020adcc3aeec83ebd5d412ec17 100644 --- a/port/portclock.c +++ b/port/portclock.c @@ -95,8 +95,6 @@ timerdel(Timer *dt) void hzclock(Ureg *ur) { - int callsched; - m->ticks++; if(m->proc) m->proc->pc = ur->pc; @@ -126,29 +124,13 @@ hzclock(Ureg *ur) if(up == 0 || up->state != Running) return; - if(up->fixedpri){ - /* fixed priority processes are only preempted by - * higher piority processes. - */ - if(anyhigher()) - callsched = 1; - } else { - /* floating priority processes are are preempted - * by all sorts of things. - */ - if(anyready() && !edf->isedf(up)) - callsched = 1; - } - if(callsched){ - sched(); - splhi(); - } - /* user profiling clock */ - if(userureg(ur)) { + if(userureg(ur)){ (*(ulong*)(USTKTOP-BY2WD)) += TK2MS(1); segclock(ur->pc); } + + hzsched(); /* in proc.c */ } void diff --git a/port/portdat.h b/port/portdat.h index e4440ed61cf2e33890899c43a8db7e74faf1c3fe..3d0fba91213d389c54b204e809163fca241c6380 100644 --- a/port/portdat.h +++ b/port/portdat.h @@ -657,10 +657,9 @@ struct Proc ulong priority; /* priority level */ ulong basepri; /* base priority level */ uchar fixedpri; /* priority level deson't change */ - ulong rt; /* # ticks used since last blocked */ - ulong art; /* avg # ticks used since last blocked */ + int quanta; /* quanta left */ + ulong readytime; /* time process came ready */ ulong movetime; /* last time process switched processors */ - ulong readytime; /* time process went ready */ int preempted; /* true if this process hasn't finished the interrupt * that last preempted it */ diff --git a/port/portfns.h b/port/portfns.h index e141c8aa0ddbce1ce9915121529afd35eaeee4be..1d4cc1ccfe9b2b46aec268ce6520a0191f75917b 100644 --- a/port/portfns.h +++ b/port/portfns.h @@ -119,6 +119,7 @@ char* getconfenv(void); int haswaitq(void*); long hostdomainwrite(char*, int); long hostownerwrite(char*, int); +void hzsched(void); void iallocinit(void); Block* iallocb(int); void iallocsummary(void); @@ -204,6 +205,7 @@ void panic(char*, ...); Cmdbuf* parsecmd(char *a, int n); ulong perfticks(void); void pexit(char*, int); +int preempted(void); void printinit(void); int procindex(ulong); void pgrpcpy(Pgrp*, Pgrp*); @@ -222,6 +224,7 @@ void procdump(void); int procfdprint(Chan*, int, int, char*, int); void procinit0(void); void procflushseg(Segment*); +void procpriority(Proc*, int, int); Proc* proctab(int); void procwired(Proc*, int); Pte* ptealloc(void); diff --git a/port/proc.c b/port/proc.c index 27e3322a5b776311f66119c488e0685957375393..4a9646dffaa9df00f2f98f4910bc18d6435eaf3c 100644 --- a/port/proc.c +++ b/port/proc.c @@ -20,7 +20,22 @@ static struct Procalloc Proc* free; } procalloc; +enum +{ + Q=(HZ/20)*4, + DQ=((HZ-Q)/40)*2, +}; + static Schedq runq[Nrq]; +static ulong runvec; +static int quanta[Nrq] = +{ + Q+19*DQ, Q+18*DQ, Q+17*DQ, Q+16*DQ, + Q+15*DQ, Q+14*DQ, Q+13*DQ, Q+12*DQ, + Q+11*DQ, Q+10*DQ, Q+ 9*DQ, Q+ 8*DQ, + Q+ 7*DQ, Q+ 6*DQ, Q+ 5*DQ, Q+ 4*DQ, + Q+ 3*DQ, Q+ 2*DQ, Q+ 1*DQ, Q+ 0*DQ, +}; extern Edfinterface nulledf; @@ -128,28 +143,54 @@ sched(void) int anyready(void) { - return nrdy || edf->edfanyready(); + return runvec || edf->edfanyready(); } int anyhigher(void) { - Schedq *rq; + return runvec & ~((1<<(up->priority+1))-1); +} - if(nrdy == 0) - return 0; +/* + * here once per clock tick to see if we should resched + */ +void +hzsched(void) +{ + /* another cycle, another quantum */ + up->quanta--; - for(rq = &runq[Nrq-1]; rq > &runq[up->priority]; rq--) - if(rq->head != nil) - return 1; + /* edf scheduler always gets first chance */ + if(edf->isedf(up)) + return; - return 0; + /* don't bother unless someone is elegible */ + if(anyhigher() || (!up->fixedpri && anyready())){ + sched(); + splhi(); + } } -enum +/* + * here at the end of non-clock interrupts to see if we should preempt the + * current process. Returns 1 if preempted, 0 otherwise. + */ +int +preempted(void) { - Squantum = 1, -}; + if(up && up->state == Running) + if(up->preempted == 0) + if(anyhigher()) + if(!active.exiting){ + up->preempted = 1; + sched(); + splhi(); + up->preempted = 0; + return 1; + } + return 0; +} void ready(Proc *p) @@ -164,34 +205,37 @@ ready(Proc *p) splx(s); return; } + + pri = p->priority; + if(p->fixedpri){ pri = p->basepri; + p->quanta = HZ; + } else if(p->state == Running){ + if(p->quanta <= 0){ + /* degrade priority of anyone that used their whole quanta */ + + /* processes > PriNormal and those below don't mix */ + if(p->basepri > PriNormal){ + if(pri > PriNormal) + pri--; + } else { + if(pri > 0) + pri--; + } + p->quanta = quanta[pri]; + } } else { - /* history counts */ - if(p->state == Running){ - p->rt++; - pri = (p->art + p->rt)/2; - } else { - p->art = (p->art + p->rt + 2)/2; - pri = (p->art + p->rt)/2; - p->rt = 0; + if(p->quanta > quanta[pri]/2){ + /* blocked before using half its quanta, go up */ + if(++pri > p->basepri) + pri = p->basepri; } - pri = p->basepri - (pri/Squantum); - if(pri < 0) - pri = 0; - - /* the only intersection between the classes is at PriNormal */ - if(pri < PriNormal && p->basepri > PriNormal) - pri = PriNormal; - - /* stick at low priority any process waiting for a lock */ - if(p->lockwait) - pri = PriLock; + p->quanta = quanta[pri]; } + rq = &runq[pri]; p->priority = pri; - rq = &runq[p->priority]; - lock(runq); p->rnext = 0; if(rq->tail) @@ -201,6 +245,7 @@ ready(Proc *p) rq->tail = p; rq->n++; nrdy++; + runvec |= 1<readytime = m->ticks; p->state = Ready; unlock(runq); @@ -210,10 +255,10 @@ ready(Proc *p) Proc* runproc(void) { - Schedq *rq, *xrq; + Schedq *rq; Proc *p, *l; - ulong rt; ulong start, now; + int i; start = perfticks(); @@ -221,55 +266,30 @@ runproc(void) return p; loop: - /* * find a process that last ran on this processor (affinity), - * or one that hasn't moved in a while (load balancing). + * or one that hasn't moved in a while (load balancing). Every + * time around the loop affinity goes down. */ spllo(); - for(;;){ - if((++(m->fairness) & 0x3) == 0){ - /* - * once in a while, run process that's been waiting longest - * regardless of movetime - */ - rt = 0xffffffff; - xrq = nil; - for(rq = runq; rq < &runq[Nrq]; rq++){ - p = rq->head; - if(p == 0) - continue; - if(p->readytime < rt){ - xrq = rq; - rt = p->readytime; - } - } - if(xrq != nil){ - rq = xrq; - p = rq->head; - if(p != nil && p->wired == nil) - p->movetime = 0; - goto found; - } - } else { - /* - * get highest priority process that this - * processor can run given affinity constraints - */ - for(rq = &runq[Nrq-1]; rq >= runq; rq--){ - p = rq->head; - if(p == 0) - continue; - for(; p; p = p->rnext){ - if(p->mp == MACHP(m->machno) - || p->movetime < MACHP(0)->ticks) - goto found; - } + for(i = 0;; i++){ + /* + * get highest priority process that this + * processor can run given affinity constraints + */ + for(rq = &runq[Nrq-1]; rq >= runq; rq--){ + p = rq->head; + if(p == 0) + continue; + for(; p; p = p->rnext){ + if(p->mp == MACHP(m->machno) || (!p->wired && i > 0)) + goto found; } } - /* remember how much time we're here */ idlehands(); + + /* remember how much time we're here */ now = perfticks(); m->perf.inidle += now-start; start = now; @@ -282,7 +302,7 @@ found: l = 0; for(p = rq->head; p; p = p->rnext){ - if(p->mp == MACHP(m->machno) || p->movetime <= MACHP(0)->ticks) + if(p->mp == MACHP(m->machno) || (!p->wired && i > 0)) break; l = p; } @@ -300,6 +320,8 @@ found: l->rnext = p->rnext; else rq->head = p->rnext; + if(rq->head == nil) + runvec &= ~(1<<(rq-runq)); rq->n--; nrdy--; if(p->state != Ready) @@ -307,8 +329,6 @@ found: unlock(runq); p->state = Scheding; - if(p->mp != MACHP(m->machno)) - p->movetime = MACHP(0)->ticks + HZ/10; p->mp = MACHP(m->machno); return p; @@ -366,20 +386,15 @@ newproc(void) p->kp = 0; p->procctl = 0; p->notepending = 0; - p->mp = 0; - p->movetime = 0; - p->wired = 0; p->ureg = 0; p->privatemem = 0; p->noswap = 0; - p->lockwait = nil; p->errstr = p->errbuf0; p->syserrstr = p->errbuf1; p->errbuf0[0] = '\0'; p->errbuf1[0] = '\0'; p->nlocks = 0; p->delaysched = 0; - p->movetime = 0; kstrdup(&p->user, "*nouser"); kstrdup(&p->text, "*notext"); kstrdup(&p->args, ""); @@ -394,6 +409,11 @@ newproc(void) if(p->kstack == 0) p->kstack = smalloc(KSTACK); + /* sched params */ + p->mp = 0; + p->wired = 0; + procpriority(p, PriNormal, 0); + p->task = nil; return p; @@ -430,10 +450,27 @@ procwired(Proc *p, int bm) } p->wired = MACHP(bm); - p->movetime = 0xffffffff; p->mp = p->wired; } +void +procpriority(Proc *p, int pri, int fixed) +{ + if(pri >= Nrq) + pri = Nrq - 1; + else if(pri < 0) + pri = 0; + p->basepri = pri; + p->priority = pri; + if(fixed){ + p->quanta = 0xfffff; + p->fixedpri = 1; + } else { + p->quanta = quanta[pri]; + p->fixedpri = 0; + } +} + void procinit0(void) /* bad planning - clashes with devproc.c */ { @@ -967,9 +1004,9 @@ dumpaproc(Proc *p) s = p->psstate; if(s == 0) s = statename[p->state]; - print("%3lud:%10s pc %8lux dbgpc %8lux %8s (%s) ut %ld st %ld bss %lux qpc %lux nl %lud nd %lud lpc %lux\n", + 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", p->pid, p->text, p->pc, dbgpc(p), s, statename[p->state], - p->time[0], p->time[1], bss, p->qpc, p->nlocks, p->delaysched, p->lastlock ? p->lastlock->pc : 0); + p->time[0], p->time[1], bss, p->qpc, p->nlocks, p->delaysched, p->lastlock ? p->lastlock->pc : 0, p->priority); } void @@ -1047,8 +1084,7 @@ scheddump(void) continue; print("rq%ld:", rq-runq); for(p = rq->head; p; p = p->rnext) - print(" %lud(%lud, %lud)", p->pid, m->ticks - p->readytime, - MACHP(0)->ticks - p->movetime); + print(" %lud(%lud)", p->pid, m->ticks - p->readytime); print("\n"); delay(150); } @@ -1083,8 +1119,7 @@ kproc(char *name, void (*func)(void *), void *arg) p->ureg = 0; p->dbgreg = 0; - p->basepri = PriKproc; - p->priority = p->basepri; + procpriority(p, PriKproc, 0); kprocchild(p, func, arg);