from shannon
[unix-history] / usr / src / sys / kern / kern_synch.c
CommitLineData
961945a8
SL
1/* kern_synch.c 4.25 82/12/17 */
2
3#include "../machine/pte.h"
a379cce8
BJ
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"
1edb1cf8 13#ifdef MUSH
9c25520d 14#include "../h/quota.h"
1edb1cf8
BJ
15#include "../h/share.h"
16#endif
17#include "../h/kernel.h"
18#include "../h/buf.h"
19
961945a8
SL
20#ifdef vax
21#include "../vax/mtpr.h" /* XXX */
22#endif
1edb1cf8
BJ
23/*
24 * Force switch among equal priority processes every 100ms.
25 */
26roundrobin()
27{
28
29 runrun++;
30 aston();
b32450f4 31 timeout(roundrobin, (caddr_t)0, hz / 10);
1edb1cf8
BJ
32}
33
d01b68d6 34/* constants to digital decay and forget 90% of usage in 5*loadav time */
1edb1cf8
BJ
35#undef ave
36#define ave(a,b) ((int)(((int)(a*b))/(b+1)))
37int nrscale = 2;
1edb1cf8
BJ
38double ccpu = 0.95122942450071400909; /* exp(-1/20) */
39
1edb1cf8
BJ
40/*
41 * Recompute process priorities, once a second
42 */
43schedcpu()
44{
45 register struct proc *p;
46 register int s, a;
47
1edb1cf8 48 wakeup((caddr_t)&lbolt);
1edb1cf8
BJ
49 for (p = proc; p < procNPROC; p++) if (p->p_stat && p->p_stat!=SZOMB) {
50#ifdef MUSH
1edb1cf8
BJ
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++;
1edb1cf8
BJ
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]);
b32450f4 98 timeout(schedcpu, (caddr_t)0, hz);
1edb1cf8 99}
a379cce8
BJ
100
101#define SQSIZE 0100 /* Must be power of 2 */
102#define HASH(x) (( (int) x >> 5) & (SQSIZE-1))
103struct 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 */
116sleep(chan, pri)
bd76c595
BJ
117 caddr_t chan;
118 int pri;
a379cce8 119{
e5df4be8 120 register struct proc *rp, **hp;
6fdc0335 121 register s;
a379cce8
BJ
122
123 rp = u.u_procp;
124 s = spl6();
125 if (chan==0 || rp->p_stat != SRUN || rp->p_rlink)
126 panic("sleep");
a379cce8
BJ
127 rp->p_wchan = chan;
128 rp->p_slptime = 0;
129 rp->p_pri = pri;
e5df4be8
BJ
130 hp = &slpque[HASH(chan)];
131 rp->p_link = *hp;
132 *hp = rp;
18a4549b
BJ
133 if (pri > PZERO) {
134 if (ISSIG(rp)) {
e5df4be8
BJ
135 if (rp->p_wchan)
136 unsleep(rp);
a379cce8 137 rp->p_stat = SRUN;
81263dba 138 (void) spl0();
a379cce8
BJ
139 goto psig;
140 }
e5df4be8
BJ
141 if (rp->p_wchan == 0)
142 goto out;
143 rp->p_stat = SSLEEP;
81263dba 144 (void) spl0();
bd76c595 145 u.u_ru.ru_nvcsw++;
a379cce8 146 swtch();
18a4549b 147 if (ISSIG(rp))
a379cce8
BJ
148 goto psig;
149 } else {
6fdc0335 150 rp->p_stat = SSLEEP;
81263dba 151 (void) spl0();
bd76c595 152 u.u_ru.ru_nvcsw++;
a379cce8
BJ
153 swtch();
154 }
e5df4be8 155out:
a379cce8
BJ
156 splx(s);
157 return;
158
159 /*
160 * If priority was low (>PZERO) and
18a4549b 161 * there has been a signal, execute non-local goto through
d01b68d6 162 * u.u_qsave, aborting the system call in progress (see trap.c)
18a4549b 163 * (or finishing a tsleep, see below)
a379cce8
BJ
164 */
165psig:
d01b68d6 166 longjmp(&u.u_qsave);
a379cce8
BJ
167 /*NOTREACHED*/
168}
169
87d0f32e
BJ
170/*
171 * Remove a process from its wait queue
172 */
173unsleep(p)
18a4549b 174 register struct proc *p;
87d0f32e
BJ
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
a379cce8
BJ
190/*
191 * Wake up all processes sleeping on chan.
192 */
193wakeup(chan)
18a4549b 194 register caddr_t chan;
a379cce8 195{
e5df4be8 196 register struct proc *p, **q, **h;
a379cce8
BJ
197 int s;
198
199 s = spl6();
e5df4be8 200 h = &slpque[HASH(chan)];
a379cce8 201restart:
e5df4be8 202 for (q = h; p = *q; ) {
87d0f32e 203 if (p->p_rlink || p->p_stat != SSLEEP && p->p_stat != SSTOP)
a379cce8 204 panic("wakeup");
6fdc0335 205 if (p->p_wchan==chan) {
a379cce8 206 p->p_wchan = 0;
e5df4be8 207 *q = p->p_link;
a379cce8 208 p->p_slptime = 0;
87d0f32e
BJ
209 if (p->p_stat == SSLEEP) {
210 /* OPTIMIZED INLINE EXPANSION OF setrun(p) */
211 p->p_stat = SRUN;
c74c8a79 212 if (p->p_flag & SLOAD)
87d0f32e 213 setrq(p);
18a4549b 214 if (p->p_pri < curpri) {
87d0f32e 215 runrun++;
534d9295
BJ
216 aston();
217 }
7eb2e67e
BJ
218 if ((p->p_flag&SLOAD) == 0) {
219 if (runout != 0) {
220 runout = 0;
221 wakeup((caddr_t)&runout);
222 }
223 wantin++;
87d0f32e
BJ
224 }
225 /* END INLINE EXPANSION */
e5df4be8 226 goto restart;
a379cce8 227 }
e5df4be8
BJ
228 } else
229 q = &p->p_link;
a379cce8
BJ
230 }
231 splx(s);
232}
233
a379cce8
BJ
234/*
235 * Initialize the (doubly-linked) run queues
236 * to be empty.
237 */
238rqinit()
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}
a379cce8
BJ
245
246/*
247 * Set the process running;
248 * arrange for it to be swapped in if necessary.
249 */
250setrun(p)
18a4549b 251 register struct proc *p;
a379cce8 252{
18a4549b 253 register int s;
a379cce8
BJ
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
6fdc0335 265 case SSTOP:
a379cce8 266 case SSLEEP:
87d0f32e 267 unsleep(p); /* e.g. when sending signals */
a379cce8
BJ
268 break;
269
270 case SIDL:
a379cce8
BJ
271 break;
272 }
273 p->p_stat = SRUN;
274 if (p->p_flag & SLOAD)
275 setrq(p);
276 splx(s);
18a4549b 277 if (p->p_pri < curpri) {
a379cce8 278 runrun++;
534d9295
BJ
279 aston();
280 }
7eb2e67e 281 if ((p->p_flag&SLOAD) == 0) {
18a4549b 282 if (runout != 0) {
7eb2e67e
BJ
283 runout = 0;
284 wakeup((caddr_t)&runout);
285 }
286 wantin++;
a379cce8
BJ
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 */
296setpri(pp)
18a4549b 297 register struct proc *pp;
a379cce8 298{
18a4549b 299 register int p;
a379cce8 300
16a64baa 301 p = (pp->p_cpu & 0377)/4;
598563b5 302 p += PUSER + 2*(pp->p_nice - NZERO);
9afea775
BJ
303 if (pp->p_rssize > pp->p_maxrss && freemem < desfree)
304 p += 2*4; /* effectively, nice(4) */
18a4549b 305 if (p > 127)
a379cce8 306 p = 127;
18a4549b 307 if (p < curpri) {
a379cce8 308 runrun++;
a51a6e74
BJ
309 aston();
310 }
a379cce8 311 pp->p_usrpri = p;
18a4549b 312 return (p);
a379cce8 313}