]> git.lizzy.rs Git - plan9front.git/blobdiff - sys/src/9/port/proc.c
kernel: implement portable userinit() and simplify process creation
[plan9front.git] / sys / src / 9 / port / proc.c
index 58fbc7a8b9757ee1fb98cf6e991c1dc0f2fbb325..61d2833a830165d7050cc68ae5743141219685bc 100644 (file)
@@ -14,9 +14,9 @@ void updatecpu(Proc*);
 int reprioritize(Proc*);
 
 ulong  delayedscheds;  /* statistics */
-long skipscheds;
-long preempts;
-ulong load;
+ulong  skipscheds;
+ulong  preempts;
+ulong  load;
 
 static struct Procalloc
 {
@@ -70,6 +70,9 @@ schedinit(void)               /* never returns */
                        edfrecord(up);
                m->proc = nil;
                switch(up->state) {
+               default:
+                       updatecpu(up);
+                       break;
                case Running:
                        ready(up);
                        break;
@@ -88,8 +91,8 @@ schedinit(void)               /* never returns */
                        mmurelease(up);
                        unlock(&palloc);
 
-                       up->mach = nil;
                        updatecpu(up);
+                       up->mach = nil;
 
                        up->qnext = procalloc.free;
                        procalloc.free = up;
@@ -99,8 +102,8 @@ schedinit(void)              /* never returns */
                        unlock(&procalloc);
                        sched();
                }
+               coherence();
                up->mach = nil;
-               updatecpu(up);
                up = nil;
        }
        sched();
