xref: /csrg-svn/sys/kern/kern_synch.c (revision 22722)
1*22722Skarels /*	kern_synch.c	6.9	85/06/07	*/
233Sbill 
39756Ssam #include "../machine/pte.h"
49756Ssam 
517093Sbloom #include "param.h"
617093Sbloom #include "systm.h"
717093Sbloom #include "dir.h"
817093Sbloom #include "user.h"
917093Sbloom #include "proc.h"
1017093Sbloom #include "file.h"
1117093Sbloom #include "inode.h"
1217093Sbloom #include "vm.h"
1317093Sbloom #include "kernel.h"
1417093Sbloom #include "buf.h"
159756Ssam 
169756Ssam #ifdef vax
178445Sroot #include "../vax/mtpr.h"	/* XXX */
189756Ssam #endif
198102Sroot /*
208102Sroot  * Force switch among equal priority processes every 100ms.
218102Sroot  */
228102Sroot roundrobin()
238102Sroot {
248102Sroot 
258102Sroot 	runrun++;
268102Sroot 	aston();
278624Sroot 	timeout(roundrobin, (caddr_t)0, hz / 10);
288102Sroot }
298102Sroot 
3017541Skarels /* fraction for digital decay to forget 90% of usage in 5*loadav sec */
3117541Skarels #define	filter(loadav) ((2 * (loadav)) / (2 * (loadav) + 1))
3217541Skarels 
338102Sroot double	ccpu = 0.95122942450071400909;		/* exp(-1/20) */
348102Sroot 
358102Sroot /*
368102Sroot  * Recompute process priorities, once a second
378102Sroot  */
388102Sroot schedcpu()
398102Sroot {
4016795Skarels 	register double ccpu1 = (1.0 - ccpu) / (double)hz;
418102Sroot 	register struct proc *p;
428102Sroot 	register int s, a;
4317541Skarels 	float scale = filter(avenrun[0]);
448102Sroot 
458102Sroot 	wakeup((caddr_t)&lbolt);
4616532Skarels 	for (p = allproc; p != NULL; p = p->p_nxt) {
478102Sroot 		if (p->p_time != 127)
488102Sroot 			p->p_time++;
498102Sroot 		if (p->p_stat==SSLEEP || p->p_stat==SSTOP)
508102Sroot 			if (p->p_slptime != 127)
518102Sroot 				p->p_slptime++;
5217541Skarels 		/*
5317541Skarels 		 * If the process has slept the entire second,
5417541Skarels 		 * stop recalculating its priority until it wakes up.
5517541Skarels 		 */
5617541Skarels 		if (p->p_slptime > 1) {
5717541Skarels 			p->p_pctcpu *= ccpu;
5817541Skarels 			continue;
5917541Skarels 		}
6017541Skarels 		/*
6117541Skarels 		 * p_pctcpu is only for ps.
6217541Skarels 		 */
6317541Skarels 		p->p_pctcpu = ccpu * p->p_pctcpu + ccpu1 * p->p_cpticks;
648102Sroot 		p->p_cpticks = 0;
6517541Skarels 		a = (int) (scale * (p->p_cpu & 0377)) + p->p_nice;
668102Sroot 		if (a < 0)
678102Sroot 			a = 0;
688102Sroot 		if (a > 255)
698102Sroot 			a = 255;
708102Sroot 		p->p_cpu = a;
718102Sroot 		(void) setpri(p);
7217541Skarels 		s = splhigh();	/* prevent state changes */
738102Sroot 		if (p->p_pri >= PUSER) {
7416795Skarels #define	PPQ	(128 / NQS)
758102Sroot 			if ((p != u.u_procp || noproc) &&
768102Sroot 			    p->p_stat == SRUN &&
778102Sroot 			    (p->p_flag & SLOAD) &&
7816795Skarels 			    (p->p_pri / PPQ) != (p->p_usrpri / PPQ)) {
798102Sroot 				remrq(p);
808102Sroot 				p->p_pri = p->p_usrpri;
818102Sroot 				setrq(p);
828102Sroot 			} else
838102Sroot 				p->p_pri = p->p_usrpri;
848102Sroot 		}
858102Sroot 		splx(s);
868102Sroot 	}
878102Sroot 	vmmeter();
888102Sroot 	if (runin!=0) {
898102Sroot 		runin = 0;
908102Sroot 		wakeup((caddr_t)&runin);
918102Sroot 	}
928102Sroot 	if (bclnlist != NULL)
938102Sroot 		wakeup((caddr_t)&proc[2]);
948624Sroot 	timeout(schedcpu, (caddr_t)0, hz);
958102Sroot }
968102Sroot 
9717541Skarels /*
9817541Skarels  * Recalculate the priority of a process after it has slept for a while.
9917541Skarels  */
10017541Skarels updatepri(p)
10117541Skarels 	register struct proc *p;
10217541Skarels {
10317541Skarels 	register int a = p->p_cpu & 0377;
10417541Skarels 	float scale = filter(avenrun[0]);
10517541Skarels 
10617541Skarels 	p->p_slptime--;		/* the first time was done in schedcpu */
10717541Skarels 	while (a && --p->p_slptime)
10817541Skarels 		a = (int) (scale * a) /* + p->p_nice */;
10917541Skarels 	if (a < 0)
11017541Skarels 		a = 0;
11117541Skarels 	if (a > 255)
11217541Skarels 		a = 255;
11317541Skarels 	p->p_cpu = a;
11417541Skarels 	(void) setpri(p);
11517541Skarels }
11617541Skarels 
11733Sbill #define SQSIZE 0100	/* Must be power of 2 */
11833Sbill #define HASH(x)	(( (int) x >> 5) & (SQSIZE-1))
11921099Smckusick struct slpque {
12021099Smckusick 	struct proc *sq_head;
12121099Smckusick 	struct proc **sq_tailp;
12221099Smckusick } slpque[SQSIZE];
12333Sbill 
12433Sbill /*
12533Sbill  * Give up the processor till a wakeup occurs
12633Sbill  * on chan, at which time the process
12733Sbill  * enters the scheduling queue at priority pri.
12833Sbill  * The most important effect of pri is that when
12933Sbill  * pri<=PZERO a signal cannot disturb the sleep;
13033Sbill  * if pri>PZERO signals will be processed.
13133Sbill  * Callers of this routine must be prepared for
13233Sbill  * premature return, and check that the reason for
13333Sbill  * sleeping has gone away.
13433Sbill  */
13533Sbill sleep(chan, pri)
1368033Sroot 	caddr_t chan;
1378033Sroot 	int pri;
13833Sbill {
13921099Smckusick 	register struct proc *rp;
14021099Smckusick 	register struct slpque *qp;
141207Sbill 	register s;
14233Sbill 
14333Sbill 	rp = u.u_procp;
14417541Skarels 	s = splhigh();
14518363Skarels 	if (panicstr) {
14618363Skarels 		/*
14718363Skarels 		 * After a panic, just give interrupts a chance,
14818363Skarels 		 * then just return; don't run any other procs
14918363Skarels 		 * or panic below, in case this is the idle process
15018363Skarels 		 * and already asleep.
15118363Skarels 		 * The splnet should be spl0 if the network was being used
15218363Skarels 		 * by the filesystem, but for now avoid network interrupts
15318363Skarels 		 * that might cause another panic.
15418363Skarels 		 */
15518363Skarels 		(void) splnet();
15618363Skarels 		splx(s);
15718363Skarels 		return;
15818363Skarels 	}
15918363Skarels 	if (chan==0 || rp->p_stat != SRUN || rp->p_rlink)
16033Sbill 		panic("sleep");
16133Sbill 	rp->p_wchan = chan;
16233Sbill 	rp->p_slptime = 0;
16333Sbill 	rp->p_pri = pri;
16421099Smckusick 	qp = &slpque[HASH(chan)];
16521099Smckusick 	if (qp->sq_head == 0)
16621099Smckusick 		qp->sq_head = rp;
16721099Smckusick 	else
16821099Smckusick 		*qp->sq_tailp = rp;
16921099Smckusick 	*(qp->sq_tailp = &rp->p_link) = 0;
1704826Swnj 	if (pri > PZERO) {
17121763Skarels 		/*
17221763Skarels 		 * If we stop in issig(), wakeup may already have happened
17321763Skarels 		 * when we return (rp->p_wchan will then be 0).
17421763Skarels 		 */
1754826Swnj 		if (ISSIG(rp)) {
176187Sbill 			if (rp->p_wchan)
177187Sbill 				unsleep(rp);
17833Sbill 			rp->p_stat = SRUN;
179131Sbill 			(void) spl0();
18033Sbill 			goto psig;
18133Sbill 		}
182187Sbill 		if (rp->p_wchan == 0)
183187Sbill 			goto out;
184187Sbill 		rp->p_stat = SSLEEP;
185131Sbill 		(void) spl0();
1868033Sroot 		u.u_ru.ru_nvcsw++;
18733Sbill 		swtch();
1884826Swnj 		if (ISSIG(rp))
18933Sbill 			goto psig;
19033Sbill 	} else {
191207Sbill 		rp->p_stat = SSLEEP;
192131Sbill 		(void) spl0();
1938033Sroot 		u.u_ru.ru_nvcsw++;
19433Sbill 		swtch();
19533Sbill 	}
19616795Skarels 	curpri = rp->p_usrpri;
197187Sbill out:
19833Sbill 	splx(s);
19933Sbill 	return;
20033Sbill 
20133Sbill 	/*
20233Sbill 	 * If priority was low (>PZERO) and
2034826Swnj 	 * there has been a signal, execute non-local goto through
2048113Sroot 	 * u.u_qsave, aborting the system call in progress (see trap.c)
20533Sbill 	 */
20633Sbill psig:
2078113Sroot 	longjmp(&u.u_qsave);
20833Sbill 	/*NOTREACHED*/
20933Sbill }
21033Sbill 
21133Sbill /*
212181Sbill  * Remove a process from its wait queue
213181Sbill  */
214181Sbill unsleep(p)
2154826Swnj 	register struct proc *p;
216181Sbill {
21721099Smckusick 	register struct slpque *qp;
218181Sbill 	register struct proc **hp;
21921099Smckusick 	int s;
220181Sbill 
22117541Skarels 	s = splhigh();
222181Sbill 	if (p->p_wchan) {
22321099Smckusick 		hp = &(qp = &slpque[HASH(p->p_wchan)])->sq_head;
224181Sbill 		while (*hp != p)
225181Sbill 			hp = &(*hp)->p_link;
226181Sbill 		*hp = p->p_link;
22721099Smckusick 		if (qp->sq_tailp == &p->p_link)
22821099Smckusick 			qp->sq_tailp = hp;
229181Sbill 		p->p_wchan = 0;
230181Sbill 	}
231181Sbill 	splx(s);
232181Sbill }
233181Sbill 
234181Sbill /*
23533Sbill  * Wake up all processes sleeping on chan.
23633Sbill  */
23733Sbill wakeup(chan)
2384826Swnj 	register caddr_t chan;
23933Sbill {
24021099Smckusick 	register struct slpque *qp;
24121099Smckusick 	register struct proc *p, **q;
24233Sbill 	int s;
24333Sbill 
24417541Skarels 	s = splhigh();
24521099Smckusick 	qp = &slpque[HASH(chan)];
24633Sbill restart:
24721099Smckusick 	for (q = &qp->sq_head; p = *q; ) {
248181Sbill 		if (p->p_rlink || p->p_stat != SSLEEP && p->p_stat != SSTOP)
24933Sbill 			panic("wakeup");
250207Sbill 		if (p->p_wchan==chan) {
25133Sbill 			p->p_wchan = 0;
252187Sbill 			*q = p->p_link;
25321099Smckusick 			if (qp->sq_tailp == &p->p_link)
25421099Smckusick 				qp->sq_tailp = q;
255181Sbill 			if (p->p_stat == SSLEEP) {
256181Sbill 				/* OPTIMIZED INLINE EXPANSION OF setrun(p) */
25721763Skarels 				if (p->p_slptime > 1)
25821763Skarels 					updatepri(p);
259*22722Skarels 				p->p_slptime = 0;
260181Sbill 				p->p_stat = SRUN;
2612702Swnj 				if (p->p_flag & SLOAD)
262181Sbill 					setrq(p);
26316795Skarels 				/*
26416795Skarels 				 * Since curpri is a usrpri,
26516795Skarels 				 * p->p_pri is always better than curpri.
26616795Skarels 				 */
26716795Skarels 				runrun++;
26816795Skarels 				aston();
2693545Swnj 				if ((p->p_flag&SLOAD) == 0) {
2703545Swnj 					if (runout != 0) {
2713545Swnj 						runout = 0;
2723545Swnj 						wakeup((caddr_t)&runout);
2733545Swnj 					}
2743545Swnj 					wantin++;
275181Sbill 				}
276181Sbill 				/* END INLINE EXPANSION */
277187Sbill 				goto restart;
27833Sbill 			}
279*22722Skarels 			p->p_slptime = 0;
280187Sbill 		} else
281187Sbill 			q = &p->p_link;
28233Sbill 	}
28333Sbill 	splx(s);
28433Sbill }
28533Sbill 
28633Sbill /*
28733Sbill  * Initialize the (doubly-linked) run queues
28833Sbill  * to be empty.
28933Sbill  */
29033Sbill rqinit()
29133Sbill {
29233Sbill 	register int i;
29333Sbill 
29433Sbill 	for (i = 0; i < NQS; i++)
29533Sbill 		qs[i].ph_link = qs[i].ph_rlink = (struct proc *)&qs[i];
29633Sbill }
29733Sbill 
29833Sbill /*
29933Sbill  * Set the process running;
30033Sbill  * arrange for it to be swapped in if necessary.
30133Sbill  */
30233Sbill setrun(p)
3034826Swnj 	register struct proc *p;
30433Sbill {
3054826Swnj 	register int s;
30633Sbill 
30717541Skarels 	s = splhigh();
30833Sbill 	switch (p->p_stat) {
30933Sbill 
31033Sbill 	case 0:
31133Sbill 	case SWAIT:
31233Sbill 	case SRUN:
31333Sbill 	case SZOMB:
31433Sbill 	default:
31533Sbill 		panic("setrun");
31633Sbill 
317207Sbill 	case SSTOP:
31833Sbill 	case SSLEEP:
319181Sbill 		unsleep(p);		/* e.g. when sending signals */
32033Sbill 		break;
32133Sbill 
32233Sbill 	case SIDL:
32333Sbill 		break;
32433Sbill 	}
32517541Skarels 	if (p->p_slptime > 1)
32617541Skarels 		updatepri(p);
32733Sbill 	p->p_stat = SRUN;
32833Sbill 	if (p->p_flag & SLOAD)
32933Sbill 		setrq(p);
33033Sbill 	splx(s);
3314826Swnj 	if (p->p_pri < curpri) {
33233Sbill 		runrun++;
3332443Swnj 		aston();
3342443Swnj 	}
3353545Swnj 	if ((p->p_flag&SLOAD) == 0) {
3364826Swnj 		if (runout != 0) {
3373545Swnj 			runout = 0;
3383545Swnj 			wakeup((caddr_t)&runout);
3393545Swnj 		}
3403545Swnj 		wantin++;
34133Sbill 	}
34233Sbill }
34333Sbill 
34433Sbill /*
34533Sbill  * Set user priority.
34633Sbill  * The rescheduling flag (runrun)
34733Sbill  * is set if the priority is better
34833Sbill  * than the currently running process.
34933Sbill  */
35033Sbill setpri(pp)
3514826Swnj 	register struct proc *pp;
35233Sbill {
3534826Swnj 	register int p;
35433Sbill 
3553875Swnj 	p = (pp->p_cpu & 0377)/4;
35617541Skarels 	p += PUSER + 2 * pp->p_nice;
3573530Swnj 	if (pp->p_rssize > pp->p_maxrss && freemem < desfree)
3583530Swnj 		p += 2*4;	/* effectively, nice(4) */
3594826Swnj 	if (p > 127)
36033Sbill 		p = 127;
3614826Swnj 	if (p < curpri) {
36233Sbill 		runrun++;
3632453Swnj 		aston();
3642453Swnj 	}
36533Sbill 	pp->p_usrpri = p;
3664826Swnj 	return (p);
36733Sbill }
368