static void rebalance(void) { int pri, npri, t, x; Schedq *rq; Proc *p; t = m->ticks; if(t - balancetime < HZ) return; balancetime = t; for(pri=0, rq=runq; pri<Npriq; pri++, rq++){ another: p = rq->head; if(p == nil) continue; if(p->mp != MACHP(m->machno)) continue; if(pri == p->basepri) continue; updatecpu(p); npri = reprioritize(p); if(npri != pri){ x = splhi(); p = dequeueproc(rq, p); if(p != nil) queueproc(&runq[npri], p); splx(x); goto another; } } }
/* * recalculate priorities once a second. We need to do this * since priorities will otherwise only be recalculated when * the running process blocks. */ static void rebalance(void) { Mach *m = machp(); Mpl pl; int pri, npri, t; Schedq *rq; Proc *p; t = m->ticks; if(t - run.balancetime < HZ) return; run.balancetime = t; for(pri=0, rq=run.runq; pri<Npriq; pri++, rq++){ another: p = rq->head; if(p == nil) continue; if(p->mp != sys->machptr[m->machno]) //MACHP(m->machno) continue; if(pri == p->basepri) continue; updatecpu(p); npri = reprioritize(p); if(npri != pri){ pl = splhi(); p = dequeueproc(&run, rq, p); if(p) queueproc(&run, &run.runq[npri], p, 0); splx(pl); goto another; } } }
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; }
/* * 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; }
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; }
/* * Scheduling thread run as the main loop of cpu 0 * Used in AMP sched. */ static void mach0sched(void) { Mach *m = machp(); Schedq *rq; Proc *p; Mach *mp; uint32_t start, now; int n, i; //, j; assert(m->machno == 0); acmodeset(NIXKC); /* we don't time share any more */ n = 0; start = perfticks(); loop: /* * find a ready process that we might run. */ spllo(); for(rq = &run.runq[Nrq-1]; rq >= run.runq; rq--) for(p = rq->head; p; p = p->rnext){ /* * wired processes may only run when their core is available. */ if(p->wired != nil){ if(p->wired->proc == nil) goto found; continue; } /* * find a ready process that did run at an available core * or one that has not moved for some time. */ if(p->mp == nil || p->mp->proc == nil || n>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; n++; goto loop; found: assert(m->machno == 0); splhi(); /* * find a core for this process, but honor wiring. */ mp = p->wired; if(mp != nil){ if(mp->proc != nil) goto loop; }else{ for(i = 0; i < MACHMAX; i++){ /*j = pickcore(p->color, i); if((mp = sys->machptr[j]) != nil && mp->online && mp->nixtype == NIXTC){*/ if((mp = sys->machptr[i]) != nil){ // && mp->online && mp->nixtype == NIXTC){ if(mp != m && mp->proc == nil) break; } } if(i == MACHMAX){ preemptfor(p); goto loop; } } p = dequeueproc(&run, rq, p); mp->proc = p; if(p != nil){ p->state = Scheding; p->mp = mp; } n = 0; goto loop; }