xref: /csrg-svn/sys/kern/kern_synch.c (revision 29096)
123376Smckusick /*
2*29096Smckusick  * Copyright (c) 1982, 1986 Regents of the University of California.
323376Smckusick  * All rights reserved.  The Berkeley software License Agreement
423376Smckusick  * specifies the terms and conditions for redistribution.
523376Smckusick  *
6*29096Smckusick  *	@(#)kern_synch.c	7.1 (Berkeley) 06/05/86
723376Smckusick  */
833Sbill 
99756Ssam #include "../machine/pte.h"
109756Ssam 
1117093Sbloom #include "param.h"
1217093Sbloom #include "systm.h"
1317093Sbloom #include "dir.h"
1417093Sbloom #include "user.h"
1517093Sbloom #include "proc.h"
1617093Sbloom #include "file.h"
1717093Sbloom #include "inode.h"
1817093Sbloom #include "vm.h"
1917093Sbloom #include "kernel.h"
2017093Sbloom #include "buf.h"
219756Ssam 
229756Ssam #ifdef vax
238445Sroot #include "../vax/mtpr.h"	/* XXX */
249756Ssam #endif
258102Sroot /*
268102Sroot  * Force switch among equal priority processes every 100ms.
278102Sroot  */
288102Sroot roundrobin()
298102Sroot {
308102Sroot 
318102Sroot 	runrun++;
328102Sroot 	aston();
338624Sroot 	timeout(roundrobin, (caddr_t)0, hz / 10);
348102Sroot }
358102Sroot 
3617541Skarels /* fraction for digital decay to forget 90% of usage in 5*loadav sec */
3717541Skarels #define	filter(loadav) ((2 * (loadav)) / (2 * (loadav) + 1))
3817541Skarels 
398102Sroot double	ccpu = 0.95122942450071400909;		/* exp(-1/20) */
408102Sroot 
418102Sroot /*
428102Sroot  * Recompute process priorities, once a second
438102Sroot  */
448102Sroot schedcpu()
458102Sroot {
4616795Skarels 	register double ccpu1 = (1.0 - ccpu) / (double)hz;
478102Sroot 	register struct proc *p;
488102Sroot 	register int s, a;
4917541Skarels 	float scale = filter(avenrun[0]);
508102Sroot 
518102Sroot 	wakeup((caddr_t)&lbolt);
5216532Skarels 	for (p = allproc; p != NULL; p = p->p_nxt) {
538102Sroot 		if (p->p_time != 127)
548102Sroot 			p->p_time++;
558102Sroot 		if (p->p_stat==SSLEEP || p->p_stat==SSTOP)
568102Sroot 			if (p->p_slptime != 127)
578102Sroot 				p->p_slptime++;
5817541Skarels 		/*
5917541Skarels 		 * If the process has slept the entire second,
6017541Skarels 		 * stop recalculating its priority until it wakes up.
6117541Skarels 		 */
6217541Skarels 		if (p->p_slptime > 1) {
6317541Skarels 			p->p_pctcpu *= ccpu;
6417541Skarels 			continue;
6517541Skarels 		}
6617541Skarels 		/*
6717541Skarels 		 * p_pctcpu is only for ps.
6817541Skarels 		 */
6917541Skarels 		p->p_pctcpu = ccpu * p->p_pctcpu + ccpu1 * p->p_cpticks;
708102Sroot 		p->p_cpticks = 0;
7117541Skarels 		a = (int) (scale * (p->p_cpu & 0377)) + p->p_nice;
728102Sroot 		if (a < 0)
738102Sroot 			a = 0;
748102Sroot 		if (a > 255)
758102Sroot 			a = 255;
768102Sroot 		p->p_cpu = a;
778102Sroot 		(void) setpri(p);
7817541Skarels 		s = splhigh();	/* prevent state changes */
798102Sroot 		if (p->p_pri >= PUSER) {
8016795Skarels #define	PPQ	(128 / NQS)
818102Sroot 			if ((p != u.u_procp || noproc) &&
828102Sroot 			    p->p_stat == SRUN &&
838102Sroot 			    (p->p_flag & SLOAD) &&
8416795Skarels 			    (p->p_pri / PPQ) != (p->p_usrpri / PPQ)) {
858102Sroot 				remrq(p);
868102Sroot 				p->p_pri = p->p_usrpri;
878102Sroot 				setrq(p);
888102Sroot 			} else
898102Sroot 				p->p_pri = p->p_usrpri;
908102Sroot 		}
918102Sroot 		splx(s);
928102Sroot 	}
938102Sroot 	vmmeter();
948102Sroot 	if (runin!=0) {
958102Sroot 		runin = 0;
968102Sroot 		wakeup((caddr_t)&runin);
978102Sroot 	}
988102Sroot 	if (bclnlist != NULL)
998102Sroot 		wakeup((caddr_t)&proc[2]);
1008624Sroot 	timeout(schedcpu, (caddr_t)0, hz);
1018102Sroot }
1028102Sroot 
10317541Skarels /*
10417541Skarels  * Recalculate the priority of a process after it has slept for a while.
10517541Skarels  */
10617541Skarels updatepri(p)
10717541Skarels 	register struct proc *p;
10817541Skarels {
10917541Skarels 	register int a = p->p_cpu & 0377;
11017541Skarels 	float scale = filter(avenrun[0]);
11117541Skarels 
11217541Skarels 	p->p_slptime--;		/* the first time was done in schedcpu */
11317541Skarels 	while (a && --p->p_slptime)
11417541Skarels 		a = (int) (scale * a) /* + p->p_nice */;
11517541Skarels 	if (a < 0)
11617541Skarels 		a = 0;
11717541Skarels 	if (a > 255)
11817541Skarels 		a = 255;
11917541Skarels 	p->p_cpu = a;
12017541Skarels 	(void) setpri(p);
12117541Skarels }
12217541Skarels 
12333Sbill #define SQSIZE 0100	/* Must be power of 2 */
12433Sbill #define HASH(x)	(( (int) x >> 5) & (SQSIZE-1))
12521099Smckusick struct slpque {
12621099Smckusick 	struct proc *sq_head;
12721099Smckusick 	struct proc **sq_tailp;
12821099Smckusick } slpque[SQSIZE];
12933Sbill 
13033Sbill /*
13133Sbill  * Give up the processor till a wakeup occurs
13233Sbill  * on chan, at which time the process
13333Sbill  * enters the scheduling queue at priority pri.
13433Sbill  * The most important effect of pri is that when
13533Sbill  * pri<=PZERO a signal cannot disturb the sleep;
13633Sbill  * if pri>PZERO signals will be processed.
13733Sbill  * Callers of this routine must be prepared for
13833Sbill  * premature return, and check that the reason for
13933Sbill  * sleeping has gone away.
14033Sbill  */
14133Sbill sleep(chan, pri)
1428033Sroot 	caddr_t chan;
1438033Sroot 	int pri;
14433Sbill {
14521099Smckusick 	register struct proc *rp;
14621099Smckusick 	register struct slpque *qp;
147207Sbill 	register s;
14833Sbill 
14933Sbill 	rp = u.u_procp;
15017541Skarels 	s = splhigh();
15118363Skarels 	if (panicstr) {
15218363Skarels 		/*
15318363Skarels 		 * After a panic, just give interrupts a chance,
15418363Skarels 		 * then just return; don't run any other procs
15518363Skarels 		 * or panic below, in case this is the idle process
15618363Skarels 		 * and already asleep.
15718363Skarels 		 * The splnet should be spl0 if the network was being used
15818363Skarels 		 * by the filesystem, but for now avoid network interrupts
15918363Skarels 		 * that might cause another panic.
16018363Skarels 		 */
16118363Skarels 		(void) splnet();
16218363Skarels 		splx(s);
16318363Skarels 		return;
16418363Skarels 	}
16518363Skarels 	if (chan==0 || rp->p_stat != SRUN || rp->p_rlink)
16633Sbill 		panic("sleep");
16733Sbill 	rp->p_wchan = chan;
16833Sbill 	rp->p_slptime = 0;
16933Sbill 	rp->p_pri = pri;
17021099Smckusick 	qp = &slpque[HASH(chan)];
17121099Smckusick 	if (qp->sq_head == 0)
17221099Smckusick 		qp->sq_head = rp;
17321099Smckusick 	else
17421099Smckusick 		*qp->sq_tailp = rp;
17521099Smckusick 	*(qp->sq_tailp = &rp->p_link) = 0;
1764826Swnj 	if (pri > PZERO) {
17721763Skarels 		/*
17821763Skarels 		 * If we stop in issig(), wakeup may already have happened
17921763Skarels 		 * when we return (rp->p_wchan will then be 0).
18021763Skarels 		 */
1814826Swnj 		if (ISSIG(rp)) {
182187Sbill 			if (rp->p_wchan)
183187Sbill 				unsleep(rp);
18433Sbill 			rp->p_stat = SRUN;
185131Sbill 			(void) spl0();
18633Sbill 			goto psig;
18733Sbill 		}
188187Sbill 		if (rp->p_wchan == 0)
189187Sbill 			goto out;
190187Sbill 		rp->p_stat = SSLEEP;
191131Sbill 		(void) spl0();
1928033Sroot 		u.u_ru.ru_nvcsw++;
19333Sbill 		swtch();
1944826Swnj 		if (ISSIG(rp))
19533Sbill 			goto psig;
19633Sbill 	} else {
197207Sbill 		rp->p_stat = SSLEEP;
198131Sbill 		(void) spl0();
1998033Sroot 		u.u_ru.ru_nvcsw++;
20033Sbill 		swtch();
20133Sbill 	}
20216795Skarels 	curpri = rp->p_usrpri;
203187Sbill out:
20433Sbill 	splx(s);
20533Sbill 	return;
20633Sbill 
20733Sbill 	/*
20833Sbill 	 * If priority was low (>PZERO) and
2094826Swnj 	 * there has been a signal, execute non-local goto through
2108113Sroot 	 * u.u_qsave, aborting the system call in progress (see trap.c)
21133Sbill 	 */
21233Sbill psig:
2138113Sroot 	longjmp(&u.u_qsave);
21433Sbill 	/*NOTREACHED*/
21533Sbill }
21633Sbill 
21733Sbill /*
218181Sbill  * Remove a process from its wait queue
219181Sbill  */
220181Sbill unsleep(p)
2214826Swnj 	register struct proc *p;
222181Sbill {
22321099Smckusick 	register struct slpque *qp;
224181Sbill 	register struct proc **hp;
22521099Smckusick 	int s;
226181Sbill 
22717541Skarels 	s = splhigh();
228181Sbill 	if (p->p_wchan) {
22921099Smckusick 		hp = &(qp = &slpque[HASH(p->p_wchan)])->sq_head;
230181Sbill 		while (*hp != p)
231181Sbill 			hp = &(*hp)->p_link;
232181Sbill 		*hp = p->p_link;
23321099Smckusick 		if (qp->sq_tailp == &p->p_link)
23421099Smckusick 			qp->sq_tailp = hp;
235181Sbill 		p->p_wchan = 0;
236181Sbill 	}
237181Sbill 	splx(s);
238181Sbill }
239181Sbill 
240181Sbill /*
24133Sbill  * Wake up all processes sleeping on chan.
24233Sbill  */
24333Sbill wakeup(chan)
2444826Swnj 	register caddr_t chan;
24533Sbill {
24621099Smckusick 	register struct slpque *qp;
24721099Smckusick 	register struct proc *p, **q;
24833Sbill 	int s;
24933Sbill 
25017541Skarels 	s = splhigh();
25121099Smckusick 	qp = &slpque[HASH(chan)];
25233Sbill restart:
25321099Smckusick 	for (q = &qp->sq_head; p = *q; ) {
254181Sbill 		if (p->p_rlink || p->p_stat != SSLEEP && p->p_stat != SSTOP)
25533Sbill 			panic("wakeup");
256207Sbill 		if (p->p_wchan==chan) {
25733Sbill 			p->p_wchan = 0;
258187Sbill 			*q = p->p_link;
25921099Smckusick 			if (qp->sq_tailp == &p->p_link)
26021099Smckusick 				qp->sq_tailp = q;
261181Sbill 			if (p->p_stat == SSLEEP) {
262181Sbill 				/* OPTIMIZED INLINE EXPANSION OF setrun(p) */
26321763Skarels 				if (p->p_slptime > 1)
26421763Skarels 					updatepri(p);
26522722Skarels 				p->p_slptime = 0;
266181Sbill 				p->p_stat = SRUN;
2672702Swnj 				if (p->p_flag & SLOAD)
268181Sbill 					setrq(p);
26916795Skarels 				/*
27016795Skarels 				 * Since curpri is a usrpri,
27116795Skarels 				 * p->p_pri is always better than curpri.
27216795Skarels 				 */
27316795Skarels 				runrun++;
27416795Skarels 				aston();
2753545Swnj 				if ((p->p_flag&SLOAD) == 0) {
2763545Swnj 					if (runout != 0) {
2773545Swnj 						runout = 0;
2783545Swnj 						wakeup((caddr_t)&runout);
2793545Swnj 					}
2803545Swnj 					wantin++;
281181Sbill 				}
282181Sbill 				/* END INLINE EXPANSION */
283187Sbill 				goto restart;
28433Sbill 			}
28522722Skarels 			p->p_slptime = 0;
286187Sbill 		} else
287187Sbill 			q = &p->p_link;
28833Sbill 	}
28933Sbill 	splx(s);
29033Sbill }
29133Sbill 
29233Sbill /*
29333Sbill  * Initialize the (doubly-linked) run queues
29433Sbill  * to be empty.
29533Sbill  */
29633Sbill rqinit()
29733Sbill {
29833Sbill 	register int i;
29933Sbill 
30033Sbill 	for (i = 0; i < NQS; i++)
30133Sbill 		qs[i].ph_link = qs[i].ph_rlink = (struct proc *)&qs[i];
30233Sbill }
30333Sbill 
30433Sbill /*
30533Sbill  * Set the process running;
30633Sbill  * arrange for it to be swapped in if necessary.
30733Sbill  */
30833Sbill setrun(p)
3094826Swnj 	register struct proc *p;
31033Sbill {
3114826Swnj 	register int s;
31233Sbill 
31317541Skarels 	s = splhigh();
31433Sbill 	switch (p->p_stat) {
31533Sbill 
31633Sbill 	case 0:
31733Sbill 	case SWAIT:
31833Sbill 	case SRUN:
31933Sbill 	case SZOMB:
32033Sbill 	default:
32133Sbill 		panic("setrun");
32233Sbill 
323207Sbill 	case SSTOP:
32433Sbill 	case SSLEEP:
325181Sbill 		unsleep(p);		/* e.g. when sending signals */
32633Sbill 		break;
32733Sbill 
32833Sbill 	case SIDL:
32933Sbill 		break;
33033Sbill 	}
33117541Skarels 	if (p->p_slptime > 1)
33217541Skarels 		updatepri(p);
33333Sbill 	p->p_stat = SRUN;
33433Sbill 	if (p->p_flag & SLOAD)
33533Sbill 		setrq(p);
33633Sbill 	splx(s);
3374826Swnj 	if (p->p_pri < curpri) {
33833Sbill 		runrun++;
3392443Swnj 		aston();
3402443Swnj 	}
3413545Swnj 	if ((p->p_flag&SLOAD) == 0) {
3424826Swnj 		if (runout != 0) {
3433545Swnj 			runout = 0;
3443545Swnj 			wakeup((caddr_t)&runout);
3453545Swnj 		}
3463545Swnj 		wantin++;
34733Sbill 	}
34833Sbill }
34933Sbill 
35033Sbill /*
35133Sbill  * Set user priority.
35233Sbill  * The rescheduling flag (runrun)
35333Sbill  * is set if the priority is better
35433Sbill  * than the currently running process.
35533Sbill  */
35633Sbill setpri(pp)
3574826Swnj 	register struct proc *pp;
35833Sbill {
3594826Swnj 	register int p;
36033Sbill 
3613875Swnj 	p = (pp->p_cpu & 0377)/4;
36217541Skarels 	p += PUSER + 2 * pp->p_nice;
3633530Swnj 	if (pp->p_rssize > pp->p_maxrss && freemem < desfree)
3643530Swnj 		p += 2*4;	/* effectively, nice(4) */
3654826Swnj 	if (p > 127)
36633Sbill 		p = 127;
3674826Swnj 	if (p < curpri) {
36833Sbill 		runrun++;
3692453Swnj 		aston();
3702453Swnj 	}
37133Sbill 	pp->p_usrpri = p;
3724826Swnj 	return (p);
37333Sbill }
374