| plan 9 kernel history: overview | file list | diff list |
1993/0309/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 | ||
| 1992/0309 | Ref pidalloc; | |
| 1992/0428 | Ref noteidalloc; | |
| 1990/0227 | struct { Lock; Proc *arena; Proc *free; }procalloc; | |
| 1991/0926 | struct { Lock; Waitq *free; }waitqalloc; | |
| 1991/0420 | typedef struct | |
| 1990/0227 | { Lock; Proc *head; Proc *tail; | |
| 1991/0420 | }Schedq; | |
| 1990/0227 | ||
| 1991/1112 | Schedq runhiq, runloq; int nrdy; | |
| 1991/0420 | ||
| 1992/0309 | char *statename[] = { /* BUG: generate automatically */ | |
| 1990/0227 | "Dead", "Moribund", "Ready", "Scheding", "Running", "Queueing", "Wakeme", "Broken", | |
| 1991/0705 | "Stopped", | |
| 1991/0806 | "Rendez", | |
| 1990/0227 | }; /* * Always splhi()'ed. */ void schedinit(void) /* never returns */ { Proc *p; setlabel(&m->sched); if(u){ m->proc = 0; p = u->p; | |
| 1990/1211 | invalidateu(); /* safety first */ | |
| 1990/0227 | u = 0; if(p->state == Running) ready(p); | |
| 1992/0619 | else if(p->state == Moribund) { | |
| 1990/0227 | p->pid = 0; | |
| 1992/0620 | p->state = Dead; | |
| 1991/0705 | /* | |
| 1991/0717 | * Holding locks from pexit: | |
| 1991/0705 | * procalloc, debug, palloc */ | |
| 1991/1003 | mmurelease(p); simpleputpage(p->upage); | |
| 1991/0705 | p->upage = 0; | |
| 1990/0227 | p->qnext = procalloc.free; procalloc.free = p; | |
| 1991/0705 | unlock(&palloc); | |
| 1991/1216 | qunlock(&p->debug); | |
| 1990/0227 | unlock(&procalloc); } p->mach = 0; } sched(); } void sched(void) { Proc *p; if(u){ splhi(); | |
| 1991/0425 | m->cs++; | |
| 1992/0122 | procsave(u->p); | |
| 1990/0227 | if(setlabel(&u->p->sched)){ /* woke up */ p = u->p; p->state = Running; p->mach = m; m->proc = p; | |
| 1992/0122 | procrestore(p); | |
| 1990/0227 | spllo(); return; } gotolabel(&m->sched); } p = runproc(); mapstack(p); gotolabel(&p->sched); } | |
| 1990/1227 | int anyready(void) { | |
| 1991/0420 | return runloq.head != 0 || runhiq.head != 0; | |
| 1990/1227 | } | |
| 1990/0227 | void ready(Proc *p) { | |
| 1991/0420 | Schedq *rq; | |
| 1990/0227 | int s; s = splhi(); | |
| 1991/0501 | ||
| 1991/0420 | if(p->state == Running) rq = &runloq; else rq = &runhiq; lock(&runhiq); | |
| 1990/0227 | p->rnext = 0; | |
| 1991/0420 | if(rq->tail) rq->tail->rnext = p; | |
| 1990/0227 | else | |
| 1991/0420 | rq->head = p; rq->tail = p; | |
| 1991/1112 | nrdy++; | |
| 1990/0227 | p->state = Ready; | |
| 1991/0420 | unlock(&runhiq); | |
| 1990/0227 | splx(s); } /* | |
| 1992/0603 | * Always called splhi | |
| 1990/0227 | */ Proc* runproc(void) { | |
| 1991/0420 | Schedq *rq; | |
| 1990/0227 | Proc *p; loop: | |
| 1992/0603 | spllo(); | |
| 1991/0420 | while(runhiq.head==0 && runloq.head==0) | |
| 1992/0622 | ; | |
| 1990/0227 | splhi(); | |
| 1992/0622 | ||
| 1991/0420 | lock(&runhiq); if(runhiq.head) rq = &runhiq; else rq = &runloq; p = rq->head; | |
| 1990/0227 | if(p==0 || p->mach){ /* p->mach==0 only when process state is saved */ | |
| 1991/0420 | unlock(&runhiq); | |
| 1990/0227 | goto loop; } if(p->rnext == 0) | |
| 1991/0420 | rq->tail = 0; rq->head = p->rnext; | |
| 1991/1112 | nrdy--; | |
| 1990/0227 | if(p->state != Ready) print("runproc %s %d %s\n", p->text, p->pid, statename[p->state]); | |
| 1991/0420 | unlock(&runhiq); | |
| 1990/0227 | p->state = Scheding; return p; } | |
| 1991/0705 | int canpage(Proc *p) { int ok = 0; splhi(); lock(&runhiq); | |
| 1991/0906 | /* Only reliable way to see if we are Running */ if(p->mach == 0) { | |
| 1991/0705 | p->newtlb = 1; ok = 1; } unlock(&runhiq); spllo(); return ok; } | |
| 1990/0227 | Proc* newproc(void) { Proc *p; | |
| 1991/1110 | for(;;) { lock(&procalloc); if(p = procalloc.free){ /* assign = */ procalloc.free = p->qnext; p->state = Scheding; p->psstate = "New"; unlock(&procalloc); p->mach = 0; p->qnext = 0; p->nchild = 0; p->nwait = 0; p->waitq = 0; p->pgrp = 0; p->egrp = 0; p->fgrp = 0; p->pdbg = 0; p->fpstate = FPinit; p->kp = 0; p->procctl = 0; p->notepending = 0; memset(p->seg, 0, sizeof p->seg); | |
| 1992/0309 | p->pid = incref(&pidalloc); | |
| 1992/0428 | p->noteid = incref(¬eidalloc); if(p->pid==0 || p->noteid==0) | |
| 1991/1110 | panic("pidalloc"); return p; } | |
| 1990/0227 | unlock(&procalloc); | |
| 1991/1110 | resrcwait("no procs"); | |
| 1990/0227 | } | |
| 1992/0520 | return 0; /* not reached */ | |
| 1990/0227 | } void procinit0(void) /* bad planning - clashes with devproc.c */ { Proc *p; int i; | |
| 1992/0619 | procalloc.free = xalloc(conf.nproc*sizeof(Proc)); | |
| 1990/0227 | procalloc.arena = procalloc.free; p = procalloc.free; | |
| 1990/0310 | for(i=0; i<conf.nproc-1; i++,p++) | |
| 1990/0227 | p->qnext = p+1; p->qnext = 0; } void sleep1(Rendez *r, int (*f)(void*), void *arg) { Proc *p; int s; /* * spl is to allow lock to be called * at interrupt time. lock is mutual exclusion */ s = splhi(); | |
| 1991/0727 | p = u->p; p->r = r; /* early so postnote knows */ | |
| 1990/0227 | lock(r); /* * if condition happened, never mind */ | |
| 1991/0727 | if((*f)(arg)){ p->r = 0; | |
| 1990/0227 | unlock(r); splx(s); return; } /* * now we are committed to * change state and call scheduler */ | |
| 1991/0807 | if(r->p){ | |
| 1990/03013 | print("double sleep %d %d\n", r->p->pid, p->pid); | |
| 1991/0807 | dumpstack(); } | |
| 1990/0227 | p->state = Wakeme; r->p = p; unlock(r); } void sleep(Rendez *r, int (*f)(void*), void *arg) { | |
| 1991/0727 | Proc *p; | |
| 1992/0519 | int s; | |
| 1991/0727 | p = u->p; | |
| 1990/0227 | sleep1(r, f, arg); | |
| 1991/0727 | if(p->notepending == 0) sched(); /* notepending may go true while asleep */ if(p->notepending){ p->notepending = 0; | |
| 1992/0519 | s = splhi(); | |
| 1991/0805 | lock(r); if(r->p == p) r->p = 0; unlock(r); | |
| 1992/0519 | splx(s); | |
| 1990/11211 | error(Eintr); | |
| 1990/0227 | } } | |
| 1992/0617 | int tfn(void *arg) { Proc *p; p = u->p; return MACHP(0)->ticks >= p->twhen || (*p->tfn)(arg); } | |
| 1990/0227 | void | |
| 1992/0602 | tsleep(Rendez *r, int (*fn)(void*), void *arg, int ms) | |
| 1990/0227 | { | |
| 1992/0602 | ulong when; | |
| 1992/0701 | Proc *p, *f, **l; | |
| 1990/0227 | ||
| 1991/0727 | p = u->p; | |
| 1992/0602 | when = MS2TK(ms)+MACHP(0)->ticks; lock(&talarm); | |
| 1992/0701 | /* take out of list if checkalarm didn't */ if(p->trend) { l = &talarm.list; for(f = *l; f; f = f->tlink) { if(f == p) { *l = p->tlink; 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 | } | |
| 1992/0602 | p->trend = r; p->twhen = when; | |
| 1992/0617 | p->tfn = fn; | |
| 1992/0701 | p->tlink = *l; *l = p; | |
| 1992/0602 | unlock(&talarm); | |
| 1992/0617 | sleep(r, tfn, arg); | |
| 1992/0602 | p->twhen = 0; | |
| 1990/0227 | } | |
| 1992/0909 | /* * Expects that only one process can call wakeup for any given Rendez */ | |
| 1990/0227 | void wakeup(Rendez *r) { Proc *p; int s; s = splhi(); lock(r); p = r->p; if(p){ r->p = 0; | |
| 1991/0705 | if(p->state != Wakeme) panic("wakeup: state"); | |
| 1990/0227 | p->r = 0; ready(p); } unlock(r); splx(s); | |
| 1990/03091 | } | |
| 1990/0227 | int postnote(Proc *p, int dolock, char *n, int flag) { User *up; | |
| 1990/0617 | KMap *k; | |
| 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/0112 | if(p->kp) print("sending %s to kproc %d %s\n", n, p->pid, p->text); | |
| 1991/0810 | if(p->upage == 0){ if(dolock) | |
| 1991/1216 | qunlock(&p->debug); | |
| 1992/0527 | return 0; | |
| 1991/0810 | } | |
| 1991/0425 | ||
| 1991/1115 | SET(k); | |
| 1991/0523 | if(u == 0 || p != u->p){ | |
| 1991/0109 | k = kmap(p->upage); up = (User*)VA(k); | |
| 1991/1115 | }else | |
| 1991/0109 | up = u; | |
| 1991/1127 | USED(k); | |
| 1991/0523 | ||
| 1990/0227 | if(flag!=NUser && (up->notify==0 || up->notified)) up->nnote = 0; /* force user's hand */ | |
| 1991/1120 | ret = 0; if(up->nnote < NNOTE){ strcpy(up->note[up->nnote].msg, n); up->note[up->nnote++].flag = flag; ret = 1; | |
| 1990/0617 | } | |
| 1991/0727 | p->notepending = 1; | |
| 1991/0109 | if(up != u) kunmap(k); | |
| 1990/0227 | if(dolock) | |
| 1991/1216 | qunlock(&p->debug); | |
| 1991/0705 | ||
| 1991/0727 | if(r = p->r){ /* assign = */ /* wake up; can't call wakeup itself because we're racing with it */ | |
| 1992/0909 | for(;;) { s = splhi(); if(canlock(r)) break; splx(s); } if(p->r==r && r->p==p && p->state==Wakeme){ /* check we won the race */ r->p = 0; p->r = 0; ready(p); | |
| 1990/0227 | } unlock(r); splx(s); } | |
| 1991/0807 | ||
| 1992/1206 | if(p->state != Rendezvous) return ret; /* Try and pull out of a rendezvous */ lock(p->pgrp); | |
| 1991/0806 | if(p->state == Rendezvous) { | |
| 1992/1206 | p->rendval = ~0; l = &REND(p->pgrp, p->rendtag); for(d = *l; d; d = d->rendhash) { if(d == p) { *l = p->rendhash; | |
| 1993/0216 | ready(p); | |
| 1992/1206 | break; | |
| 1991/0806 | } | |
| 1992/1206 | l = &d->rendhash; | |
| 1991/0806 | } } | |
| 1992/1206 | unlock(p->pgrp); | |
| 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); 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 | { | |
| 1991/1218 | int n; | |
| 1992/0205 | long utime, stime; | |
| 1991/0926 | Proc *p, *c; | |
| 1992/1206 | Segment **s, **es; | |
| 1991/0926 | Waitq *wq, *f, *next; | |
| 1990/0227 | ||
| 1990/03081 | c = u->p; | |
| 1991/0513 | c->alarm = 0; | |
| 1991/0517 | ||
| 1991/0712 | if(c->fgrp) closefgrp(c->fgrp); | |
| 1991/1024 | closepgrp(c->pgrp); close(u->dot); if(c->egrp) closeegrp(c->egrp); | |
| 1991/0517 | ||
| 1992/0115 | /* * if not a kernel process and have a parent, * do some housekeeping. */ | |
| 1992/0303 | if(c->kp == 0) { | |
| 1992/1206 | p = c->parent; if(p == 0) { | |
| 1992/0902 | if(exitstr == 0) exitstr = "unknown"; panic("boot process died: %s", exitstr); } | |
| 1992/0805 | while(waserror()) ; | |
| 1992/0620 | wq = smalloc(sizeof(Waitq)); | |
| 1992/0805 | poperror(); | |
| 1992/0309 | readnum(0, wq->w.pid, NUMSIZE, c->pid, NUMSIZE); | |
| 1992/0205 | utime = c->time[TUser] + c->time[TCUser]; stime = c->time[TSys] + c->time[TCSys]; | |
| 1992/0309 | readnum(0, &wq->w.time[TUser*12], NUMSIZE, TK2MS(utime), NUMSIZE); readnum(0, &wq->w.time[TSys*12], NUMSIZE, TK2MS(stime), NUMSIZE); readnum(0, &wq->w.time[TReal*12], NUMSIZE, TK2MS(MACHP(0)->ticks - c->time[TReal]), NUMSIZE); | |
| 1991/1218 | if(exitstr && exitstr[0]){ n = sprint(wq->w.msg, "%s %d:", c->text, c->pid); strncpy(wq->w.msg+n, exitstr, ERRLEN-n); | |
| 1992/1206 | } else | |
| 1991/1006 | wq->w.msg[0] = '\0'; | |
| 1991/1005 | lock(&p->exl); | |
| 1992/0309 | /* My parent still alive, processes are limited to 128 Zombies to | |
| 1992/0620 | * prevent a badly written daemon lots of wait records */ | |
| 1991/1005 | if(p->pid == c->parentpid && p->state != Broken && p->nwait < 128) { p->nchild--; | |
| 1992/0205 | p->time[TCUser] += utime; p->time[TCSys] += stime; | |
| 1991/1005 | wq->next = p->waitq; p->waitq = wq; p->nwait++; unlock(&p->exl); | |
| 1993/0309 | ||
| 1991/1005 | wakeup(&p->waitr); } else { unlock(&p->exl); | |
| 1992/0620 | free(wq); | |
| 1991/1005 | } | |
| 1990/0227 | } | |
| 1990/03081 | ||
| 1991/0926 | if(!freemem) addbroken(c); | |
| 1990/03081 | ||
| 1991/0926 | es = &c->seg[NSEG]; for(s = c->seg; s < es; s++) | |
| 1992/1206 | if(*s) putseg(*s); | |
| 1991/0926 | lock(&c->exl); /* Prevent my children from leaving waits */ c->pid = 0; unlock(&c->exl); for(f = c->waitq; f; f = next) { next = f->next; | |
| 1992/0620 | free(f); | |
| 1991/0926 | } | |
| 1991/0705 | /* * sched() cannot wait on these locks */ | |
| 1991/1216 | qlock(&c->debug); | |
| 1991/1110 | /* release debuggers */ if(c->pdbg) { wakeup(&c->pdbg->sleep); c->pdbg = 0; } lock(&procalloc); | |
| 1991/0705 | lock(&palloc); | |
| 1990/03081 | c->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) { | |
| 1991/0926 | Proc *p; | |
| 1990/0227 | ulong cpid; | |
| 1991/0926 | Waitq *wq; | |
| 1990/0227 | p = u->p; | |
| 1991/0926 | ||
| 1993/0309 | if(!canqlock(&p->qwaitr)) error(Einuse); if(waserror()) { qunlock(&p->qwaitr); nexterror(); } | |
| 1991/0926 | lock(&p->exl); if(p->nchild == 0 && p->waitq == 0) { unlock(&p->exl); error(Enochild); | |
| 1990/0227 | } | |
| 1991/0926 | unlock(&p->exl); sleep(&p->waitr, haswaitq, u->p); lock(&p->exl); wq = p->waitq; p->waitq = wq->next; p->nwait--; unlock(&p->exl); | |
| 1993/0309 | qunlock(&p->qwaitr); poperror(); | |
| 1991/0926 | ||
| 1990/0227 | if(w) | |
| 1991/0926 | memmove(w, &wq->w, sizeof(Waitmsg)); | |
| 1992/0309 | cpid = atoi(wq->w.pid); | |
| 1992/0620 | free(wq); | |
| 1990/0227 | return cpid; } Proc* proctab(int i) { return &procalloc.arena[i]; } | |
| 1990/1220 | void | |
| 1991/0608 | procdump(void) | |
| 1990/0227 | { | |
| 1990/0330 | int i; | |
| 1992/0805 | char *s; | |
| 1990/0227 | Proc *p; | |
| 1992/0805 | ulong bss; | |
| 1990/0227 | for(i=0; i<conf.nproc; i++){ p = procalloc.arena+i; | |
| 1990/0312 | if(p->state != Dead){ | |
| 1992/0805 | bss = 0; if(p->seg[BSEG]) bss = p->seg[BSEG]->top; s = p->psstate; if(s == 0) s = "kproc"; print("%3d:%10s %10s pc %8lux %8s (%s) ut %ld st %ld r %lux qpc %lux bss %lux\n", | |
| 1991/1105 | p->pid, p->text, p->user, p->pc, | |
| 1992/0805 | s, statename[p->state], p->time[0], p->time[1], p->r, p->qlockpc, bss); | |
| 1990/0312 | } | |
| 1990/0227 | } } void kproc(char *name, void (*func)(void *), void *arg) { Proc *p; int n; ulong upa; | |
| 1990/0617 | User *up; KMap *k; | |
| 1990/0722 | static Pgrp *kpgrp; | |
| 1991/0705 | char *user; | |
| 1992/0703 | int lastvar; /* used to compute stack address */ | |
| 1990/0227 | /* * Kernel stack */ p = newproc(); | |
| 1991/0926 | p->psstate = 0; | |
| 1991/1112 | p->procmode = 0644; | |
| 1990/1212 | p->kp = 1; | |
| 1990/0227 | p->upage = newpage(1, 0, USERADDR|(p->pid&0xFFFF)); | |
| 1990/0617 | k = kmap(p->upage); upa = VA(k); up = (User*)upa; | |
| 1990/0227 | /* * Save time: only copy u-> data and useful stack */ | |
| 1991/0318 | memmove(up, u, sizeof(User)); | |
| 1990/0227 | n = USERADDR+BY2PG - (ulong)&lastvar; n = (n+32) & ~(BY2WD-1); /* be safe & word align */ | |
| 1991/0318 | memmove((void*)(upa+BY2PG-n), (void*)(USERADDR+BY2PG-n), n); | |
| 1991/0820 | up->p = p; | |
| 1990/0227 | /* * Refs */ incref(up->dot); | |
| 1990/0617 | kunmap(k); | |
| 1990/0227 | /* * Sched */ if(setlabel(&p->sched)){ p->state = Running; p->mach = m; m->proc = p; spllo(); (*func)(arg); pexit(0, 1); } | |
| 1991/0705 | ||
| 1991/1109 | user = eve; | |
| 1991/1105 | strcpy(p->user, user); | |
| 1990/0722 | if(kpgrp == 0){ kpgrp = newpgrp(); } p->pgrp = kpgrp; incref(kpgrp); | |
| 1991/0705 | ||
| 1992/0703 | strcpy(p->text, name); | |
| 1991/0705 | ||
| 1990/0227 | p->nchild = 0; p->parent = 0; 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. */ | |
| 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; | |
| 1991/0705 | switch(p->procctl) { case Proc_exitme: | |
| 1992/0609 | spllo(); /* pexit has locks in it */ | |
| 1991/0705 | pexit("Killed", 1); | |
| 1992/0620 | ||
| 1991/1110 | case Proc_traceme: if(u->nnote == 0) 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 */ | |
| 1991/1216 | qlock(&p->debug); | |
| 1991/1110 | if(p->pdbg) { wakeup(&p->pdbg->sleep); p->pdbg = 0; } | |
| 1991/1216 | qunlock(&p->debug); | |
| 1991/0705 | p->state = Stopped; | |
| 1992/0609 | sched(); /* sched returns spllo() */ splhi(); | |
| 1991/1108 | p->psstate = state; | |
| 1991/0705 | return; } | |
| 1990/0227 | } | |
| 1991/0710 | #include "errstr.h" void | |
| 1992/0604 | error(char *err) | |
| 1991/0710 | { | |
| 1992/0111 | strncpy(u->error, err, ERRLEN); | |
| 1991/0710 | nexterror(); } void | |
| 1992/0114 | nexterror(void) | |
| 1991/0710 | { | |
| 1992/0114 | gotolabel(&u->errlab[--u->nerrlab]); | |
| 1991/0710 | } void | |
| 1992/0114 | exhausted(char *resource) | |
| 1991/0710 | { | |
| 1992/0114 | char buf[ERRLEN]; sprint(buf, "no free %s", resource); error(buf); | |
| 1991/0926 | } | |