/* * EPISODE 12B * How to recognise different types of trees from quite a long way away. * NO. 1 * THE LARCH */ #include "u.h" #include "../port/lib.h" #include "mem.h" #include "dat.h" #include "fns.h" #include "../port/error.h" void procrestore(Proc *p) { uint64_t t; if(p->kp) return; cycles(&t); p->pcycles -= t; } /* * Save the mach dependent part of the process state. */ void procsave(Proc *p) { uint64_t t; cycles(&t); p->pcycles += t; if(p->fpstate == FPactive){ if(p->state == Moribund) fpclear(); else{ /* * Fpsave() stores without handling pending * unmasked exeptions. Postnote() can't be called * here as sleep() already has up->rlock, so * the handling of pending exceptions is delayed * until the process runs again and generates an * emulation fault to activate the FPU. */ fpsave(&p->fpsave); } p->fpstate = FPinactive; } /* * While this processor is in the scheduler, the process could run * on another processor and exit, returning the page tables to * the free list where they could be reallocated and overwritten. * When this processor eventually has to get an entry from the * trashed page tables it will crash. * * If there's only one processor, this can't happen. * You might think it would be a win not to do this in that case, * especially on VMware, but it turns out not to matter. */ mmuflushtlb(); } static void linkproc(void) { spllo(); up->kpfun(up->kparg); pexit("kproc dying", 0); } void kprocchild(Proc* p, void (*func)(void*), void* arg) { /* * gotolabel() needs a word on the stack in * which to place the return PC used to jump * to linkproc(). */ p->sched.pc = PTR2UINT(linkproc); p->sched.sp = PTR2UINT(p->kstack+KSTACK-BY2SE); p->sched.sp = STACKALIGN(p->sched.sp); p->kpfun = func; p->kparg = arg; } static int spinOnIdle; void onIdleSpin(void) { spinOnIdle = 1; } /* * put the processor in the halt state if we've no processes to run. * an interrupt will get us going again. * * halting in an smp system can result in a startup latency for * processes that become ready. * if idle_spin is zero, we care more about saving energy * than reducing this latency. * * the performance loss with idle_spin == 0 seems to be slight * and it reduces lock contention (thus system time and real time) * on many-core systems with large values of NPROC. */ void idlehands(void) { extern int nrdy; if(sys->nmach == 1) halt(); else if (SUPPORT_MWAIT) mwait32(&nrdy, 0); else if(!spinOnIdle) halt(); }