xref: /csrg-svn/sys/kern/kern_synch.c (revision 8102)
1*8102Sroot /*	kern_synch.c	4.20	82/09/06	*/
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"
14*8102Sroot #ifdef MUSH
157485Skre #include "../h/quota.h"
16*8102Sroot #include "../h/share.h"
17*8102Sroot #endif
18*8102Sroot #include "../h/kernel.h"
19*8102Sroot #include "../h/buf.h"
2033Sbill 
21*8102Sroot /*
22*8102Sroot  * Force switch among equal priority processes every 100ms.
23*8102Sroot  */
24*8102Sroot roundrobin()
25*8102Sroot {
26*8102Sroot 
27*8102Sroot 	runrun++;
28*8102Sroot 	aston();
29*8102Sroot 	timeout(roundrobin, 0, hz / 10);
30*8102Sroot }
31*8102Sroot 
32*8102Sroot /*
33*8102Sroot  * The digital decay cpu usage priority assignment is scaled to run in
34*8102Sroot  * time as expanded by the 1 minute load average.  Each second we
35*8102Sroot  * multiply the the previous cpu usage estimate by
36*8102Sroot  *		nrscale*avenrun[0]
37*8102Sroot  * The following relates the load average to the period over which
38*8102Sroot  * cpu usage is 90% forgotten:
39*8102Sroot  *	loadav 1	 5 seconds
40*8102Sroot  *	loadav 5	24 seconds
41*8102Sroot  *	loadav 10	47 seconds
42*8102Sroot  *	loadav 20	93 seconds
43*8102Sroot  * This is a great improvement on the previous algorithm which
44*8102Sroot  * decayed the priorities by a constant, and decayed away all knowledge
45*8102Sroot  * of previous activity in about 20 seconds.  Under heavy load,
46*8102Sroot  * the previous algorithm degenerated to round-robin with poor response
47*8102Sroot  * time when there was a high load average.
48*8102Sroot  */
49*8102Sroot #undef ave
50*8102Sroot #define	ave(a,b) ((int)(((int)(a*b))/(b+1)))
51*8102Sroot int	nrscale = 2;
52*8102Sroot double	avenrun[];
53*8102Sroot 
54*8102Sroot /*
55*8102Sroot  * Constant for decay filter for cpu usage field
56*8102Sroot  * in process table (used by ps au).
57*8102Sroot  */
58*8102Sroot double	ccpu = 0.95122942450071400909;		/* exp(-1/20) */
59*8102Sroot 
60*8102Sroot #ifdef MELB
61*8102Sroot /*
62*8102Sroot  * Automatic niceness rate & max constants
63*8102Sroot  */
64*8102Sroot #define	MAXNICE	(8 + NZERO)	/* maximum auto nice value */
65*8102Sroot #define	NFACT	(40 * hz)	/* nice++ every 40 secs cpu+sys time */
66*8102Sroot #endif
67*8102Sroot 
68*8102Sroot /*
69*8102Sroot  * Recompute process priorities, once a second
70*8102Sroot  */
71*8102Sroot schedcpu()
72*8102Sroot {
73*8102Sroot 	register struct proc *p;
74*8102Sroot 	register int s, a;
75*8102Sroot 
76*8102Sroot 	s = spl6(); time.tv_sec += lbolt / hz; lbolt %= hz; splx(s);
77*8102Sroot 	wakeup((caddr_t)&lbolt);
78*8102Sroot 
79*8102Sroot 	for (p = proc; p < procNPROC; p++) if (p->p_stat && p->p_stat!=SZOMB) {
80*8102Sroot #ifdef MUSH
81*8102Sroot 		/*
82*8102Sroot 		 * Charge process for memory in use
83*8102Sroot 		 */
84*8102Sroot 		if (p->p_quota->q_uid)
85*8102Sroot 			p->p_quota->q_cost +=
86*8102Sroot 			    shconsts.sc_click * p->p_rssize;
87*8102Sroot #endif
88*8102Sroot 		if (p->p_time != 127)
89*8102Sroot 			p->p_time++;
90*8102Sroot 		if (timerisset(&p->p_seltimer) &&
91*8102Sroot 		     --p->p_seltimer.tv_sec <= 0) {
92*8102Sroot 			timerclear(&p->p_seltimer);
93*8102Sroot 			s = spl6();
94*8102Sroot 			switch (p->p_stat) {
95*8102Sroot 
96*8102Sroot 			case SSLEEP:
97*8102Sroot 				setrun(p);
98*8102Sroot 				break;
99*8102Sroot 
100*8102Sroot 			case SSTOP:
101*8102Sroot 				unsleep(p);
102*8102Sroot 				break;
103*8102Sroot 			}
104*8102Sroot 			splx(s);
105*8102Sroot 		}
106*8102Sroot 		if (timerisset(&p->p_realtimer.it_value) &&
107*8102Sroot 		    itimerdecr(&p->p_realtimer, 1000000) == 0)
108*8102Sroot 			psignal(p, SIGALRM);
109*8102Sroot 		if (p->p_stat==SSLEEP || p->p_stat==SSTOP)
110*8102Sroot 			if (p->p_slptime != 127)
111*8102Sroot 				p->p_slptime++;
112*8102Sroot 		if (p->p_flag&SLOAD)
113*8102Sroot 			p->p_pctcpu = ccpu * p->p_pctcpu +
114*8102Sroot 			    (1.0 - ccpu) * (p->p_cpticks/(float)hz);
115*8102Sroot 		p->p_cpticks = 0;
116*8102Sroot #ifdef MUSH
117*8102Sroot 		a = ave((p->p_cpu & 0377), avenrun[0]*nrscale) +
118*8102Sroot 		     p->p_nice - NZERO + p->p_quota->q_nice;
119*8102Sroot #else
120*8102Sroot 		a = ave((p->p_cpu & 0377), avenrun[0]*nrscale) +
121*8102Sroot 		     p->p_nice - NZERO;
122*8102Sroot #endif
123*8102Sroot 		if (a < 0)
124*8102Sroot 			a = 0;
125*8102Sroot 		if (a > 255)
126*8102Sroot 			a = 255;
127*8102Sroot 		p->p_cpu = a;
128*8102Sroot 		(void) setpri(p);
129*8102Sroot 		s = spl6();	/* prevent state changes */
130*8102Sroot 		if (p->p_pri >= PUSER) {
131*8102Sroot 			if ((p != u.u_procp || noproc) &&
132*8102Sroot 			    p->p_stat == SRUN &&
133*8102Sroot 			    (p->p_flag & SLOAD) &&
134*8102Sroot 			    p->p_pri != p->p_usrpri) {
135*8102Sroot 				remrq(p);
136*8102Sroot 				p->p_pri = p->p_usrpri;
137*8102Sroot 				setrq(p);
138*8102Sroot 			} else
139*8102Sroot 				p->p_pri = p->p_usrpri;
140*8102Sroot 		}
141*8102Sroot 		splx(s);
142*8102Sroot 	}
143*8102Sroot 	vmmeter();
144*8102Sroot 	if (runin!=0) {
145*8102Sroot 		runin = 0;
146*8102Sroot 		wakeup((caddr_t)&runin);
147*8102Sroot 	}
148*8102Sroot 	if (bclnlist != NULL)
149*8102Sroot 		wakeup((caddr_t)&proc[2]);
150*8102Sroot 	timeout(schedcpu, 0, hz);
151*8102Sroot }
152*8102Sroot 
15333Sbill #define SQSIZE 0100	/* Must be power of 2 */
15433Sbill #define HASH(x)	(( (int) x >> 5) & (SQSIZE-1))
15533Sbill struct proc *slpque[SQSIZE];
15633Sbill 
15733Sbill /*
15833Sbill  * Give up the processor till a wakeup occurs
15933Sbill  * on chan, at which time the process
16033Sbill  * enters the scheduling queue at priority pri.
16133Sbill  * The most important effect of pri is that when
16233Sbill  * pri<=PZERO a signal cannot disturb the sleep;
16333Sbill  * if pri>PZERO signals will be processed.
16433Sbill  * Callers of this routine must be prepared for
16533Sbill  * premature return, and check that the reason for
16633Sbill  * sleeping has gone away.
16733Sbill  */
16833Sbill sleep(chan, pri)
1698033Sroot 	caddr_t chan;
1708033Sroot 	int pri;
17133Sbill {
172187Sbill 	register struct proc *rp, **hp;
173207Sbill 	register s;
17433Sbill 
17533Sbill 	rp = u.u_procp;
17633Sbill 	s = spl6();
17733Sbill 	if (chan==0 || rp->p_stat != SRUN || rp->p_rlink)
17833Sbill 		panic("sleep");
17933Sbill 	rp->p_wchan = chan;
18033Sbill 	rp->p_slptime = 0;
18133Sbill 	rp->p_pri = pri;
182187Sbill 	hp = &slpque[HASH(chan)];
183187Sbill 	rp->p_link = *hp;
184187Sbill 	*hp = rp;
1854826Swnj 	if (pri > PZERO) {
1864826Swnj 		if (ISSIG(rp)) {
187187Sbill 			if (rp->p_wchan)
188187Sbill 				unsleep(rp);
18933Sbill 			rp->p_stat = SRUN;
190131Sbill 			(void) spl0();
19133Sbill 			goto psig;
19233Sbill 		}
193187Sbill 		if (rp->p_wchan == 0)
194187Sbill 			goto out;
195187Sbill 		rp->p_stat = SSLEEP;
196131Sbill 		(void) spl0();
1978033Sroot 		u.u_ru.ru_nvcsw++;
19833Sbill 		swtch();
1994826Swnj 		if (ISSIG(rp))
20033Sbill 			goto psig;
20133Sbill 	} else {
202207Sbill 		rp->p_stat = SSLEEP;
203131Sbill 		(void) spl0();
2048033Sroot 		u.u_ru.ru_nvcsw++;
20533Sbill 		swtch();
20633Sbill 	}
207187Sbill out:
20833Sbill 	splx(s);
20933Sbill 	return;
21033Sbill 
21133Sbill 	/*
21233Sbill 	 * If priority was low (>PZERO) and
2134826Swnj 	 * there has been a signal, execute non-local goto through
2144826Swnj 	 * u.u_qsav, aborting the system call in progress (see trap.c)
2154826Swnj 	 * (or finishing a tsleep, see below)
21633Sbill 	 */
21733Sbill psig:
21833Sbill 	longjmp(u.u_qsav);
21933Sbill 	/*NOTREACHED*/
22033Sbill }
22133Sbill 
22233Sbill /*
2238033Sroot  * Sleep on chan at pri for at most a specified amount of time.
2248033Sroot  * Return (TS_OK,TS_TIME,TS_SIG) on (normal,timeout,signal) condition.
225100Sbill  */
2268033Sroot tsleep(chan, pri, tvp)
2274826Swnj 	caddr_t chan;
2288033Sroot 	int pri;
2298033Sroot 	struct timeval *tvp;
230100Sbill {
2318033Sroot 	register struct proc *p = u.u_procp;
2328033Sroot 	int s, rval;
233100Sbill 
2348033Sroot 	s = spl7();
235*8102Sroot 	if (timercmp(tvp, &p->p_realtimer.it_value, >)) {
2368033Sroot 		/* alarm will occur first! */
237100Sbill 		sleep(chan, pri);
2388033Sroot 		rval = TS_OK;		/* almost NOTREACHED modulo fuzz */
2398033Sroot 	} else {
2408033Sroot 		label_t lqsav;
2418033Sroot 
2428033Sroot 		bcopy((caddr_t)u.u_qsav, (caddr_t)lqsav, sizeof (label_t));
2438033Sroot 		p->p_seltimer = *tvp;
2448033Sroot 		if (setjmp(u.u_qsav))
2458033Sroot 			rval = TS_SIG;
2468033Sroot 		else {
2478033Sroot 			sleep(chan, pri);
248100Sbill 			rval = TS_OK;
2498033Sroot 		}
2508033Sroot 		timerclear(&p->p_seltimer);
2518033Sroot 		bcopy((caddr_t)lqsav, (caddr_t)u.u_qsav, sizeof (label_t));
252100Sbill 	}
2538033Sroot 	splx(s);
2544826Swnj 	return (rval);
255100Sbill }
256100Sbill 
257100Sbill /*
258181Sbill  * Remove a process from its wait queue
259181Sbill  */
260181Sbill unsleep(p)
2614826Swnj 	register struct proc *p;
262181Sbill {
263181Sbill 	register struct proc **hp;
264181Sbill 	register s;
265181Sbill 
266181Sbill 	s = spl6();
267181Sbill 	if (p->p_wchan) {
268181Sbill 		hp = &slpque[HASH(p->p_wchan)];
269181Sbill 		while (*hp != p)
270181Sbill 			hp = &(*hp)->p_link;
271181Sbill 		*hp = p->p_link;
272181Sbill 		p->p_wchan = 0;
273181Sbill 	}
274181Sbill 	splx(s);
275181Sbill }
276181Sbill 
277181Sbill /*
27833Sbill  * Wake up all processes sleeping on chan.
27933Sbill  */
28033Sbill wakeup(chan)
2814826Swnj 	register caddr_t chan;
28233Sbill {
283187Sbill 	register struct proc *p, **q, **h;
28433Sbill 	int s;
28533Sbill 
28633Sbill 	s = spl6();
287187Sbill 	h = &slpque[HASH(chan)];
28833Sbill restart:
289187Sbill 	for (q = h; p = *q; ) {
290181Sbill 		if (p->p_rlink || p->p_stat != SSLEEP && p->p_stat != SSTOP)
29133Sbill 			panic("wakeup");
292207Sbill 		if (p->p_wchan==chan) {
29333Sbill 			p->p_wchan = 0;
294187Sbill 			*q = p->p_link;
29533Sbill 			p->p_slptime = 0;
296181Sbill 			if (p->p_stat == SSLEEP) {
297181Sbill 				/* OPTIMIZED INLINE EXPANSION OF setrun(p) */
298181Sbill 				p->p_stat = SRUN;
2992702Swnj 				if (p->p_flag & SLOAD)
300181Sbill 					setrq(p);
3014826Swnj 				if (p->p_pri < curpri) {
302181Sbill 					runrun++;
3032443Swnj 					aston();
3042443Swnj 				}
3053545Swnj 				if ((p->p_flag&SLOAD) == 0) {
3063545Swnj 					if (runout != 0) {
3073545Swnj 						runout = 0;
3083545Swnj 						wakeup((caddr_t)&runout);
3093545Swnj 					}
3103545Swnj 					wantin++;
311181Sbill 				}
312181Sbill 				/* END INLINE EXPANSION */
313187Sbill 				goto restart;
31433Sbill 			}
315187Sbill 		} else
316187Sbill 			q = &p->p_link;
31733Sbill 	}
31833Sbill 	splx(s);
31933Sbill }
32033Sbill 
32133Sbill /*
32233Sbill  * Initialize the (doubly-linked) run queues
32333Sbill  * to be empty.
32433Sbill  */
32533Sbill rqinit()
32633Sbill {
32733Sbill 	register int i;
32833Sbill 
32933Sbill 	for (i = 0; i < NQS; i++)
33033Sbill 		qs[i].ph_link = qs[i].ph_rlink = (struct proc *)&qs[i];
33133Sbill }
33233Sbill 
33333Sbill /*
33433Sbill  * Set the process running;
33533Sbill  * arrange for it to be swapped in if necessary.
33633Sbill  */
33733Sbill setrun(p)
3384826Swnj 	register struct proc *p;
33933Sbill {
3404826Swnj 	register int s;
34133Sbill 
34233Sbill 	s = spl6();
34333Sbill 	switch (p->p_stat) {
34433Sbill 
34533Sbill 	case 0:
34633Sbill 	case SWAIT:
34733Sbill 	case SRUN:
34833Sbill 	case SZOMB:
34933Sbill 	default:
35033Sbill 		panic("setrun");
35133Sbill 
352207Sbill 	case SSTOP:
35333Sbill 	case SSLEEP:
354181Sbill 		unsleep(p);		/* e.g. when sending signals */
35533Sbill 		break;
35633Sbill 
35733Sbill 	case SIDL:
35833Sbill 		break;
35933Sbill 	}
36033Sbill 	p->p_stat = SRUN;
36133Sbill 	if (p->p_flag & SLOAD)
36233Sbill 		setrq(p);
36333Sbill 	splx(s);
3644826Swnj 	if (p->p_pri < curpri) {
36533Sbill 		runrun++;
3662443Swnj 		aston();
3672443Swnj 	}
3683545Swnj 	if ((p->p_flag&SLOAD) == 0) {
3694826Swnj 		if (runout != 0) {
3703545Swnj 			runout = 0;
3713545Swnj 			wakeup((caddr_t)&runout);
3723545Swnj 		}
3733545Swnj 		wantin++;
37433Sbill 	}
37533Sbill }
37633Sbill 
37733Sbill /*
37833Sbill  * Set user priority.
37933Sbill  * The rescheduling flag (runrun)
38033Sbill  * is set if the priority is better
38133Sbill  * than the currently running process.
38233Sbill  */
38333Sbill setpri(pp)
3844826Swnj 	register struct proc *pp;
38533Sbill {
3864826Swnj 	register int p;
38733Sbill 
3883875Swnj 	p = (pp->p_cpu & 0377)/4;
3891543Sbill 	p += PUSER + 2*(pp->p_nice - NZERO);
3903530Swnj 	if (pp->p_rssize > pp->p_maxrss && freemem < desfree)
3913530Swnj 		p += 2*4;	/* effectively, nice(4) */
3924826Swnj 	if (p > 127)
39333Sbill 		p = 127;
3944826Swnj 	if (p < curpri) {
39533Sbill 		runrun++;
3962453Swnj 		aston();
3972453Swnj 	}
39833Sbill 	pp->p_usrpri = p;
3994826Swnj 	return (p);
40033Sbill }
401