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