added my responsibility for the `cpm' port
[unix-history] / sys / kern / kern_synch.c
CommitLineData
15637ed4
RG
1/*-
2 * Copyright (c) 1982, 1986, 1990 The Regents of the University of California.
3 * Copyright (c) 1991 The Regents of the University of California.
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 3. All advertising materials mentioning features or use of this software
15 * must display the following acknowledgement:
16 * This product includes software developed by the University of
17 * California, Berkeley and its contributors.
18 * 4. Neither the name of the University nor the names of its contributors
19 * may be used to endorse or promote products derived from this software
20 * without specific prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 * SUCH DAMAGE.
33 *
600f7f07 34 * from: @(#)kern_synch.c 7.18 (Berkeley) 6/27/91
097b27e3 35 * $Id: kern_synch.c,v 1.4 1994/02/11 21:14:28 guido Exp $
15637ed4
RG
36 */
37
38#include "param.h"
39#include "systm.h"
40#include "proc.h"
41#include "kernel.h"
42#include "buf.h"
43#include "signalvar.h"
44#include "resourcevar.h"
45
46#include "machine/cpu.h"
47
4c45483e
GW
48static void endtsleep(caddr_t, int);
49
15637ed4
RG
50u_char curpri; /* usrpri of curproc */
51
52/*
53 * Force switch among equal priority processes every 100ms.
54 */
4c45483e
GW
55void
56roundrobin(dummy1, dummy2)
57 caddr_t dummy1;
58 int dummy2;
15637ed4
RG
59{
60
61 need_resched();
62 timeout(roundrobin, (caddr_t)0, hz / 10);
63}
64
65/*
66 * constants for digital decay and forget
67 * 90% of (p_cpu) usage in 5*loadav time
68 * 95% of (p_pctcpu) usage in 60 seconds (load insensitive)
69 * Note that, as ps(1) mentions, this can let percentages
70 * total over 100% (I've seen 137.9% for 3 processes).
71 *
72 * Note that hardclock updates p_cpu and p_cpticks independently.
73 *
74 * We wish to decay away 90% of p_cpu in (5 * loadavg) seconds.
75 * That is, the system wants to compute a value of decay such
76 * that the following for loop:
77 * for (i = 0; i < (5 * loadavg); i++)
78 * p_cpu *= decay;
79 * will compute
80 * p_cpu *= 0.1;
81 * for all values of loadavg:
82 *
83 * Mathematically this loop can be expressed by saying:
84 * decay ** (5 * loadavg) ~= .1
85 *
86 * The system computes decay as:
87 * decay = (2 * loadavg) / (2 * loadavg + 1)
88 *
89 * We wish to prove that the system's computation of decay
90 * will always fulfill the equation:
91 * decay ** (5 * loadavg) ~= .1
92 *
93 * If we compute b as:
94 * b = 2 * loadavg
95 * then
96 * decay = b / (b + 1)
97 *
98 * We now need to prove two things:
99 * 1) Given factor ** (5 * loadavg) ~= .1, prove factor == b/(b+1)
100 * 2) Given b/(b+1) ** power ~= .1, prove power == (5 * loadavg)
101 *
102 * Facts:
103 * For x close to zero, exp(x) =~ 1 + x, since
104 * exp(x) = 0! + x**1/1! + x**2/2! + ... .
105 * therefore exp(-1/b) =~ 1 - (1/b) = (b-1)/b.
106 * For x close to zero, ln(1+x) =~ x, since
107 * ln(1+x) = x - x**2/2 + x**3/3 - ... -1 < x < 1
108 * therefore ln(b/(b+1)) = ln(1 - 1/(b+1)) =~ -1/(b+1).
109 * ln(.1) =~ -2.30
110 *
111 * Proof of (1):
112 * Solve (factor)**(power) =~ .1 given power (5*loadav):
113 * solving for factor,
114 * ln(factor) =~ (-2.30/5*loadav), or
115 * factor =~ exp(-1/((5/2.30)*loadav)) =~ exp(-1/(2*loadav)) =
116 * exp(-1/b) =~ (b-1)/b =~ b/(b+1). QED
117 *
118 * Proof of (2):
119 * Solve (factor)**(power) =~ .1 given factor == (b/(b+1)):
120 * solving for power,
121 * power*ln(b/(b+1)) =~ -2.30, or
122 * power =~ 2.3 * (b + 1) = 4.6*loadav + 2.3 =~ 5*loadav. QED
123 *
124 * Actual power values for the implemented algorithm are as follows:
125 * loadav: 1 2 3 4
126 * power: 5.68 10.32 14.94 19.55
127 */
128
129/* calculations for digital decay to forget 90% of usage in 5*loadav sec */
130#define loadfactor(loadav) (2 * (loadav))
131#define decay_cpu(loadfac, cpu) (((loadfac) * (cpu)) / ((loadfac) + FSCALE))
132
133/* decay 95% of `p_pctcpu' in 60 seconds; see CCPU_SHIFT before changing */
134fixpt_t ccpu = 0.95122942450071400909 * FSCALE; /* exp(-1/20) */
135
136/*
137 * If `ccpu' is not equal to `exp(-1/20)' and you still want to use the
138 * faster/more-accurate formula, you'll have to estimate CCPU_SHIFT below
139 * and possibly adjust FSHIFT in "param.h" so that (FSHIFT >= CCPU_SHIFT).
140 *
141 * To estimate CCPU_SHIFT for exp(-1/20), the following formula was used:
142 * 1 - exp(-1/20) ~= 0.0487 ~= 0.0488 == 1 (fixed pt, *11* bits).
143 *
144 * If you dont want to bother with the faster/more-accurate formula, you
145 * can set CCPU_SHIFT to (FSHIFT + 1) which will use a slower/less-accurate
146 * (more general) method of calculating the %age of CPU used by a process.
147 */
148#define CCPU_SHIFT 11
149
150/*
151 * Recompute process priorities, once a second
152 */
4c45483e
GW
153void
154schedcpu(dummy1, dummy2)
155 caddr_t dummy1;
156 int dummy2;
15637ed4
RG
157{
158 register fixpt_t loadfac = loadfactor(averunnable[0]);
159 register struct proc *p;
160 register int s;
161 register unsigned int newcpu;
162
163 wakeup((caddr_t)&lbolt);
164 for (p = allproc; p != NULL; p = p->p_nxt) {
165 /*
166 * Increment time in/out of memory and sleep time
167 * (if sleeping). We ignore overflow; with 16-bit int's
168 * (remember them?) overflow takes 45 days.
169 */
170 p->p_time++;
171 if (p->p_stat == SSLEEP || p->p_stat == SSTOP)
172 p->p_slptime++;
173 p->p_pctcpu = (p->p_pctcpu * ccpu) >> FSHIFT;
174 /*
175 * If the process has slept the entire second,
176 * stop recalculating its priority until it wakes up.
177 */
178 if (p->p_slptime > 1)
179 continue;
180 /*
181 * p_pctcpu is only for ps.
182 */
183#if (FSHIFT >= CCPU_SHIFT)
184 p->p_pctcpu += (hz == 100)?
185 ((fixpt_t) p->p_cpticks) << (FSHIFT - CCPU_SHIFT):
186 100 * (((fixpt_t) p->p_cpticks)
187 << (FSHIFT - CCPU_SHIFT)) / hz;
188#else
189 p->p_pctcpu += ((FSCALE - ccpu) *
190 (p->p_cpticks * FSCALE / hz)) >> FSHIFT;
191#endif
192 p->p_cpticks = 0;
193 newcpu = (u_int) decay_cpu(loadfac, p->p_cpu) + p->p_nice;
194 p->p_cpu = min(newcpu, UCHAR_MAX);
195 setpri(p);
196 s = splhigh(); /* prevent state changes */
197 if (p->p_pri >= PUSER) {
198#define PPQ (128 / NQS) /* priorities per queue */
199 if ((p != curproc) &&
200 p->p_stat == SRUN &&
201 (p->p_flag & (SLOAD|SWEXIT)) == SLOAD &&
202 (p->p_pri / PPQ) != (p->p_usrpri / PPQ)) {
203 remrq(p);
204 p->p_pri = p->p_usrpri;
205 setrq(p);
206 } else
207 p->p_pri = p->p_usrpri;
208 }
209 splx(s);
210 }
211 vmmeter();
212 if (bclnlist != NULL)
213 wakeup((caddr_t)pageproc);
214 timeout(schedcpu, (caddr_t)0, hz);
215}
216
217/*
218 * Recalculate the priority of a process after it has slept for a while.
219 * For all load averages >= 1 and max p_cpu of 255, sleeping for at least
220 * six times the loadfactor will decay p_cpu to zero.
221 */
4c45483e 222void
15637ed4
RG
223updatepri(p)
224 register struct proc *p;
225{
226 register unsigned int newcpu = p->p_cpu;
227 register fixpt_t loadfac = loadfactor(averunnable[0]);
228
229 if (p->p_slptime > 5 * loadfac)
230 p->p_cpu = 0;
231 else {
232 p->p_slptime--; /* the first time was done in schedcpu */
233 while (newcpu && --p->p_slptime)
234 newcpu = (int) decay_cpu(loadfac, newcpu);
235 p->p_cpu = min(newcpu, UCHAR_MAX);
236 }
237 setpri(p);
238}
239
240#define SQSIZE 0100 /* Must be power of 2 */
241#define HASH(x) (( (int) x >> 5) & (SQSIZE-1))
242struct slpque {
243 struct proc *sq_head;
244 struct proc **sq_tailp;
245} slpque[SQSIZE];
246
247/*
248 * During autoconfiguration or after a panic, a sleep will simply
249 * lower the priority briefly to allow interrupts, then return.
250 * The priority to be used (safepri) is machine-dependent, thus this
251 * value is initialized and maintained in the machine-dependent layers.
252 * This priority will typically be 0, or the lowest priority
253 * that is safe for use on the interrupt stack; it can be made
254 * higher to block network software interrupts after panics.
255 */
256int safepri;
257
258/*
259 * General sleep call.
260 * Suspends current process until a wakeup is made on chan.
261 * The process will then be made runnable with priority pri.
262 * Sleeps at most timo/hz seconds (0 means no timeout).
263 * If pri includes PCATCH flag, signals are checked
264 * before and after sleeping, else signals are not checked.
265 * Returns 0 if awakened, EWOULDBLOCK if the timeout expires.
266 * If PCATCH is set and a signal needs to be delivered,
267 * ERESTART is returned if the current system call should be restarted
268 * if possible, and EINTR is returned if the system call should
269 * be interrupted by the signal (return EINTR).
270 */
4c45483e 271int
15637ed4
RG
272tsleep(chan, pri, wmesg, timo)
273 caddr_t chan;
274 int pri;
4c45483e 275 const char *wmesg;
15637ed4
RG
276 int timo;
277{
278 register struct proc *p = curproc;
279 register struct slpque *qp;
280 register s;
4c45483e 281 int sig = 0, catch = pri & PCATCH;
15637ed4 282 extern int cold;
15637ed4
RG
283
284 s = splhigh();
285 if (cold || panicstr) {
286 /*
287 * After a panic, or during autoconfiguration,
288 * just give interrupts a chance, then just return;
289 * don't run any other procs or panic below,
290 * in case this is the idle process and already asleep.
291 */
292 splx(safepri);
293 splx(s);
294 return (0);
295 }
296#ifdef DIAGNOSTIC
297 if (chan == 0 || p->p_stat != SRUN || p->p_rlink)
298 panic("tsleep");
299#endif
300 p->p_wchan = chan;
301 p->p_wmesg = wmesg;
302 p->p_slptime = 0;
303 p->p_pri = pri & PRIMASK;
304 qp = &slpque[HASH(chan)];
305 if (qp->sq_head == 0)
306 qp->sq_head = p;
307 else
308 *qp->sq_tailp = p;
309 *(qp->sq_tailp = &p->p_link) = 0;
310 if (timo)
311 timeout(endtsleep, (caddr_t)p, timo);
312 /*
313 * We put ourselves on the sleep queue and start our timeout
314 * before calling CURSIG, as we could stop there, and a wakeup
315 * or a SIGCONT (or both) could occur while we were stopped.
316 * A SIGCONT would cause us to be marked as SSLEEP
317 * without resuming us, thus we must be ready for sleep
318 * when CURSIG is called. If the wakeup happens while we're
319 * stopped, p->p_wchan will be 0 upon return from CURSIG.
320 */
321 if (catch) {
322 p->p_flag |= SSINTR;
323 if (sig = CURSIG(p)) {
324 if (p->p_wchan)
325 unsleep(p);
326 p->p_stat = SRUN;
327 goto resume;
328 }
329 if (p->p_wchan == 0) {
330 catch = 0;
331 goto resume;
332 }
333 }
334 p->p_stat = SSLEEP;
335 p->p_stats->p_ru.ru_nvcsw++;
336 swtch();
337#include "ddb.h"
4c45483e 338#if NDDB > 0
15637ed4
RG
339 /* handy breakpoint location after process "wakes" */
340 asm(".globl bpendtsleep ; bpendtsleep:");
341#endif
342resume:
343 curpri = p->p_usrpri;
344 splx(s);
345 p->p_flag &= ~SSINTR;
346 if (p->p_flag & STIMO) {
347 p->p_flag &= ~STIMO;
348 if (catch == 0 || sig == 0)
349 return (EWOULDBLOCK);
350 } else if (timo)
351 untimeout(endtsleep, (caddr_t)p);
352 if (catch && (sig != 0 || (sig = CURSIG(p)))) {
353 if (p->p_sigacts->ps_sigintr & sigmask(sig))
354 return (EINTR);
355 return (ERESTART);
356 }
357 return (0);
358}
359
360/*
361 * Implement timeout for tsleep.
362 * If process hasn't been awakened (wchan non-zero),
363 * set timeout flag and undo the sleep. If proc
364 * is stopped, just unsleep so it will remain stopped.
365 */
4c45483e
GW
366void
367endtsleep(arg1, dummy)
368 caddr_t arg1;
369 int dummy;
15637ed4 370{
4c45483e 371 register struct proc *p = (struct proc *)arg1;
15637ed4
RG
372 int s = splhigh();
373
374 if (p->p_wchan) {
375 if (p->p_stat == SSLEEP)
376 setrun(p);
377 else
378 unsleep(p);
379 p->p_flag |= STIMO;
380 }
381 splx(s);
382}
383
097b27e3 384#if 0 /* This is obsolete, use tsleep(). */
15637ed4
RG
385/*
386 * Short-term, non-interruptable sleep.
387 */
4c45483e 388void
15637ed4
RG
389sleep(chan, pri)
390 caddr_t chan;
391 int pri;
392{
393 register struct proc *p = curproc;
394 register struct slpque *qp;
395 register s;
396 extern int cold;
397
398#ifdef DIAGNOSTIC
399 if (pri > PZERO) {
400 printf("sleep called with pri %d > PZERO, wchan: %x\n",
401 pri, chan);
402 panic("old sleep");
403 }
404#endif
405 s = splhigh();
406 if (cold || panicstr) {
407 /*
408 * After a panic, or during autoconfiguration,
409 * just give interrupts a chance, then just return;
410 * don't run any other procs or panic below,
411 * in case this is the idle process and already asleep.
412 */
413 splx(safepri);
414 splx(s);
415 return;
416 }
417#ifdef DIAGNOSTIC
418 if (chan==0 || p->p_stat != SRUN || p->p_rlink)
419 panic("sleep");
420#endif
421 p->p_wchan = chan;
422 p->p_wmesg = NULL;
423 p->p_slptime = 0;
424 p->p_pri = pri;
425 qp = &slpque[HASH(chan)];
426 if (qp->sq_head == 0)
427 qp->sq_head = p;
428 else
429 *qp->sq_tailp = p;
430 *(qp->sq_tailp = &p->p_link) = 0;
431 p->p_stat = SSLEEP;
432 p->p_stats->p_ru.ru_nvcsw++;
433 swtch();
4c45483e 434#if NDDB > 0
15637ed4
RG
435 /* handy breakpoint location after process "wakes" */
436 asm(".globl bpendsleep ; bpendsleep:");
437#endif
438 curpri = p->p_usrpri;
439 splx(s);
440}
4c45483e 441#endif
15637ed4
RG
442
443/*
444 * Remove a process from its wait queue
445 */
4c45483e 446void
15637ed4
RG
447unsleep(p)
448 register struct proc *p;
449{
450 register struct slpque *qp;
451 register struct proc **hp;
452 int s;
453
454 s = splhigh();
455 if (p->p_wchan) {
456 hp = &(qp = &slpque[HASH(p->p_wchan)])->sq_head;
457 while (*hp != p)
458 hp = &(*hp)->p_link;
459 *hp = p->p_link;
460 if (qp->sq_tailp == &p->p_link)
461 qp->sq_tailp = hp;
462 p->p_wchan = 0;
463 }
464 splx(s);
465}
466
467/*
468 * Wakeup on "chan"; set all processes
469 * sleeping on chan to run state.
470 */
4c45483e 471void
15637ed4
RG
472wakeup(chan)
473 register caddr_t chan;
474{
475 register struct slpque *qp;
476 register struct proc *p, **q;
477 int s;
478
479 s = splhigh();
480 qp = &slpque[HASH(chan)];
481restart:
482 for (q = &qp->sq_head; p = *q; ) {
483#ifdef DIAGNOSTIC
484 if (p->p_rlink || p->p_stat != SSLEEP && p->p_stat != SSTOP)
485 panic("wakeup");
486#endif
487 if (p->p_wchan == chan) {
488 p->p_wchan = 0;
489 *q = p->p_link;
490 if (qp->sq_tailp == &p->p_link)
491 qp->sq_tailp = q;
492 if (p->p_stat == SSLEEP) {
493 /* OPTIMIZED INLINE EXPANSION OF setrun(p) */
494 if (p->p_slptime > 1)
495 updatepri(p);
496 p->p_slptime = 0;
497 p->p_stat = SRUN;
498 if (p->p_flag & SLOAD)
499 setrq(p);
500 /*
501 * Since curpri is a usrpri,
502 * p->p_pri is always better than curpri.
503 */
504 if ((p->p_flag&SLOAD) == 0)
505 wakeup((caddr_t)&proc0);
506 else
507 need_resched();
508 /* END INLINE EXPANSION */
509 goto restart;
510 }
511 } else
512 q = &p->p_link;
513 }
514 splx(s);
515}
516
517/*
518 * Initialize the (doubly-linked) run queues
519 * to be empty.
520 */
4c45483e 521void
15637ed4
RG
522rqinit()
523{
524 register int i;
525
526 for (i = 0; i < NQS; i++)
527 qs[i].ph_link = qs[i].ph_rlink = (struct proc *)&qs[i];
528}
529
530/*
531 * Change process state to be runnable,
532 * placing it on the run queue if it is in memory,
533 * and awakening the swapper if it isn't in memory.
534 */
4c45483e 535void
15637ed4
RG
536setrun(p)
537 register struct proc *p;
538{
539 register int s;
540
541 s = splhigh();
542 switch (p->p_stat) {
543
544 case 0:
545 case SWAIT:
546 case SRUN:
547 case SZOMB:
548 default:
549 panic("setrun");
550
551 case SSTOP:
552 case SSLEEP:
553 unsleep(p); /* e.g. when sending signals */
554 break;
555
556 case SIDL:
557 break;
558 }
559 p->p_stat = SRUN;
560 if (p->p_flag & SLOAD)
561 setrq(p);
562 splx(s);
563 if (p->p_slptime > 1)
564 updatepri(p);
565 p->p_slptime = 0;
566 if ((p->p_flag&SLOAD) == 0)
567 wakeup((caddr_t)&proc0);
568 else if (p->p_pri < curpri)
569 need_resched();
570}
571
572/*
573 * Compute priority of process when running in user mode.
574 * Arrange to reschedule if the resulting priority
575 * is better than that of the current process.
576 */
4c45483e 577void
15637ed4
RG
578setpri(p)
579 register struct proc *p;
580{
581 register unsigned int newpri;
582
583 newpri = PUSER + p->p_cpu / 4 + 2 * p->p_nice;
584 newpri = min(newpri, MAXPRI);
585 p->p_usrpri = newpri;
586 if (newpri < curpri)
587 need_resched();
588}
589
4c45483e 590#if NDDB > 0
173a1695 591#define DDBFUNC(s) db_##s
4c45483e 592void
15637ed4
RG
593DDBFUNC(ps) () {
594 int np;
173a1695 595 int nl=0;
15637ed4
RG
596 struct proc *ap, *p, *pp;
597 np = nprocs;
598 p = ap = allproc;
173a1695 599 db_printf(" pid proc addr uid ppid pgrp flag stat comm wchan\n");
15637ed4 600 while (--np >= 0) {
173a1695
GR
601 /*
602 * XXX just take 20 for now...
603 */
604 if(nl++==20) {
605 db_printf("--More--");
606 cngetc();
607 db_printf("\b\b\b\b\b\b\b\b");
608 nl=0;
609 }
15637ed4
RG
610 pp = p->p_pptr;
611 if (pp == 0)
612 pp = p;
613 if (p->p_stat) {
173a1695 614 db_printf("%5d %06x %06x %3d %5d %5d %06x %d %s ",
15637ed4
RG
615 p->p_pid, ap, p->p_addr, p->p_cred->p_ruid, pp->p_pid,
616 p->p_pgrp->pg_id, p->p_flag, p->p_stat,
617 p->p_comm);
618 if (p->p_wchan) {
619 if (p->p_wmesg)
173a1695
GR
620 db_printf("%s ", p->p_wmesg);
621 db_printf("%x", p->p_wchan);
15637ed4 622 }
173a1695 623 db_printf("\n");
15637ed4
RG
624 }
625 ap = p->p_nxt;
626 if (ap == 0 && np > 0)
627 ap = zombproc;
628 p = ap;
629 }
630}
631#endif