more timer stuff
[unix-history] / usr / src / sys / kern / kern_synch.c
CommitLineData
1edb1cf8 1/* kern_synch.c 4.20 82/09/06 */
a379cce8
BJ
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"
87d0f32e 12#include "../h/inline.h"
534d9295 13#include "../h/mtpr.h"
1edb1cf8 14#ifdef MUSH
9c25520d 15#include "../h/quota.h"
1edb1cf8
BJ
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 */
24roundrobin()
25{
26
27 runrun++;
28 aston();
29 timeout(roundrobin, 0, hz / 10);
30}
31
32/*
33 * The digital decay cpu usage priority assignment is scaled to run in
34 * time as expanded by the 1 minute load average. Each second we
35 * multiply the the previous cpu usage estimate by
36 * nrscale*avenrun[0]
37 * The following relates the load average to the period over which
38 * cpu usage is 90% forgotten:
39 * loadav 1 5 seconds
40 * loadav 5 24 seconds
41 * loadav 10 47 seconds
42 * loadav 20 93 seconds
43 * This is a great improvement on the previous algorithm which
44 * decayed the priorities by a constant, and decayed away all knowledge
45 * of previous activity in about 20 seconds. Under heavy load,
46 * the previous algorithm degenerated to round-robin with poor response
47 * time when there was a high load average.
48 */
49#undef ave
50#define ave(a,b) ((int)(((int)(a*b))/(b+1)))
51int nrscale = 2;
52double avenrun[];
53
54/*
55 * Constant for decay filter for cpu usage field
56 * in process table (used by ps au).
57 */
58double ccpu = 0.95122942450071400909; /* exp(-1/20) */
59
60#ifdef MELB
61/*
62 * Automatic niceness rate & max constants
63 */
64#define MAXNICE (8 + NZERO) /* maximum auto nice value */
65#define NFACT (40 * hz) /* nice++ every 40 secs cpu+sys time */
66#endif
67
68/*
69 * Recompute process priorities, once a second
70 */
71schedcpu()
72{
73 register struct proc *p;
74 register int s, a;
75
76 s = spl6(); time.tv_sec += lbolt / hz; lbolt %= hz; splx(s);
77 wakeup((caddr_t)&lbolt);
78
79 for (p = proc; p < procNPROC; p++) if (p->p_stat && p->p_stat!=SZOMB) {
80#ifdef MUSH
81 /*
82 * Charge process for memory in use
83 */
84 if (p->p_quota->q_uid)
85 p->p_quota->q_cost +=
86 shconsts.sc_click * p->p_rssize;
87#endif
88 if (p->p_time != 127)
89 p->p_time++;
90 if (timerisset(&p->p_seltimer) &&
91 --p->p_seltimer.tv_sec <= 0) {
92 timerclear(&p->p_seltimer);
93 s = spl6();
94 switch (p->p_stat) {
95
96 case SSLEEP:
97 setrun(p);
98 break;
99
100 case SSTOP:
101 unsleep(p);
102 break;
103 }
104 splx(s);
105 }
106 if (timerisset(&p->p_realtimer.it_value) &&
107 itimerdecr(&p->p_realtimer, 1000000) == 0)
108 psignal(p, SIGALRM);
109 if (p->p_stat==SSLEEP || p->p_stat==SSTOP)
110 if (p->p_slptime != 127)
111 p->p_slptime++;
112 if (p->p_flag&SLOAD)
113 p->p_pctcpu = ccpu * p->p_pctcpu +
114 (1.0 - ccpu) * (p->p_cpticks/(float)hz);
115 p->p_cpticks = 0;
116#ifdef MUSH
117 a = ave((p->p_cpu & 0377), avenrun[0]*nrscale) +
118 p->p_nice - NZERO + p->p_quota->q_nice;
119#else
120 a = ave((p->p_cpu & 0377), avenrun[0]*nrscale) +
121 p->p_nice - NZERO;
122#endif
123 if (a < 0)
124 a = 0;
125 if (a > 255)
126 a = 255;
127 p->p_cpu = a;
128 (void) setpri(p);
129 s = spl6(); /* prevent state changes */
130 if (p->p_pri >= PUSER) {
131 if ((p != u.u_procp || noproc) &&
132 p->p_stat == SRUN &&
133 (p->p_flag & SLOAD) &&
134 p->p_pri != p->p_usrpri) {
135 remrq(p);
136 p->p_pri = p->p_usrpri;
137 setrq(p);
138 } else
139 p->p_pri = p->p_usrpri;
140 }
141 splx(s);
142 }
143 vmmeter();
144 if (runin!=0) {
145 runin = 0;
146 wakeup((caddr_t)&runin);
147 }
148 if (bclnlist != NULL)
149 wakeup((caddr_t)&proc[2]);
150 timeout(schedcpu, 0, hz);
151}
a379cce8
BJ
152
153#define SQSIZE 0100 /* Must be power of 2 */
154#define HASH(x) (( (int) x >> 5) & (SQSIZE-1))
155struct proc *slpque[SQSIZE];
156
157/*
158 * Give up the processor till a wakeup occurs
159 * on chan, at which time the process
160 * enters the scheduling queue at priority pri.
161 * The most important effect of pri is that when
162 * pri<=PZERO a signal cannot disturb the sleep;
163 * if pri>PZERO signals will be processed.
164 * Callers of this routine must be prepared for
165 * premature return, and check that the reason for
166 * sleeping has gone away.
167 */
168sleep(chan, pri)
bd76c595
BJ
169 caddr_t chan;
170 int pri;
a379cce8 171{
e5df4be8 172 register struct proc *rp, **hp;
6fdc0335 173 register s;
a379cce8
BJ
174
175 rp = u.u_procp;
176 s = spl6();
177 if (chan==0 || rp->p_stat != SRUN || rp->p_rlink)
178 panic("sleep");
a379cce8
BJ
179 rp->p_wchan = chan;
180 rp->p_slptime = 0;
181 rp->p_pri = pri;
e5df4be8
BJ
182 hp = &slpque[HASH(chan)];
183 rp->p_link = *hp;
184 *hp = rp;
18a4549b
BJ
185 if (pri > PZERO) {
186 if (ISSIG(rp)) {
e5df4be8
BJ
187 if (rp->p_wchan)
188 unsleep(rp);
a379cce8 189 rp->p_stat = SRUN;
81263dba 190 (void) spl0();
a379cce8
BJ
191 goto psig;
192 }
e5df4be8
BJ
193 if (rp->p_wchan == 0)
194 goto out;
195 rp->p_stat = SSLEEP;
81263dba 196 (void) spl0();
bd76c595 197 u.u_ru.ru_nvcsw++;
a379cce8 198 swtch();
18a4549b 199 if (ISSIG(rp))
a379cce8
BJ
200 goto psig;
201 } else {
6fdc0335 202 rp->p_stat = SSLEEP;
81263dba 203 (void) spl0();
bd76c595 204 u.u_ru.ru_nvcsw++;
a379cce8
BJ
205 swtch();
206 }
e5df4be8 207out:
a379cce8
BJ
208 splx(s);
209 return;
210
211 /*
212 * If priority was low (>PZERO) and
18a4549b
BJ
213 * there has been a signal, execute non-local goto through
214 * u.u_qsav, aborting the system call in progress (see trap.c)
215 * (or finishing a tsleep, see below)
a379cce8
BJ
216 */
217psig:
a379cce8 218 longjmp(u.u_qsav);
a379cce8
BJ
219 /*NOTREACHED*/
220}
221
a7bf190d 222/*
bd76c595
BJ
223 * Sleep on chan at pri for at most a specified amount of time.
224 * Return (TS_OK,TS_TIME,TS_SIG) on (normal,timeout,signal) condition.
a7bf190d 225 */
bd76c595 226tsleep(chan, pri, tvp)
18a4549b 227 caddr_t chan;
bd76c595
BJ
228 int pri;
229 struct timeval *tvp;
a7bf190d 230{
bd76c595
BJ
231 register struct proc *p = u.u_procp;
232 int s, rval;
a7bf190d 233
bd76c595 234 s = spl7();
1edb1cf8 235 if (timercmp(tvp, &p->p_realtimer.it_value, >)) {
bd76c595 236 /* alarm will occur first! */
a7bf190d 237 sleep(chan, pri);
bd76c595
BJ
238 rval = TS_OK; /* almost NOTREACHED modulo fuzz */
239 } else {
240 label_t lqsav;
241
242 bcopy((caddr_t)u.u_qsav, (caddr_t)lqsav, sizeof (label_t));
243 p->p_seltimer = *tvp;
244 if (setjmp(u.u_qsav))
245 rval = TS_SIG;
246 else {
247 sleep(chan, pri);
a7bf190d 248 rval = TS_OK;
9c25520d 249 }
bd76c595
BJ
250 timerclear(&p->p_seltimer);
251 bcopy((caddr_t)lqsav, (caddr_t)u.u_qsav, sizeof (label_t));
252 }
253 splx(s);
18a4549b 254 return (rval);
a7bf190d
BJ
255}
256
87d0f32e
BJ
257/*
258 * Remove a process from its wait queue
259 */
260unsleep(p)
18a4549b 261 register struct proc *p;
87d0f32e
BJ
262{
263 register struct proc **hp;
264 register s;
265
266 s = spl6();
267 if (p->p_wchan) {
268 hp = &slpque[HASH(p->p_wchan)];
269 while (*hp != p)
270 hp = &(*hp)->p_link;
271 *hp = p->p_link;
272 p->p_wchan = 0;
273 }
274 splx(s);
275}
276
a379cce8
BJ
277/*
278 * Wake up all processes sleeping on chan.
279 */
280wakeup(chan)
18a4549b 281 register caddr_t chan;
a379cce8 282{
e5df4be8 283 register struct proc *p, **q, **h;
a379cce8
BJ
284 int s;
285
286 s = spl6();
e5df4be8 287 h = &slpque[HASH(chan)];
a379cce8 288restart:
e5df4be8 289 for (q = h; p = *q; ) {
87d0f32e 290 if (p->p_rlink || p->p_stat != SSLEEP && p->p_stat != SSTOP)
a379cce8 291 panic("wakeup");
6fdc0335 292 if (p->p_wchan==chan) {
a379cce8 293 p->p_wchan = 0;
e5df4be8 294 *q = p->p_link;
a379cce8 295 p->p_slptime = 0;
87d0f32e
BJ
296 if (p->p_stat == SSLEEP) {
297 /* OPTIMIZED INLINE EXPANSION OF setrun(p) */
298 p->p_stat = SRUN;
c74c8a79 299 if (p->p_flag & SLOAD)
87d0f32e 300 setrq(p);
18a4549b 301 if (p->p_pri < curpri) {
87d0f32e 302 runrun++;
534d9295
BJ
303 aston();
304 }
7eb2e67e
BJ
305 if ((p->p_flag&SLOAD) == 0) {
306 if (runout != 0) {
307 runout = 0;
308 wakeup((caddr_t)&runout);
309 }
310 wantin++;
87d0f32e
BJ
311 }
312 /* END INLINE EXPANSION */
e5df4be8 313 goto restart;
a379cce8 314 }
e5df4be8
BJ
315 } else
316 q = &p->p_link;
a379cce8
BJ
317 }
318 splx(s);
319}
320
a379cce8
BJ
321/*
322 * Initialize the (doubly-linked) run queues
323 * to be empty.
324 */
325rqinit()
326{
327 register int i;
328
329 for (i = 0; i < NQS; i++)
330 qs[i].ph_link = qs[i].ph_rlink = (struct proc *)&qs[i];
331}
a379cce8
BJ
332
333/*
334 * Set the process running;
335 * arrange for it to be swapped in if necessary.
336 */
337setrun(p)
18a4549b 338 register struct proc *p;
a379cce8 339{
18a4549b 340 register int s;
a379cce8
BJ
341
342 s = spl6();
343 switch (p->p_stat) {
344
345 case 0:
346 case SWAIT:
347 case SRUN:
348 case SZOMB:
349 default:
350 panic("setrun");
351
6fdc0335 352 case SSTOP:
a379cce8 353 case SSLEEP:
87d0f32e 354 unsleep(p); /* e.g. when sending signals */
a379cce8
BJ
355 break;
356
357 case SIDL:
a379cce8
BJ
358 break;
359 }
360 p->p_stat = SRUN;
361 if (p->p_flag & SLOAD)
362 setrq(p);
363 splx(s);
18a4549b 364 if (p->p_pri < curpri) {
a379cce8 365 runrun++;
534d9295
BJ
366 aston();
367 }
7eb2e67e 368 if ((p->p_flag&SLOAD) == 0) {
18a4549b 369 if (runout != 0) {
7eb2e67e
BJ
370 runout = 0;
371 wakeup((caddr_t)&runout);
372 }
373 wantin++;
a379cce8
BJ
374 }
375}
376
377/*
378 * Set user priority.
379 * The rescheduling flag (runrun)
380 * is set if the priority is better
381 * than the currently running process.
382 */
383setpri(pp)
18a4549b 384 register struct proc *pp;
a379cce8 385{
18a4549b 386 register int p;
a379cce8 387
16a64baa 388 p = (pp->p_cpu & 0377)/4;
598563b5 389 p += PUSER + 2*(pp->p_nice - NZERO);
9afea775
BJ
390 if (pp->p_rssize > pp->p_maxrss && freemem < desfree)
391 p += 2*4; /* effectively, nice(4) */
18a4549b 392 if (p > 127)
a379cce8 393 p = 127;
18a4549b 394 if (p < curpri) {
a379cce8 395 runrun++;
a51a6e74
BJ
396 aston();
397 }
a379cce8 398 pp->p_usrpri = p;
18a4549b 399 return (p);
a379cce8 400}