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 debuggotolabel(Label *p) { Mach *m = machp(); if(0)hi("debuggotolabel"); iprint("gotolabel: pid %p rip %p sp %p\n", m && m->externup? m->externup->pid : 0, (void *)p->pc, (void *)p->sp); /* */ if (!p->pc) die("PC IS ZERO!"); /* this is an example of putting a breakpoint * here so we can capture a particular process. * startup is very deterministic so this can * be very useful. You can then attach with * gdb and single step. In practice this helped us show * that our return stack for sysrforkret was bogus. if (m && m->externup && m->externup->pid == 6) die("PID 6\n"); */ gotolabel(p); }
/* * sleep if a condition is not true. Another process will * awaken us after it sets the condition. When we awaken * the condition may no longer be true. * * we lock both the process and the rendezvous to keep r->p * and p->r synchronized. */ void sleep(Rendez *r, int (*f)(void*), void *arg) { int s; void (*pt)(Proc*, int, vlong); s = splhi(); if(up->nlocks) print("process %lud sleeps with %d locks held, last lock %#p locked at pc %#p, sleep called from %#p\n", up->pid, up->nlocks, up->lastlock, up->lastlock->pc, getcallerpc(&r)); lock(r); lock(&up->rlock); if(r->p != nil){ print("double sleep called from %#p, %lud %lud\n", getcallerpc(&r), r->p->pid, up->pid); dumpstack(); } /* * Wakeup only knows there may be something to do by testing * r->p in order to get something to lock on. * Flush that information out to memory in case the sleep is * committed. */ r->p = up; if((*f)(arg) || up->notepending){ /* * if condition happened or a note is pending * never mind */ r->p = nil; unlock(&up->rlock); unlock(r); } else { /* * now we are committed to * change state and call scheduler */ pt = proctrace; if(pt != nil) pt(up, SSleep, 0); up->state = Wakeme; up->r = r; /* statistics */ m->cs++; procsave(up); if(setlabel(&up->sched)) { /* * here when the process is awakened */ procrestore(up); spllo(); } else { /* * here to go to sleep (i.e. stop Running) */ unlock(&up->rlock); unlock(r); gotolabel(&m->sched); } } if(up->notepending) { up->notepending = 0; splx(s); interrupted(); } splx(s); }
void nexterror(void) { assert(up->nerrlab > 0); gotolabel(&up->errlab[--up->nerrlab]); }
/* * If changing this routine, look also at sleep(). It * contains a copy of the guts of sched(). */ void sched(void) { Proc *p; if(m->ilockdepth) panic("cpu%d: ilockdepth %d, last lock %#p at %#p, sched called from %#p", m->machno, m->ilockdepth, up != nil ? up->lastilock: nil, (up != nil && up->lastilock != nil) ? up->lastilock->pc: 0, getcallerpc(&p+2)); if(up != nil) { /* * Delay the sched until the process gives up the locks * it is holding. This avoids dumb lock loops. * Don't delay if the process is Moribund. * It called sched to die. * But do sched eventually. This avoids a missing unlock * from hanging the entire kernel. * But don't reschedule procs holding palloc or procalloc. * Those are far too important to be holding while asleep. * * This test is not exact. There can still be a few instructions * in the middle of taslock when a process holds a lock * but Lock.p has not yet been initialized. */ if(up->nlocks) if(up->state != Moribund) if(up->delaysched < 20 || palloc.Lock.p == up || procalloc.Lock.p == up){ up->delaysched++; delayedscheds++; return; } up->delaysched = 0; splhi(); /* statistics */ m->cs++; procsave(up); if(setlabel(&up->sched)){ procrestore(up); spllo(); return; } gotolabel(&m->sched); } p = runproc(); if(p->edf == nil){ updatecpu(p); p->priority = reprioritize(p); } if(p != m->readied) m->schedticks = m->ticks + HZ/10; m->readied = nil; up = p; up->state = Running; up->mach = MACHP(m->machno); m->proc = up; mmuswitch(up); gotolabel(&up->sched); }
void nexterror(void) { Mach *m = machp(); /*debug*/gotolabel(&m->externup->errlab[--m->externup->nerrlab]); }
/* * If changing this routine, look also at sleep(). It * contains a copy of the guts of sched(). */ void sched(void) { Mach *m = machp(); Proc *p; if(m->ilockdepth) panic("cpu%d: ilockdepth %d, last lock %#p at %#p, sched called from %#p", m->machno, m->ilockdepth, m->externup? m->externup->lastilock: nil, (m->externup && m->externup->lastilock)? m->externup->lastilock->_pc: 0, getcallerpc(&p+2)); kstackok(); if(m->externup){ /* * Delay the sched until the process gives up the locks * it is holding. This avoids dumb lock loops. * Don't delay if the process is Moribund. * It called sched to die. * But do sched eventually. This avoids a missing unlock * from hanging the entire kernel. * But don't reschedule procs holding palloc or procalloc. * Those are far too important to be holding while asleep. * * This test is not exact. There can still be a few * instructions in the middle of taslock when a process * holds a lock but Lock.p has not yet been initialized. */ if(m->externup->nlocks) if(m->externup->state != Moribund) if(m->externup->delaysched < 20 || pga.Lock.p == m->externup || procalloc.Lock.p == m->externup){ m->externup->delaysched++; run.delayedscheds++; return; } m->externup->delaysched = 0; splhi(); /* statistics */ if(m->externup->nqtrap == 0 && m->externup->nqsyscall == 0) m->externup->nfullq++; m->cs++; procsave(m->externup); mmuflushtlb(m->pml4->pa); if(setlabel(&m->externup->sched)){ procrestore(m->externup); spllo(); return; } /*debug*/gotolabel(&m->sched); } m->inidle = 1; p = runproc(); /* core 0 never returns */ m->inidle = 0; if(!p->edf){ updatecpu(p); p->priority = reprioritize(p); } if(nosmp){ if(p != m->readied) m->schedticks = m->ticks + HZ/10; m->readied = 0; } m->externup = p; m->qstart = m->ticks; m->externup->nqtrap = 0; m->externup->nqsyscall = 0; m->externup->state = Running; //m->externup->mach = m; m->externup->mach = sys->machptr[m->machno]; m->proc = m->externup; // iprint("m->externup->sched.sp %p * %p\n", up->sched.sp, // *(void **) m->externup->sched.sp); mmuswitch(m->externup); assert(!m->externup->wired || m->externup->wired == m); if (0) hi("gotolabel\n"); /*debug*/gotolabel(&m->externup->sched); }
/* * sleep if a condition is not true. Another process will * awaken us after it sets the condition. When we awaken * the condition may no longer be true. * * we lock both the process and the rendezvous to keep r->p * and p->r synchronized. */ void sleep(Rendez *r, int (*f)(void*), void *arg) { Mach *m = machp(); Mpl pl; pl = splhi(); if(m->externup->nlocks) print("process %d sleeps with %d locks held, last lock %#p locked at pc %#p, sleep called from %#p\n", m->externup->pid, m->externup->nlocks, m->externup->lastlock, m->externup->lastlock->_pc, getcallerpc(&r)); lock(r); lock(&m->externup->rlock); if(r->_p){ print("double sleep called from %#p, %d %d\n", getcallerpc(&r), r->_p->pid, m->externup->pid); dumpstack(); } /* * Wakeup only knows there may be something to do by testing * r->p in order to get something to lock on. * Flush that information out to memory in case the sleep is * committed. */ r->_p = m->externup; if((*f)(arg) || m->externup->notepending){ /* * if condition happened or a note is pending * never mind */ r->_p = nil; unlock(&m->externup->rlock); unlock(r); } else { /* * now we are committed to * change state and call scheduler */ if(m->externup->trace) proctrace(m->externup, SSleep, 0); m->externup->state = Wakeme; m->externup->r = r; /* statistics */ m->cs++; procsave(m->externup); mmuflushtlb(m->pml4->pa); if(setlabel(&m->externup->sched)) { /* * here when the process is awakened */ procrestore(m->externup); spllo(); } else { /* * here to go to sleep (i.e. stop Running) */ unlock(&m->externup->rlock); unlock(r); /*debug*/gotolabel(&m->sched); } } if(m->externup->notepending) { m->externup->notepending = 0; splx(pl); if(m->externup->procctl == Proc_exitme && m->externup->closingfgrp) forceclosefgrp(); error(Eintr); } splx(pl); }
void nexterror(void) { gotolabel(&up->errlab[--up->nerrlab]); }
void nexterror(void) { Proc *up = externup(); /*debug*/gotolabel(&up->errlab[--up->nerrlab]); }