| plan 9 kernel history: overview | file list | diff list |
2002/1010/port/proc.c (diff list | history)
| port/proc.c on 1990/0227 | ||
| 1990/0227 | #include "u.h" | |
| 1992/0321 | #include "../port/lib.h" | |
| 1990/0227 | #include "mem.h" #include "dat.h" #include "fns.h" | |
| 1992/0111 | #include "../port/error.h" | |
| 1990/0227 | ||
| 2001/0527 | int nrdy; | |
| 1992/0428 | Ref noteidalloc; | |
| 1990/0227 | ||
| 2002/0403 | long delayedscheds; /* statistics */ | |
| 2001/0527 | static Ref pidalloc; static struct Procalloc | |
| 1990/0227 | { Lock; | |
| 2001/0510 | Proc* ht[128]; | |
| 1997/0327 | Proc* arena; Proc* free; | |
| 2001/0527 | } procalloc; | |
| 1990/0227 | ||
| 2001/0527 | static Schedq runq[Nrq]; | |
| 1994/0728 | ||
| 2002/0704 | extern Edfinterface nulledf; Edfinterface *edf = &nulledf; | |
| 1992/0309 | char *statename[] = | |
| 2002/0315 | { /* BUG: generate automatically */ | |
| 1990/0227 | "Dead", "Moribund", "Ready", "Scheding", "Running", "Queueing", | |
| 1998/0806 | "QueueingR", | |
| 1998/0325 | "QueueingW", | |
| 1990/0227 | "Wakeme", "Broken", | |
| 1991/0705 | "Stopped", | |
| 1991/0806 | "Rendez", | |
| 2002/0315 | "Released", | |
| 1990/0227 | }; | |
| 2001/0510 | static void pidhash(Proc*); static void pidunhash(Proc*); | |
| 1990/0227 | /* * Always splhi()'ed. */ void schedinit(void) /* never returns */ { setlabel(&m->sched); | |
| 1993/0501 | if(up) { | |
| 1990/0227 | m->proc = 0; | |
| 1993/0501 | switch(up->state) { case Running: ready(up); break; case Moribund: up->state = Dead; | |
| 2002/0704 | if (edf->isedf(up)) edf->edfbury(up); | |
| 2002/0315 | ||
| 1998/0512 | /* | |
| 1991/0717 | * Holding locks from pexit: | |
| 1995/0112 | * procalloc | |
| 1998/0605 | * palloc | |
| 1991/0705 | */ | |
| 1993/0501 | mmurelease(up); | |
| 1991/0705 | ||
| 1993/0501 | up->qnext = procalloc.free; procalloc.free = up; | |
| 1995/1230 | unlock(&palloc); | |
| 1990/0227 | unlock(&procalloc); | |
| 1993/0501 | break; | |
| 1990/0227 | } | |
| 1993/0501 | up->mach = 0; | |
| 2002/0315 | up = nil; | |
| 1990/0227 | } sched(); } | |
| 1998/0514 | /* * If changing this routine, look also at sleep(). It * contains a copy of the guts of sched(). */ | |
| 1990/0227 | void sched(void) { | |
| 2002/0925 | int x[1]; | |
| 2002/0420 | if(m->ilockdepth) | |
| 2002/0925 | panic("ilockdepth %d, last lock 0x%p at 0x%lux, sched called from 0x%lux", | |
| 2002/0626 | m->ilockdepth, up?up->lastilock:nil, | |
| 2002/0925 | (up && up->lastilock)?up->lastilock->pc:0, getcallerpc(x+3)); | |
| 2002/0420 | ||
| 2002/0403 | if(up){ | |
| 2002/0420 | if(up->nlocks && up->state != Moribund){ delayedscheds++; | |
| 2002/0403 | return; } | |
| 1990/0227 | splhi(); | |
| 1993/1212 | /* statistics */ | |
| 1991/0425 | m->cs++; | |
| 1993/1212 | ||
| 1993/0501 | procsave(up); | |
| 2002/0403 | if(setlabel(&up->sched)){ | |
| 1993/0501 | procrestore(up); | |
| 1990/0227 | spllo(); return; } gotolabel(&m->sched); } | |
| 1993/0501 | up = runproc(); up->state = Running; | |
| 1995/0811 | up->mach = MACHP(m->machno); | |
| 1993/0501 | m->proc = up; mmuswitch(up); gotolabel(&up->sched); | |
| 1994/0311 | } | |
| 1994/0321 | int anyready(void) { | |
| 2002/0704 | return nrdy || edf->edfanyready(); | |
| 1990/1227 | } | |
| 1994/0809 | int | |
| 1994/0817 | anyhigher(void) | |
| 1994/0809 | { | |
| 1999/0326 | Schedq *rq; | |
| 1994/0817 | ||
| 1999/0326 | if(nrdy == 0) return 0; for(rq = &runq[Nrq-1]; rq > &runq[up->priority]; rq--) if(rq->head != nil) return 1; | |
| 2002/0315 | ||
| 1999/0326 | return 0; | |
| 1994/0809 | } | |
| 1995/0110 | enum { | |
| 2002/0228 | Squantum = 1, | |
| 1995/0110 | }; | |
| 1990/0227 | void ready(Proc *p) { | |
| 1996/0523 | int s, pri; | |
| 1995/0110 | Schedq *rq; | |
| 1990/0227 | s = splhi(); | |
| 1991/0501 | ||
| 2002/0704 | if(edf->isedf(p)){ edf->edfready(p); | |
| 2002/0404 | splx(s); return; } | |
| 2001/0315 | if(p->fixedpri){ pri = p->basepri; | |
| 1995/0110 | } else { | |
| 2001/0315 | /* history counts */ if(p->state == Running){ p->rt++; | |
| 2002/0228 | pri = (p->art + p->rt)/2; | |
| 2001/0315 | } else { | |
| 2002/0228 | p->art = (p->art + p->rt + 2)/2; pri = (p->art + p->rt)/2; | |
| 2001/0315 | p->rt = 0; } | |
| 2002/0228 | pri = p->basepri - (pri/Squantum); | |
| 2001/0315 | if(pri < 0) pri = 0; | |
| 2002/0315 | ||
| 2001/0315 | /* the only intersection between the classes is at PriNormal */ if(pri < PriNormal && p->basepri > PriNormal) pri = PriNormal; | |
| 1995/0110 | ||
| 2001/0315 | /* stick at low priority any process waiting for a lock */ if(p->lockwait) pri = PriLock; } | |
| 1998/0606 | ||
| 1996/0523 | p->priority = pri; | |
| 1995/0110 | rq = &runq[p->priority]; lock(runq); | |
| 1990/0227 | p->rnext = 0; | |
| 1995/0110 | if(rq->tail) rq->tail->rnext = p; | |
| 1990/0227 | else | |
| 1995/0110 | rq->head = p; rq->tail = p; rq->n++; nrdy++; p->readytime = m->ticks; | |
| 1990/0227 | p->state = Ready; | |
| 1995/0110 | unlock(runq); | |
| 1990/0227 | splx(s); } Proc* runproc(void) { | |
| 1998/0901 | Schedq *rq, *xrq; | |
| 1995/0110 | Proc *p, *l; | |
| 1998/0901 | ulong rt; | |
| 2002/0822 | ulong start, now; | |
| 1990/0227 | ||
| 2002/0822 | start = perfticks(); | |
| 2002/0821 | ||
| 2002/0704 | if ((p = edf->edfrunproc()) != nil) | |
| 2002/0404 | return p; | |
| 1990/0227 | loop: | |
| 1995/0110 | /* * find a process that last ran on this processor (affinity), * or one that hasn't moved in a while (load balancing). */ | |
| 1992/0603 | spllo(); | |
| 1995/0912 | for(;;){ | |
| 1999/0811 | if((++(m->fairness) & 0x3) == 0){ | |
| 1998/0901 | /* * once in a while, run process that's been waiting longest * regardless of movetime */ rt = 0xffffffff; xrq = nil; | |
| 1995/0110 | for(rq = runq; rq < &runq[Nrq]; rq++){ p = rq->head; | |
| 1996/0315 | if(p == 0) | |
| 1995/0110 | continue; | |
| 1998/0901 | if(p->readytime < rt){ xrq = rq; rt = p->readytime; } } if(xrq != nil){ rq = xrq; p = rq->head; | |
| 1999/0711 | if(p != nil && p->wired == nil) | |
| 1998/0901 | p->movetime = 0; | |
| 1998/0923 | goto found; | |
| 1998/0901 | } } 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; | |
| 1996/0315 | for(; p; p = p->rnext){ | |
| 1998/0901 | if(p->mp == MACHP(m->machno) | |
| 1999/0811 | || p->movetime < MACHP(0)->ticks) | |
| 1996/0315 | goto found; } | |
| 1995/0110 | } } | |
| 2002/0822 | /* remember how much time we're here */ | |
| 2000/1130 | idlehands(); | |
| 2002/0822 | now = perfticks(); m->perf.inidle += now-start; start = now; | |
| 1994/0729 | } | |
| 1995/0110 | found: | |
| 1994/0729 | splhi(); | |
| 1997/0821 | if(!canlock(runq)) goto loop; | |
| 1991/0420 | ||
| 1995/0110 | l = 0; for(p = rq->head; p; p = p->rnext){ | |
| 2002/0415 | if(p->mp == MACHP(m->machno) || p->movetime <= MACHP(0)->ticks) | |
| 1995/0110 | break; l = p; | |
| 1994/0728 | } | |
| 1995/0110 | /* * p->mach==0 only when process state is saved */ | |
| 1998/0512 | if(p == 0 || p->mach){ | |
| 1995/0110 | unlock(runq); | |
| 1990/0227 | goto loop; } | |
| 1995/0110 | if(p->rnext == 0) rq->tail = l; if(l) l->rnext = p->rnext; | |
| 1994/0728 | else | |
| 1995/0110 | rq->head = p->rnext; rq->n--; nrdy--; if(p->state != Ready) | |
| 1998/0825 | print("runproc %s %lud %s\n", p->text, p->pid, statename[p->state]); | |
| 1995/0110 | unlock(runq); | |
| 1995/0102 | ||
| 1995/0110 | p->state = Scheding; | |
| 1995/0811 | if(p->mp != MACHP(m->machno)) | |
| 1999/0811 | p->movetime = MACHP(0)->ticks + HZ/10; | |
| 1995/0811 | p->mp = MACHP(m->machno); | |
| 2002/0315 | ||
| 1995/0110 | return p; | |
| 1990/0227 | } | |
| 1991/0705 | int canpage(Proc *p) { int ok = 0; splhi(); | |
| 1995/0110 | lock(runq); | |
| 1991/0906 | /* Only reliable way to see if we are Running */ if(p->mach == 0) { | |
| 1991/0705 | p->newtlb = 1; ok = 1; } | |
| 1995/0110 | unlock(runq); | |
| 1991/0705 | spllo(); return ok; } | |
| 1990/0227 | Proc* newproc(void) { Proc *p; | |
| 1993/0501 | lock(&procalloc); | |
| 1991/1110 | for(;;) { | |
| 1993/0501 | if(p = procalloc.free) break; | |
| 1990/0227 | unlock(&procalloc); | |
| 1991/1110 | resrcwait("no procs"); | |
| 1993/0501 | lock(&procalloc); | |
| 1990/0227 | } | |
| 1993/0501 | procalloc.free = p->qnext; unlock(&procalloc); p->state = Scheding; p->psstate = "New"; p->mach = 0; p->qnext = 0; p->nchild = 0; p->nwait = 0; p->waitq = 0; | |
| 2001/0802 | p->parent = 0; | |
| 1993/0501 | p->pgrp = 0; p->egrp = 0; p->fgrp = 0; | |
| 1994/0812 | p->rgrp = 0; | |
| 1993/0501 | p->pdbg = 0; | |
| 2000/1027 | p->fpstate = FPinit; | |
| 1993/0501 | p->kp = 0; p->procctl = 0; p->notepending = 0; | |
| 1995/0110 | p->mp = 0; p->movetime = 0; | |
| 1995/0102 | p->wired = 0; | |
| 1995/0115 | p->ureg = 0; | |
| 2001/1117 | p->privatemem = 0; | |
| 2002/0502 | p->noswap = 0; | |
| 2002/0328 | p->lockwait = nil; | |
| 2001/0924 | p->errstr = p->errbuf0; p->syserrstr = p->errbuf1; p->errbuf0[0] = '\0'; p->errbuf1[0] = '\0'; | |
| 2002/0404 | p->nlocks = 0; p->delaysched = 0; | |
| 2002/0415 | p->movetime = 0; | |
| 2001/0527 | kstrdup(&p->user, "*nouser"); kstrdup(&p->text, "*notext"); kstrdup(&p->args, ""); p->nargs = 0; | |
| 1993/0501 | memset(p->seg, 0, sizeof p->seg); p->pid = incref(&pidalloc); | |
| 2001/0510 | pidhash(p); | |
| 1993/0501 | p->noteid = incref(¬eidalloc); if(p->pid==0 || p->noteid==0) panic("pidalloc"); if(p->kstack == 0) p->kstack = smalloc(KSTACK); | |
| 2002/0315 | p->task = nil; | |
| 1993/0501 | return p; | |
| 1990/0227 | } | |
| 1995/0102 | /* * wire this proc to a machine */ | |
| 1990/0227 | void | |
| 1999/0711 | procwired(Proc *p, int bm) | |
| 1995/0102 | { Proc *pp; | |
| 1999/0711 | int i; | |
| 1995/0102 | char nwired[MAXMACH]; | |
| 1999/0711 | Mach *wm; | |
| 1995/0102 | ||
| 1999/0711 | if(bm < 0){ /* pick a machine to wire to */ memset(nwired, 0, sizeof(nwired)); p->wired = 0; pp = proctab(0); for(i=0; i<conf.nproc; i++, pp++){ wm = pp->wired; if(wm && pp->pid) nwired[wm->machno]++; } bm = 0; for(i=0; i<conf.nmach; i++) if(nwired[i] < nwired[bm]) bm = i; } else { /* use the virtual machine requested */ bm = bm % conf.nmach; } | |
| 1995/0102 | p->wired = MACHP(bm); | |
| 1995/0110 | p->movetime = 0xffffffff; p->mp = p->wired; | |
| 1995/0102 | } void | |
| 1990/0227 | procinit0(void) /* bad planning - clashes with devproc.c */ { Proc *p; int i; | |
| 1992/0619 | procalloc.free = xalloc(conf.nproc*sizeof(Proc)); | |
| 1997/0327 | if(procalloc.free == nil) | |
| 2002/0114 | panic("cannot allocate %lud procs\n", conf.nproc); | |
| 1990/0227 | procalloc.arena = procalloc.free; p = procalloc.free; | |
| 1994/0612 | for(i=0; i<conf.nproc-1; i++,p++) | |
| 1990/0227 | p->qnext = p+1; p->qnext = 0; } | |
| 1998/0514 | /* | |
| 2000/0919 | * sleep if a condition is not true. Another process will * awaken us after it sets the condition. When we awaken * the condition may no longer be true. | |
| 1998/0514 | * | |
| 2000/0919 | * we lock both the process and the rendezvous to keep r->p * and p->r synchronized. | |
| 1998/0514 | */ | |
| 1990/0227 | void | |
| 1998/0513 | sleep(Rendez *r, int (*f)(void*), void *arg) | |
| 1990/0227 | { int s; s = splhi(); | |
| 1998/0513 | ||
| 2002/0404 | if (up->nlocks) print("process %lud sleeps with %lud locks held, last lock 0x%p locked at pc 0x%lux\n", up->pid, up->nlocks, up->lastlock, up->lastlock->pc); | |
| 2000/0919 | lock(r); | |
| 1996/1016 | lock(&up->rlock); | |
| 1996/1017 | if(r->p){ | |
| 1998/0825 | print("double sleep %lud %lud\n", r->p->pid, up->pid); | |
| 1996/1017 | dumpstack(); } | |
| 1990/0227 | /* | |
| 1998/0514 | * Wakeup only knows there may be something to do by testing * r->p in order to get something to lock on. * Flush that information out to memory in case the sleep is * committed. | |
| 1990/0227 | */ | |
| 1998/0513 | r->p = up; if((*f)(arg) || up->notepending){ /* * if condition happened or a note is pending * never mind */ r->p = nil; | |
| 1996/1016 | unlock(&up->rlock); | |
| 2000/0919 | unlock(r); | |
| 1998/0513 | } else { /* * now we are committed to * change state and call scheduler */ up->state = Wakeme; up->r = r; /* statistics */ m->cs++; | |
| 2002/0315 | ||
| 1998/0513 | procsave(up); if(setlabel(&up->sched)) { /* * here when the process is awakened */ procrestore(up); spllo(); } else { /* * here to go to sleep (i.e. stop Running) */ unlock(&up->rlock); | |
| 2000/0919 | unlock(r); | |
| 2002/0315 | // Behind unlock, we may call wakeup on ourselves. | |
| 2002/0704 | if (edf->isedf(up)) edf->edfblock(up); | |
| 2002/0404 | ||
| 1998/0513 | gotolabel(&m->sched); } | |
| 1990/0227 | } | |
| 1993/0501 | if(up->notepending) { up->notepending = 0; | |
| 1992/0519 | splx(s); | |
| 2001/1218 | error(Eintr); | |
| 1990/0227 | } | |
| 1998/0513 | splx(s); | |
| 1990/0227 | } | |
| 1992/0617 | int tfn(void *arg) { | |
| 1997/0327 | return MACHP(0)->ticks >= up->twhen || up->tfn(arg); | |
| 1992/0617 | } | |
| 1990/0227 | void | |
| 1992/0602 | tsleep(Rendez *r, int (*fn)(void*), void *arg, int ms) | |
| 1990/0227 | { | |
| 1994/0812 | ulong when; | |
| 1993/0501 | Proc *f, **l; | |
| 1990/0227 | ||
| 2002/0326 | when = ms2tk(ms) + MACHP(0)->ticks; | |
| 1992/0602 | lock(&talarm); | |
| 1992/0701 | /* take out of list if checkalarm didn't */ | |
| 1993/0501 | if(up->trend) { | |
| 1992/0701 | l = &talarm.list; for(f = *l; f; f = f->tlink) { | |
| 1993/0501 | if(f == up) { *l = up->tlink; | |
| 1992/0701 | break; } l = &f->tlink; } } /* insert in increasing time order */ | |
| 1992/0602 | l = &talarm.list; | |
| 1992/0701 | for(f = *l; f; f = f->tlink) { if(f->twhen >= when) break; | |
| 1992/0602 | l = &f->tlink; | |
| 1991/0727 | } | |
| 1993/0501 | up->trend = r; up->twhen = when; up->tfn = fn; up->tlink = *l; *l = up; | |
| 1992/0602 | unlock(&talarm); | |
| 2000/0129 | if(waserror()){ up->twhen = 0; nexterror(); } | |
| 1992/0617 | sleep(r, tfn, arg); | |
| 1993/0501 | up->twhen = 0; | |
| 2000/0129 | poperror(); | |
| 1990/0227 | } | |
| 1992/0909 | /* | |
| 2000/0919 | * Expects that only one process can call wakeup for any given Rendez. * We hold both locks to ensure that r->p and p->r remain consistent. * Richard Miller has a better solution that doesn't require both to * be held simultaneously, but I'm a paranoid - presotto. | |
| 1992/0909 | */ | |
| 2001/0207 | Proc* | |
| 1990/0227 | wakeup(Rendez *r) { | |
| 2001/0529 | Proc *p; | |
| 2001/0207 | int s; | |
| 1990/0227 | ||
| 1996/1017 | s = splhi(); | |
| 2000/0919 | lock(r); p = r->p; if(p != nil){ lock(&p->rlock); if(p->state != Wakeme || p->r != r) | |
| 1991/0705 | panic("wakeup: state"); | |
| 2000/0919 | r->p = nil; p->r = nil; | |
| 1990/0227 | ready(p); | |
| 2000/0919 | unlock(&p->rlock); | |
| 1990/0227 | } | |
| 2000/0919 | unlock(r); | |
| 1990/0227 | splx(s); | |
| 1997/0220 | ||
| 2001/0529 | return p; | |
| 1990/03091 | } | |
| 2000/0919 | /* * if waking a sleeping process, this routine must hold both * p->rlock and r->lock. However, it can't know them in * the same order as wakeup causing a possible lock ordering * deadlock. We break the deadlock by giving up the p->rlock * lock if we can't get the r->lock and retrying. */ | |
| 1990/0227 | int postnote(Proc *p, int dolock, char *n, int flag) { | |
| 1991/1120 | int s, ret; | |
| 1990/0227 | Rendez *r; | |
| 1991/0806 | Proc *d, **l; | |
| 1990/0227 | if(dolock) | |
| 1991/1216 | qlock(&p->debug); | |
| 1991/0430 | ||
| 1993/0501 | if(flag != NUser && (p->notify == 0 || p->notified)) p->nnote = 0; | |
| 1991/0425 | ||
| 1991/1120 | ret = 0; | |
| 1993/0501 | if(p->nnote < NNOTE) { | |
| 1996/0626 | strcpy(p->note[p->nnote].msg, n); | |
| 1993/0501 | p->note[p->nnote++].flag = flag; | |
| 1991/1120 | ret = 1; | |
| 1990/0617 | } | |
| 1991/0727 | p->notepending = 1; | |
| 1990/0227 | if(dolock) | |
| 1991/1216 | qunlock(&p->debug); | |
| 1991/0705 | ||
| 2000/0919 | /* this loop is to avoid lock ordering problems. */ for(;;){ s = splhi(); lock(&p->rlock); r = p->r; /* waiting for a wakeup? */ if(r == nil) break; /* no */ /* try for the second lock */ if(canlock(r)){ if(p->state != Wakeme || r->p != p) panic("postnote: state %d %d %d", r->p != p, p->r != r, p->state); p->r = nil; r->p = nil; ready(p); unlock(r); break; } /* give other process time to get out of critical section and try again */ unlock(&p->rlock); splx(s); sched(); | |
| 1990/0227 | } | |
| 1996/1017 | unlock(&p->rlock); splx(s); | |
| 1991/0807 | ||
| 1992/1206 | if(p->state != Rendezvous) return ret; /* Try and pull out of a rendezvous */ | |
| 1994/0812 | lock(p->rgrp); | |
| 1991/0806 | if(p->state == Rendezvous) { | |
| 1992/1206 | p->rendval = ~0; | |
| 1994/0812 | l = &REND(p->rgrp, p->rendtag); | |
| 1992/1206 | for(d = *l; d; d = d->rendhash) { if(d == p) { *l = p->rendhash; break; | |
| 1991/0806 | } | |
| 1992/1206 | l = &d->rendhash; | |
| 1991/0806 | } | |
| 1993/0501 | ready(p); | |
| 1991/0806 | } | |
| 1994/0812 | unlock(p->rgrp); | |
| 1991/1120 | return ret; | |
| 1990/0227 | } | |
| 1990/1101 | /* * weird thing: keep at most NBROKEN around */ #define NBROKEN 4 | |
| 1992/1206 | struct { QLock; | |
| 1990/1101 | int n; Proc *p[NBROKEN]; }broken; | |
| 1990/0227 | void | |
| 1992/1206 | addbroken(Proc *p) | |
| 1990/1101 | { | |
| 1992/1206 | qlock(&broken); if(broken.n == NBROKEN) { | |
| 1990/1101 | ready(broken.p[0]); | |
| 1991/0318 | memmove(&broken.p[0], &broken.p[1], sizeof(Proc*)*(NBROKEN-1)); | |
| 1990/1101 | --broken.n; } | |
| 1992/1206 | broken.p[broken.n++] = p; qunlock(&broken); | |
| 2002/0704 | if (edf->isedf(up)) edf->edfbury(up); | |
| 1992/1206 | p->state = Broken; p->psstate = 0; sched(); | |
| 1990/1101 | } | |
| 1992/1206 | void unbreak(Proc *p) { int b; qlock(&broken); | |
| 1992/1208 | for(b=0; b < broken.n; b++) | |
| 1992/1225 | if(broken.p[b] == p) { | |
| 1992/1208 | broken.n--; memmove(&broken.p[b], &broken.p[b+1], sizeof(Proc*)*(NBROKEN-(b+1))); ready(p); break; } | |
| 1992/1206 | qunlock(&broken); } | |
| 1990/1101 | int freebroken(void) { | |
| 1991/0109 | int i, n; | |
| 1990/1101 | ||
| 1992/1206 | qlock(&broken); | |
| 1990/1101 | n = broken.n; | |
| 1992/1206 | for(i=0; i<n; i++) { | |
| 1991/0109 | ready(broken.p[i]); | |
| 1992/1206 | broken.p[i] = 0; } | |
| 1991/0109 | broken.n = 0; | |
| 1992/1206 | qunlock(&broken); | |
| 1990/1101 | return n; } void | |
| 1991/0717 | pexit(char *exitstr, int freemem) | |
| 1990/0227 | { | |
| 1993/0501 | Proc *p; | |
| 1992/1206 | Segment **s, **es; | |
| 1993/0501 | long utime, stime; | |
| 1991/0926 | Waitq *wq, *f, *next; | |
| 1997/1104 | Fgrp *fgrp; | |
| 2000/0331 | Egrp *egrp; Rgrp *rgrp; Pgrp *pgrp; Chan *dot; | |
| 1990/0227 | ||
| 1993/0501 | up->alarm = 0; | |
| 1991/0517 | ||
| 2000/0331 | /* nil out all the resources under lock (free later) */ qlock(&up->debug); fgrp = up->fgrp; up->fgrp = nil; egrp = up->egrp; up->egrp = nil; rgrp = up->rgrp; up->rgrp = nil; pgrp = up->pgrp; up->pgrp = nil; dot = up->dot; | |
| 2000/0325 | up->dot = nil; | |
| 2000/0331 | qunlock(&up->debug); if(fgrp) closefgrp(fgrp); if(egrp) closeegrp(egrp); if(rgrp) closergrp(rgrp); if(dot) cclose(dot); if(pgrp) closepgrp(pgrp); | |
| 1993/0501 | ||
| 1992/0115 | /* * if not a kernel process and have a parent, * do some housekeeping. */ | |
| 1993/0501 | if(up->kp == 0) { p = up->parent; | |
| 1992/1206 | if(p == 0) { | |
| 1992/0902 | if(exitstr == 0) exitstr = "unknown"; panic("boot process died: %s", exitstr); } | |
| 1992/0805 | while(waserror()) | |
| 1993/0501 | ; | |
| 1998/0512 | ||
| 1992/0620 | wq = smalloc(sizeof(Waitq)); | |
| 1992/0805 | poperror(); | |
| 2001/0819 | wq->w.pid = up->pid; | |
| 2002/0501 | utime = up->time[TUser] + up->time[TCUser]; stime = up->time[TSys] + up->time[TCSys]; | |
| 2002/0710 | wq->w.time[TUser] = tk2ms(utime); wq->w.time[TSys] = tk2ms(stime); wq->w.time[TReal] = tk2ms(MACHP(0)->ticks - up->time[TReal]); | |
| 2001/0819 | if(exitstr && exitstr[0]) snprint(wq->w.msg, sizeof(wq->w.msg), "%s %lud: %s", up->text, up->pid, exitstr); | |
| 1992/1206 | else | |
| 1991/1006 | wq->w.msg[0] = '\0'; | |
| 1991/1005 | lock(&p->exl); | |
| 1996/1016 | /* * If my parent is no longer alive, or if there would be more * than 128 zombie child processes for my parent, then don't * leave a wait record behind. This helps prevent badly * written daemon processes from accumulating lots of wait * records. | |
| 1992/0620 | */ | |
| 1998/0512 | if(p->pid == up->parentpid && p->state != Broken && p->nwait < 128) { | |
| 1991/1005 | p->nchild--; | |
| 1992/0205 | p->time[TCUser] += utime; p->time[TCSys] += stime; | |
| 1998/0512 | ||
| 1991/1005 | wq->next = p->waitq; p->waitq = wq; p->nwait++; | |
| 1998/0512 | ||
| 1991/1005 | wakeup(&p->waitr); | |
| 1996/1016 | unlock(&p->exl); | |
| 1991/1005 | } else { unlock(&p->exl); | |
| 1992/0620 | free(wq); | |
| 1991/1005 | } | |
| 1990/0227 | } | |
| 1990/03081 | ||
| 1991/0926 | if(!freemem) | |
| 1993/0501 | addbroken(up); | |
| 1990/03081 | ||
| 1999/0108 | qlock(&up->seglock); | |
| 1993/0501 | es = &up->seg[NSEG]; | |
| 1995/0104 | for(s = up->seg; s < es; s++) { if(*s) { | |
| 1992/1206 | putseg(*s); | |
| 1995/0104 | *s = 0; } } | |
| 1999/0108 | qunlock(&up->seglock); | |
| 1991/0926 | ||
| 1993/0501 | lock(&up->exl); /* Prevent my children from leaving waits */ | |
| 2001/0510 | pidunhash(up); | |
| 1993/0501 | up->pid = 0; | |
| 1996/0121 | wakeup(&up->waitr); | |
| 1993/0501 | unlock(&up->exl); | |
| 1991/0926 | ||
| 1993/0501 | for(f = up->waitq; f; f = next) { | |
| 1991/0926 | next = f->next; | |
| 1992/0620 | free(f); | |
| 1991/0926 | } | |
| 1991/1110 | /* release debuggers */ | |
| 1995/0104 | qlock(&up->debug); | |
| 1993/0501 | if(up->pdbg) { wakeup(&up->pdbg->sleep); up->pdbg = 0; | |
| 1991/1110 | } | |
| 1995/0104 | qunlock(&up->debug); | |
| 1991/1110 | ||
| 1998/0605 | /* Sched must not loop for these locks */ | |
| 1991/1110 | lock(&procalloc); | |
| 1995/1230 | lock(&palloc); | |
| 1991/0705 | ||
| 2002/0704 | if (edf->isedf(up)) edf->edfbury(up); | |
| 1993/0501 | up->state = Moribund; | |
| 1991/0705 | sched(); panic("pexit"); | |
| 1990/0227 | } | |
| 1991/0926 | int haswaitq(void *x) { Proc *p; p = (Proc *)x; return p->waitq != 0; } | |
| 1990/0227 | ulong pwait(Waitmsg *w) { ulong cpid; | |
| 1991/0926 | Waitq *wq; | |
| 1990/0227 | ||
| 1993/0501 | if(!canqlock(&up->qwaitr)) | |
| 1993/0309 | error(Einuse); if(waserror()) { | |
| 1993/0501 | qunlock(&up->qwaitr); | |
| 1993/0309 | nexterror(); } | |
| 1993/0501 | lock(&up->exl); if(up->nchild == 0 && up->waitq == 0) { unlock(&up->exl); | |
| 1991/0926 | error(Enochild); | |
| 1990/0227 | } | |
| 1993/0501 | unlock(&up->exl); | |
| 1991/0926 | ||
| 1993/0501 | sleep(&up->waitr, haswaitq, up); | |
| 1991/0926 | ||
| 1993/0501 | lock(&up->exl); wq = up->waitq; up->waitq = wq->next; up->nwait--; unlock(&up->exl); | |
| 1993/0309 | ||
| 1993/0501 | qunlock(&up->qwaitr); | |
| 1993/0309 | poperror(); | |
| 1991/0926 | ||
| 1990/0227 | if(w) | |
| 1991/0926 | memmove(w, &wq->w, sizeof(Waitmsg)); | |
| 2001/0819 | cpid = wq->w.pid; | |
| 1992/0620 | free(wq); | |
| 1990/0227 | return cpid; } Proc* proctab(int i) { return &procalloc.arena[i]; } | |
| 1990/1220 | void | |
| 1995/1030 | dumpaproc(Proc *p) { ulong bss; char *s; if(p == 0) return; bss = 0; if(p->seg[BSEG]) bss = p->seg[BSEG]->top; s = p->psstate; if(s == 0) | |
| 2001/0217 | s = statename[p->state]; | |
| 2002/0404 | print("%3lud:%10s pc %8lux dbgpc %8lux %8s (%s) ut %ld st %ld bss %lux qpc %lux nl %lud nd %lud lpc %lux\n", | |
| 1995/1030 | p->pid, p->text, p->pc, dbgpc(p), s, statename[p->state], | |
| 2002/0404 | p->time[0], p->time[1], bss, p->qpc, p->nlocks, p->delaysched, p->lastlock ? p->lastlock->pc : 0); | |
| 1995/1030 | } void | |
| 1991/0608 | procdump(void) | |
| 1990/0227 | { | |
| 1990/0330 | int i; | |
| 1990/0227 | Proc *p; | |
| 1995/1009 | if(up) | |
| 1998/0825 | print("up %lud\n", up->pid); | |
| 1995/1009 | else print("no current process\n"); | |
| 1993/0501 | for(i=0; i<conf.nproc; i++) { p = &procalloc.arena[i]; if(p->state == Dead) continue; | |
| 1992/0805 | ||
| 1995/1030 | dumpaproc(p); | |
| 1994/0728 | } | |
| 1995/1030 | } | |
| 1998/0725 | /* * wait till all processes have flushed their mmu * state about segement s */ void procflushseg(Segment *s) { int i, ns, nm, nwait; Proc *p; /* * tell all processes with this * segment to flush their mmu's */ nwait = 0; for(i=0; i<conf.nproc; i++) { p = &procalloc.arena[i]; if(p->state == Dead) continue; for(ns = 0; ns < NSEG; ns++) if(p->seg[ns] == s){ p->newtlb = 1; for(nm = 0; nm < conf.nmach; nm++){ if(MACHP(nm)->proc == p){ MACHP(nm)->flushmmu = 1; nwait++; } } break; } } if(nwait == 0) return; /* * wait for all processors to take a clock interrupt * and flush their mmu's */ for(nm = 0; nm < conf.nmach; nm++) if(MACHP(nm) != m) while(MACHP(nm)->flushmmu) sched(); } | |
| 1995/1030 | void scheddump(void) { Proc *p; Schedq *rq; | |
| 1995/0110 | for(rq = &runq[Nrq-1]; rq >= runq; rq--){ if(rq->head == 0) continue; | |
| 1998/0825 | print("rq%ld:", rq-runq); | |
| 1995/0110 | for(p = rq->head; p; p = p->rnext) | |
| 1998/0825 | print(" %lud(%lud, %lud)", p->pid, m->ticks - p->readytime, | |
| 1999/0811 | MACHP(0)->ticks - p->movetime); | |
| 1994/0728 | print("\n"); | |
| 1995/1030 | delay(150); | |
| 1990/0227 | } | |
| 1995/0110 | print("nrdy %d\n", nrdy); | |
| 1990/0227 | } void kproc(char *name, void (*func)(void *), void *arg) { Proc *p; | |
| 1990/0722 | static Pgrp *kpgrp; | |
| 1990/0227 | p = newproc(); | |
| 2001/0527 | p->psstate = 0; p->procmode = 0640; | |
| 1990/1212 | p->kp = 1; | |
| 2002/0502 | p->noswap = 1; | |
| 1990/0227 | ||
| 1993/0501 | p->fpsave = up->fpsave; p->scallnr = up->scallnr; p->s = up->s; p->nerrlab = 0; p->slash = up->slash; p->dot = up->dot; incref(p->dot); | |
| 1990/0227 | ||
| 1993/0501 | memmove(p->note, up->note, sizeof(p->note)); p->nnote = up->nnote; p->notified = 0; p->lastnote = up->lastnote; p->notify = up->notify; p->ureg = 0; p->dbgreg = 0; | |
| 1994/0920 | ||
| 1995/0110 | p->basepri = PriKproc; p->priority = p->basepri; | |
| 1990/0227 | ||
| 1993/0501 | kprocchild(p, func, arg); | |
| 1991/0705 | ||
| 2001/0527 | kstrdup(&p->user, eve); kstrdup(&p->text, name); | |
| 1993/0501 | if(kpgrp == 0) | |
| 1990/0722 | kpgrp = newpgrp(); p->pgrp = kpgrp; incref(kpgrp); | |
| 1991/0705 | ||
| 1990/0227 | memset(p->time, 0, sizeof(p->time)); p->time[TReal] = MACHP(0)->ticks; | |
| 1991/0926 | ready(p); | |
| 1991/0529 | /* * since the bss/data segments are now shareable, * any mmu info about this process is now stale * and has to be discarded. */ | |
| 2000/1018 | p->newtlb = 1; | |
| 1990/0227 | flushmmu(); | |
| 1991/0705 | } | |
| 1992/0609 | /* * called splhi() by notify(). See comment in notify for the * reasoning. */ | |
| 1991/0705 | void procctl(Proc *p) { | |
| 1991/1108 | char *state; | |
| 1995/0112 | ulong s; | |
| 1991/1108 | ||
| 1991/0705 | switch(p->procctl) { | |
| 1995/0215 | case Proc_exitbig: spllo(); pexit("Killed: Insufficient physical memory", 1); | |
| 1991/0705 | case Proc_exitme: | |
| 1993/0501 | spllo(); /* pexit has locks in it */ | |
| 1991/0705 | pexit("Killed", 1); | |
| 1992/0620 | ||
| 1991/1110 | case Proc_traceme: | |
| 1993/0501 | if(p->nnote == 0) | |
| 1991/1110 | return; /* No break */ | |
| 1992/0620 | ||
| 1991/0705 | case Proc_stopme: p->procctl = 0; | |
| 1991/1108 | state = p->psstate; p->psstate = "Stopped"; | |
| 1991/1110 | /* free a waiting debugger */ | |
| 1995/0112 | s = spllo(); | |
| 1991/1216 | qlock(&p->debug); | |
| 1991/1110 | if(p->pdbg) { wakeup(&p->pdbg->sleep); p->pdbg = 0; } | |
| 1991/1216 | qunlock(&p->debug); | |
| 1995/0105 | splhi(); | |
| 1991/0705 | p->state = Stopped; | |
| 2002/0704 | if (edf->isedf(up)) edf->edfblock(up); | |
| 1995/0112 | sched(); | |
| 1991/1108 | p->psstate = state; | |
| 1995/0112 | splx(s); | |
| 1991/0705 | return; } | |
| 1990/0227 | } | |
| 1991/0710 | #include "errstr.h" void | |
| 1992/0604 | error(char *err) | |
| 1991/0710 | { | |
| 1995/0110 | spllo(); | |
| 2001/0924 | kstrcpy(up->errstr, err, ERRMAX); | |
| 2002/0413 | setlabel(&up->errlab[NERR-1]); | |
| 1991/0710 | nexterror(); } void | |
| 1992/0114 | nexterror(void) | |
| 1991/0710 | { | |
| 1993/0501 | gotolabel(&up->errlab[--up->nerrlab]); | |
| 1991/0710 | } void | |
| 1992/0114 | exhausted(char *resource) | |
| 1991/0710 | { | |
| 2001/0527 | char buf[ERRMAX]; | |
| 1992/0114 | sprint(buf, "no free %s", resource); | |
| 1997/0327 | iprint("%s\n", buf); | |
| 1992/0114 | error(buf); | |
| 1991/0926 | } | |
| 1993/1123 | void killbig(void) { int i; Segment *s; ulong l, max; Proc *p, *ep, *kp; max = 0; kp = 0; ep = procalloc.arena+conf.nproc; for(p = procalloc.arena; p < ep; p++) { if(p->state == Dead || p->kp) continue; l = 0; | |
| 1994/0325 | for(i=1; i<NSEG; i++) { | |
| 1993/1123 | s = p->seg[i]; | |
| 1995/0104 | if(s != 0) | |
| 1993/1123 | l += s->top - s->base; } | |
| 2002/0506 | if(l > max && strcmp(p->text, "kfs") != 0){ | |
| 1993/1123 | kp = p; max = l; } } | |
| 1995/0215 | kp->procctl = Proc_exitbig; | |
| 1995/0104 | for(i = 0; i < NSEG; i++) { s = kp->seg[i]; if(s != 0 && canqlock(&s->lk)) { mfreeseg(s, s->base, (s->top - s->base)/BY2PG); qunlock(&s->lk); } } | |
| 1998/0825 | print("%lud: %s killed because no swap configured\n", kp->pid, kp->text); | |
| 1993/1123 | } | |
| 1994/1027 | /* * change ownership to 'new' of all processes owned by 'old'. Used when * eve changes. */ void renameuser(char *old, char *new) { Proc *p, *ep; ep = procalloc.arena+conf.nproc; for(p = procalloc.arena; p < ep; p++) | |
| 2001/0527 | if(p->user!=nil && strcmp(old, p->user)==0) kstrdup(&p->user, new); | |
| 1995/0104 | } /* * time accounting called by clock() splhi'd */ void accounttime(void) { Proc *p; | |
| 2002/0822 | ulong n, per; | |
| 2002/0821 | static ulong nrun; | |
| 1995/0104 | p = m->proc; if(p) { nrun++; p->time[p->insyscall]++; } | |
| 2002/0822 | /* calculate decaying duty cycles */ n = perfticks(); per = n - m->perf.last; m->perf.last = n; | |
| 2002/1010 | per = (m->perf.period*(HZ-1) + per)/HZ; if(per != 0) m->perf.period = per; | |
| 2002/0822 | m->perf.avg_inidle = (m->perf.avg_inidle*(HZ-1)+m->perf.inidle)/HZ; m->perf.inidle = 0; m->perf.avg_inintr = (m->perf.avg_inintr*(HZ-1)+m->perf.inintr)/HZ; m->perf.inintr = 0; | |
| 1995/0104 | /* only one processor gets to compute system load averages */ if(m->machno != 0) return; /* calculate decaying load average */ | |
| 1995/0110 | n = nrun; | |
| 1995/0104 | nrun = 0; | |
| 1995/0110 | n = (nrdy+n)*1000; m->load = (m->load*19+n)/20; | |
| 2001/0510 | } static void pidhash(Proc *p) { int h; h = p->pid % nelem(procalloc.ht); lock(&procalloc); p->pidhash = procalloc.ht[h]; procalloc.ht[h] = p; unlock(&procalloc); } static void pidunhash(Proc *p) { int h; Proc **l; h = p->pid % nelem(procalloc.ht); lock(&procalloc); for(l = &procalloc.ht[h]; *l != nil; l = &(*l)->pidhash) if(*l == p){ *l = p->pidhash; break; } unlock(&procalloc); } int | |
| 2001/0527 | procindex(ulong pid) | |
| 2001/0510 | { Proc *p; int h; int s; s = -1; h = pid % nelem(procalloc.ht); lock(&procalloc); for(p = procalloc.ht[h]; p != nil; p = p->pidhash) if(p->pid == pid){ s = p - procalloc.arena; break; } unlock(&procalloc); return s; | |
| 1994/1027 | } | |