From c935dc90dbbadda92d6cb5eb457ea84f088c6214 Mon Sep 17 00:00:00 2001 From: David du Colombier <0intro@gmail.com> Date: Tue, 10 Jan 1995 00:00:00 +0000 Subject: [PATCH] Plan 9 from Bell Labs 1995-01-10 --- carrera/clock.c | 3 +- carrera/trap.c | 2 +- pc/clock.c | 2 +- port/auth.c | 8 +- port/devXXX.c | 46 +++++---- port/devproc.c | 18 ++-- port/portdat.h | 21 ++-- port/proc.c | 264 ++++++++++++++++++++++++++---------------------- port/sysproc.c | 14 +-- port/taslock.c | 69 ++++--------- power/clock.c | 2 +- 11 files changed, 229 insertions(+), 220 deletions(-) diff --git a/carrera/clock.c b/carrera/clock.c index da3bef9a3b828bcac5a48e7c52715b419742ff92..2d01dc7ced66a516b23d31993f72d6ac0f1eb30a 100644 --- a/carrera/clock.c +++ b/carrera/clock.c @@ -47,7 +47,6 @@ clockinit(void) void clock(Ureg *ur) { - int n; wrcompare(rdcount()+(m->speed*1000000)/HZ); @@ -78,7 +77,7 @@ clock(Ureg *ur) if(up == 0 || up->state != Running) return; - if(anyready() && !up->inlock) + if(anyready()) sched(); /* user profiling clock */ diff --git a/carrera/trap.c b/carrera/trap.c index a98f8308343eb7377e904c9de80dcc652889fff5..839ff2ed9df9722cda66d48a77153758371be8b4 100644 --- a/carrera/trap.c +++ b/carrera/trap.c @@ -397,7 +397,7 @@ intr(Ureg *ur) } /* preemptive scheduling */ - if(up && up->state == Running && anyhigher() && !up->inlock) + if(up && up->state == Running && anyhigher()) sched(); } diff --git a/pc/clock.c b/pc/clock.c index 042928816766422d5f33b0f16128ea0444c7b475..713f6efe2db9333190f94f19197ce9e9db36f84d 100644 --- a/pc/clock.c +++ b/pc/clock.c @@ -45,7 +45,7 @@ clock(Ureg *ur, void *arg) uartclock(); if(up && up->state == Running){ - if(anyready() && !up->inlock) + if(anyready()) sched(); /* user profiling clock */ diff --git a/port/auth.c b/port/auth.c index 2c2e3b4730fb3d250b2bcbd080f1628d862349d7..93896256cb3379907e7c57e70a980f446001d42d 100644 --- a/port/auth.c +++ b/port/auth.c @@ -124,10 +124,8 @@ sysfsession(ulong *arg) unlock(c); /* back off if someone else is doing an fsession */ - while(!canlock(&s->send)) { - up->yield = 1; + while(!canlock(&s->send)) sched(); - } if(s->valid == 0){ /* @@ -575,7 +573,7 @@ userwrite(char *a, int n) error(Eperm); memset(up->user, 0, NAMELEN); strcpy(up->user, "none"); - up->nice = NiceNormal; + up->basepri = PriNormal; return n; } @@ -600,7 +598,7 @@ hostownerwrite(char *a, int n) renameuser(eve, buf); memmove(eve, buf, NAMELEN); memmove(up->user, buf, NAMELEN); - up->nice = NiceNormal; + up->basepri = PriNormal; return n; } diff --git a/port/devXXX.c b/port/devXXX.c index 8f6d94764cdfd35344ecd07eb0471a09eaa1162b..023fca71617993026fac945f9712d9dad8b2372c 100644 --- a/port/devXXX.c +++ b/port/devXXX.c @@ -12,13 +12,13 @@ #include "devtab.h" enum{ - XXXdirqid, - XXXdataqid, + Qdir, + Qdata, }; Dirtab XXXtab[]={ - "data", XXXdataqid, 0, 0600, + "data", {Qdata, 0}, 0, 0600, }; -#define NXXXtab (sizeof(XXXTab)/sizeof(Dirtab)) +#define NXXXtab (sizeof(XXXtab)/sizeof(Dirtab)) void XXXreset(void) @@ -45,43 +45,39 @@ XXXclone(Chan *c, Chan *nc) int XXXwalk(Chan *c, char *name) { - return devwalk(c, name, XXXtab, (long)NXXXtab, devgen); + return devwalk(c, name, XXXtab, NXXXtab, devgen); } void XXXstat(Chan *c, char *db) { - devstat(c, db, XXXtab, (long)NXXXtab, devgen); + devstat(c, db, XXXtab, NXXXtab, devgen); } Chan * XXXopen(Chan *c, int omode) { - if(c->qid.path == CHDIR){ - if(omode != OREAD) - error(Eperm); - } - c->mode = openmode(omode); - c->flag |= COPEN; - c->offset = 0; - return c; + return devopen(c, omode, XXXtab, NXXXtab, devgen); } void XXXcreate(Chan *c, char *name, int omode, ulong perm) { + USED(c, name, omode, perm); error(Eperm); } void XXXremove(Chan *c) { + USED(c); error(Eperm); } void XXXwstat(Chan *c, char *dp) { + USED(c, dp); error(Eperm); } @@ -93,10 +89,10 @@ XXXclose(Chan *c) long XXXread(Chan *c, void *a, long n, ulong offset) { - switch((int)(c->qid.path&~CHDIR)){ - case XXXdirqid: + switch(c->qid.path & ~CHDIR){ + case Qdir: return devdirread(c, a, n, XXXtab, NXXXtab, devgen); - case XXXdataqid: + case Qdata: break; default: n=0; @@ -105,14 +101,26 @@ XXXread(Chan *c, void *a, long n, ulong offset) return n; } +Block* +XXXbread(Chan *c, long n, ulong offset) +{ + return devbread(c, n, offset); +} + long XXXwrite(Chan *c, char *a, long n, ulong offset) { - switch((int)(c->qid.path&~CHDIR)){ - case XXXdataqid: + switch(c->qid.path & ~CHDIR){ + case Qdata: break; default: error(Ebadusefd); } return n; } + +long +XXXbwrite(Chan *c, Block *bp, ulong offset) +{ + return devbwrite(c, bp, offset); +} diff --git a/port/devproc.c b/port/devproc.c index cb7bb53c384fc1fcc97c05ebb3ec651e9f16d131..5299af71f64a7be763634917d1d0b40a5faff957 100644 --- a/port/devproc.c +++ b/port/devproc.c @@ -396,8 +396,8 @@ procread(Chan *c, void *va, long n, ulong offset) l += s->top - s->base; } readnum(0, statbuf+j+NUMSIZE*6, NUMSIZE, l>>10, NUMSIZE); - readnum(0, statbuf+j+NUMSIZE*7, NUMSIZE, p->nice, NUMSIZE); - readnum(0, statbuf+j+NUMSIZE*8, NUMSIZE, p->pri, NUMSIZE); + readnum(0, statbuf+j+NUMSIZE*7, NUMSIZE, p->basepri, NUMSIZE); + readnum(0, statbuf+j+NUMSIZE*8, NUMSIZE, p->priority, NUMSIZE); memmove(a, statbuf+offset, n); return n; @@ -749,15 +749,17 @@ procctlreq(Proc *p, char *va, int n) ready(p); } else - if(strncmp(buf, "nice", 4) == 0){ - if(n < 5) + if(strncmp(buf, "pri", 3) == 0){ + if(n < 4) error(Ebadctl); - i = NiceNormal+atoi(buf+5); + i = atoi(buf+4); if(i < 0) i = 0; - if(i >= NiceMax) - i = NiceMax - 1; - p->nice = i; + if(i >= Nrq) + i = Nrq - 1; + if(i < p->basepri && !iseve()) + error(Eperm); + p->basepri = i; } else if(strncmp(buf, "wired", 5) == 0){ diff --git a/port/portdat.h b/port/portdat.h index b5dfd80f1c8af983f07ac26c89c3ab0f6c1291d6..7df3351283b071a5151161e5421a44323c2fa24d 100644 --- a/port/portdat.h +++ b/port/portdat.h @@ -503,10 +503,10 @@ enum NERR = 15, NNOTE = 5, - NiceMax = 10, /* max nice */ - NiceNormal = 5, /* base nice for normal processes */ - NiceKproc = NiceNormal-2, /* nice for kernel processes */ - NiceRoot = NiceNormal-2, /* nice for root processes */ + Nrq = 20, /* number of scheduler priority levels */ + PriNormal = 10, /* base priority for normal processes */ + PriKproc = 13, /* base priority for kernel processes */ + PriRoot = 13, /* base priority for root processes */ }; struct Proc @@ -586,11 +586,14 @@ struct Proc Note lastnote; int (*notify)(void*, char*); - Mach *wired; /* machine this process must run on */ - int pri; /* scheduling priority - low is high priority */ - short nice; /* time-passing algorithm - low is high priority */ - char yield; /* force one lap in the runq */ - char inlock; /* temp hi proirity ~= 2*num of locks set */ + Mach *wired; + Mach *mp; /* machine this process last ran on */ + ulong priority; /* priority level */ + ulong basepri; /* base priority level */ + ulong rt; /* # ticks used since last blocked */ + ulong art; /* avg # ticks used since last blocked */ + ulong movetime; /* last time process switched processors */ + ulong readytime; /* time process went ready */ void *ureg; /* User registers for notes */ void *dbgreg; /* User registers for devproc */ diff --git a/port/proc.c b/port/proc.c index 005ac95edfe44b3dfd36776d233faf565fb63297..9c20b566713cfe64f89c047f3a00eed3a1427647 100644 --- a/port/proc.c +++ b/port/proc.c @@ -29,8 +29,9 @@ typedef struct int n; } Schedq; -Schedq runq; -int priconst[NiceMax]; +int nrdy; +int lastreadied; +Schedq runq[Nrq]; char *statename[] = { /* BUG: generate automatically */ @@ -106,109 +107,155 @@ sched(void) int anyready(void) { - return runq.n; + return nrdy; } int anyhigher(void) { - Proc *p; - int pri; + int x; - pri = up->pri; - for(p=runq.head; p; p=p->rnext) - if(p->pri <= pri) - if(p->wired == 0 || p->wired == m) - return 1; - return 0; + x = lastreadied; + lastreadied = 0; + return nrdy && x >= up->priority; } +enum +{ + Squantum = (HZ+Nrq-1)/Nrq, +}; + void ready(Proc *p) { - int s; + int s, pri; + Schedq *rq; s = splhi(); - lock(&runq); + /* history counts */ + if(p->state == Running){ + p->rt++; + pri = ((p->art + (p->rt<<1))>>2)/Squantum; + } else { + p->art = (p->art + (p->rt<<1))>>2; + p->rt = 0; + pri = p->art/Squantum; + } + pri = p->basepri - pri; + if(pri < 0) + pri = 0; + + /* the only intersection between the classes is at PriNormal */ + if(pri < PriNormal && p->basepri > PriNormal) + pri = PriNormal; + p->priority = pri; + rq = &runq[p->priority]; + + lock(runq); p->rnext = 0; - if(runq.tail) - runq.tail->rnext = p; + if(rq->tail) + rq->tail->rnext = p; else - runq.head = p; - runq.tail = p; - runq.n++; + rq->head = p; + rq->tail = p; + rq->n++; + nrdy++; + p->readytime = m->ticks; p->state = Ready; - unlock(&runq); + if(p->priority > lastreadied) + lastreadied = p->priority; + unlock(runq); splx(s); } Proc* runproc(void) { - Proc *p, *bp, *op; + int i; + Schedq *rq; + Proc *p, *l; loop: + + /* + * find a process that last ran on this processor (affinity), + * or one that hasn't moved in a while (load balancing). + */ spllo(); + for(;;){ + /* + * Once a second we look for a long waiting process + * in the lowest priority queue to make sure nothing + * gets starved out by a malfunctioning high priority + * process. + */ + if((m->ticks % HZ) == 0){ + for(rq = runq; rq < &runq[Nrq]; rq++){ + p = rq->head; + if(p == 0 || p->mp != m) + continue; + + i = m->ticks - p->readytime; + if(i < HZ) + break; + + p->art = 0; + goto found; + } + } - /* look for potential proc while not locked */ - for(p = runq.head; p; p=p->rnext) { /* - * state is not saved or wired to another machine + * get highest priority process that this + * processor can run given affinity constraints */ - if(!(p->mach || (p->wired && p->wired != m))) - break; + for(rq = &runq[Nrq-1]; rq >= runq; rq--){ + p = rq->head; + if(p == 0) + continue; + for(; p; p = p->rnext){ + if(p->mp == m || p->movetime < m->ticks) + goto found; + } + } } - if(p == 0) - goto loop; + +found: splhi(); - lock(&runq); + lock(runq); - /* find best proc while locked */ - bp = 0; - for(p = runq.head; p; p=p->rnext) { - if(p->mach || (p->wired && p->wired != m)) - continue; - if(bp == 0) { - if(p->yield) - p->yield = 0; - bp = p; - } else - if(p->yield == 0 && p->pri < bp->pri) - bp = p; - } - if(bp == 0) { - unlock(&runq); - goto loop; + l = 0; + for(p = rq->head; p; p = p->rnext){ + if(p->mp == m || p->movetime < m->ticks) + break; + l = p; } -found: - /* unlink found proc from runq */ - op = 0; - for(p=runq.head; p; p=p->rnext) { - if(p == bp) - break; - op = p; + /* + * p->mach==0 only when process state is saved + */ + if(p == 0 || p->mach){ + unlock(runq); + goto loop; } - if(op == 0) - runq.head = bp->rnext; + if(p->rnext == 0) + rq->tail = l; + if(l) + l->rnext = p->rnext; else - op->rnext = bp->rnext; - if(bp == runq.tail) - runq.tail = op; - - /* clear next so that unlocked runq will not loop */ - bp->rnext = 0; + rq->head = p->rnext; + rq->n--; + nrdy--; + if(p->state != Ready) + print("runproc %s %d %s\n", p->text, p->pid, statename[p->state]); + unlock(runq); - runq.n--; - - if(bp->state != Ready) - print("runproc %s %d %s\n", bp->text, bp->pid, statename[bp->state]); - unlock(&runq); - - bp->state = Scheding; - return bp; + p->state = Scheding; + if(p->mp != m) + p->movetime = m->ticks + HZ/2; + p->mp = m; + return p; } int @@ -217,13 +264,13 @@ canpage(Proc *p) int ok = 0; splhi(); - lock(&runq); + lock(runq); /* Only reliable way to see if we are Running */ if(p->mach == 0) { p->newtlb = 1; ok = 1; } - unlock(&runq); + unlock(runq); spllo(); return ok; @@ -263,8 +310,8 @@ newproc(void) p->kp = 0; p->procctl = 0; p->notepending = 0; - p->nice = NiceNormal; - p->pri = 0; + p->mp = 0; + p->movetime = 0; p->wired = 0; memset(p->seg, 0, sizeof p->seg); p->pid = incref(&pidalloc); @@ -298,6 +345,8 @@ procwired(Proc *p) if(nwired[i] < nwired[bm]) bm = i; p->wired = MACHP(bm); + p->movetime = 0xffffffff; + p->mp = p->wired; } void @@ -313,14 +362,6 @@ procinit0(void) /* bad planning - clashes with devproc.c */ for(i=0; iqnext = p+1; p->qnext = 0; - - /* - * set up priority increments - * normal priority sb about 1000/HZ - * highest pri (lowest number) sb about 0 - */ - for(i=0; inotepending == 0) { - up->yield = 1; + if(up->notepending == 0) sched(); /* notepending may go true while asleep */ - } if(up->notepending) { up->notepending = 0; @@ -394,6 +436,9 @@ tsleep(Rendez *r, int (*fn)(void*), void *arg, int ms) ulong when; Proc *f, **l; + if((getstatus()&IE) == 0) + print("tsleep hi %lux\n", getcallerpc(r)); + when = MS2TK(ms)+MACHP(0)->ticks; lock(&talarm); @@ -750,6 +795,7 @@ procdump(void) char *s; Proc *p; ulong bss; + Schedq *rq; for(i=0; ipid, p->text, p->pc, s, statename[p->state], p->time[0], p->time[1], bss); } - if(runq.head != 0) { - print("rq:"); - for(p = runq.head; p; p = p->rnext) - print(" %d(%d)", p->pid, p->pri); + for(rq = &runq[Nrq-1]; rq >= runq; rq--){ + if(rq->head == 0) + continue; + print("rq%d:", rq-runq); + for(p = rq->head; p; p = p->rnext) + print(" %d(%d)", p->pid, m->ticks - p->readytime); print("\n"); } - print("nrdy %d\n", runq.n); + print("nrdy %d\n", nrdy); } void @@ -802,8 +850,8 @@ kproc(char *name, void (*func)(void *), void *arg) p->ureg = 0; p->dbgreg = 0; - p->nice = NiceKproc; - p->pri = 0; + p->basepri = PriKproc; + p->priority = p->basepri; kprocchild(p, func, arg); @@ -872,6 +920,9 @@ procctl(Proc *p) void error(char *err) { + if((getstatus()&IE) == 0) + print("error hi %lux\n", getcallerpc(err)); + spllo(); strncpy(up->error, err, ERRLEN); nexterror(); } @@ -950,21 +1001,13 @@ void accounttime(void) { Proc *p; - int i, pri; - static int nrun, m0ticks; + int n; + static int nrun; p = m->proc; if(p) { nrun++; p->time[p->insyscall]++; - p->pri += priconst[p->nice]; - } - - if(up) { - i = up->inlock-1; - if(i < 0) - i = 0; - up->inlock = i; } /* only one processor gets to compute system load averages */ @@ -972,26 +1015,9 @@ accounttime(void) return; /* calculate decaying load average */ - pri = nrun; + n = nrun; nrun = 0; - pri = (runq.n+pri)*1000; - m->load = (m->load*19+pri)/20; - - /* - * decay per-process cpu usage - * pri = (3/4)*pri twice per second - * tc = (3/4)^2/(1-(3/4)^2) = 1.286 sec - */ - m0ticks--; - if(m0ticks <= 0) { - m0ticks = HZ/2; - p = proctab(0); - for(i=conf.nproc-1; i!=0; i--,p++) - if(p->state != Dead) { - pri = p->pri; - pri -= pri >> 2; - p->pri = pri; - } - } + n = (nrdy+n)*1000; + m->load = (m->load*19+n)/20; } diff --git a/port/sysproc.c b/port/sysproc.c index 8f4d7f3e4725f3adf61fac2ce8b49f4e88299786..1aea815bac0e54295ad6f135e9d8df5a12c1d259 100644 --- a/port/sysproc.c +++ b/port/sysproc.c @@ -178,8 +178,9 @@ sysrfork(ulong *arg) * (i.e. has bad properties) and has to be discarded. */ flushmmu(); - p->nice = up->nice; - p->pri = up->pri; + p->priority = up->priority; + p->basepri = up->basepri; + p->mp = up->mp; if(up->wired) procwired(p); ready(p); @@ -397,10 +398,9 @@ sysexec(ulong *arg) /* * '/' processes are higher priority (hack to make /ip more responsive). */ - if(devchar[tc->type] == L'/') { - up->nice = NiceRoot; - up->pri = 0; - } + if(devchar[tc->type] == L'/') + up->basepri = PriRoot; + up->priority = up->basepri; poperror(); close(tc); @@ -462,11 +462,11 @@ return0(void *a) long syssleep(ulong *arg) { + int n; n = arg[0]; if(n <= 0) { - up->yield = 1; sched(); return 0; } diff --git a/port/taslock.c b/port/taslock.c index 4b47aabad23cffc51b8f183406a946b5155e56b6..0e1bd45d6d83eb749e8f3f975e403f603323e2ef 100644 --- a/port/taslock.c +++ b/port/taslock.c @@ -8,86 +8,59 @@ void lock(Lock *l) { - int n; + if(tas(&l->key) == 0) + return; - if(up) { - n = up->inlock+2; - up->inlock = n; + for(;;){ + while(l->key) + ; if(tas(&l->key) == 0) return; - - for(;;){ - while(l->key) - if(conf.nproc == 1) { - up->yield = 1; - sched(); - } - up->inlock = n; - if(tas(&l->key) == 0) - return; - } } +} - if(tas(&l->key) == 0) +void +ilock(Lock *l) +{ + ulong x; + + x = splhi(); + if(tas(&l->key) == 0){ + l->sr = x; return; + } + for(;;){ while(l->key) ; - if(tas(&l->key) == 0) + if(tas(&l->key) == 0){ + l->sr = x; return; + } } } int canlock(Lock *l) { - int n; - - if(up) { - n = up->inlock; - up->inlock = n+2; - if(tas(&l->key)) { - up->inlock = n; - return 0; - } - return 1; - } - if(tas(&l->key)) return 0; + return 1; } void unlock(Lock *l) { - int n; - - if(up) { - n = up->inlock-2; - if(n < 0) - n = 0; - up->inlock = n; - } l->key = 0; } -void -ilock(Lock *l) -{ - ulong sr; - - sr = splhi(); - lock(l); - l->sr = sr; -} - void iunlock(Lock *l) { ulong sr; sr = l->sr; - unlock(l); + l->key = 0; splx(sr); } diff --git a/power/clock.c b/power/clock.c index e7caaf0fac7bcbc00e731946a4c73c65f5c11b4a..4c865ca970782c07b1a0525d1f9c443db082d348 100644 --- a/power/clock.c +++ b/power/clock.c @@ -103,7 +103,7 @@ clock(Ureg *ur) if(up == 0 || (ur->status&IEP) == 0 || up->state != Running) return; - if(anyready() && !up->inlock) + if(anyready()) sched(); /* user profiling clock */