summaryrefslogtreecommitdiff
path: root/os/port/proc.c
diff options
context:
space:
mode:
authorCharles.Forsyth <devnull@localhost>2006-12-22 21:39:35 +0000
committerCharles.Forsyth <devnull@localhost>2006-12-22 21:39:35 +0000
commit74a4d8c26dd3c1e9febcb717cfd6cb6512991a7a (patch)
treec6e220ba61db3a6ea4052e6841296d829654e664 /os/port/proc.c
parent46439007cf417cbd9ac8049bb4122c890097a0fa (diff)
20060303
Diffstat (limited to 'os/port/proc.c')
-rw-r--r--os/port/proc.c788
1 files changed, 788 insertions, 0 deletions
diff --git a/os/port/proc.c b/os/port/proc.c
new file mode 100644
index 00000000..a652669a
--- /dev/null
+++ b/os/port/proc.c
@@ -0,0 +1,788 @@
+#include "u.h"
+#include "../port/lib.h"
+#include "mem.h"
+#include "dat.h"
+#include "fns.h"
+#include "../port/error.h"
+#include <interp.h>
+
+Ref pidalloc;
+
+struct
+{
+ Lock;
+ Proc* arena;
+ Proc* free;
+}procalloc;
+
+typedef struct
+{
+ Lock;
+ Proc* head;
+ Proc* tail;
+}Schedq;
+
+static Schedq runq[Nrq];
+static ulong occupied;
+int nrdy;
+
+char *statename[] =
+{ /* BUG: generate automatically */
+ "Dead",
+ "Moribund",
+ "Ready",
+ "Scheding",
+ "Running",
+ "Queueing",
+ "Wakeme",
+ "Broken",
+ "Stopped",
+ "Rendez",
+};
+
+/*
+ * Always splhi()'ed.
+ */
+void
+schedinit(void) /* never returns */
+{
+ setlabel(&m->sched);
+ if(up) {
+/*
+ if((e = up->edf) && (e->flags & Admitted))
+ edfrecord(up);
+*/
+ m->proc = nil;
+ switch(up->state) {
+ case Running:
+ ready(up);
+ break;
+ case Moribund:
+ up->state = Dead;
+/*
+ edfstop(up);
+ if(up->edf){
+ free(up->edf);
+ up->edf = nil;
+ }
+*/
+ /*
+ * Holding locks from pexit:
+ * procalloc
+ */
+ up->qnext = procalloc.free;
+ procalloc.free = up;
+ unlock(&procalloc);
+ break;
+ }
+ up->mach = nil;
+ up = nil;
+ }
+ sched();
+}
+
+void
+sched(void)
+{
+ if(up) {
+ splhi();
+ procsave(up);
+ if(setlabel(&up->sched)) {
+ /* procrestore(up); */
+ spllo();
+ return;
+ }
+ gotolabel(&m->sched);
+ }
+ up = runproc();
+ up->state = Running;
+ up->mach = MACHP(m->machno); /* m might be a fixed address; use MACHP */
+ m->proc = up;
+ gotolabel(&up->sched);
+}
+
+void
+ready(Proc *p)
+{
+ int s;
+ Schedq *rq;
+
+ s = splhi();
+/*
+ if(edfready(p)){
+ splx(s);
+ return;
+ }
+*/
+ rq = &runq[p->pri];
+ lock(runq);
+ p->rnext = 0;
+ if(rq->tail)
+ rq->tail->rnext = p;
+ else
+ rq->head = p;
+ rq->tail = p;
+
+ nrdy++;
+ occupied |= 1<<p->pri;
+ p->state = Ready;
+ unlock(runq);
+ splx(s);
+}
+
+int
+anyready(void)
+{
+ /* same priority only */
+ return occupied & (1<<up->pri);
+}
+
+int
+anyhigher(void)
+{
+ return occupied & ((1<<up->pri)-1);
+}
+
+int
+preemption(int tick)
+{
+ if(up != nil && up->state == Running && !up->preempted &&
+ (anyhigher() || tick && anyready())){
+ up->preempted = 1;
+ sched();
+ splhi();
+ up->preempted = 0;
+ return 1;
+ }
+ return 0;
+}
+
+Proc*
+runproc(void)
+{
+ Proc *p, *l;
+ Schedq *rq, *erq;
+
+ erq = runq + Nrq - 1;
+loop:
+ splhi();
+ for(rq = runq; rq->head == 0; rq++)
+ if(rq >= erq) {
+ idlehands();
+ spllo();
+ goto loop;
+ }
+
+ if(!canlock(runq))
+ goto loop;
+ /* choose first one we last ran on this processor at this level or hasn't moved recently */
+ l = nil;
+ for(p = rq->head; p != nil; p = p->rnext)
+ if(p->mp == nil || p->mp == MACHP(m->machno) || p->movetime < MACHP(0)->ticks)
+ break;
+ if(p == nil)
+ p = rq->head;
+ /* p->mach==0 only when process state is saved */
+ if(p == 0 || p->mach) {
+ unlock(runq);
+ goto loop;
+ }
+ if(p->rnext == nil)
+ rq->tail = l;
+ if(l)
+ l->rnext = p->rnext;
+ else
+ rq->head = p->rnext;
+ if(rq->head == nil){
+ rq->tail = nil;
+ occupied &= ~(1<<p->pri);
+ }
+ nrdy--;
+ if(p->dbgstop){
+ p->state = Stopped;
+ unlock(runq);
+ goto loop;
+ }
+ if(p->state != Ready)
+ print("runproc %s %lud %s\n", p->text, p->pid, statename[p->state]);
+ unlock(runq);
+ p->state = Scheding;
+ if(p->mp != MACHP(m->machno))
+ p->movetime = MACHP(0)->ticks + HZ/10;
+ p->mp = MACHP(m->machno);
+
+/*
+ if(edflock(p)){
+ edfrun(p, rq == &runq[PriEdf]); // start deadline timer and do admin
+ edfunlock();
+ }
+*/
+ return p;
+}
+
+int
+setpri(int pri)
+{
+ int p;
+
+ /* called by up so not on run queue */
+ p = up->pri;
+ up->pri = pri;
+ if(up->state == Running && anyhigher())
+ sched();
+ return p;
+}
+
+Proc*
+newproc(void)
+{
+ Proc *p;
+
+ lock(&procalloc);
+ for(;;) {
+ if(p = procalloc.free)
+ break;
+
+ unlock(&procalloc);
+ resrcwait("no procs");
+ lock(&procalloc);
+ }
+ procalloc.free = p->qnext;
+ unlock(&procalloc);
+
+ p->type = Unknown;
+ p->state = Scheding;
+ p->pri = PriNormal;
+ p->psstate = "New";
+ p->mach = 0;
+ p->qnext = 0;
+ p->fpstate = FPINIT;
+ p->kp = 0;
+ p->killed = 0;
+ p->swipend = 0;
+ p->mp = 0;
+ p->movetime = 0;
+ p->delaysched = 0;
+ p->edf = nil;
+ memset(&p->defenv, 0, sizeof(p->defenv));
+ p->env = &p->defenv;
+ p->dbgreg = 0;
+ kstrdup(&p->env->user, "*nouser");
+ p->env->errstr = p->env->errbuf0;
+ p->env->syserrstr = p->env->errbuf1;
+
+ p->pid = incref(&pidalloc);
+ if(p->pid == 0)
+ panic("pidalloc");
+ if(p->kstack == 0)
+ p->kstack = smalloc(KSTACK);
+ addprog(p);
+
+ return p;
+}
+
+void
+procinit(void)
+{
+ Proc *p;
+ int i;
+
+ procalloc.free = xalloc(conf.nproc*sizeof(Proc));
+ procalloc.arena = procalloc.free;
+
+ p = procalloc.free;
+ for(i=0; i<conf.nproc-1; i++,p++)
+ p->qnext = p+1;
+ p->qnext = 0;
+
+ debugkey('p', "processes", procdump, 0);
+}
+
+void
+sleep(Rendez *r, int (*f)(void*), void *arg)
+{
+ int s;
+
+ if(up == nil)
+ panic("sleep() not in process (%lux)", getcallerpc(&r));
+ /*
+ * spl is to allow lock to be called
+ * at interrupt time. lock is mutual exclusion
+ */
+ s = splhi();
+
+ lock(&up->rlock);
+ lock(r);
+
+ /*
+ * if killed or condition happened, never mind
+ */
+ if(up->killed || f(arg)){
+ unlock(r);
+ }else{
+
+ /*
+ * now we are committed to
+ * change state and call scheduler
+ */
+ if(r->p != nil) {
+ print("double sleep pc=0x%lux %lud %lud r=0x%lux\n", getcallerpc(&r), r->p->pid, up->pid, r);
+ dumpstack();
+ panic("sleep");
+ }
+ up->state = Wakeme;
+ r->p = up;
+ unlock(r);
+ up->swipend = 0;
+ up->r = r; /* for swiproc */
+ unlock(&up->rlock);
+
+ sched();
+ splhi(); /* sched does spllo */
+
+ lock(&up->rlock);
+ up->r = nil;
+ }
+
+ if(up->killed || up->swipend) {
+ up->killed = 0;
+ up->swipend = 0;
+ unlock(&up->rlock);
+ splx(s);
+ error(Eintr);
+ }
+ unlock(&up->rlock);
+ splx(s);
+}
+
+int
+tfn(void *arg)
+{
+ return MACHP(0)->ticks >= up->twhen || (*up->tfn)(arg);
+}
+
+void
+tsleep(Rendez *r, int (*fn)(void*), void *arg, int ms)
+{
+ ulong when;
+ Proc *f, **l;
+
+ if(up == nil)
+ panic("tsleep() not in process (0x%lux)", getcallerpc(&r));
+
+ when = MS2TK(ms)+MACHP(0)->ticks;
+ lock(&talarm);
+ /* take out of list if checkalarm didn't */
+ if(up->trend) {
+ l = &talarm.list;
+ for(f = *l; f; f = f->tlink) {
+ if(f == up) {
+ *l = up->tlink;
+ break;
+ }
+ l = &f->tlink;
+ }
+ }
+ /* insert in increasing time order */
+ l = &talarm.list;
+ for(f = *l; f; f = f->tlink) {
+ if(f->twhen >= when)
+ break;
+ l = &f->tlink;
+ }
+ up->trend = r;
+ up->twhen = when;
+ up->tfn = fn;
+ up->tlink = *l;
+ *l = up;
+ unlock(&talarm);
+
+ if(waserror()){
+ up->twhen = 0;
+ nexterror();
+ }
+ sleep(r, tfn, arg);
+ up->twhen = 0;
+ poperror();
+}
+
+int
+wakeup(Rendez *r)
+{
+ Proc *p;
+ int s;
+
+ s = splhi();
+ lock(r);
+ p = r->p;
+ if(p){
+ r->p = nil;
+ if(p->state != Wakeme)
+ panic("wakeup: state");
+ ready(p);
+ }
+ unlock(r);
+ splx(s);
+ return p != nil;
+}
+
+void
+swiproc(Proc *p, int interp)
+{
+ ulong s;
+ Rendez *r;
+
+ if(p == nil)
+ return;
+
+ s = splhi();
+ lock(&p->rlock);
+ if(!interp)
+ p->killed = 1;
+ r = p->r;
+ if(r != nil) {
+ lock(r);
+ if(r->p == p){
+ p->swipend = 1;
+ r->p = nil;
+ ready(p);
+ }
+ unlock(r);
+ }
+ unlock(&p->rlock);
+ splx(s);
+}
+
+void
+notkilled(void)
+{
+ lock(&up->rlock);
+ up->killed = 0;
+ unlock(&up->rlock);
+}
+
+void
+pexit(char*, int)
+{
+ Osenv *o;
+
+ up->alarm = 0;
+
+ o = up->env;
+ if(o != nil){
+ closefgrp(o->fgrp);
+ closepgrp(o->pgrp);
+ closeegrp(o->egrp);
+ closesigs(o->sigs);
+ }
+
+ /* Sched must not loop for this lock */
+ lock(&procalloc);
+
+/*
+ edfstop(up);
+*/
+ up->state = Moribund;
+ sched();
+ panic("pexit");
+}
+
+Proc*
+proctab(int i)
+{
+ return &procalloc.arena[i];
+}
+
+void
+procdump(void)
+{
+ int i;
+ char *s;
+ Proc *p;
+ char tmp[14];
+
+ for(i=0; i<conf.nproc; i++) {
+ p = &procalloc.arena[i];
+ if(p->state == Dead)
+ continue;
+
+ s = p->psstate;
+ if(s == nil)
+ s = "kproc";
+ if(p->state == Wakeme)
+ snprint(tmp, sizeof(tmp), " /%.8lux", p->r);
+ else
+ *tmp = '\0';
+ print("%lux:%3lud:%14s pc %.8lux %s/%s qpc %.8lux pri %d%s\n",
+ p, p->pid, p->text, p->pc, s, statename[p->state], p->qpc, p->pri, tmp);
+ }
+}
+
+void
+kproc(char *name, void (*func)(void *), void *arg, int flags)
+{
+ Proc *p;
+ Pgrp *pg;
+ Fgrp *fg;
+ Egrp *eg;
+
+ p = newproc();
+ p->psstate = 0;
+ p->kp = 1;
+
+ p->fpsave = up->fpsave;
+ p->scallnr = up->scallnr;
+ p->nerrlab = 0;
+
+ kstrdup(&p->env->user, up->env->user);
+ if(flags & KPDUPPG) {
+ pg = up->env->pgrp;
+ incref(pg);
+ p->env->pgrp = pg;
+ }
+ if(flags & KPDUPFDG) {
+ fg = up->env->fgrp;
+ incref(fg);
+ p->env->fgrp = fg;
+ }
+ if(flags & KPDUPENVG) {
+ eg = up->env->egrp;
+ if(eg != nil)
+ incref(eg);
+ p->env->egrp = eg;
+ }
+
+ kprocchild(p, func, arg);
+
+ strcpy(p->text, name);
+
+ ready(p);
+}
+
+void
+errorf(char *fmt, ...)
+{
+ va_list arg;
+ char buf[PRINTSIZE];
+
+ va_start(arg, fmt);
+ vseprint(buf, buf+sizeof(buf), fmt, arg);
+ va_end(arg);
+ error(buf);
+}
+
+void
+error(char *err)
+{
+ if(up == nil)
+ panic("error(%s) not in a process", err);
+ spllo();
+ if(up->nerrlab > NERR)
+ panic("error stack too deep");
+ if(err != up->env->errstr)
+ kstrcpy(up->env->errstr, err, ERRMAX);
+ setlabel(&up->errlab[NERR-1]);
+ nexterror();
+}
+
+#include "errstr.h"
+
+/* Set kernel error string */
+void
+kerrstr(char *err, uint size)
+{
+
+ char tmp[ERRMAX];
+
+ kstrcpy(tmp, up->env->errstr, sizeof(tmp));
+ kstrcpy(up->env->errstr, err, ERRMAX);
+ kstrcpy(err, tmp, size);
+}
+
+/* Get kernel error string */
+void
+kgerrstr(char *err, uint size)
+{
+ char tmp[ERRMAX];
+
+ kstrcpy(tmp, up->env->errstr, sizeof(tmp));
+ kstrcpy(up->env->errstr, err, ERRMAX);
+ kstrcpy(err, tmp, size);
+}
+
+/* Set kernel error string, using formatted print */
+void
+kwerrstr(char *fmt, ...)
+{
+ va_list arg;
+ char buf[ERRMAX];
+
+ va_start(arg, fmt);
+ vseprint(buf, buf+sizeof(buf), fmt, arg);
+ va_end(arg);
+ kstrcpy(up->env->errstr, buf, ERRMAX);
+}
+
+void
+werrstr(char *fmt, ...)
+{
+ va_list arg;
+ char buf[ERRMAX];
+
+ va_start(arg, fmt);
+ vseprint(buf, buf+sizeof(buf), fmt, arg);
+ va_end(arg);
+ kstrcpy(up->env->errstr, buf, ERRMAX);
+}
+
+void
+nexterror(void)
+{
+ gotolabel(&up->errlab[--up->nerrlab]);
+}
+
+/* for dynamic modules - functions not macros */
+
+void*
+waserr(void)
+{
+ up->nerrlab++;
+ return &up->errlab[up->nerrlab-1];
+}
+
+void
+poperr(void)
+{
+ up->nerrlab--;
+}
+
+char*
+enverror(void)
+{
+ return up->env->errstr;
+}
+
+void
+exhausted(char *resource)
+{
+ char buf[64];
+
+ snprint(buf, sizeof(buf), "no free %s", resource);
+ iprint("%s\n", buf);
+ error(buf);
+}
+
+/*
+ * change ownership to 'new' of all processes owned by 'old'. Used when
+ * eve changes.
+ */
+void
+renameuser(char *old, char *new)
+{
+ Proc *p, *ep;
+ Osenv *o;
+
+ ep = procalloc.arena+conf.nproc;
+ for(p = procalloc.arena; p < ep; p++) {
+ o = &p->defenv;
+ if(o->user != nil && strcmp(o->user, old) == 0)
+ kstrdup(&o->user, new);
+ }
+}
+
+int
+return0(void*)
+{
+ return 0;
+}
+
+void
+setid(char *name, int owner)
+{
+ if(!owner || iseve())
+ kstrdup(&up->env->user, name);
+}
+
+void
+rptwakeup(void *o, void *ar)
+{
+ Rept *r;
+
+ r = ar;
+ if(r == nil)
+ return;
+ lock(&r->l);
+ r->o = o;
+ unlock(&r->l);
+ wakeup(&r->r);
+}
+
+static int
+rptactive(void *a)
+{
+ Rept *r = a;
+ int i;
+ lock(&r->l);
+ i = r->active(r->o);
+ unlock(&r->l);
+ return i;
+}
+
+static void
+rproc(void *a)
+{
+ long now, then;
+ ulong t;
+ int i;
+ void *o;
+ Rept *r;
+
+ r = a;
+ t = r->t;
+
+Wait:
+ sleep(&r->r, rptactive, r);
+ lock(&r->l);
+ o = r->o;
+ unlock(&r->l);
+ then = TK2MS(MACHP(0)->ticks);
+ for(;;){
+ tsleep(&up->sleep, return0, nil, t);
+ now = TK2MS(MACHP(0)->ticks);
+ if(waserror())
+ break;
+ i = r->ck(o, now-then);
+ poperror();
+ if(i == -1)
+ goto Wait;
+ if(i == 0)
+ continue;
+ then = now;
+ acquire();
+ if(waserror()) {
+ release();
+ break;
+ }
+ r->f(o);
+ poperror();
+ release();
+ }
+ pexit("", 0);
+}
+
+void*
+rptproc(char *s, int t, void *o, int (*active)(void*), int (*ck)(void*, int), void (*f)(void*))
+{
+ Rept *r;
+
+ r = mallocz(sizeof(Rept), 1);
+ if(r == nil)
+ return nil;
+ r->t = t;
+ r->active = active;
+ r->ck = ck;
+ r->f = f;
+ r->o = o;
+ kproc(s, rproc, r, KPDUP);
+ return r;
+}