xref: /csrg-svn/sys/kern/kern_synch.c (revision 17541)
1*17541Skarels /*	kern_synch.c	6.5	84/12/20	*/
233Sbill 
39756Ssam #include "../machine/pte.h"
49756Ssam 
517093Sbloom #include "param.h"
617093Sbloom #include "systm.h"
717093Sbloom #include "dir.h"
817093Sbloom #include "user.h"
917093Sbloom #include "proc.h"
1017093Sbloom #include "file.h"
1117093Sbloom #include "inode.h"
1217093Sbloom #include "vm.h"
1317093Sbloom #include "kernel.h"
1417093Sbloom #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 
30*17541Skarels /* fraction for digital decay to forget 90% of usage in 5*loadav sec */
31*17541Skarels #define	filter(loadav) ((2 * (loadav)) / (2 * (loadav) + 1))
32*17541Skarels 
338102Sroot double	ccpu = 0.95122942450071400909;		/* exp(-1/20) */
348102Sroot 
358102Sroot /*
368102Sroot  * Recompute process priorities, once a second
378102Sroot  */
388102Sroot schedcpu()
398102Sroot {
4016795Skarels 	register double ccpu1 = (1.0 - ccpu) / (double)hz;
418102Sroot 	register struct proc *p;
428102Sroot 	register int s, a;
43*17541Skarels 	float scale = filter(avenrun[0]);
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++;
52*17541Skarels 		/*
53*17541Skarels 		 * If the process has slept the entire second,
54*17541Skarels 		 * stop recalculating its priority until it wakes up.
55*17541Skarels 		 */
56*17541Skarels 		if (p->p_slptime > 1) {
57*17541Skarels 			p->p_pctcpu *= ccpu;
58*17541Skarels 			continue;
59*17541Skarels 		}
60*17541Skarels 		/*
61*17541Skarels 		 * p_pctcpu is only for ps.
62*17541Skarels 		 */
63*17541Skarels 		p->p_pctcpu = ccpu * p->p_pctcpu + ccpu1 * p->p_cpticks;
648102Sroot 		p->p_cpticks = 0;
65*17541Skarels 		a = (int) (scale * (p->p_cpu & 0377)) + p->p_nice;
668102Sroot 		if (a < 0)
678102Sroot 			a = 0;
688102Sroot 		if (a > 255)
698102Sroot 			a = 255;
708102Sroot 		p->p_cpu = a;
718102Sroot 		(void) setpri(p);
72*17541Skarels 		s = splhigh();	/* prevent state changes */
738102Sroot 		if (p->p_pri >= PUSER) {
7416795Skarels #define	PPQ	(128 / NQS)
758102Sroot 			if ((p != u.u_procp || noproc) &&
768102Sroot 			    p->p_stat == SRUN &&
778102Sroot 			    (p->p_flag & SLOAD) &&
7816795Skarels 			    (p->p_pri / PPQ) != (p->p_usrpri / PPQ)) {
798102Sroot 				remrq(p);
808102Sroot 				p->p_pri = p->p_usrpri;
818102Sroot 				setrq(p);
828102Sroot 			} else
838102Sroot 				p->p_pri = p->p_usrpri;
848102Sroot 		}
858102Sroot 		splx(s);
868102Sroot 	}
878102Sroot 	vmmeter();
888102Sroot 	if (runin!=0) {
898102Sroot 		runin = 0;
908102Sroot 		wakeup((caddr_t)&runin);
918102Sroot 	}
928102Sroot 	if (bclnlist != NULL)
938102Sroot 		wakeup((caddr_t)&proc[2]);
948624Sroot 	timeout(schedcpu, (caddr_t)0, hz);
958102Sroot }
968102Sroot 
97*17541Skarels /*
98*17541Skarels  * Recalculate the priority of a process after it has slept for a while.
99*17541Skarels  */
100*17541Skarels updatepri(p)
101*17541Skarels 	register struct proc *p;
102*17541Skarels {
103*17541Skarels 	register int a = p->p_cpu & 0377;
104*17541Skarels 	float scale = filter(avenrun[0]);
105*17541Skarels 
106*17541Skarels 	p->p_slptime--;		/* the first time was done in schedcpu */
107*17541Skarels 	while (a && --p->p_slptime)
108*17541Skarels 		a = (int) (scale * a) /* + p->p_nice */;
109*17541Skarels 	if (a < 0)
110*17541Skarels 		a = 0;
111*17541Skarels 	if (a > 255)
112*17541Skarels 		a = 255;
113*17541Skarels 	p->p_cpu = a;
114*17541Skarels 	(void) setpri(p);
115*17541Skarels }
116*17541Skarels 
11733Sbill #define SQSIZE 0100	/* Must be power of 2 */
11833Sbill #define HASH(x)	(( (int) x >> 5) & (SQSIZE-1))
11933Sbill struct proc *slpque[SQSIZE];
12033Sbill 
12133Sbill /*
12233Sbill  * Give up the processor till a wakeup occurs
12333Sbill  * on chan, at which time the process
12433Sbill  * enters the scheduling queue at priority pri.
12533Sbill  * The most important effect of pri is that when
12633Sbill  * pri<=PZERO a signal cannot disturb the sleep;
12733Sbill  * if pri>PZERO signals will be processed.
12833Sbill  * Callers of this routine must be prepared for
12933Sbill  * premature return, and check that the reason for
13033Sbill  * sleeping has gone away.
13133Sbill  */
13233Sbill sleep(chan, pri)
1338033Sroot 	caddr_t chan;
1348033Sroot 	int pri;
13533Sbill {
136187Sbill 	register struct proc *rp, **hp;
137207Sbill 	register s;
13833Sbill 
13933Sbill 	rp = u.u_procp;
140*17541Skarels 	s = splhigh();
141*17541Skarels 	if ((chan==0 || rp->p_stat != SRUN || rp->p_rlink) &&
142*17541Skarels 	    panicstr == (char *) NULL)
14333Sbill 		panic("sleep");
14433Sbill 	rp->p_wchan = chan;
14533Sbill 	rp->p_slptime = 0;
14633Sbill 	rp->p_pri = pri;
147187Sbill 	hp = &slpque[HASH(chan)];
148187Sbill 	rp->p_link = *hp;
149187Sbill 	*hp = rp;
1504826Swnj 	if (pri > PZERO) {
1514826Swnj 		if (ISSIG(rp)) {
152187Sbill 			if (rp->p_wchan)
153187Sbill 				unsleep(rp);
15433Sbill 			rp->p_stat = SRUN;
155131Sbill 			(void) spl0();
15633Sbill 			goto psig;
15733Sbill 		}
158187Sbill 		if (rp->p_wchan == 0)
159187Sbill 			goto out;
160187Sbill 		rp->p_stat = SSLEEP;
161131Sbill 		(void) spl0();
1628033Sroot 		u.u_ru.ru_nvcsw++;
16333Sbill 		swtch();
1644826Swnj 		if (ISSIG(rp))
16533Sbill 			goto psig;
16633Sbill 	} else {
167207Sbill 		rp->p_stat = SSLEEP;
168131Sbill 		(void) spl0();
1698033Sroot 		u.u_ru.ru_nvcsw++;
17033Sbill 		swtch();
17133Sbill 	}
17216795Skarels 	curpri = rp->p_usrpri;
173187Sbill out:
17433Sbill 	splx(s);
17533Sbill 	return;
17633Sbill 
17733Sbill 	/*
17833Sbill 	 * If priority was low (>PZERO) and
1794826Swnj 	 * there has been a signal, execute non-local goto through
1808113Sroot 	 * u.u_qsave, aborting the system call in progress (see trap.c)
18133Sbill 	 */
18233Sbill psig:
1838113Sroot 	longjmp(&u.u_qsave);
18433Sbill 	/*NOTREACHED*/
18533Sbill }
18633Sbill 
18733Sbill /*
188181Sbill  * Remove a process from its wait queue
189181Sbill  */
190181Sbill unsleep(p)
1914826Swnj 	register struct proc *p;
192181Sbill {
193181Sbill 	register struct proc **hp;
194181Sbill 	register s;
195181Sbill 
196*17541Skarels 	s = splhigh();
197181Sbill 	if (p->p_wchan) {
198181Sbill 		hp = &slpque[HASH(p->p_wchan)];
199181Sbill 		while (*hp != p)
200181Sbill 			hp = &(*hp)->p_link;
201181Sbill 		*hp = p->p_link;
202181Sbill 		p->p_wchan = 0;
203181Sbill 	}
204181Sbill 	splx(s);
205181Sbill }
206181Sbill 
207181Sbill /*
20833Sbill  * Wake up all processes sleeping on chan.
20933Sbill  */
21033Sbill wakeup(chan)
2114826Swnj 	register caddr_t chan;
21233Sbill {
213187Sbill 	register struct proc *p, **q, **h;
21433Sbill 	int s;
21533Sbill 
216*17541Skarels 	s = splhigh();
217187Sbill 	h = &slpque[HASH(chan)];
21833Sbill restart:
219187Sbill 	for (q = h; p = *q; ) {
220181Sbill 		if (p->p_rlink || p->p_stat != SSLEEP && p->p_stat != SSTOP)
22133Sbill 			panic("wakeup");
222207Sbill 		if (p->p_wchan==chan) {
22333Sbill 			p->p_wchan = 0;
224187Sbill 			*q = p->p_link;
225*17541Skarels 			if (p->p_slptime > 1)
226*17541Skarels 				updatepri(p);
22733Sbill 			p->p_slptime = 0;
228181Sbill 			if (p->p_stat == SSLEEP) {
229181Sbill 				/* OPTIMIZED INLINE EXPANSION OF setrun(p) */
230181Sbill 				p->p_stat = SRUN;
2312702Swnj 				if (p->p_flag & SLOAD)
232181Sbill 					setrq(p);
23316795Skarels 				/*
23416795Skarels 				 * Since curpri is a usrpri,
23516795Skarels 				 * p->p_pri is always better than curpri.
23616795Skarels 				 */
23716795Skarels 				runrun++;
23816795Skarels 				aston();
2393545Swnj 				if ((p->p_flag&SLOAD) == 0) {
2403545Swnj 					if (runout != 0) {
2413545Swnj 						runout = 0;
2423545Swnj 						wakeup((caddr_t)&runout);
2433545Swnj 					}
2443545Swnj 					wantin++;
245181Sbill 				}
246181Sbill 				/* END INLINE EXPANSION */
247187Sbill 				goto restart;
24833Sbill 			}
249187Sbill 		} else
250187Sbill 			q = &p->p_link;
25133Sbill 	}
25233Sbill 	splx(s);
25333Sbill }
25433Sbill 
25533Sbill /*
25633Sbill  * Initialize the (doubly-linked) run queues
25733Sbill  * to be empty.
25833Sbill  */
25933Sbill rqinit()
26033Sbill {
26133Sbill 	register int i;
26233Sbill 
26333Sbill 	for (i = 0; i < NQS; i++)
26433Sbill 		qs[i].ph_link = qs[i].ph_rlink = (struct proc *)&qs[i];
26533Sbill }
26633Sbill 
26733Sbill /*
26833Sbill  * Set the process running;
26933Sbill  * arrange for it to be swapped in if necessary.
27033Sbill  */
27133Sbill setrun(p)
2724826Swnj 	register struct proc *p;
27333Sbill {
2744826Swnj 	register int s;
27533Sbill 
276*17541Skarels 	s = splhigh();
27733Sbill 	switch (p->p_stat) {
27833Sbill 
27933Sbill 	case 0:
28033Sbill 	case SWAIT:
28133Sbill 	case SRUN:
28233Sbill 	case SZOMB:
28333Sbill 	default:
28433Sbill 		panic("setrun");
28533Sbill 
286207Sbill 	case SSTOP:
28733Sbill 	case SSLEEP:
288181Sbill 		unsleep(p);		/* e.g. when sending signals */
28933Sbill 		break;
29033Sbill 
29133Sbill 	case SIDL:
29233Sbill 		break;
29333Sbill 	}
294*17541Skarels 	if (p->p_slptime > 1)
295*17541Skarels 		updatepri(p);
29633Sbill 	p->p_stat = SRUN;
29733Sbill 	if (p->p_flag & SLOAD)
29833Sbill 		setrq(p);
29933Sbill 	splx(s);
3004826Swnj 	if (p->p_pri < curpri) {
30133Sbill 		runrun++;
3022443Swnj 		aston();
3032443Swnj 	}
3043545Swnj 	if ((p->p_flag&SLOAD) == 0) {
3054826Swnj 		if (runout != 0) {
3063545Swnj 			runout = 0;
3073545Swnj 			wakeup((caddr_t)&runout);
3083545Swnj 		}
3093545Swnj 		wantin++;
31033Sbill 	}
31133Sbill }
31233Sbill 
31333Sbill /*
31433Sbill  * Set user priority.
31533Sbill  * The rescheduling flag (runrun)
31633Sbill  * is set if the priority is better
31733Sbill  * than the currently running process.
31833Sbill  */
31933Sbill setpri(pp)
3204826Swnj 	register struct proc *pp;
32133Sbill {
3224826Swnj 	register int p;
32333Sbill 
3243875Swnj 	p = (pp->p_cpu & 0377)/4;
325*17541Skarels 	p += PUSER + 2 * pp->p_nice;
3263530Swnj 	if (pp->p_rssize > pp->p_maxrss && freemem < desfree)
3273530Swnj 		p += 2*4;	/* effectively, nice(4) */
3284826Swnj 	if (p > 127)
32933Sbill 		p = 127;
3304826Swnj 	if (p < curpri) {
33133Sbill 		runrun++;
3322453Swnj 		aston();
3332453Swnj 	}
33433Sbill 	pp->p_usrpri = p;
3354826Swnj 	return (p);
33633Sbill }
337