static int canflush(Proc *p, Segment *s) { int i, x; lock(s); if(s->ref == 1) { /* Easy if we are the only user */ s->ref++; unlock(s); return canpage(p); } s->ref++; unlock(s); /* Now we must do hardwork to ensure all processes which have tlb * entries for this segment will be flushed if we succeed in paging it out */ for(x = 0; (p = psincref(x)) != nil; x++){ if(p->state != Dead) { for(i = 0; i < NSEG; i++){ if(p->seg[i] == s && !canpage(p)){ psdecref(p); return 0; } } } psdecref(p); } return 1; }
void pgrpnote(ulong noteid, char *a, long n, int flag) { int i; Proc *p; char buf[ERRMAX]; if(n >= ERRMAX-1) error(Etoobig); memmove(buf, a, n); buf[n] = 0; for(i = 0; (p = psincref(i)) != nil; i++){ if(p == up || p->state == Dead || p->noteid != noteid || p->kp){ psdecref(p); continue; } qlock(&p->debug); if(p->pid == 0 || p->noteid != noteid){ qunlock(&p->debug); psdecref(p); continue; } if(!waserror()) { postnote(p, 0, buf, flag); poperror(); } qunlock(&p->debug); psdecref(p); } }
/* * wait till all processes have flushed their mmu * state about segement s */ void procflushseg(Segment *s) { Mach *m = machp(); int i, ns, nm, nwait; Proc *p; Mach *mp; /* * tell all processes with this * segment to flush their mmu's */ nwait = 0; for(i=0; (p = psincref(i)) != nil; i++) { if(p->state == Dead){ psdecref(p); continue; } for(ns = 0; ns < NSEG; ns++){ if(p->seg[ns] == s){ p->newtlb = 1; for(nm = 0; nm < MACHMAX; nm++) if((mp = sys->machptr[nm]) != nil && mp->online) if(mp->proc == p){ mp->mmuflush = 1; nwait++; } break; } } psdecref(p); } if(nwait == 0) return; /* * wait for all processors to take a clock interrupt * and flush their mmu's. * NIX BUG: this won't work if another core is in AC mode. * In that case we must IPI it, but only if that core is * using this segment. */ for(i = 0; i < MACHMAX; i++) if((mp = sys->machptr[i]) != nil && mp->online) if(mp != m) while(mp->mmuflush) sched(); }
void killbig(char *why) { int i, x; Segment *s; uintptr_t l, max; Proc *p, *kp; max = 0; kp = nil; for(x = 0; (p = psincref(x)) != nil; x++) { if(p->state == Dead || p->kp){ psdecref(p); continue; } l = 0; for(i=1; i<NSEG; i++) { s = p->seg[i]; if(s != 0) l += s->top - s->base; } if(l > max && ((p->procmode&0222) || strcmp(eve, p->user)!=0)) { if(kp != nil) psdecref(kp); kp = p; max = l; } else psdecref(p); } if(kp == nil) return; print("%d: %s killed: %s\n", kp->pid, kp->text, why); for(x = 0; (p = psincref(x)) != nil; x++) { if(p->state == Dead || p->kp){ psdecref(p); continue; } /* TODO(aki): figure out what this was for. the oom killer is broken anyway though? if(p != kp && p->seg[BSEG] && p->seg[BSEG] == kp->seg[BSEG]) p->procctl = Proc_exitbig; */ psdecref(p); } kp->procctl = Proc_exitbig; for(i = 0; i < NSEG; i++) { s = kp->seg[i]; if(s != 0 && canqlock(&s->lk)) { mfreeseg(s, s->base, (s->top - s->base)/BIGPGSZ); qunlock(&s->lk); } } psdecref(kp); }
void procdump(void) { int i; Proc *p; if(up) print("up %d\n", up->pid); else print("no current process\n"); for(i=0; (p = psincref(i)) != nil; i++) { if(p->state != Dead) dumpaproc(p); psdecref(p); } }
static void pageouttext(int pgszi, int color) { Proc *p; Pgsza *pa; int i, n, np, x; Segment *s; int prepaged; USED(color); pa = &pga.pgsza[pgszi]; n = x = 0; prepaged = 0; /* * Try first to steal text pages from non-prepaged processes, * then from anyone. */ Again: do{ if((p = psincref(x)) == nil) break; np = 0; if(p->prepagemem == 0 || prepaged != 0) if(p->state != Dead && p->noswap == 0 && canqlock(&p->seglock)){ for(i = 0; i < NSEG; i++){ if((s = p->seg[i]) == nil) continue; if((s->type&SG_TYPE) == SG_TEXT) np = pageout(p, s); } qunlock(&p->seglock); } /* * else process dead or locked or changing its segments */ psdecref(p); n += np; if(np > 0) DBG("pager: %d from proc #%d %#p\n", np, x, p); x++; }while(pa->freecount < Minpages); if(pa->freecount < Minpages && prepaged++ == 0) goto Again; }
/* * wire this proc to a machine */ void procwired(Proc *p, int bm) { Mach *m = machp(); Proc *pp; int i; char nwired[MACHMAX]; Mach *wm; if(bm < 0){ /* pick a machine to wire to */ memset(nwired, 0, sizeof(nwired)); p->wired = 0; for(i=0; (pp = psincref(i)) != nil; i++){ wm = pp->wired; if(wm && pp->pid) nwired[wm->machno]++; psdecref(pp); } bm = 0; for(i=0; i<sys->nmach; i++) if(nwired[i] < nwired[bm]) bm = i; } else { /* use the virtual machine requested */ bm = bm % sys->nmach; } p->wired = sys->machptr[bm]; p->mp = p->wired; /* * adjust our color to the new domain. */ if(m->externup == nil || p != m->externup) return; m->externup->color = corecolor(m->externup->mp->machno); qlock(&m->externup->seglock); for(i = 0; i < NSEG; i++) if(m->externup->seg[i]) m->externup->seg[i]->color = m->externup->color; qunlock(&m->externup->seglock); }
static char * testschedulability(Proc *theproc) { Proc *p; int32_t H, G, Cb, ticks; int steps, i; /* initialize */ DPRINT("schedulability test %d\n", theproc->pid); qschedulability = nil; for(i=0; (p = psincref(i)) != nil; i++) { if(p->state == Dead){ psdecref(p); continue; } if ((p->edf == nil || (p->edf->flags & Admitted) == 0) && p != theproc){ psdecref(p); continue; } p->edf->testtype = Rl; p->edf->testtime = 0; DPRINT("\tInit: edfenqueue %d\n", p->pid); testenq(p); psdecref(p); } H=0; G=0; for(steps = 0; steps < Maxsteps; steps++){ p = qschedulability; qschedulability = p->edf->testnext; ticks = p->edf->testtime; switch (p->edf->testtype){ case Dl: H += p->edf->C; Cb = 0; DPRINT("\tStep %3d, Ticks %lu, pid %d, deadline, H += %lu → %lu, Cb = %lu\n", steps, ticks, p->pid, p->edf->C, H, Cb); if (H+Cb>ticks){ DPRINT("not schedulable\n"); return "not schedulable"; } p->edf->testtime += p->edf->T - p->edf->D; p->edf->testtype = Rl; testenq(p); break; case Rl: DPRINT("\tStep %3d, Ticks %lu, pid %d, release, G %lu, C%lu\n", steps, ticks, p->pid, p->edf->C, G); if(ticks && G <= ticks){ DPRINT("schedulable\n"); return nil; } G += p->edf->C; p->edf->testtime += p->edf->D; p->edf->testtype = Dl; testenq(p); break; default: assert(0); } } DPRINT("probably not schedulable\n"); return "probably not schedulable"; }
char * edfadmit(Proc *p) { Proc *up = externup(); char *err; Edf *e; int i; Proc *r; int32_t tns; e = p->edf; if (e->flags & Admitted) return "task state"; /* should never happen */ /* simple sanity checks */ if (e->T == 0) return "T not set"; if (e->C == 0) return "C not set"; if (e->D > e->T) return "D > T"; if (e->D == 0) /* if D is not set, set it to T */ e->D = e->T; if (e->C > e->D) return "C > D"; qlock(&edfschedlock); if (err = testschedulability(p)){ qunlock(&edfschedlock); return err; } e->flags |= Admitted; edflock(p); if(p->trace) proctrace(p, SAdmit, 0); /* Look for another proc with the same period to synchronize to */ for(i=0; (r = psincref(i)) != nil; i++) { if(r->state == Dead || r == p){ psdecref(r); continue; } if (r->edf == nil || (r->edf->flags & Admitted) == 0){ psdecref(r); continue; } if (r->edf->T == e->T) break; } if (r == nil){ /* Can't synchronize to another proc, release now */ e->t = now; e->d = 0; release(p); if (p == up){ DPRINT("%lu edfadmit self %d[%s], release now: r=%lu d=%lu t=%lu\n", now, p->pid, statename[p->state], e->r, e->d, e->t); /* We're already running */ edfrun(p, 1); }else{ /* We're releasing another proc */ DPRINT("%lu edfadmit other %d[%s], release now: r=%lu d=%lu t=%lu\n", now, p->pid, statename[p->state], e->r, e->d, e->t); p->Timer.ta = p; edfunlock(); qunlock(&edfschedlock); releaseintr(nil, &p->Timer); return nil; } }else{ /* Release in synch to something else */ e->t = r->edf->t; psdecref(r); if (p == up){ DPRINT("%lu edfadmit self %d[%s], release at %lu\n", now, p->pid, statename[p->state], e->t); }else{ DPRINT("%lu edfadmit other %d[%s], release at %lu\n", now, p->pid, statename[p->state], e->t); if(e->Timer.tt == nil){ e->Timer.tf = releaseintr; e->Timer.ta = p; tns = e->t - now; if(tns < 20) tns = 20; e->Timer.tns = 1000LL * tns; e->Timer.tmode = Trelative; timeradd(&e->Timer); } } } edfunlock(); qunlock(&edfschedlock); return nil; }
static int procgen(Chan *c, char *name, Dirtab *tab, int, int s, Dir *dp) { Qid qid; Proc *p; char *ename; Segment *q; int pid; ulong path, perm, len; if(s == DEVDOTDOT){ mkqid(&qid, Qdir, 0, QTDIR); devdir(c, qid, "#p", 0, eve, 0555, dp); return 1; } if(c->qid.path == Qdir){ if(s == 0){ strcpy(up->genbuf, "trace"); mkqid(&qid, Qtrace, -1, QTFILE); devdir(c, qid, up->genbuf, 0, eve, 0444, dp); return 1; } if(name != nil){ /* ignore s and use name to find pid */ pid = strtol(name, &ename, 10); if(pid<=0 || ename[0]!='\0') return -1; s = psindex(pid); if(s < 0) return -1; } else if(--s >= procalloc.nproc) return -1; if((p = psincref(s)) == nil || (pid = p->pid) == 0) return 0; sprint(up->genbuf, "%d", pid); /* * String comparison is done in devwalk so * name must match its formatted pid. */ if(name != nil && strcmp(name, up->genbuf) != 0) return -1; mkqid(&qid, (s+1)<<QSHIFT, pid, QTDIR); devdir(c, qid, up->genbuf, 0, p->user, DMDIR|0555, dp); psdecref(p); return 1; } if(c->qid.path == Qtrace){ strcpy(up->genbuf, "trace"); mkqid(&qid, Qtrace, -1, QTFILE); devdir(c, qid, up->genbuf, 0, eve, 0444, dp); return 1; } if(s >= nelem(procdir)) return -1; if(tab) panic("procgen"); tab = &procdir[s]; path = c->qid.path&~(((1<<QSHIFT)-1)); /* slot component */ if((p = psincref(SLOT(c->qid))) == nil) return -1; perm = tab->perm; if(perm == 0) perm = p->procmode; else /* just copy read bits */ perm |= p->procmode & 0444; len = tab->length; switch(QID(c->qid)) { case Qwait: len = p->nwait; /* incorrect size, but >0 means there's something to read */ break; case Qprofile: q = p->seg[TSEG]; if(q && q->profile) { len = (q->top-q->base)>>LRESPROF; len *= sizeof(*q->profile); } break; }
static int procgen(Chan *c, char *name, Dirtab *tab, int j, int s, Dir *dp) { Proc *up = externup(); Qid qid; Proc *p; char *ename; int pid, sno; uint32_t path, perm, len; if(s == DEVDOTDOT){ mkqid(&qid, Qdir, 0, QTDIR); devdir(c, qid, "#p", 0, eve, 0555, dp); return 1; } if(c->qid.path == Qdir){ if(s == 0){ strcpy(up->genbuf, "trace"); mkqid(&qid, Qtrace, -1, QTFILE); devdir(c, qid, up->genbuf, 0, eve, 0444, dp); return 1; } if(s == 1){ strcpy(up->genbuf, "tracepids"); mkqid(&qid, Qtracepids, -1, QTFILE); devdir(c, qid, up->genbuf, 0, eve, 0444, dp); return 1; } s -= 2; if(name != nil){ /* ignore s and use name to find pid */ pid = strtol(name, &ename, 10); if(pid<=0 || ename[0]!='\0') return -1; s = psindex(pid); if(s < 0) return -1; } else if(s >= conf.nproc) return -1; if((p = psincref(s)) == nil || (pid = p->pid) == 0) return 0; snprint(up->genbuf, sizeof up->genbuf, "%u", pid); /* * String comparison is done in devwalk so * name must match its formatted pid. */ if(name != nil && strcmp(name, up->genbuf) != 0) return -1; mkqid(&qid, (s+1)<<QSHIFT, pid, QTDIR); devdir(c, qid, up->genbuf, 0, p->user, DMDIR|0555, dp); psdecref(p); return 1; } if(c->qid.path == Qtrace){ strcpy(up->genbuf, "trace"); mkqid(&qid, Qtrace, -1, QTFILE); devdir(c, qid, up->genbuf, 0, eve, 0444, dp); return 1; } if(c->qid.path == Qtracepids){ strcpy(up->genbuf, "tracepids"); mkqid(&qid, Qtrace, -1, QTFILE); devdir(c, qid, up->genbuf, 0, eve, 0444, dp); return 1; } if(s >= nelem(procdir)) return -1; if(tab) panic("procgen"); tab = &procdir[s]; path = c->qid.path&~(((1<<QSHIFT)-1)); /* slot component */ if((p = psincref(SLOT(c->qid))) == nil) return -1; perm = tab->perm; if(perm == 0) perm = p->procmode; else /* just copy read bits */ perm |= p->procmode & 0444; len = tab->length; switch(QID(c->qid)) { case Qwait: len = p->nwait; /* incorrect size, but >0 means there's something to read */ break; case Qprofile: /* TODO(aki): test this */ len = 0; for(sno = 0; sno < NSEG; sno++){ if(p->seg[sno] != nil && (p->seg[sno]->type & SG_EXEC) != 0){ Segment *s; s = p->seg[sno]; if(s->profile) len += ((s->top-s->base)>>LRESPROF) * sizeof s->profile[0]; } } break; }