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