@@ -141,6 +144,7 @@ sched(void)
                if(up->state != Moribund)
                if(up->delaysched < 20
                || palloc.Lock.p == up
+               || fscache.Lock.p == up
                || procalloc.Lock.p == up){
                        up->delaysched++;
                        delayedscheds++;
@@ -201,7 +205,7 @@ hzsched(void)
 
        /* unless preempted, get to run for at least 100ms */
        if(anyhigher()
-       || (!up->fixedpri && m->ticks > m->schedticks && anyready())){
+       || (!up->fixedpri && (long)(m->ticks - m->schedticks) > 0 && anyready())){
                m->readied = nil;       /* avoid cooperative scheduling */
                up->delaysched++;
        }
@@ -271,18 +275,18 @@ preempted(void)
 void
 updatecpu(Proc *p)
 {
-       int n, t, ocpu;
-       int D = schedgain*HZ*Scaling;
+       ulong t, ocpu, n, D;
 
        if(p->edf != nil)
                return;
 
        t = MACHP(0)->ticks*Scaling + Scaling/2;
        n = t - p->lastupdate;
-       p->lastupdate = t;
-
        if(n == 0)
                return;
+       p->lastupdate = t;
+
+       D = schedgain*HZ*Scaling;
        if(n > D)
                n = D;
 
@@ -294,8 +298,7 @@ updatecpu(Proc *p)
                t = (t*(D-n))/D;
                p->cpu = 1000 - t;
        }
-
-//iprint("pid %d %s for %d cpu %d -> %d\n", p->pid,p==up?"active":"inactive",n, ocpu,p->cpu);
+//iprint("pid %lud %s for %lud cpu %lud -> %lud\n", p->pid,p==up?"active":"inactive",n, ocpu,p->cpu);
 }
 
 /*
@@ -330,7 +333,7 @@ reprioritize(Proc *p)
                ratio = p->basepri;
        if(ratio < 0)
                panic("reprioritize");
-//iprint("pid %d cpu %d load %d fair %d pri %d\n", p->pid, p->cpu, load, fairshare, ratio);
+//iprint("pid %lud cpu %lud load %d fair %d pri %d\n", p->pid, p->cpu, load, fairshare, ratio);
        return ratio;
 }
 
@@ -463,9 +466,10 @@ ulong balancetime;
 static void
 rebalance(void)
 {
-       int pri, npri, t, x;
+       int pri, npri, x;
        Schedq *rq;
        Proc *p;
+       ulong t;
 
        t = m->ticks;
        if(t - balancetime < HZ)
@@ -477,8 +481,6 @@ another:
                p = rq->head;
                if(p == nil)
                        continue;
-               if(p->mp != MACHP(m->machno))
-                       continue;
                if(pri == p->basepri)
                        continue;
                updatecpu(p);
@@ -523,8 +525,7 @@ runproc(void)
 loop:
        /*
         *  find a process that last ran on this processor (affinity),
-        *  or one that hasn't moved in a while (load balancing).  Every
-        *  time around the loop affinity goes down.
+        *  or one that can be moved to this processor.
         */
        spllo();
        for(i = 0;; i++){
@@ -607,7 +608,7 @@ newproc(void)
        procalloc.free = p->qnext;
        unlock(&procalloc);
 
-       p->state = Scheding;
+       assert(p->state == Dead);
        p->psstate = "New";
        p->mach = nil;
        p->eql = nil;
@@ -627,8 +628,10 @@ newproc(void)
        p->syscalltrace = nil;  
        p->notepending = 0;
        p->ureg = nil;
+       p->dbgreg = nil;
        p->privatemem = 0;
        p->noswap = 0;
+       p->nerrlab = 0;
        p->errstr = p->errbuf0;
        p->syserrstr = p->errbuf1;
        p->errbuf0[0] = '\0';
@@ -636,14 +639,11 @@ newproc(void)
        p->nlocks = 0;
        p->delaysched = 0;
        p->trace = 0;
-       kstrdup(&p->user, "*nouser");
-       kstrdup(&p->text, "*notext");
-       kstrdup(&p->args, "");
        p->nargs = 0;
        p->setargs = 0;
        memset(p->seg, 0, sizeof p->seg);
        p->parentpid = 0;
-       p->noteid = pidalloc(p);
+       p->noteid = 0;
        if(p->kstack == nil)
                p->kstack = smalloc(KSTACK);
 
@@ -830,16 +830,18 @@ twakeup(Ureg*, Timer *t)
 
        p = t->ta;
        trend = p->trend;
-       p->trend = nil;
-       if(trend != nil)
+       if(trend != nil){
+               p->trend = nil;
                wakeup(trend);
+       }
 }
 
 void
 tsleep(Rendez *r, int (*fn)(void*), void *arg, ulong ms)
 {
        if(up->tt != nil){
-               print("tsleep: timer active: mode %d, tf %#p\n", up->tmode, up->tf);
+               print("%s %lud: tsleep timer active: mode %d, tf %#p, pc %#p\n",
+                       up->text, up->pid, up->tmode, up->tf, getcallerpc(&r));
                timerdel(up);
        }
        up->tns = MS2NS(ms);
@@ -851,13 +853,13 @@ tsleep(Rendez *r, int (*fn)(void*), void *arg, ulong ms)
        timeradd(up);
 
        if(waserror()){
+               up->trend = nil;
                timerdel(up);
                nexterror();
        }
        sleep(r, tfn, arg);
-       if(up->tt != nil)
-               timerdel(up);
-       up->twhen = 0;
+       up->trend = nil;
+       timerdel(up);
        poperror();
 }
 
@@ -921,7 +923,7 @@ postnote(Proc *p, int dolock, char *n, int flag)
                return 0;
        }
 
-       if(n != nil && flag != NUser && (p->notify == 0 || p->notified))
+       if(n != nil && flag != NUser && (p->notify == nil || p->notified))
                p->nnote = 0;
 
        ret = 0;
