xref: /csrg-svn/sys/kern/kern_synch.c (revision 16532)
1*16532Skarels /*	kern_synch.c	6.2	84/05/22	*/
233Sbill 
39756Ssam #include "../machine/pte.h"
49756Ssam 
533Sbill #include "../h/param.h"
633Sbill #include "../h/systm.h"
733Sbill #include "../h/dir.h"
833Sbill #include "../h/user.h"
933Sbill #include "../h/proc.h"
1033Sbill #include "../h/file.h"
1133Sbill #include "../h/inode.h"
1233Sbill #include "../h/vm.h"
138102Sroot #include "../h/kernel.h"
148102Sroot #include "../h/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 {
418102Sroot 	register struct proc *p;
428102Sroot 	register int s, a;
438102Sroot 
448102Sroot 	wakeup((caddr_t)&lbolt);
45*16532Skarels 	for (p = allproc; p != NULL; p = p->p_nxt) {
468102Sroot 		if (p->p_time != 127)
478102Sroot 			p->p_time++;
488102Sroot 		if (p->p_stat==SSLEEP || p->p_stat==SSTOP)
498102Sroot 			if (p->p_slptime != 127)
508102Sroot 				p->p_slptime++;
518102Sroot 		if (p->p_flag&SLOAD)
528102Sroot 			p->p_pctcpu = ccpu * p->p_pctcpu +
538102Sroot 			    (1.0 - ccpu) * (p->p_cpticks/(float)hz);
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) {
658102Sroot 			if ((p != u.u_procp || noproc) &&
668102Sroot 			    p->p_stat == SRUN &&
678102Sroot 			    (p->p_flag & SLOAD) &&
688102Sroot 			    p->p_pri != p->p_usrpri) {
698102Sroot 				remrq(p);
708102Sroot 				p->p_pri = p->p_usrpri;
718102Sroot 				setrq(p);
728102Sroot 			} else
738102Sroot 				p->p_pri = p->p_usrpri;
748102Sroot 		}
758102Sroot 		splx(s);
768102Sroot 	}
778102Sroot 	vmmeter();
788102Sroot 	if (runin!=0) {
798102Sroot 		runin = 0;
808102Sroot 		wakeup((caddr_t)&runin);
818102Sroot 	}
828102Sroot 	if (bclnlist != NULL)
838102Sroot 		wakeup((caddr_t)&proc[2]);
848624Sroot 	timeout(schedcpu, (caddr_t)0, hz);
858102Sroot }
868102Sroot 
8733Sbill #define SQSIZE 0100	/* Must be power of 2 */
8833Sbill #define HASH(x)	(( (int) x >> 5) & (SQSIZE-1))
8933Sbill struct proc *slpque[SQSIZE];
9033Sbill 
9133Sbill /*
9233Sbill  * Give up the processor till a wakeup occurs
9333Sbill  * on chan, at which time the process
9433Sbill  * enters the scheduling queue at priority pri.
9533Sbill  * The most important effect of pri is that when
9633Sbill  * pri<=PZERO a signal cannot disturb the sleep;
9733Sbill  * if pri>PZERO signals will be processed.
9833Sbill  * Callers of this routine must be prepared for
9933Sbill  * premature return, and check that the reason for
10033Sbill  * sleeping has gone away.
10133Sbill  */
10233Sbill sleep(chan, pri)
1038033Sroot 	caddr_t chan;
1048033Sroot 	int pri;
10533Sbill {
106187Sbill 	register struct proc *rp, **hp;
107207Sbill 	register s;
10833Sbill 
10933Sbill 	rp = u.u_procp;
11033Sbill 	s = spl6();
11133Sbill 	if (chan==0 || rp->p_stat != SRUN || rp->p_rlink)
11233Sbill 		panic("sleep");
11333Sbill 	rp->p_wchan = chan;
11433Sbill 	rp->p_slptime = 0;
11533Sbill 	rp->p_pri = pri;
116187Sbill 	hp = &slpque[HASH(chan)];
117187Sbill 	rp->p_link = *hp;
118187Sbill 	*hp = rp;
1194826Swnj 	if (pri > PZERO) {
1204826Swnj 		if (ISSIG(rp)) {
121187Sbill 			if (rp->p_wchan)
122187Sbill 				unsleep(rp);
12333Sbill 			rp->p_stat = SRUN;
124131Sbill 			(void) spl0();
12533Sbill 			goto psig;
12633Sbill 		}
127187Sbill 		if (rp->p_wchan == 0)
128187Sbill 			goto out;
129187Sbill 		rp->p_stat = SSLEEP;
130131Sbill 		(void) spl0();
1318033Sroot 		u.u_ru.ru_nvcsw++;
13233Sbill 		swtch();
1334826Swnj 		if (ISSIG(rp))
13433Sbill 			goto psig;
13533Sbill 	} else {
136207Sbill 		rp->p_stat = SSLEEP;
137131Sbill 		(void) spl0();
1388033Sroot 		u.u_ru.ru_nvcsw++;
13933Sbill 		swtch();
14033Sbill 	}
141187Sbill out:
14233Sbill 	splx(s);
14333Sbill 	return;
14433Sbill 
14533Sbill 	/*
14633Sbill 	 * If priority was low (>PZERO) and
1474826Swnj 	 * there has been a signal, execute non-local goto through
1488113Sroot 	 * u.u_qsave, aborting the system call in progress (see trap.c)
1494826Swnj 	 * (or finishing a tsleep, see below)
15033Sbill 	 */
15133Sbill psig:
1528113Sroot 	longjmp(&u.u_qsave);
15333Sbill 	/*NOTREACHED*/
15433Sbill }
15533Sbill 
15633Sbill /*
157181Sbill  * Remove a process from its wait queue
158181Sbill  */
159181Sbill unsleep(p)
1604826Swnj 	register struct proc *p;
161181Sbill {
162181Sbill 	register struct proc **hp;
163181Sbill 	register s;
164181Sbill 
165181Sbill 	s = spl6();
166181Sbill 	if (p->p_wchan) {
167181Sbill 		hp = &slpque[HASH(p->p_wchan)];
168181Sbill 		while (*hp != p)
169181Sbill 			hp = &(*hp)->p_link;
170181Sbill 		*hp = p->p_link;
171181Sbill 		p->p_wchan = 0;
172181Sbill 	}
173181Sbill 	splx(s);
174181Sbill }
175181Sbill 
176181Sbill /*
17733Sbill  * Wake up all processes sleeping on chan.
17833Sbill  */
17933Sbill wakeup(chan)
1804826Swnj 	register caddr_t chan;
18133Sbill {
182187Sbill 	register struct proc *p, **q, **h;
18333Sbill 	int s;
18433Sbill 
18533Sbill 	s = spl6();
186187Sbill 	h = &slpque[HASH(chan)];
18733Sbill restart:
188187Sbill 	for (q = h; p = *q; ) {
189181Sbill 		if (p->p_rlink || p->p_stat != SSLEEP && p->p_stat != SSTOP)
19033Sbill 			panic("wakeup");
191207Sbill 		if (p->p_wchan==chan) {
19233Sbill 			p->p_wchan = 0;
193187Sbill 			*q = p->p_link;
19433Sbill 			p->p_slptime = 0;
195181Sbill 			if (p->p_stat == SSLEEP) {
196181Sbill 				/* OPTIMIZED INLINE EXPANSION OF setrun(p) */
197181Sbill 				p->p_stat = SRUN;
1982702Swnj 				if (p->p_flag & SLOAD)
199181Sbill 					setrq(p);
2004826Swnj 				if (p->p_pri < curpri) {
201181Sbill 					runrun++;
2022443Swnj 					aston();
2032443Swnj 				}
2043545Swnj 				if ((p->p_flag&SLOAD) == 0) {
2053545Swnj 					if (runout != 0) {
2063545Swnj 						runout = 0;
2073545Swnj 						wakeup((caddr_t)&runout);
2083545Swnj 					}
2093545Swnj 					wantin++;
210181Sbill 				}
211181Sbill 				/* END INLINE EXPANSION */
212187Sbill 				goto restart;
21333Sbill 			}
214187Sbill 		} else
215187Sbill 			q = &p->p_link;
21633Sbill 	}
21733Sbill 	splx(s);
21833Sbill }
21933Sbill 
22033Sbill /*
22133Sbill  * Initialize the (doubly-linked) run queues
22233Sbill  * to be empty.
22333Sbill  */
22433Sbill rqinit()
22533Sbill {
22633Sbill 	register int i;
22733Sbill 
22833Sbill 	for (i = 0; i < NQS; i++)
22933Sbill 		qs[i].ph_link = qs[i].ph_rlink = (struct proc *)&qs[i];
23033Sbill }
23133Sbill 
23233Sbill /*
23333Sbill  * Set the process running;
23433Sbill  * arrange for it to be swapped in if necessary.
23533Sbill  */
23633Sbill setrun(p)
2374826Swnj 	register struct proc *p;
23833Sbill {
2394826Swnj 	register int s;
24033Sbill 
24133Sbill 	s = spl6();
24233Sbill 	switch (p->p_stat) {
24333Sbill 
24433Sbill 	case 0:
24533Sbill 	case SWAIT:
24633Sbill 	case SRUN:
24733Sbill 	case SZOMB:
24833Sbill 	default:
24933Sbill 		panic("setrun");
25033Sbill 
251207Sbill 	case SSTOP:
25233Sbill 	case SSLEEP:
253181Sbill 		unsleep(p);		/* e.g. when sending signals */
25433Sbill 		break;
25533Sbill 
25633Sbill 	case SIDL:
25733Sbill 		break;
25833Sbill 	}
25933Sbill 	p->p_stat = SRUN;
26033Sbill 	if (p->p_flag & SLOAD)
26133Sbill 		setrq(p);
26233Sbill 	splx(s);
2634826Swnj 	if (p->p_pri < curpri) {
26433Sbill 		runrun++;
2652443Swnj 		aston();
2662443Swnj 	}
2673545Swnj 	if ((p->p_flag&SLOAD) == 0) {
2684826Swnj 		if (runout != 0) {
2693545Swnj 			runout = 0;
2703545Swnj 			wakeup((caddr_t)&runout);
2713545Swnj 		}
2723545Swnj 		wantin++;
27333Sbill 	}
27433Sbill }
27533Sbill 
27633Sbill /*
27733Sbill  * Set user priority.
27833Sbill  * The rescheduling flag (runrun)
27933Sbill  * is set if the priority is better
28033Sbill  * than the currently running process.
28133Sbill  */
28233Sbill setpri(pp)
2834826Swnj 	register struct proc *pp;
28433Sbill {
2854826Swnj 	register int p;
28633Sbill 
2873875Swnj 	p = (pp->p_cpu & 0377)/4;
2881543Sbill 	p += PUSER + 2*(pp->p_nice - NZERO);
2893530Swnj 	if (pp->p_rssize > pp->p_maxrss && freemem < desfree)
2903530Swnj 		p += 2*4;	/* effectively, nice(4) */
2914826Swnj 	if (p > 127)
29233Sbill 		p = 127;
2934826Swnj 	if (p < curpri) {
29433Sbill 		runrun++;
2952453Swnj 		aston();
2962453Swnj 	}
29733Sbill 	pp->p_usrpri = p;
2984826Swnj 	return (p);
29933Sbill }
300