2016-11-25 17:18:40 +01:00
|
|
|
/*
|
|
|
|
* 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;
|
|
|
|
|
2017-08-11 01:47:15 +02:00
|
|
|
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;
|
|
|
|
}
|
2016-11-25 17:18:40 +01:00
|
|
|
|
|
|
|
/*
|
2017-08-11 01:47:15 +02:00
|
|
|
* 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.
|
2016-11-25 17:18:40 +01:00
|
|
|
*/
|
2017-08-11 01:47:15 +02:00
|
|
|
mmuflushtlb();
|
2016-11-25 17:18:40 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
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.
|
2017-08-11 01:47:15 +02:00
|
|
|
*
|
|
|
|
* 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.
|
2016-11-25 17:18:40 +01:00
|
|
|
*/
|
|
|
|
void
|
|
|
|
idlehands(void)
|
|
|
|
{
|
|
|
|
extern int nrdy;
|
2017-08-11 01:47:15 +02:00
|
|
|
if(sys->nmach == 1)
|
2016-11-25 17:18:40 +01:00
|
|
|
halt();
|
|
|
|
else if (SUPPORT_MWAIT)
|
|
|
|
mwait32(&nrdy, 0);
|
|
|
|
else if(!spinOnIdle)
|
|
|
|
halt();
|
|
|
|
}
|