xref: /csrg-svn/sys/kern/kern_synch.c (revision 17093)
1*17093Sbloom /*	kern_synch.c	6.4	84/08/29	*/
233Sbill 
39756Ssam #include "../machine/pte.h"
49756Ssam 
5*17093Sbloom #include "param.h"
6*17093Sbloom #include "systm.h"
7*17093Sbloom #include "dir.h"
8*17093Sbloom #include "user.h"
9*17093Sbloom #include "proc.h"
10*17093Sbloom #include "file.h"
11*17093Sbloom #include "inode.h"
12*17093Sbloom #include "vm.h"
13*17093Sbloom #include "kernel.h"
14*17093Sbloom #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 
308113Sroot /* constants to digital decay and forget 90% of usage in 5*loadav time */
318102Sroot #undef ave
328102Sroot #define	ave(a,b) ((int)(((int)(a*b))/(b+1)))
338102Sroot int	nrscale = 2;
348102Sroot double	ccpu = 0.95122942450071400909;		/* exp(-1/20) */
358102Sroot 
368102Sroot /*
378102Sroot  * Recompute process priorities, once a second
388102Sroot  */
398102Sroot schedcpu()
408102Sroot {
4116795Skarels 	register double ccpu1 = (1.0 - ccpu) / (double)hz;
428102Sroot 	register struct proc *p;
438102Sroot 	register int s, a;
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++;
528102Sroot 		if (p->p_flag&SLOAD)
5316795Skarels 			p->p_pctcpu = ccpu * p->p_pctcpu + ccpu1 * p->p_cpticks;
548102Sroot 		p->p_cpticks = 0;
558102Sroot 		a = ave((p->p_cpu & 0377), avenrun[0]*nrscale) +
568102Sroot 		     p->p_nice - NZERO;
578102Sroot 		if (a < 0)
588102Sroot 			a = 0;
598102Sroot 		if (a > 255)
608102Sroot 			a = 255;
618102Sroot 		p->p_cpu = a;
628102Sroot 		(void) setpri(p);
638102Sroot 		s = spl6();	/* prevent state changes */
648102Sroot 		if (p->p_pri >= PUSER) {
6516795Skarels #define	PPQ	(128 / NQS)
668102Sroot 			if ((p != u.u_procp || noproc) &&
678102Sroot 			    p->p_stat == SRUN &&
688102Sroot 			    (p->p_flag & SLOAD) &&
6916795Skarels 			    (p->p_pri / PPQ) != (p->p_usrpri / PPQ)) {
708102Sroot 				remrq(p);
718102Sroot 				p->p_pri = p->p_usrpri;
728102Sroot 				setrq(p);
738102Sroot 			} else
748102Sroot 				p->p_pri = p->p_usrpri;
758102Sroot 		}
768102Sroot 		splx(s);
778102Sroot 	}
788102Sroot 	vmmeter();
798102Sroot 	if (runin!=0) {
808102Sroot 		runin = 0;
818102Sroot 		wakeup((caddr_t)&runin);
828102Sroot 	}
838102Sroot 	if (bclnlist != NULL)
848102Sroot 		wakeup((caddr_t)&proc[2]);
858624Sroot 	timeout(schedcpu, (caddr_t)0, hz);
868102Sroot }
878102Sroot 
8833Sbill #define SQSIZE 0100	/* Must be power of 2 */
8933Sbill #define HASH(x)	(( (int) x >> 5) & (SQSIZE-1))
9033Sbill struct proc *slpque[SQSIZE];
9133Sbill 
9233Sbill /*
9333Sbill  * Give up the processor till a wakeup occurs
9433Sbill  * on chan, at which time the process
9533Sbill  * enters the scheduling queue at priority pri.
9633Sbill  * The most important effect of pri is that when
9733Sbill  * pri<=PZERO a signal cannot disturb the sleep;
9833Sbill  * if pri>PZERO signals will be processed.
9933Sbill  * Callers of this routine must be prepared for
10033Sbill  * premature return, and check that the reason for
10133Sbill  * sleeping has gone away.
10233Sbill  */
10333Sbill sleep(chan, pri)
1048033Sroot 	caddr_t chan;
1058033Sroot 	int pri;
10633Sbill {
107187Sbill 	register struct proc *rp, **hp;
108207Sbill 	register s;
10933Sbill 
11033Sbill 	rp = u.u_procp;
11133Sbill 	s = spl6();
11233Sbill 	if (chan==0 || rp->p_stat != SRUN || rp->p_rlink)
11333Sbill 		panic("sleep");
11433Sbill 	rp->p_wchan = chan;
11533Sbill 	rp->p_slptime = 0;
11633Sbill 	rp->p_pri = pri;
117187Sbill 	hp = &slpque[HASH(chan)];
118187Sbill 	rp->p_link = *hp;
119187Sbill 	*hp = rp;
1204826Swnj 	if (pri > PZERO) {
1214826Swnj 		if (ISSIG(rp)) {
122187Sbill 			if (rp->p_wchan)
123187Sbill 				unsleep(rp);
12433Sbill 			rp->p_stat = SRUN;
125131Sbill 			(void) spl0();
12633Sbill 			goto psig;
12733Sbill 		}
128187Sbill 		if (rp->p_wchan == 0)
129187Sbill 			goto out;
130187Sbill 		rp->p_stat = SSLEEP;
131131Sbill 		(void) spl0();
1328033Sroot 		u.u_ru.ru_nvcsw++;
13333Sbill 		swtch();
1344826Swnj 		if (ISSIG(rp))
13533Sbill 			goto psig;
13633Sbill 	} else {
137207Sbill 		rp->p_stat = SSLEEP;
138131Sbill 		(void) spl0();
1398033Sroot 		u.u_ru.ru_nvcsw++;
14033Sbill 		swtch();
14133Sbill 	}
14216795Skarels 	curpri = rp->p_usrpri;
143187Sbill out:
14433Sbill 	splx(s);
14533Sbill 	return;
14633Sbill 
14733Sbill 	/*
14833Sbill 	 * If priority was low (>PZERO) and
1494826Swnj 	 * there has been a signal, execute non-local goto through
1508113Sroot 	 * u.u_qsave, aborting the system call in progress (see trap.c)
1514826Swnj 	 * (or finishing a tsleep, see below)
15233Sbill 	 */
15333Sbill psig:
1548113Sroot 	longjmp(&u.u_qsave);
15533Sbill 	/*NOTREACHED*/
15633Sbill }
15733Sbill 
15833Sbill /*
159181Sbill  * Remove a process from its wait queue
160181Sbill  */
161181Sbill unsleep(p)
1624826Swnj 	register struct proc *p;
163181Sbill {
164181Sbill 	register struct proc **hp;
165181Sbill 	register s;
166181Sbill 
167181Sbill 	s = spl6();
168181Sbill 	if (p->p_wchan) {
169181Sbill 		hp = &slpque[HASH(p->p_wchan)];
170181Sbill 		while (*hp != p)
171181Sbill 			hp = &(*hp)->p_link;
172181Sbill 		*hp = p->p_link;
173181Sbill 		p->p_wchan = 0;
174181Sbill 	}
175181Sbill 	splx(s);
176181Sbill }
177181Sbill 
178181Sbill /*
17933Sbill  * Wake up all processes sleeping on chan.
18033Sbill  */
18133Sbill wakeup(chan)
1824826Swnj 	register caddr_t chan;
18333Sbill {
184187Sbill 	register struct proc *p, **q, **h;
18533Sbill 	int s;
18633Sbill 
18733Sbill 	s = spl6();
188187Sbill 	h = &slpque[HASH(chan)];
18933Sbill restart:
190187Sbill 	for (q = h; p = *q; ) {
191181Sbill 		if (p->p_rlink || p->p_stat != SSLEEP && p->p_stat != SSTOP)
19233Sbill 			panic("wakeup");
193207Sbill 		if (p->p_wchan==chan) {
19433Sbill 			p->p_wchan = 0;
195187Sbill 			*q = p->p_link;
19633Sbill 			p->p_slptime = 0;
197181Sbill 			if (p->p_stat == SSLEEP) {
198181Sbill 				/* OPTIMIZED INLINE EXPANSION OF setrun(p) */
199181Sbill 				p->p_stat = SRUN;
2002702Swnj 				if (p->p_flag & SLOAD)
201181Sbill 					setrq(p);
20216795Skarels 				/*
20316795Skarels 				 * Since curpri is a usrpri,
20416795Skarels 				 * p->p_pri is always better than curpri.
20516795Skarels 				 */
20616795Skarels 				runrun++;
20716795Skarels 				aston();
2083545Swnj 				if ((p->p_flag&SLOAD) == 0) {
2093545Swnj 					if (runout != 0) {
2103545Swnj 						runout = 0;
2113545Swnj 						wakeup((caddr_t)&runout);
2123545Swnj 					}
2133545Swnj 					wantin++;
214181Sbill 				}
215181Sbill 				/* END INLINE EXPANSION */
216187Sbill 				goto restart;
21733Sbill 			}
218187Sbill 		} else
219187Sbill 			q = &p->p_link;
22033Sbill 	}
22133Sbill 	splx(s);
22233Sbill }
22333Sbill 
22433Sbill /*
22533Sbill  * Initialize the (doubly-linked) run queues
22633Sbill  * to be empty.
22733Sbill  */
22833Sbill rqinit()
22933Sbill {
23033Sbill 	register int i;
23133Sbill 
23233Sbill 	for (i = 0; i < NQS; i++)
23333Sbill 		qs[i].ph_link = qs[i].ph_rlink = (struct proc *)&qs[i];
23433Sbill }
23533Sbill 
23633Sbill /*
23733Sbill  * Set the process running;
23833Sbill  * arrange for it to be swapped in if necessary.
23933Sbill  */
24033Sbill setrun(p)
2414826Swnj 	register struct proc *p;
24233Sbill {
2434826Swnj 	register int s;
24433Sbill 
24533Sbill 	s = spl6();
24633Sbill 	switch (p->p_stat) {
24733Sbill 
24833Sbill 	case 0:
24933Sbill 	case SWAIT:
25033Sbill 	case SRUN:
25133Sbill 	case SZOMB:
25233Sbill 	default:
25333Sbill 		panic("setrun");
25433Sbill 
255207Sbill 	case SSTOP:
25633Sbill 	case SSLEEP:
257181Sbill 		unsleep(p);		/* e.g. when sending signals */
25833Sbill 		break;
25933Sbill 
26033Sbill 	case SIDL:
26133Sbill 		break;
26233Sbill 	}
26333Sbill 	p->p_stat = SRUN;
26433Sbill 	if (p->p_flag & SLOAD)
26533Sbill 		setrq(p);
26633Sbill 	splx(s);
2674826Swnj 	if (p->p_pri < curpri) {
26833Sbill 		runrun++;
2692443Swnj 		aston();
2702443Swnj 	}
2713545Swnj 	if ((p->p_flag&SLOAD) == 0) {
2724826Swnj 		if (runout != 0) {
2733545Swnj 			runout = 0;
2743545Swnj 			wakeup((caddr_t)&runout);
2753545Swnj 		}
2763545Swnj 		wantin++;
27733Sbill 	}
27833Sbill }
27933Sbill 
28033Sbill /*
28133Sbill  * Set user priority.
28233Sbill  * The rescheduling flag (runrun)
28333Sbill  * is set if the priority is better
28433Sbill  * than the currently running process.
28533Sbill  */
28633Sbill setpri(pp)
2874826Swnj 	register struct proc *pp;
28833Sbill {
2894826Swnj 	register int p;
29033Sbill 
2913875Swnj 	p = (pp->p_cpu & 0377)/4;
2921543Sbill 	p += PUSER + 2*(pp->p_nice - NZERO);
2933530Swnj 	if (pp->p_rssize > pp->p_maxrss && freemem < desfree)
2943530Swnj 		p += 2*4;	/* effectively, nice(4) */
2954826Swnj 	if (p > 127)
29633Sbill 		p = 127;
2974826Swnj 	if (p < curpri) {
29833Sbill 		runrun++;
2992453Swnj 		aston();
3002453Swnj 	}
30133Sbill 	pp->p_usrpri = p;
3024826Swnj 	return (p);
30333Sbill }
304