Files
retrobsd/sys/kernel/vm_sched.c
Serge Vakulenko 5cb608d7e1 Rename other disk drivers which needed rdisk.
Delete device names from all the drivers.
Move device inslude files from include/sys to include/machine directory.
Only include files which have something useful for user layer
(like special ioctls codes) should be placed into sys.
2015-09-26 23:00:13 -07:00

262 lines
7.1 KiB
C

/*
* Copyright (c) 1986 Regents of the University of California.
* All rights reserved. The Berkeley software License Agreement
* specifies the terms and conditions for redistribution.
*/
#include <sys/param.h>
#include <sys/user.h>
#include <sys/proc.h>
#include <sys/vm.h>
#include <sys/kernel.h>
#include <sys/systm.h>
#include <machine/debug.h>
#define MINFINITY -32767 /* minus infinity */
int maxslp = MAXSLP;
char runin; /* scheduling flag */
char runout; /* scheduling flag */
/*
* The main loop of the scheduling (swapping) process.
* The basic idea is:
* see if anyone wants to be swapped in
* swap out processes until there is room
* swap him in
* repeat
* The runout flag is set whenever someone is swapped out. Sched sleeps on
* it awaiting work. Sched sleeps on runin whenever it cannot find enough
* core (by swapping out or otherwise) to fit the selected swapped process.
* It is awakened when the core situation changes and in any case once per
* second.
*/
void
sched()
{
register struct proc *rp;
struct proc *swapped_out = 0, *in_core = 0;
register int out_time, rptime;
for (;;) {
/* Perform swap-out/swap-in action. */
spl0();
if (in_core)
swapout (in_core, X_FREECORE, X_OLDSIZE, X_OLDSIZE);
if (swapped_out)
swapin (swapped_out);
splhigh();
in_core = 0;
swapped_out = 0;
/* Find user to swap in; of users ready,
* select one out longest. */
out_time = -20000;
for (rp = allproc; rp; rp = rp->p_nxt) {
if (rp->p_stat != SRUN || (rp->p_flag & SLOAD))
continue;
rptime = rp->p_time - rp->p_nice * 8;
/*
* Always bring in parents ending a vfork,
* to avoid deadlock
*/
if (rptime > out_time || (rp->p_flag & SVFPRNT)) {
swapped_out = rp;
out_time = rptime;
if (rp->p_flag & SVFPRNT)
break;
}
}
/* If there is no one there, wait. */
if (! swapped_out) {
++runout;
//SETVAL(0);
sleep ((caddr_t) &runout, PSWP);
continue;
}
//SETVAL(swapped_out->p_pid);
/*
* Look around for somebody to swap out.
* There may be only one non-system loaded process.
*/
for (rp = allproc; rp != NULL; rp = rp->p_nxt) {
if (rp->p_stat != SZOMB &&
(rp->p_flag & (SSYS | SLOAD)) == SLOAD) {
in_core = rp;
break;
}
}
if (! in_core) {
/* In-core memory is empty. */
continue;
}
/*
* Swap found user out if sleeping interruptibly, or if he has spent at
* least 1 second in core and the swapped-out process has spent at
* least 2 seconds out. Otherwise wait a bit and try again.
*/
if (! (in_core->p_flag & SLOCK) &&
(in_core->p_stat == SSTOP ||
(in_core->p_stat == SSLEEP && (in_core->p_flag & P_SINTR)) ||
((in_core->p_stat == SRUN || in_core->p_stat == SSLEEP) &&
out_time >= 2 &&
in_core->p_time + in_core->p_nice >= 1)))
{
/* Swap out in-core process. */
in_core->p_flag &= ~SLOAD;
if (in_core->p_stat == SRUN)
remrq (in_core);
} else {
/* Nothing to swap in/out. */
in_core = 0;
swapped_out = 0;
++runin;
sleep ((caddr_t) &runin, PSWP);
}
}
}
/*
* Count up various things once a second
*/
void
vmmeter()
{
#ifdef UCB_METER
register u_short *cp, *rp;
register long *sp;
ave(avefree, freemem, 5);
ave(avefree30, freemem, 30);
cp = &cnt.v_first;
rp = &rate.v_first;
sp = &sum.v_first;
while (cp <= &cnt.v_last) {
ave(*rp, *cp, 5);
*sp += *cp;
*cp = 0;
rp++, cp++, sp++;
}
#endif
if (time.tv_sec % 5 == 0) {
vmtotal();
#ifdef UCB_METER
rate.v_swpin = cnt.v_swpin;
sum.v_swpin += cnt.v_swpin;
cnt.v_swpin = 0;
rate.v_swpout = cnt.v_swpout;
sum.v_swpout += cnt.v_swpout;
cnt.v_swpout = 0;
#endif
}
}
/*
* Compute Tenex style load average. This code is adapted from similar code
* by Bill Joy on the Vax system. The major change is that we avoid floating
* point since not all pdp-11's have it. This makes the code quite hard to
* read - it was derived with some algebra.
*
* "floating point" numbers here are stored in a 16 bit short, with 8 bits on
* each side of the decimal point. Some partial products will have 16 bits to
* the right.
*/
static void
loadav (avg, n)
register short *avg;
register int n;
{
register int i;
static const long cexp[3] = {
0353, /* 256 * exp(-1/12) */
0373, /* 256 * exp(-1/60) */
0376, /* 256 * exp(-1/180) */
};
for (i = 0; i < 3; i++)
avg[i] = (cexp[i] * (avg[i]-(n<<8)) + (((long)n)<<16)) >> 8;
}
void
vmtotal()
{
register struct proc *p;
register int nrun = 0;
#ifdef UCB_METER
total.t_vmtxt = 0;
total.t_avmtxt = 0;
total.t_rmtxt = 0;
total.t_armtxt = 0;
total.t_vm = 0;
total.t_avm = 0;
total.t_rm = 0;
total.t_arm = 0;
total.t_rq = 0;
total.t_dw = 0;
total.t_sl = 0;
total.t_sw = 0;
#endif
for (p = allproc; p != NULL; p = p->p_nxt) {
if (p->p_flag & SSYS)
continue;
if (p->p_stat) {
#ifdef UCB_METER
if (p->p_stat != SZOMB) {
total.t_vm += p->p_dsize + p->p_ssize + USIZE;
if (p->p_flag & SLOAD)
total.t_rm += p->p_dsize + p->p_ssize
+ USIZE;
}
#endif
switch (p->p_stat) {
case SSLEEP:
case SSTOP:
if (!(p->p_flag & P_SINTR) && p->p_stat == SSLEEP)
nrun++;
#ifdef UCB_METER
if (p->p_flag & SLOAD) {
if (!(p->p_flag & P_SINTR))
total.t_dw++;
else if (p->p_slptime < maxslp)
total.t_sl++;
} else if (p->p_slptime < maxslp)
total.t_sw++;
if (p->p_slptime < maxslp)
goto active;
#endif
break;
case SRUN:
case SIDL:
nrun++;
#ifdef UCB_METER
if (p->p_flag & SLOAD)
total.t_rq++;
else
total.t_sw++;
active:
total.t_avm += p->p_dsize + p->p_ssize + USIZE;
if (p->p_flag & SLOAD)
total.t_arm += p->p_dsize + p->p_ssize
+ USIZE;
#endif
break;
}
}
}
#ifdef UCB_METER
total.t_vm += total.t_vmtxt;
total.t_avm += total.t_avmtxt;
total.t_rm += total.t_rmtxt;
total.t_arm += total.t_armtxt;
total.t_free = avefree;
#endif
loadav (avenrun, nrun);
}