|
|
researchv10 Norman
#include "sys/param.h"
#include "sys/systm.h"
#include "sys/meter.h"
#include "sys/callout.h"
#include "sys/user.h"
#include "sys/proc.h"
#include "sys/psl.h"
#include "sys/vm.h"
#include "sys/buf.h"
#include "sys/text.h"
#include "sys/vlimit.h"
#include "sys/mtpr.h"
#include "sys/clock.h"
int queueflag;
/*
* trivial kernel profiling; quite expensive in space
*/
#define KMAX (200*1024) /* max kernel text */
#define KPSIZE (50*256) /* number of buckets */
#define KPROF 1
#if KPROF
long kprof[KPSIZE];
#endif
/*
* Hardclock is called straight from
* the real time clock interrupt.
* We limit the work we do at real clock interrupt time to:
* reloading clock
* decrementing time to callouts
* recording cpu time usage
* modifying priority of current process
* arrange for soft clock interrupt
* kernel pc profiling
*
* At software (softclock) interrupt time we:
* implement callouts
* maintain date
* lightning bolt wakeup (every second)
* alarm clock signals
* jab the scheduler
*
* On the vax softclock interrupts are implemented by
* software interrupts. Note that we may have multiple softclock
* interrupts compressed into one (due to excessive interrupt load),
* but that hardclock interrupts should never be lost.
*/
/*ARGSUSED*/
hardclock(pc, ps)
caddr_t pc;
{
register struct callout *p1;
register struct proc *pp;
register int s, cpstate;
/*
* reprime clock
*/
clkreld();
/*
* update callout times
*/
for (p1 = calltodo.c_next; p1 && p1->c_time <= 0; p1 = p1->c_next)
;
if (p1)
p1->c_time--;
pp = u.u_procp;
if (USERMODE(ps)) {
u.u_vm.vm_utime++;
if (pp->p_nice > NZERO)
cpstate = CP_NICE;
else
cpstate = CP_USER;
s = 1;
} else {
#if KPROF
s = (long)pc - KSTART;
if (s < 0)
s = 0; /* shouldn't */
else if (s >= KMAX)
s = KMAX - 1;
s /= KMAX/KPSIZE;
kprof[s]++;
#endif
cpstate = CP_SYS;
if (queueflag) {
cpstate = CP_QUEUE;
s = 0;
} else if (noproc) {
if (BASEPRI(ps) == 0)
cpstate = CP_IDLE;
s = 0;
} else {
u.u_vm.vm_stime++;
s = 1;
}
}
cp_time[cpstate]++;
/*
* Adjust priority of current process.
*/
if (s) {
pp->p_cpticks++;
if(++pp->p_cpu == 0)
--pp->p_cpu;
}
++lbolt;
setsoftclock();
}
#define cpuave(a,b) ((int)(((int)((a)*(b)))/((b)+1)))
extern double avenrun[];
/*
* Constant for decay filter for cpu usage field
* in process table (used by ps au).
*/
static float ccpu = 0.9512294245; /* exp(-1/20) */
/*
* Software clock interrupt.
* This routine runs at lower priority than device interrupts.
*
* Processes have their (32-bit) priority depend on their owner's ``normalised
* usage'' of resources. However, V9's low-level scheduler only has 127 priorities,
* (in fact, only 32, so that someone could use an 'ffs' instruction),
* so we normalise this ``sharepri'' into the 7-bit ``usrpri''. Note that
* the 'ffs' hack means that (after PUSER) there are only 20 real priorities
* for processes to run in, and that defined kernel priorities should differ
* by more than 4 to be meaningful.
*/
/*ARGSUSED*/
softclock(pc, ps)
caddr_t pc;
{
register struct callout *p1;
register struct proc *pp;
register int a, s;
extern char *panicstr;
/*
* Perform callouts (but not after panics)
*/
if (panicstr == 0) {
for (;;) {
register caddr_t arg;
register int (*func)();
s = spl7();
if ((p1 = calltodo.c_next) == 0 || p1->c_time > 0) {
splx(s);
break;
}
calltodo.c_next = p1->c_next;
arg = p1->c_arg;
func = p1->c_func;
p1->c_next = callfree;
callfree = p1;
(void) splx(s);
(*func)(arg);
}
}
/*
* If idling and processes are waiting to swap in,
* check on them.
*/
if (noproc && runin) {
runin = 0;
wakeup((caddr_t)&runin);
}
if (lbolt % (HZ/10) == 0) {
runrun++;
aston();
}
/*
* Lightning bolt every second:
* sleep timeouts
* process priority recomputation
* process %cpu averaging
* p_time and p_slptime for the swapper
* kick swapper if processes want in
*/
if (lbolt >= HZ) {
/* meaningless on VAX; meant for hardclock */
if (BASEPRI(ps))
return;
time += lbolt / HZ;
lbolt %= HZ;
wakeup((caddr_t)&lbolt);
for (pp = proc; pp < procNPROC; pp++)
if ((a=pp->p_stat)!=0 && a!=SZOMB) {
if (pp->p_time != 127)
pp->p_time++;
if (pp->p_clktim && --pp->p_clktim == 0)
psignal(pp, SIGALRM);
if (pp->p_tsleep && --pp->p_tsleep == 0) {
s = spl6();
switch (pp->p_stat) { /* != a if interrupted */
case SSLEEP:
setrun(pp);
break;
case SSTOP:
unsleep(pp);
break;
}
pp->p_flag |= STIMO;
splx(s);
}
if (a==SSLEEP || a==SSTOP)
if (pp->p_slptime != 127)
pp->p_slptime++;
/*
* update silly numbers for ps to print
*/
if (pp->p_flag&SLOAD)
pp->p_pctcpu = ccpu*pp->p_pctcpu +
(1.0 - ccpu) * (pp->p_cpticks/(float)HZ);
pp->p_cpticks = 0;
/*
* Update p_cpu for scheduling
*/
a = cpuave(pp->p_cpu, 2*avenrun[0]);
if (a < 0)
a = 0;
if (a > 255)
a = 255;
pp->p_cpu = a;
(void) setpri(pp);
/*
* p_usrpri == new process priority
* now fix p_pri to match, carefully
*/
s = spl6();
if (pp->p_pri >= PUSER && pp->p_pri != pp->p_usrpri) {
if ((pp != u.u_procp || noproc) && pp->p_stat == SRUN &&
(pp->p_flag & SLOAD)) {
remrq(pp);
pp->p_pri = pp->p_usrpri;
setrq(pp);
} else
pp->p_pri = pp->p_usrpri;
}
splx(s);
}
if (runin!=0) {
runin = 0;
wakeup((caddr_t)&runin);
}
}
if (noproc)
return;
pp = u.u_procp;
/*
* If trapped user-mode, give it a profiling tick.
*/
if (USERMODE(ps) && u.u_prof.pr_scale) {
pp->p_flag |= SOWEUPC;
aston();
}
/*
* random statistics, apparently computed just so
* that programs like ps can print them? not a good reason
*/
s = pp->p_rssize;
u.u_vm.vm_idsrss += s;
if (pp->p_textp) {
a = pp->p_textp->x_rssize;
s += a;
u.u_vm.vm_ixrss += a;
}
if (s > u.u_vm.vm_maxrss)
u.u_vm.vm_maxrss = s;
/*
* cpu time limit
*/
if ((u.u_vm.vm_utime+u.u_vm.vm_stime+1)/HZ > u.u_limit[LIM_CPU]) {
psignal(pp, SIGXCPU);
if (u.u_limit[LIM_CPU] < INFINITY - 5)
u.u_limit[LIM_CPU] += 5;
}
}
/*
* Timeout is called to arrange that
* fun(arg) is called in tim/HZ seconds.
* An entry is linked into the callout
* structure. The time in each structure
* entry is the number of HZ's more
* than the previous entry.
* In this way, decrementing the
* first entry has the effect of
* updating all entries.
*
* The panic is there because there is nothing
* intelligent to be done if an entry won't fit.
*/
timeout(fun, arg, tim)
int (*fun)();
caddr_t arg;
{
register struct callout *p1, *p2, *pnew;
register int t;
int s;
t = tim;
s = spl7();
pnew = callfree;
if (pnew == NULL)
panic("timeout table overflow");
callfree = pnew->c_next;
pnew->c_arg = arg;
pnew->c_func = fun;
for (p1 = &calltodo; (p2 = p1->c_next) && p2->c_time < t; p1 = p2)
t -= p2->c_time;
p1->c_next = pnew;
pnew->c_next = p2;
pnew->c_time = t;
if (p2)
p2->c_time -= t;
splx(s);
}
/*
* Delay goes to sleep on a unique address for a
* guaranteed minimum period ticks/HZ secs.
* Because a timeout() can't be cancelled, the process
* will be unkillable while asleep. Beware of giving
* delay() an argument of more than a few hundred.
*
* used by one device driver and by sys nap.
* do we really need it?
*/
delay(ticks)
{
register int x;
extern wakeup();
if (ticks<=0)
return;
x = spl7();
timeout(wakeup, (caddr_t)u.u_procp+1, ticks);
sleep((caddr_t)u.u_procp+1, PZERO-1);
splx(x);
}
/*
* init callouts
* called from main
*/
callinit()
{
register int i;
callfree = callout;
for (i = 1; i < calloutcnt; i++)
callout[i-1].c_next = &callout[i];
}
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.