@@ -1081,7 +1083,7 @@ pexit(char *exitstr, int freemem)
 {
        Proc *p;
        Segment **s, **es;
-       long utime, stime;
+       ulong utime, stime;
        Waitq *wq;
        Fgrp *fgrp;
        Egrp *egrp;
@@ -1090,9 +1092,9 @@ pexit(char *exitstr, int freemem)
        Chan *dot;
        void (*pt)(Proc*, int, vlong);
 
+       up->fpstate &= ~FPillegal;
        up->alarm = 0;
-       if(up->tt != nil)
-               timerdel(up);
+       timerdel(up);
        pt = proctrace;
        if(pt != nil)
                pt(up, SDead, 0);
@@ -1126,7 +1128,14 @@ pexit(char *exitstr, int freemem)
         * if not a kernel process and have a parent,
         * do some housekeeping.
         */
-       if(up->kp == 0 && up->parentpid != 0) {
+       if(up->kp)
+               goto Nowait;
+
+       p = up->parent;
+       if(p != nil){
+               if(p->pid != up->parentpid || p->state == Broken)
+                       goto Nowait;
+
                wq = smalloc(sizeof(Waitq));
                wq->w.pid = up->pid;
                utime = up->time[TUser] + up->time[TCUser];
@@ -1139,7 +1148,6 @@ pexit(char *exitstr, int freemem)
                else
                        wq->w.msg[0] = '\0';
 
-               p = up->parent;
                lock(&p->exl);
                /*
                 * Check that parent is still alive.
@@ -1167,12 +1175,13 @@ pexit(char *exitstr, int freemem)
                if(wq != nil)
                        free(wq);
        }
-       else if(up->kp == 0 && up->parent == nil){
+       else if(up->parentpid == 0){
                if(exitstr == nil)
                        exitstr = "unknown";
                panic("boot process died: %s", exitstr);
        }
 
+Nowait:
        if(!freemem)
                addbroken(up);
 
@@ -1207,6 +1216,11 @@ pexit(char *exitstr, int freemem)
                free(up->syscalltrace);
                up->syscalltrace = nil;
        }
+       if(up->watchpt != nil){
+               free(up->watchpt);
+               up->watchpt = nil;
+       }
+       up->nwatchpt = 0;
        qunlock(&up->debug);
 
        /* Sched must not loop for these locks */
@@ -1310,47 +1324,101 @@ procdump(void)
 }
 
 /*
- *  wait till all processes have flushed their mmu
- *  state about segement s
+ *  wait till all matching processes have flushed their mmu
  */
-void
-procflushseg(Segment *s)
+static void
+procflushmmu(int (*match)(Proc*, void*), void *a)
 {
-       int i, ns, nm, nwait;
+       Proc *await[MAXMACH];
+       int i, nm, nwait;
        Proc *p;
 
        /*
-        *  tell all processes with this
-        *  segment to flush their mmu's
+        *  tell all matching processes to flush their mmu's
         */
+       memset(await, 0, conf.nmach*sizeof(await[0]));
        nwait = 0;
-       for(i=0; i<conf.nproc; i++) {
+       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;
+               if(p->state != Dead && (*match)(p, a)){
+                       p->newtlb = 1;
+                       for(nm = 0; nm < conf.nmach; nm++){
+                               if(MACHP(nm)->proc == p){
+                                       coherence();
+                                       MACHP(nm)->flushmmu = 1;
+                                       if(await[nm] == nil)
                                                nwait++;
-                                       }
+                                       await[nm] = p;
                                }
-                               break;
                        }
+               }
        }
 
-       if(nwait == 0)
-               return;
-
        /*
         *  wait for all other processors to take a clock interrupt
         *  and flush their mmu's
         */
-       for(nm = 0; nm < conf.nmach; nm++)
-               while(m->machno != nm && MACHP(nm)->flushmmu)
-                       sched();
+       for(;;){
+               if(nwait == 0 || nwait == 1 && await[m->machno] != nil)
+                       break;
+
+               sched();
+
+               for(nm = 0; nm < conf.nmach; nm++){
+                       p = await[nm];
+                       if(p != nil && (MACHP(nm)->proc != p || MACHP(nm)->flushmmu == 0)){
+                               await[nm] = nil;
+                               nwait--;
+                       }
+               }
+       }
+}
+
+static int
+matchseg(Proc *p, void *a)
+{
+       int ns;
+
+       for(ns = 0; ns < NSEG; ns++){
+               if(p->seg[ns] == a)
+                       return 1;
+       }
+       return 0;
+}
+void
+procflushseg(Segment *s)
+{
+       procflushmmu(matchseg, s);
+}
+
+static int
+matchpseg(Proc *p, void *a)
+{
+       Segment *s;
+       int ns;
+
+       for(ns = 0; ns < NSEG; ns++){
+               s = p->seg[ns];
+               if(s != nil && s->pseg == a)
+                       return 1;
+       }
+       return 0;
+}
+void
+procflushpseg(Physseg *ps)
+{
+       procflushmmu(matchpseg, ps);
+}
+
+static int
+matchother(Proc *p, void *a)
+{
+       return p != a;
+}
+void
+procflushothers(void)
+{
+       procflushmmu(matchother, up);
 }
 
 void
@@ -1362,7 +1430,7 @@ scheddump(void)
        for(rq = &runq[Nrq-1]; rq >= runq; rq--){
                if(rq->head == nil)
                        continue;
-               print("rq%ld:", rq-runq);
+               print("rq%zd:", rq-runq);
                for(p = rq->head; p != nil; p = p->rnext)
                        print(" %lud(%lud)", p->pid, m->ticks - p->readytime);
                print("\n");
@@ -1374,44 +1442,49 @@ scheddump(void)
 void
 kproc(char *name, void (*func)(void *), void *arg)
 {
-       Proc *p;
        static Pgrp *kpgrp;
+       Proc *p;
 
        p = newproc();
-       p->psstate = nil;
-       p->procmode = 0640;
-       p->kp = 1;
-       p->noswap = 1;
 
-       p->scallnr = up->scallnr;
-       p->s = up->s;
-       p->nerrlab = 0;
-       p->slash = up->slash;
-       p->dot = up->dot;
-       if(p->dot != nil)
-               incref(p->dot);
+       if(up != nil){
+               p->slash = up->slash;
+               p->dot = up->slash;     /* unlike fork, do not inherit the dot for kprocs */
+               if(p->dot != nil)
+                       incref(p->dot);
+       } else {
+               p->slash = nil;
+               p->dot = nil;
+       }
 
-       memmove(p->note, up->note, sizeof(p->note));
-       p->nnote = up->nnote;
+       p->nnote = 0;
+       p->notify = nil;
        p->notified = 0;
-       p->lastnote = up->lastnote;
-       p->notify = up->notify;
-       p->ureg = nil;
-       p->dbgreg = nil;
 
-       procpriority(p, PriKproc, 0);
+       p->procmode = 0640;
+       p->noswap = 1;
+       p->kp = 1;
 
        kprocchild(p, func, arg);
 
-       kstrdup(&p->user, eve);
        kstrdup(&p->text, name);
+       kstrdup(&p->user, eve);
+       kstrdup(&p->args, "");
+
        if(kpgrp == nil)
                kpgrp = newpgrp();
        p->pgrp = kpgrp;
        incref(kpgrp);
 
+       p->insyscall = 1;
        memset(p->time, 0, sizeof(p->time));
        p->time[TReal] = MACHP(0)->ticks;
+
+       pidalloc(p);
+
+       procpriority(p, PriKproc, 0);
+
+       p->psstate = nil;
        ready(p);
 }
 
@@ -1420,14 +1493,15 @@ kproc(char *name, void (*func)(void *), void *arg)
  *  reasoning.
  */
 void
-procctl(Proc *p)
+procctl(void)
 {
        char *state;
        ulong s;
 
-       switch(p->procctl) {
+       switch(up->procctl) {
        case Proc_exitbig:
                spllo();
+               up->fpstate &= ~FPillegal;
                pprint("Killed: Insufficient physical memory\n");
                pexit("Killed: Insufficient physical memory", 1);
 
@@ -1436,26 +1510,26 @@ procctl(Proc *p)
                pexit("Killed", 1);
 
        case Proc_traceme:
-               if(p->nnote == 0)
+               if(up->nnote == 0)
                        return;
                /* No break */
 
        case Proc_stopme:
-               p->procctl = 0;
-               state = p->psstate;
-               p->psstate = "Stopped";
+               up->procctl = 0;
+               state = up->psstate;
+               up->psstate = "Stopped";
                /* free a waiting debugger */
                s = spllo();
-               qlock(&p->debug);
-               if(p->pdbg != nil) {
-                       wakeup(&p->pdbg->sleep);
-                       p->pdbg = nil;
+               qlock(&up->debug);
+               if(up->pdbg != nil) {
+                       wakeup(&up->pdbg->sleep);
+                       up->pdbg = nil;
                }
-               qunlock(&p->debug);
+               qunlock(&up->debug);
                splhi();
-               p->state = Stopped;
+               up->state = Stopped;
                sched();
-               p->psstate = state;
+               up->psstate = state;
                splx(s);
                return;
        }
@@ -1491,6 +1565,32 @@ exhausted(char *resource)
        error(buf);
 }
 
+ulong
+procpagecount(Proc *p)
+{
+       Segment *s;
+       ulong pages;
+       int i;
+
+       eqlock(&p->seglock);
+       if(waserror()){
+               qunlock(&p->seglock);
+               nexterror();
+       }
+       pages = 0;
+       for(i=0; i<NSEG; i++){
+               if((s = p->seg[i]) != nil){
+                       eqlock(s);
+                       pages += mcountseg(s);
+                       qunlock(s);
+               }
+       }
+       qunlock(&p->seglock);
+       poperror();
+
+       return pages;
+}
+
 void
 killbig(char *why)
 {
@@ -1503,25 +1603,20 @@ killbig(char *why)
        kp = nil;
        ep = procalloc.arena+conf.nproc;
        for(p = procalloc.arena; p < ep; p++) {
-               if(p->state == Dead || p->kp || !canqlock(&p->seglock))
+               if(p->state == Dead || p->kp)
                        continue;
-               l = 0;
-               for(i=1; i<NSEG; i++) {
-                       s = p->seg[i];
-                       if(s == nil || !canqlock(s))
-                               continue;
-                       l += mcountseg(s);
-                       qunlock(s);
-               }
-               qunlock(&p->seglock);
-               if(l > max && ((p->procmode&0222) || strcmp(eve, p->user)!=0)) {
+               if((p->noswap || (p->procmode & 0222) == 0) && strcmp(eve, p->user) == 0)
+                       continue;
+               l = procpagecount(p);
+               if(l > max){
                        kp = p;
                        max = l;
                }
        }
-       if(kp == nil || !canqlock(&kp->seglock))
+       if(kp == nil)
                return;
        print("%lud: %s killed: %s\n", kp->pid, kp->text, why);
+       qlock(&kp->seglock);
        for(p = procalloc.arena; p < ep; p++) {
                if(p->state == Dead || p->kp)
                        continue;
@@ -1531,10 +1626,18 @@ killbig(char *why)
        kp->procctl = Proc_exitbig;
        for(i = 0; i < NSEG; i++) {
                s = kp->seg[i];
-               if(s != nil && canqlock(s)) {
-                       mfreeseg(s, s->base, (s->top - s->base)/BY2PG);
-                       qunlock(s);
+               if(s == nil)
+                       continue;
+               switch(s->type & SG_TYPE){
+               case SG_SHARED:
+               case SG_PHYSICAL:
+               case SG_FIXED:
+               case SG_STICKY:
+                       continue;
                }
+               qlock(s);
+               mfreeseg(s, s->base, (s->top - s->base)/BY2PG);
+               qunlock(s);
        }
        qunlock(&kp->seglock);
 }
@@ -1574,14 +1677,14 @@ accounttime(void)
        n = perfticks();
        per = n - m->perf.last;
        m->perf.last = n;
-       per = (m->perf.period*(HZ-1) + per)/HZ;
+       per = ((uvlong)m->perf.period*(HZ-1) + per)/HZ;
        if(per != 0)
                m->perf.period = per;
 
-       m->perf.avg_inidle = (m->perf.avg_inidle*(HZ-1)+m->perf.inidle)/HZ;
+       m->perf.avg_inidle = ((uvlong)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.avg_inintr = ((uvlong)m->perf.avg_inintr*(HZ-1)+m->perf.inintr)/HZ;
        m->perf.inintr = 0;
 
        /* only one processor gets to compute system load averages */
@@ -1599,8 +1702,9 @@ accounttime(void)
         */
        n = nrun;
        nrun = 0;
-       n = (nrdy+n)*1000;
-       m->load = (m->load*(HZ-1)+n)/HZ;
+       n = (nrdy+n)*1000*100;
+       load = ((uvlong)load*(HZ-1)+n)/HZ;
+       m->load = load/100;
 }
 
 int