xref: /csrg-svn/sys/kern/kern_synch.c (revision 8624)
1 /*	kern_synch.c	4.23	82/10/17	*/
2 
3 #include "../h/param.h"
4 #include "../h/systm.h"
5 #include "../h/dir.h"
6 #include "../h/user.h"
7 #include "../h/proc.h"
8 #include "../h/file.h"
9 #include "../h/inode.h"
10 #include "../h/vm.h"
11 #include "../h/pte.h"
12 #ifdef MUSH
13 #include "../h/quota.h"
14 #include "../h/share.h"
15 #endif
16 #include "../h/kernel.h"
17 #include "../h/buf.h"
18 #include "../vax/mtpr.h"	/* XXX */
19 
20 /*
21  * Force switch among equal priority processes every 100ms.
22  */
23 roundrobin()
24 {
25 
26 	runrun++;
27 	aston();
28 	timeout(roundrobin, (caddr_t)0, hz / 10);
29 }
30 
31 /* constants to digital decay and forget 90% of usage in 5*loadav time */
32 #undef ave
33 #define	ave(a,b) ((int)(((int)(a*b))/(b+1)))
34 int	nrscale = 2;
35 double	avenrun[];
36 double	ccpu = 0.95122942450071400909;		/* exp(-1/20) */
37 
38 /*
39  * Recompute process priorities, once a second
40  */
41 schedcpu()
42 {
43 	register struct proc *p;
44 	register int s, a;
45 
46 	wakeup((caddr_t)&lbolt);
47 	for (p = proc; p < procNPROC; p++) if (p->p_stat && p->p_stat!=SZOMB) {
48 #ifdef MUSH
49 		if (p->p_quota->q_uid)
50 			p->p_quota->q_cost +=
51 			    shconsts.sc_click * p->p_rssize;
52 #endif
53 		if (p->p_time != 127)
54 			p->p_time++;
55 		if (p->p_stat==SSLEEP || p->p_stat==SSTOP)
56 			if (p->p_slptime != 127)
57 				p->p_slptime++;
58 		if (p->p_flag&SLOAD)
59 			p->p_pctcpu = ccpu * p->p_pctcpu +
60 			    (1.0 - ccpu) * (p->p_cpticks/(float)hz);
61 		p->p_cpticks = 0;
62 #ifdef MUSH
63 		a = ave((p->p_cpu & 0377), avenrun[0]*nrscale) +
64 		     p->p_nice - NZERO + p->p_quota->q_nice;
65 #else
66 		a = ave((p->p_cpu & 0377), avenrun[0]*nrscale) +
67 		     p->p_nice - NZERO;
68 #endif
69 		if (a < 0)
70 			a = 0;
71 		if (a > 255)
72 			a = 255;
73 		p->p_cpu = a;
74 		(void) setpri(p);
75 		s = spl6();	/* prevent state changes */
76 		if (p->p_pri >= PUSER) {
77 			if ((p != u.u_procp || noproc) &&
78 			    p->p_stat == SRUN &&
79 			    (p->p_flag & SLOAD) &&
80 			    p->p_pri != p->p_usrpri) {
81 				remrq(p);
82 				p->p_pri = p->p_usrpri;
83 				setrq(p);
84 			} else
85 				p->p_pri = p->p_usrpri;
86 		}
87 		splx(s);
88 	}
89 	vmmeter();
90 	if (runin!=0) {
91 		runin = 0;
92 		wakeup((caddr_t)&runin);
93 	}
94 	if (bclnlist != NULL)
95 		wakeup((caddr_t)&proc[2]);
96 	timeout(schedcpu, (caddr_t)0, hz);
97 }
98 
99 #define SQSIZE 0100	/* Must be power of 2 */
100 #define HASH(x)	(( (int) x >> 5) & (SQSIZE-1))
101 struct proc *slpque[SQSIZE];
102 
103 /*
104  * Give up the processor till a wakeup occurs
105  * on chan, at which time the process
106  * enters the scheduling queue at priority pri.
107  * The most important effect of pri is that when
108  * pri<=PZERO a signal cannot disturb the sleep;
109  * if pri>PZERO signals will be processed.
110  * Callers of this routine must be prepared for
111  * premature return, and check that the reason for
112  * sleeping has gone away.
113  */
114 sleep(chan, pri)
115 	caddr_t chan;
116 	int pri;
117 {
118 	register struct proc *rp, **hp;
119 	register s;
120 
121 	rp = u.u_procp;
122 	s = spl6();
123 	if (chan==0 || rp->p_stat != SRUN || rp->p_rlink)
124 		panic("sleep");
125 	rp->p_wchan = chan;
126 	rp->p_slptime = 0;
127 	rp->p_pri = pri;
128 	hp = &slpque[HASH(chan)];
129 	rp->p_link = *hp;
130 	*hp = rp;
131 	if (pri > PZERO) {
132 		if (ISSIG(rp)) {
133 			if (rp->p_wchan)
134 				unsleep(rp);
135 			rp->p_stat = SRUN;
136 			(void) spl0();
137 			goto psig;
138 		}
139 		if (rp->p_wchan == 0)
140 			goto out;
141 		rp->p_stat = SSLEEP;
142 		(void) spl0();
143 		u.u_ru.ru_nvcsw++;
144 		swtch();
145 		if (ISSIG(rp))
146 			goto psig;
147 	} else {
148 		rp->p_stat = SSLEEP;
149 		(void) spl0();
150 		u.u_ru.ru_nvcsw++;
151 		swtch();
152 	}
153 out:
154 	splx(s);
155 	return;
156 
157 	/*
158 	 * If priority was low (>PZERO) and
159 	 * there has been a signal, execute non-local goto through
160 	 * u.u_qsave, aborting the system call in progress (see trap.c)
161 	 * (or finishing a tsleep, see below)
162 	 */
163 psig:
164 	longjmp(&u.u_qsave);
165 	/*NOTREACHED*/
166 }
167 
168 /*
169  * Remove a process from its wait queue
170  */
171 unsleep(p)
172 	register struct proc *p;
173 {
174 	register struct proc **hp;
175 	register s;
176 
177 	s = spl6();
178 	if (p->p_wchan) {
179 		hp = &slpque[HASH(p->p_wchan)];
180 		while (*hp != p)
181 			hp = &(*hp)->p_link;
182 		*hp = p->p_link;
183 		p->p_wchan = 0;
184 	}
185 	splx(s);
186 }
187 
188 /*
189  * Wake up all processes sleeping on chan.
190  */
191 wakeup(chan)
192 	register caddr_t chan;
193 {
194 	register struct proc *p, **q, **h;
195 	int s;
196 
197 	s = spl6();
198 	h = &slpque[HASH(chan)];
199 restart:
200 	for (q = h; p = *q; ) {
201 		if (p->p_rlink || p->p_stat != SSLEEP && p->p_stat != SSTOP)
202 			panic("wakeup");
203 		if (p->p_wchan==chan) {
204 			p->p_wchan = 0;
205 			*q = p->p_link;
206 			p->p_slptime = 0;
207 			if (p->p_stat == SSLEEP) {
208 				/* OPTIMIZED INLINE EXPANSION OF setrun(p) */
209 				p->p_stat = SRUN;
210 				if (p->p_flag & SLOAD)
211 					setrq(p);
212 				if (p->p_pri < curpri) {
213 					runrun++;
214 					aston();
215 				}
216 				if ((p->p_flag&SLOAD) == 0) {
217 					if (runout != 0) {
218 						runout = 0;
219 						wakeup((caddr_t)&runout);
220 					}
221 					wantin++;
222 				}
223 				/* END INLINE EXPANSION */
224 				goto restart;
225 			}
226 		} else
227 			q = &p->p_link;
228 	}
229 	splx(s);
230 }
231 
232 /*
233  * Initialize the (doubly-linked) run queues
234  * to be empty.
235  */
236 rqinit()
237 {
238 	register int i;
239 
240 	for (i = 0; i < NQS; i++)
241 		qs[i].ph_link = qs[i].ph_rlink = (struct proc *)&qs[i];
242 }
243 
244 /*
245  * Set the process running;
246  * arrange for it to be swapped in if necessary.
247  */
248 setrun(p)
249 	register struct proc *p;
250 {
251 	register int s;
252 
253 	s = spl6();
254 	switch (p->p_stat) {
255 
256 	case 0:
257 	case SWAIT:
258 	case SRUN:
259 	case SZOMB:
260 	default:
261 		panic("setrun");
262 
263 	case SSTOP:
264 	case SSLEEP:
265 		unsleep(p);		/* e.g. when sending signals */
266 		break;
267 
268 	case SIDL:
269 		break;
270 	}
271 	p->p_stat = SRUN;
272 	if (p->p_flag & SLOAD)
273 		setrq(p);
274 	splx(s);
275 	if (p->p_pri < curpri) {
276 		runrun++;
277 		aston();
278 	}
279 	if ((p->p_flag&SLOAD) == 0) {
280 		if (runout != 0) {
281 			runout = 0;
282 			wakeup((caddr_t)&runout);
283 		}
284 		wantin++;
285 	}
286 }
287 
288 /*
289  * Set user priority.
290  * The rescheduling flag (runrun)
291  * is set if the priority is better
292  * than the currently running process.
293  */
294 setpri(pp)
295 	register struct proc *pp;
296 {
297 	register int p;
298 
299 	p = (pp->p_cpu & 0377)/4;
300 	p += PUSER + 2*(pp->p_nice - NZERO);
301 	if (pp->p_rssize > pp->p_maxrss && freemem < desfree)
302 		p += 2*4;	/* effectively, nice(4) */
303 	if (p > 127)
304 		p = 127;
305 	if (p < curpri) {
306 		runrun++;
307 		aston();
308 	}
309 	pp->p_usrpri = p;
310 	return (p);
311 }
312