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