xref: /csrg-svn/sys/kern/kern_synch.c (revision 8113)
1*8113Sroot /*	kern_synch.c	4.21	82/09/08	*/
233Sbill 
333Sbill #include "../h/param.h"
433Sbill #include "../h/systm.h"
533Sbill #include "../h/dir.h"
633Sbill #include "../h/user.h"
733Sbill #include "../h/proc.h"
833Sbill #include "../h/file.h"
933Sbill #include "../h/inode.h"
1033Sbill #include "../h/vm.h"
1133Sbill #include "../h/pte.h"
12181Sbill #include "../h/inline.h"
132443Swnj #include "../h/mtpr.h"
148102Sroot #ifdef MUSH
157485Skre #include "../h/quota.h"
168102Sroot #include "../h/share.h"
178102Sroot #endif
188102Sroot #include "../h/kernel.h"
198102Sroot #include "../h/buf.h"
2033Sbill 
218102Sroot /*
228102Sroot  * Force switch among equal priority processes every 100ms.
238102Sroot  */
248102Sroot roundrobin()
258102Sroot {
268102Sroot 
278102Sroot 	runrun++;
288102Sroot 	aston();
298102Sroot 	timeout(roundrobin, 0, hz / 10);
308102Sroot }
318102Sroot 
32*8113Sroot /* constants to digital decay and forget 90% of usage in 5*loadav time */
338102Sroot #undef ave
348102Sroot #define	ave(a,b) ((int)(((int)(a*b))/(b+1)))
358102Sroot int	nrscale = 2;
368102Sroot double	avenrun[];
378102Sroot double	ccpu = 0.95122942450071400909;		/* exp(-1/20) */
388102Sroot 
398102Sroot /*
408102Sroot  * Recompute process priorities, once a second
418102Sroot  */
428102Sroot schedcpu()
438102Sroot {
448102Sroot 	register struct proc *p;
458102Sroot 	register int s, a;
468102Sroot 
478102Sroot 	wakeup((caddr_t)&lbolt);
488102Sroot 	for (p = proc; p < procNPROC; p++) if (p->p_stat && p->p_stat!=SZOMB) {
498102Sroot #ifdef MUSH
508102Sroot 		if (p->p_quota->q_uid)
518102Sroot 			p->p_quota->q_cost +=
528102Sroot 			    shconsts.sc_click * p->p_rssize;
538102Sroot #endif
548102Sroot 		if (p->p_time != 127)
558102Sroot 			p->p_time++;
568102Sroot 		if (p->p_stat==SSLEEP || p->p_stat==SSTOP)
578102Sroot 			if (p->p_slptime != 127)
588102Sroot 				p->p_slptime++;
598102Sroot 		if (p->p_flag&SLOAD)
608102Sroot 			p->p_pctcpu = ccpu * p->p_pctcpu +
618102Sroot 			    (1.0 - ccpu) * (p->p_cpticks/(float)hz);
628102Sroot 		p->p_cpticks = 0;
638102Sroot #ifdef MUSH
648102Sroot 		a = ave((p->p_cpu & 0377), avenrun[0]*nrscale) +
658102Sroot 		     p->p_nice - NZERO + p->p_quota->q_nice;
668102Sroot #else
678102Sroot 		a = ave((p->p_cpu & 0377), avenrun[0]*nrscale) +
688102Sroot 		     p->p_nice - NZERO;
698102Sroot #endif
708102Sroot 		if (a < 0)
718102Sroot 			a = 0;
728102Sroot 		if (a > 255)
738102Sroot 			a = 255;
748102Sroot 		p->p_cpu = a;
758102Sroot 		(void) setpri(p);
768102Sroot 		s = spl6();	/* prevent state changes */
778102Sroot 		if (p->p_pri >= PUSER) {
788102Sroot 			if ((p != u.u_procp || noproc) &&
798102Sroot 			    p->p_stat == SRUN &&
808102Sroot 			    (p->p_flag & SLOAD) &&
818102Sroot 			    p->p_pri != p->p_usrpri) {
828102Sroot 				remrq(p);
838102Sroot 				p->p_pri = p->p_usrpri;
848102Sroot 				setrq(p);
858102Sroot 			} else
868102Sroot 				p->p_pri = p->p_usrpri;
878102Sroot 		}
888102Sroot 		splx(s);
898102Sroot 	}
908102Sroot 	vmmeter();
918102Sroot 	if (runin!=0) {
928102Sroot 		runin = 0;
938102Sroot 		wakeup((caddr_t)&runin);
948102Sroot 	}
958102Sroot 	if (bclnlist != NULL)
968102Sroot 		wakeup((caddr_t)&proc[2]);
978102Sroot 	timeout(schedcpu, 0, hz);
988102Sroot }
998102Sroot 
10033Sbill #define SQSIZE 0100	/* Must be power of 2 */
10133Sbill #define HASH(x)	(( (int) x >> 5) & (SQSIZE-1))
10233Sbill struct proc *slpque[SQSIZE];
10333Sbill 
10433Sbill /*
10533Sbill  * Give up the processor till a wakeup occurs
10633Sbill  * on chan, at which time the process
10733Sbill  * enters the scheduling queue at priority pri.
10833Sbill  * The most important effect of pri is that when
10933Sbill  * pri<=PZERO a signal cannot disturb the sleep;
11033Sbill  * if pri>PZERO signals will be processed.
11133Sbill  * Callers of this routine must be prepared for
11233Sbill  * premature return, and check that the reason for
11333Sbill  * sleeping has gone away.
11433Sbill  */
11533Sbill sleep(chan, pri)
1168033Sroot 	caddr_t chan;
1178033Sroot 	int pri;
11833Sbill {
119187Sbill 	register struct proc *rp, **hp;
120207Sbill 	register s;
12133Sbill 
12233Sbill 	rp = u.u_procp;
12333Sbill 	s = spl6();
12433Sbill 	if (chan==0 || rp->p_stat != SRUN || rp->p_rlink)
12533Sbill 		panic("sleep");
12633Sbill 	rp->p_wchan = chan;
12733Sbill 	rp->p_slptime = 0;
12833Sbill 	rp->p_pri = pri;
129187Sbill 	hp = &slpque[HASH(chan)];
130187Sbill 	rp->p_link = *hp;
131187Sbill 	*hp = rp;
1324826Swnj 	if (pri > PZERO) {
1334826Swnj 		if (ISSIG(rp)) {
134187Sbill 			if (rp->p_wchan)
135187Sbill 				unsleep(rp);
13633Sbill 			rp->p_stat = SRUN;
137131Sbill 			(void) spl0();
13833Sbill 			goto psig;
13933Sbill 		}
140187Sbill 		if (rp->p_wchan == 0)
141187Sbill 			goto out;
142187Sbill 		rp->p_stat = SSLEEP;
143131Sbill 		(void) spl0();
1448033Sroot 		u.u_ru.ru_nvcsw++;
14533Sbill 		swtch();
1464826Swnj 		if (ISSIG(rp))
14733Sbill 			goto psig;
14833Sbill 	} else {
149207Sbill 		rp->p_stat = SSLEEP;
150131Sbill 		(void) spl0();
1518033Sroot 		u.u_ru.ru_nvcsw++;
15233Sbill 		swtch();
15333Sbill 	}
154187Sbill out:
15533Sbill 	splx(s);
15633Sbill 	return;
15733Sbill 
15833Sbill 	/*
15933Sbill 	 * If priority was low (>PZERO) and
1604826Swnj 	 * there has been a signal, execute non-local goto through
161*8113Sroot 	 * u.u_qsave, aborting the system call in progress (see trap.c)
1624826Swnj 	 * (or finishing a tsleep, see below)
16333Sbill 	 */
16433Sbill psig:
165*8113Sroot 	longjmp(&u.u_qsave);
16633Sbill 	/*NOTREACHED*/
16733Sbill }
16833Sbill 
16933Sbill /*
170181Sbill  * Remove a process from its wait queue
171181Sbill  */
172181Sbill unsleep(p)
1734826Swnj 	register struct proc *p;
174181Sbill {
175181Sbill 	register struct proc **hp;
176181Sbill 	register s;
177181Sbill 
178181Sbill 	s = spl6();
179181Sbill 	if (p->p_wchan) {
180181Sbill 		hp = &slpque[HASH(p->p_wchan)];
181181Sbill 		while (*hp != p)
182181Sbill 			hp = &(*hp)->p_link;
183181Sbill 		*hp = p->p_link;
184181Sbill 		p->p_wchan = 0;
185181Sbill 	}
186181Sbill 	splx(s);
187181Sbill }
188181Sbill 
189181Sbill /*
19033Sbill  * Wake up all processes sleeping on chan.
19133Sbill  */
19233Sbill wakeup(chan)
1934826Swnj 	register caddr_t chan;
19433Sbill {
195187Sbill 	register struct proc *p, **q, **h;
19633Sbill 	int s;
19733Sbill 
19833Sbill 	s = spl6();
199187Sbill 	h = &slpque[HASH(chan)];
20033Sbill restart:
201187Sbill 	for (q = h; p = *q; ) {
202181Sbill 		if (p->p_rlink || p->p_stat != SSLEEP && p->p_stat != SSTOP)
20333Sbill 			panic("wakeup");
204207Sbill 		if (p->p_wchan==chan) {
20533Sbill 			p->p_wchan = 0;
206187Sbill 			*q = p->p_link;
20733Sbill 			p->p_slptime = 0;
208181Sbill 			if (p->p_stat == SSLEEP) {
209181Sbill 				/* OPTIMIZED INLINE EXPANSION OF setrun(p) */
210181Sbill 				p->p_stat = SRUN;
2112702Swnj 				if (p->p_flag & SLOAD)
212181Sbill 					setrq(p);
2134826Swnj 				if (p->p_pri < curpri) {
214181Sbill 					runrun++;
2152443Swnj 					aston();
2162443Swnj 				}
2173545Swnj 				if ((p->p_flag&SLOAD) == 0) {
2183545Swnj 					if (runout != 0) {
2193545Swnj 						runout = 0;
2203545Swnj 						wakeup((caddr_t)&runout);
2213545Swnj 					}
2223545Swnj 					wantin++;
223181Sbill 				}
224181Sbill 				/* END INLINE EXPANSION */
225187Sbill 				goto restart;
22633Sbill 			}
227187Sbill 		} else
228187Sbill 			q = &p->p_link;
22933Sbill 	}
23033Sbill 	splx(s);
23133Sbill }
23233Sbill 
23333Sbill /*
23433Sbill  * Initialize the (doubly-linked) run queues
23533Sbill  * to be empty.
23633Sbill  */
23733Sbill rqinit()
23833Sbill {
23933Sbill 	register int i;
24033Sbill 
24133Sbill 	for (i = 0; i < NQS; i++)
24233Sbill 		qs[i].ph_link = qs[i].ph_rlink = (struct proc *)&qs[i];
24333Sbill }
24433Sbill 
24533Sbill /*
24633Sbill  * Set the process running;
24733Sbill  * arrange for it to be swapped in if necessary.
24833Sbill  */
24933Sbill setrun(p)
2504826Swnj 	register struct proc *p;
25133Sbill {
2524826Swnj 	register int s;
25333Sbill 
25433Sbill 	s = spl6();
25533Sbill 	switch (p->p_stat) {
25633Sbill 
25733Sbill 	case 0:
25833Sbill 	case SWAIT:
25933Sbill 	case SRUN:
26033Sbill 	case SZOMB:
26133Sbill 	default:
26233Sbill 		panic("setrun");
26333Sbill 
264207Sbill 	case SSTOP:
26533Sbill 	case SSLEEP:
266181Sbill 		unsleep(p);		/* e.g. when sending signals */
26733Sbill 		break;
26833Sbill 
26933Sbill 	case SIDL:
27033Sbill 		break;
27133Sbill 	}
27233Sbill 	p->p_stat = SRUN;
27333Sbill 	if (p->p_flag & SLOAD)
27433Sbill 		setrq(p);
27533Sbill 	splx(s);
2764826Swnj 	if (p->p_pri < curpri) {
27733Sbill 		runrun++;
2782443Swnj 		aston();
2792443Swnj 	}
2803545Swnj 	if ((p->p_flag&SLOAD) == 0) {
2814826Swnj 		if (runout != 0) {
2823545Swnj 			runout = 0;
2833545Swnj 			wakeup((caddr_t)&runout);
2843545Swnj 		}
2853545Swnj 		wantin++;
28633Sbill 	}
28733Sbill }
28833Sbill 
28933Sbill /*
29033Sbill  * Set user priority.
29133Sbill  * The rescheduling flag (runrun)
29233Sbill  * is set if the priority is better
29333Sbill  * than the currently running process.
29433Sbill  */
29533Sbill setpri(pp)
2964826Swnj 	register struct proc *pp;
29733Sbill {
2984826Swnj 	register int p;
29933Sbill 
3003875Swnj 	p = (pp->p_cpu & 0377)/4;
3011543Sbill 	p += PUSER + 2*(pp->p_nice - NZERO);
3023530Swnj 	if (pp->p_rssize > pp->p_maxrss && freemem < desfree)
3033530Swnj 		p += 2*4;	/* effectively, nice(4) */
3044826Swnj 	if (p > 127)
30533Sbill 		p = 127;
3064826Swnj 	if (p < curpri) {
30733Sbill 		runrun++;
3082453Swnj 		aston();
3092453Swnj 	}
31033Sbill 	pp->p_usrpri = p;
3114826Swnj 	return (p);
31233Sbill }
313