void edfyield(void) { /* sleep until next release */ Edf *e; void (*pt)(Proc*, int, vlong); if((e = edflock(up)) == nil) return; if(pt = proctrace) pt(up, SYield, now); while(e->t < now) e->t += e->T; e->r = e->t; e->flags |= Yield; e->d = now; if (up->tt == nil){ up->tns = e->t; up->tf = releaseintr; up->tmode = Tabsolute; up->ta = up; up->trend = &up->sleep; timeradd(up); }else if(up->tf != releaseintr) print("edfyield: surprise! 0x%lux\n", up->tf); edfunlock(); sleep(&up->sleep, yfn, nil); }
void edfrecord(Proc *p) { int32_t used; Edf *e; if((e = edflock(p)) == nil) return; used = now - e->s; if(e->d - now <= 0) e->edfused += used; else e->extraused += used; if(e->S > 0){ if(e->S <= used){ if(p->trace) proctrace(p, SSlice, 0); DPRINT("%lu edfrecord slice used up\n", now); e->d = now; e->S = 0; }else e->S -= used; } e->s = now; edfunlock(); }
void edfrecord(Proc *p) { vlong used; Edf *e; void (*pt)(Proc*, int, vlong); if((e = edflock(p)) == nil) return; used = now - e->s; if (e->d <= now) e->edfused += used; else e->extraused += used; if (e->S > 0){ if (e->S <= used){ if(pt = proctrace) pt(p, SSlice, now); DPRINT("%t edfrecord slice used up\n", now); e->d = now; e->S = 0; }else e->S -= used; } e->s = now; edfunlock(); }
static void releaseintr(Ureg*, Timer *t) { Proc *p; extern int panicking; Schedq *rq; if(panicking || active.exiting) return; p = t->ta; if((edflock(p)) == nil) return; DPRINT("%lud releaseintr %d[%s]\n", now, p->pid, statename[p->state]); switch(p->state){ default: edfunlock(); return; case Ready: /* remove proc from current runq */ rq = &runq[p->priority]; if(dequeueproc(rq, p) != p){ DPRINT("releaseintr: can't find proc or lock race\n"); release(p); /* It'll start best effort */ edfunlock(); return; } p->state = Waitrelease; /* fall through */ case Waitrelease: release(p); edfunlock(); if(p->state == Wakeme){ iprint("releaseintr: wakeme\n"); } ready(p); if(up){ up->delaysched++; delayedscheds++; } return; case Running: release(p); edfrun(p, 1); break; case Wakeme: release(p); edfunlock(); if(p->trend) wakeup(p->trend); p->trend = nil; if(up){ up->delaysched++; delayedscheds++; } return; } edfunlock(); }
/* * SMP performs better than AMP with few cores. * So, leave this here by now. We should probably * write a unified version of runproc good enough for * both SMP and AMP. */ static Proc* smprunproc(void) { Mach *m = machp(); Schedq *rq; Proc *p; uint32_t start, now; int i; start = perfticks(); run.preempts++; 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. */ spllo(); for(i = 0;; i++){ /* * find the highest priority target process that this * processor can run given affinity constraints. * */ for(rq = &run.runq[Nrq-1]; rq >= run.runq; rq--){ for(p = rq->head; p; p = p->rnext){ if(p->mp == nil || p->mp == sys->machptr[m->machno] || (!p->wired && i > 0)) goto found; } } /* waste time or halt the CPU */ idlehands(); /* remember how much time we're here */ now = perfticks(); m->perf.inidle += now-start; start = now; } found: splhi(); p = dequeueproc(&run, rq, p); if(p == nil) goto loop; p->state = Scheding; p->mp = sys->machptr[m->machno]; if(edflock(p)){ edfrun(p, rq == &run.runq[PriEdf]); /* start deadline timer and do admin */ edfunlock(); } if(p->trace) proctrace(p, SRun, 0); return p; }
void edfstop(Proc *p) { Edf *e; if(e = edflock(p)){ DPRINT("%lu edfstop %d[%s]\n", now, p->pid, statename[p->state]); if(p->trace) proctrace(p, SExpel, 0); e->flags &= ~Admitted; if(e->Timer.tt) timerdel(&e->Timer); edfunlock(); } }
void edfstop(Proc *p) { Edf *e; void (*pt)(Proc*, int, vlong); if (e = edflock(p)){ DPRINT("%t edfstop %lud[%s]\n", now, p->pid, statename[p->state]); if(pt = proctrace) pt(p, SExpel, now); e->flags &= ~Admitted; if (e->tt) timerdel(e); edfunlock(); } }
Proc* runproc(void) { Mach *m = machp(); Schedq *rq; Proc *p; uint32_t start, now; if(nosmp) return singlerunproc(); //NIX modeset cannot work without halt every cpu at boot //if(sys->nmach <= AMPmincores) else return smprunproc(); start = perfticks(); run.preempts++; rq = nil; if(m->machno != 0){ do{ spllo(); while(m->proc == nil) idlehands(); now = perfticks(); m->perf.inidle += now-start; start = now; splhi(); p = m->proc; }while(p == nil); p->state = Scheding; p->mp = sys->machptr[m->machno]; if(edflock(p)){ edfrun(p, rq == &run.runq[PriEdf]); /* start deadline timer and do admin */ edfunlock(); } if(p->trace) proctrace(p, SRun, 0); return p; } mach0sched(); return nil; /* not reached */ }
void edfyield(void) { Proc *up = externup(); /* sleep until next release */ Edf *e; int32_t n; if((e = edflock(up)) == nil) return; if(up->trace) proctrace(up, SYield, 0); if((n = now - e->t) > 0){ if(n < e->T) e->t += e->T; else e->t = now + e->T - (n % e->T); } e->r = e->t; e->flags |= Yield; e->d = now; if (up->Timer.tt == nil){ n = e->t - now; if(n < 20) n = 20; up->Timer.tns = 1000LL * n; up->Timer.tf = releaseintr; up->Timer.tmode = Trelative; up->Timer.ta = up; up->trend = &up->sleep; timeradd(&up->Timer); }else if(up->Timer.tf != releaseintr) print("edfyield: surprise! %#p\n", up->Timer.tf); edfunlock(); sleep(&up->sleep, yfn, nil); }
void edfyield(void) { /* sleep until next release */ Edf *e; void (*pt)(Proc*, int, vlong, vlong); long n; if((e = edflock(up)) == nil) return; if(up->trace && (pt = proctrace)) pt(up, SYield, 0, 0); if((n = now - e->t) > 0){ if(n < e->T) e->t += e->T; else e->t = now + e->T - (n % e->T); } e->r = e->t; e->flags |= Yield; e->d = now; if (up->tt == nil){ n = e->t - now; if(n < 20) n = 20; up->tns = 1000LL * n; up->tf = releaseintr; up->tmode = Trelative; up->ta = up; up->trend = &up->sleep; timeradd(up); }else if(up->tf != releaseintr) print("edfyield: surprise! %#p\n", up->tf); edfunlock(); sleep(&up->sleep, yfn, nil); }
/* * pick a process to run */ Proc* runproc(void) { Schedq *rq; Proc *p; ulong start, now; int i; void (*pt)(Proc*, int, vlong); start = perfticks(); /* cooperative scheduling until the clock ticks */ if((p = m->readied) != nil && p->mach == nil && p->state == Ready && (p->wired == nil || p->wired == MACHP(m->machno)) && runq[Nrq-1].head == nil && runq[Nrq-2].head == nil){ skipscheds++; rq = &runq[p->priority]; goto found; } preempts++; 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. */ spllo(); for(i = 0;; i++){ /* * find the highest priority target process that this * processor can run given affinity constraints. * */ for(rq = &runq[Nrq-1]; rq >= runq; rq--){ for(p = rq->head; p != nil; p = p->rnext){ if(p->mp == nil || p->mp == MACHP(m->machno) || (p->wired == nil && i > 0)) goto found; } } /* waste time or halt the CPU */ idlehands(); /* remember how much time we're here */ now = perfticks(); m->perf.inidle += now-start; start = now; } found: splhi(); p = dequeueproc(rq, p); if(p == nil) goto loop; p->state = Scheding; p->mp = MACHP(m->machno); if(edflock(p)){ edfrun(p, rq == &runq[PriEdf]); /* start deadline timer and do admin */ edfunlock(); } pt = proctrace; if(pt != nil) pt(p, SRun, 0); return p; }
int edfready(Proc *p) { Edf *e; Sched *sch; Schedq *rq; Proc *l, *pp; int32_t n; if((e = edflock(p)) == nil) return 0; if(p->state == Wakeme && p->r){ iprint("edfready: wakeme\n"); } if(e->d - now <= 0){ /* past deadline, arrange for next release */ if((e->flags & Sporadic) == 0){ /* * Non sporadic processes stay true to their period; * calculate next release time. */ if((n = now - e->t) > 0){ if(n < e->T) e->t += e->T; else e->t = now + e->T - (n % e->T); } } if(now - e->t < 0){ /* Next release is in the future, schedule it */ if(e->Timer.tt == nil || e->Timer.tf != releaseintr){ n = e->t - now; if(n < 20) n = 20; e->Timer.tns = 1000LL * n; e->Timer.tmode = Trelative; e->Timer.tf = releaseintr; e->Timer.ta = p; timeradd(&e->Timer); DPRINT("%lu edfready %d[%s], release=%lu\n", now, p->pid, statename[p->state], e->t); } if(p->state == Running && (e->flags & (Yield|Yieldonblock)) == 0 && (e->flags & Extratime)){ /* If we were running, we've overrun our CPU allocation * or missed the deadline, continue running best-effort at low priority * Otherwise we were blocked. If we don't yield on block, we continue * best effort */ DPRINT(">"); p->basepri = PriExtra; p->fixedpri = 1; edfunlock(); return 0; /* Stick on runq[PriExtra] */ } DPRINT("%lu edfready %d[%s] wait release at %lu\n", now, p->pid, statename[p->state], e->t); p->state = Waitrelease; edfunlock(); return 1; /* Make runnable later */ } DPRINT("%lu edfready %d %s release now\n", now, p->pid, statename[p->state]); /* release now */ release(p); } edfunlock(); DPRINT("^"); sch = procsched(p); rq = &sch->runq[PriEdf]; /* insert in queue in earliest deadline order */ lock(&sch->l); l = nil; for(pp = rq->head; pp; pp = pp->rnext){ if(pp->edf->d > e->d) break; l = pp; } p->rnext = pp; if (l == nil) rq->head = p; else l->rnext = p; if(pp == nil) rq->tail = p; rq->n++; sch->nrdy++; sch->runvec |= 1 << PriEdf; p->priority = PriEdf; p->readytime = machp()->ticks; p->state = Ready; unlock(&sch->l); if(p->trace) proctrace(p, SReady, 0); return 1; }
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 Proc* singlerunproc(void) { Mach *m = machp(); Schedq *rq; Proc *p; uint32_t start, now, skipscheds; int i; start = perfticks(); /* cooperative scheduling until the clock ticks */ if((p=m->readied) && p->mach==0 && p->state==Ready && &run.runq[Nrq-1].head == nil && &run.runq[Nrq-2].head == nil){ skipscheds++; rq = &run.runq[p->priority]; if(0)hi("runproc going to found before loop...\n"); goto found; } run.preempts++; 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. */ spllo(); for(i = 0;; i++){ /* * find the highest priority target process that this * processor can run given affinity constraints. * */ for(rq = &run.runq[Nrq-1]; rq >= run.runq; rq--){ for(p = rq->head; p; p = p->rnext){ if(p->mp == nil || p->mp == sys->machptr[m->machno] || (!p->wired && i > 0)) { if(0)hi("runproc going to found inside loop...\n"); goto found; } } } /* waste time or halt the CPU */ idlehands(); /* remember how much time we're here */ now = perfticks(); m->perf.inidle += now-start; start = now; } found: splhi(); if(0)hi("runproc into found...\n"); p = dequeueproc(&run, rq, p); if(p == nil) { if(0)hi("runproc p=nil :(\n"); goto loop; } p->state = Scheding; if(0)hi("runproc, pm->mp = sys->machptr[m->machno]\n"); p->mp = sys->machptr[m->machno]; if(0){hi("runproc, sys->machptr[m->machno] = "); put64((uint64_t)p->mp); hi("\n");} if(edflock(p)){ edfrun(p, rq == &run.runq[PriEdf]); /* start deadline timer and do admin */ edfunlock(); } if(p->trace) proctrace(p, SRun, 0); /* avoiding warnings, this will be removed */ USED(mach0sched); USED(smprunproc); if(0){hi("runproc, returning p "); put64((uint64_t)p); hi("\n");} return p; }
int edfready(Proc *p) { Edf *e; Schedq *rq; Proc *l, *pp; void (*pt)(Proc*, int, vlong); if((e = edflock(p)) == nil) return 0; if (e->d <= now){ /* past deadline, arrange for next release */ if ((e->flags & Sporadic) == 0){ /* Non sporadic processes stay true to their period, calculate next release time */ while(e->t < now) e->t += e->T; } if (now < e->t){ /* Next release is in the future, schedule it */ if (e->tt == nil || e->tf != releaseintr){ e->tns = e->t; e->tmode = Tabsolute; e->tf = releaseintr; e->ta = p; timeradd(e); DPRINT("%t edfready %lud[%s], release=%t\n", now, p->pid, statename[p->state], e->t); } if(p->state == Running && (e->flags & (Yield|Yieldonblock)) == 0 && (e->flags & Extratime)){ /* If we were running, we've overrun our CPU allocation * or missed the deadline, continue running best-effort at low priority * Otherwise we were blocked. If we don't yield on block, we continue * best effort */ DPRINT(">"); p->pri = PriExtra; edfunlock(); return 0; /* Stick on runq[PriExtra] */ } DPRINT("%t edfready %lud[%s] wait release at %t\n", now, p->pid, statename[p->state], e->t); p->state = Waitrelease; edfunlock(); return 1; /* Make runnable later */ } DPRINT("%t edfready %lud %s release now\n", now, p->pid, statename[p->state]); /* release now */ release(p); } edfunlock(); DPRINT("^"); rq = &runq[PriEdf]; /* insert in queue in earliest deadline order */ lock(runq); l = nil; for(pp = rq->head; pp; pp = pp->rnext){ if(pp->edf->d > e->d) break; l = pp; } p->rnext = pp; if (l == nil) rq->head = p; else l->rnext = p; if(pp == nil) rq->tail = p; rq->n++; nrdy++; runvec |= 1 << PriEdf; p->pri = PriEdf; p->readytime = m->ticks; p->state = Ready; unlock(runq); if(pt = proctrace) pt(p, SReady, now); return 1; }
char * edfadmit(Proc *p) { char *err; Edf *e; int i; Proc *r; void (*pt)(Proc*, int, vlong); 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(pt = proctrace) pt(p, SAdmit, now); /* Look for another proc with the same period to synchronize to */ SET(r); for(i=0; i<conf.nproc; i++) { r = proctab(i); if(r->state == Dead || r == p) continue; if (r->edf == nil || (r->edf->flags & Admitted) == 0) continue; if (r->edf->T == e->T) break; } if (i == conf.nproc){ /* Can't synchronize to another proc, release now */ e->t = now; e->d = 0; release(p); if (p == up){ DPRINT("%t edfadmit self %lud[%s], release now: r=%t d=%t t=%t\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("%t edfadmit other %lud[%s], release now: r=%t d=%t t=%t\n", now, p->pid, statename[p->state], e->r, e->d, e->t); p->ta = p; edfunlock(); qunlock(&edfschedlock); releaseintr(nil, p); return nil; } }else{ /* Release in synch to something else */ e->t = r->edf->t; if (p == up){ DPRINT("%t edfadmit self %lud[%s], release at %t\n", now, p->pid, statename[p->state], e->t); edfunlock(); qunlock(&edfschedlock); return nil; }else{ DPRINT("%t edfadmit other %lud[%s], release at %t\n", now, p->pid, statename[p->state], e->t); if(e->tt == nil){ e->tf = releaseintr; e->ta = p; e->tns = e->t; e->tmode = Tabsolute; timeradd(e); } } } edfunlock(); qunlock(&edfschedlock); return nil; }