Commit | Line | Data |
---|---|---|
964bcfb1 | 1 | /* kern_clock.c 4.16 81/03/09 */ |
83be5fac BJ |
2 | |
3 | #include "../h/param.h" | |
4 | #include "../h/systm.h" | |
d9b8447e | 5 | #include "../h/dk.h" |
0a34b6fd | 6 | #include "../h/callout.h" |
83be5fac BJ |
7 | #include "../h/seg.h" |
8 | #include "../h/dir.h" | |
9 | #include "../h/user.h" | |
10 | #include "../h/proc.h" | |
11 | #include "../h/reg.h" | |
12 | #include "../h/psl.h" | |
13 | #include "../h/vm.h" | |
14 | #include "../h/buf.h" | |
15 | #include "../h/text.h" | |
95ce0d37 BJ |
16 | #include "../h/vlimit.h" |
17 | #include "../h/mtpr.h" | |
18 | #include "../h/clock.h" | |
e5a79c70 | 19 | #include "../h/cpu.h" |
83be5fac | 20 | |
ec213dfb BJ |
21 | #include "dh.h" |
22 | #include "dz.h" | |
6602c75b | 23 | |
83be5fac | 24 | /* |
f403d99f | 25 | * Hardclock is called straight from |
83be5fac | 26 | * the real time clock interrupt. |
f403d99f BJ |
27 | * We limit the work we do at real clock interrupt time to: |
28 | * reloading clock | |
29 | * decrementing time to callouts | |
30 | * recording cpu time usage | |
4512b9a4 | 31 | * modifying priority of current process |
f403d99f BJ |
32 | * arrange for soft clock interrupt |
33 | * kernel pc profiling | |
83be5fac | 34 | * |
964bcfb1 | 35 | * At software (softclock) interrupt time we: |
83be5fac | 36 | * implement callouts |
83be5fac | 37 | * maintain date |
83be5fac BJ |
38 | * lightning bolt wakeup (every second) |
39 | * alarm clock signals | |
40 | * jab the scheduler | |
f403d99f BJ |
41 | * |
42 | * On the vax softclock interrupts are implemented by | |
43 | * software interrupts. Note that we may have multiple softclock | |
44 | * interrupts compressed into one (due to excessive interrupt load), | |
45 | * but that hardclock interrupts should never be lost. | |
83be5fac | 46 | */ |
83be5fac | 47 | |
260ea681 | 48 | /*ARGSUSED*/ |
f403d99f | 49 | hardclock(pc, ps) |
4512b9a4 | 50 | caddr_t pc; |
83be5fac | 51 | { |
0a34b6fd | 52 | register struct callout *p1; |
83be5fac | 53 | register struct proc *pp; |
f403d99f | 54 | register int s, cpstate; |
83be5fac BJ |
55 | |
56 | /* | |
57 | * reprime clock | |
58 | */ | |
59 | clkreld(); | |
60 | ||
61 | /* | |
f403d99f | 62 | * update callout times |
83be5fac | 63 | */ |
964bcfb1 | 64 | if (callout[0].c_func == NULL) |
83be5fac | 65 | goto out; |
f403d99f | 66 | p1 = &callout[0]; |
964bcfb1 | 67 | while (p1->c_time<=0 && p1->c_func!=NULL) |
f403d99f BJ |
68 | p1++; |
69 | p1->c_time--; | |
83be5fac | 70 | out: |
5da67d35 BJ |
71 | |
72 | /* | |
f403d99f | 73 | * Maintain iostat and per-process cpu statistics |
5da67d35 | 74 | */ |
83be5fac BJ |
75 | if (!noproc) { |
76 | s = u.u_procp->p_rssize; | |
77 | u.u_vm.vm_idsrss += s; | |
78 | if (u.u_procp->p_textp) { | |
79 | register int xrss = u.u_procp->p_textp->x_rssize; | |
80 | ||
81 | s += xrss; | |
82 | u.u_vm.vm_ixrss += xrss; | |
83 | } | |
84 | if (s > u.u_vm.vm_maxrss) | |
85 | u.u_vm.vm_maxrss = s; | |
0a34b6fd | 86 | if ((u.u_vm.vm_utime+u.u_vm.vm_stime+1)/hz > u.u_limit[LIM_CPU]) { |
39f2f769 BJ |
87 | psignal(u.u_procp, SIGXCPU); |
88 | if (u.u_limit[LIM_CPU] < INFINITY - 5) | |
89 | u.u_limit[LIM_CPU] += 5; | |
90 | } | |
83be5fac | 91 | } |
964bcfb1 BJ |
92 | /* |
93 | * Update iostat information. | |
94 | */ | |
83be5fac BJ |
95 | if (USERMODE(ps)) { |
96 | u.u_vm.vm_utime++; | |
97 | if(u.u_procp->p_nice > NZERO) | |
41888f16 BJ |
98 | cpstate = CP_NICE; |
99 | else | |
100 | cpstate = CP_USER; | |
83be5fac | 101 | } else { |
41888f16 | 102 | cpstate = CP_SYS; |
83be5fac | 103 | if (noproc) |
41888f16 | 104 | cpstate = CP_IDLE; |
83be5fac BJ |
105 | else |
106 | u.u_vm.vm_stime++; | |
107 | } | |
2d7d59e9 | 108 | cp_time[cpstate]++; |
f403d99f BJ |
109 | for (s = 0; s < DK_NDRIVE; s++) |
110 | if (dk_busy&(1<<s)) | |
111 | dk_time[s]++; | |
964bcfb1 BJ |
112 | /* |
113 | * Adjust priority of current process. | |
114 | */ | |
83be5fac BJ |
115 | if (!noproc) { |
116 | pp = u.u_procp; | |
dd808ba3 | 117 | pp->p_cpticks++; |
83be5fac BJ |
118 | if(++pp->p_cpu == 0) |
119 | pp->p_cpu--; | |
120 | if(pp->p_cpu % 16 == 0) { | |
81263dba | 121 | (void) setpri(pp); |
83be5fac BJ |
122 | if (pp->p_pri >= PUSER) |
123 | pp->p_pri = pp->p_usrpri; | |
124 | } | |
125 | } | |
964bcfb1 BJ |
126 | /* |
127 | * Time moves on. | |
128 | */ | |
83be5fac | 129 | ++lbolt; |
e5a79c70 | 130 | #if VAX780 |
964bcfb1 BJ |
131 | /* |
132 | * On 780's, impelement a fast UBA watcher, | |
133 | * to make sure uba's don't get stuck. | |
134 | */ | |
287d9996 | 135 | if (cpu == VAX_780 && panicstr == 0 && !BASEPRI(ps)) |
f403d99f BJ |
136 | unhang(); |
137 | #endif | |
964bcfb1 BJ |
138 | /* |
139 | * Schedule a software interrupt for the rest | |
140 | * of clock activities. | |
141 | */ | |
f403d99f BJ |
142 | setsoftclock(); |
143 | } | |
144 | ||
145 | /* | |
964bcfb1 BJ |
146 | * SCHMAG is the constant in the digital decay cpu |
147 | * usage priority assignment. Each second we multiply | |
148 | * the previous cpu usage estimate by SCHMAG. At 9/10 | |
149 | * it tends to decay away all knowledge of previous activity | |
150 | * in about 10 seconds. | |
151 | */ | |
152 | #define SCHMAG 9/10 | |
153 | ||
154 | /* | |
155 | * Constant for decay filter for cpu usage field | |
156 | * in process table (used by ps au). | |
f403d99f BJ |
157 | */ |
158 | double ccpu = 0.95122942450071400909; /* exp(-1/20) */ | |
159 | ||
160 | /* | |
161 | * Software clock interrupt. | |
964bcfb1 | 162 | * This routine runs at lower priority than device interrupts. |
f403d99f | 163 | */ |
260ea681 | 164 | /*ARGSUSED*/ |
f403d99f | 165 | softclock(pc, ps) |
4512b9a4 | 166 | caddr_t pc; |
f403d99f | 167 | { |
0a34b6fd | 168 | register struct callout *p1, *p2; |
f403d99f BJ |
169 | register struct proc *pp; |
170 | register int a, s; | |
171 | ||
172 | /* | |
287d9996 | 173 | * Perform callouts (but not after panic's!) |
f403d99f | 174 | */ |
287d9996 | 175 | if (panicstr == 0 && callout[0].c_time <= 0) { |
f403d99f | 176 | p1 = &callout[0]; |
287d9996 | 177 | while (p1->c_func != 0 && p1->c_time <= 0) { |
f403d99f BJ |
178 | (*p1->c_func)(p1->c_arg); |
179 | p1++; | |
180 | } | |
181 | p2 = &callout[0]; | |
287d9996 | 182 | while (p2->c_func = p1->c_func) { |
f403d99f BJ |
183 | p2->c_time = p1->c_time; |
184 | p2->c_arg = p1->c_arg; | |
185 | p1++; | |
186 | p2++; | |
187 | } | |
188 | } | |
189 | ||
190 | /* | |
191 | * Drain silos. | |
192 | */ | |
3b90686d | 193 | #if NDH > 0 |
f403d99f BJ |
194 | s = spl5(); dhtimer(); splx(s); |
195 | #endif | |
3b90686d | 196 | #if NDZ > 0 |
f403d99f BJ |
197 | s = spl5(); dztimer(); splx(s); |
198 | #endif | |
199 | ||
4512b9a4 BJ |
200 | /* |
201 | * If idling and processes are waiting to swap in, | |
202 | * check on them. | |
203 | */ | |
204 | if (noproc && runin) { | |
205 | runin = 0; | |
206 | wakeup((caddr_t)&runin); | |
207 | } | |
208 | ||
f403d99f BJ |
209 | /* |
210 | * Run paging daemon and reschedule every 1/4 sec. | |
211 | */ | |
0a34b6fd | 212 | if (lbolt % (hz/4) == 0) { |
83be5fac BJ |
213 | vmpago(); |
214 | runrun++; | |
f403d99f | 215 | aston(); |
83be5fac | 216 | } |
f403d99f BJ |
217 | |
218 | /* | |
219 | * Lightning bolt every second: | |
220 | * sleep timeouts | |
221 | * process priority recomputation | |
222 | * process %cpu averaging | |
223 | * virtual memory metering | |
224 | * kick swapper if processes want in | |
225 | */ | |
0a34b6fd | 226 | if (lbolt >= hz) { |
287d9996 | 227 | /* |
964bcfb1 | 228 | * This doesn't mean much on VAX since we run at |
287d9996 BJ |
229 | * software interrupt time... if hardclock() |
230 | * calls softclock() directly, it prevents | |
231 | * this code from running when the priority | |
232 | * was raised when the clock interrupt occurred. | |
233 | */ | |
83be5fac BJ |
234 | if (BASEPRI(ps)) |
235 | return; | |
287d9996 BJ |
236 | |
237 | /* | |
238 | * If we didn't run a few times because of | |
239 | * long blockage at high ipl, we don't | |
240 | * really want to run this code several times, | |
241 | * so squish out all multiples of hz here. | |
242 | */ | |
243 | time += lbolt / hz; | |
244 | lbolt %= hz; | |
245 | ||
246 | /* | |
247 | * Wakeup lightning bolt sleepers. | |
248 | * Processes sleep on lbolt to wait | |
249 | * for short amounts of time (e.g. 1 second). | |
250 | */ | |
83be5fac | 251 | wakeup((caddr_t)&lbolt); |
287d9996 BJ |
252 | |
253 | /* | |
254 | * Recompute process priority and process | |
255 | * sleep() system calls as well as internal | |
256 | * sleeps with timeouts (tsleep() kernel routine). | |
257 | */ | |
258 | for (pp = proc; pp < procNPROC; pp++) | |
8418f526 | 259 | if (pp->p_stat && pp->p_stat!=SZOMB) { |
287d9996 BJ |
260 | /* |
261 | * Increase resident time, to max of 127 seconds | |
262 | * (it is kept in a character.) For | |
263 | * loaded processes this is time in core; for | |
264 | * swapped processes, this is time on drum. | |
265 | */ | |
266 | if (pp->p_time != 127) | |
83be5fac | 267 | pp->p_time++; |
287d9996 BJ |
268 | /* |
269 | * If process has clock counting down, and it | |
270 | * expires, set it running (if this is a tsleep()), | |
271 | * or give it an SIGALRM (if the user process | |
272 | * is using alarm signals. | |
273 | */ | |
274 | if (pp->p_clktim && --pp->p_clktim == 0) | |
275 | if (pp->p_flag & STIMO) { | |
276 | s = spl6(); | |
277 | switch (pp->p_stat) { | |
daac5944 | 278 | |
287d9996 BJ |
279 | case SSLEEP: |
280 | setrun(pp); | |
281 | break; | |
daac5944 | 282 | |
287d9996 BJ |
283 | case SSTOP: |
284 | unsleep(pp); | |
285 | break; | |
286 | } | |
287 | pp->p_flag &= ~STIMO; | |
288 | splx(s); | |
289 | } else | |
290 | psignal(pp, SIGALRM); | |
291 | /* | |
292 | * If process is blocked, increment computed | |
293 | * time blocked. This is used in swap scheduling. | |
294 | */ | |
295 | if (pp->p_stat==SSLEEP || pp->p_stat==SSTOP) | |
83be5fac BJ |
296 | if (pp->p_slptime != 127) |
297 | pp->p_slptime++; | |
287d9996 BJ |
298 | /* |
299 | * Update digital filter estimation of process | |
300 | * cpu utilization for loaded processes. | |
301 | */ | |
dd808ba3 BJ |
302 | if (pp->p_flag&SLOAD) |
303 | pp->p_pctcpu = ccpu * pp->p_pctcpu + | |
0a34b6fd | 304 | (1.0 - ccpu) * (pp->p_cpticks/(float)hz); |
287d9996 BJ |
305 | /* |
306 | * Recompute process priority. The number p_cpu | |
307 | * is a weighted estimate of cpu time consumed. | |
308 | * A process which consumes cpu time has this | |
309 | * increase regularly. We here decrease it by | |
310 | * a fraction (SCHMAG is 90%), giving a digital | |
311 | * decay filter which damps out in about 10 seconds. | |
312 | * | |
313 | * If a process is niced, then the nice directly | |
314 | * affects the new priority. The final priority | |
315 | * is in the range 0 to 255, to fit in a character. | |
316 | */ | |
dd808ba3 | 317 | pp->p_cpticks = 0; |
83be5fac | 318 | a = (pp->p_cpu & 0377)*SCHMAG + pp->p_nice - NZERO; |
287d9996 | 319 | if (a < 0) |
83be5fac | 320 | a = 0; |
287d9996 | 321 | if (a > 255) |
83be5fac BJ |
322 | a = 255; |
323 | pp->p_cpu = a; | |
81263dba | 324 | (void) setpri(pp); |
287d9996 BJ |
325 | /* |
326 | * Now have computed new process priority | |
327 | * in p->p_usrpri. Carefully change p->p_pri. | |
328 | * A process is on a run queue associated with | |
329 | * this priority, so we must block out process | |
330 | * state changes during the transition. | |
331 | */ | |
83be5fac | 332 | s = spl6(); |
287d9996 | 333 | if (pp->p_pri >= PUSER) { |
83be5fac BJ |
334 | if ((pp != u.u_procp || noproc) && |
335 | pp->p_stat == SRUN && | |
336 | (pp->p_flag & SLOAD) && | |
337 | pp->p_pri != pp->p_usrpri) { | |
338 | remrq(pp); | |
339 | pp->p_pri = pp->p_usrpri; | |
340 | setrq(pp); | |
341 | } else | |
342 | pp->p_pri = pp->p_usrpri; | |
343 | } | |
344 | splx(s); | |
345 | } | |
287d9996 BJ |
346 | |
347 | /* | |
348 | * Perform virtual memory metering. | |
349 | */ | |
83be5fac | 350 | vmmeter(); |
287d9996 BJ |
351 | |
352 | /* | |
353 | * If the swap process is trying to bring | |
354 | * a process in, have it look again to see | |
355 | * if it is possible now. | |
356 | */ | |
357 | if (runin!=0) { | |
83be5fac BJ |
358 | runin = 0; |
359 | wakeup((caddr_t)&runin); | |
360 | } | |
287d9996 | 361 | |
83be5fac BJ |
362 | /* |
363 | * If there are pages that have been cleaned, | |
364 | * jolt the pageout daemon to process them. | |
365 | * We do this here so that these pages will be | |
366 | * freed if there is an abundance of memory and the | |
367 | * daemon would not be awakened otherwise. | |
368 | */ | |
369 | if (bclnlist != NULL) | |
370 | wakeup((caddr_t)&proc[2]); | |
287d9996 BJ |
371 | |
372 | /* | |
373 | * If the trap occurred from usermode, | |
374 | * then check to see if it has now been | |
375 | * running more than 10 minutes of user time | |
376 | * and should thus run with reduced priority | |
377 | * to give other processes a chance. | |
378 | */ | |
83be5fac BJ |
379 | if (USERMODE(ps)) { |
380 | pp = u.u_procp; | |
287d9996 BJ |
381 | if (pp->p_uid && pp->p_nice == NZERO && |
382 | u.u_vm.vm_utime > 600 * hz) | |
383 | pp->p_nice = NZERO+4; | |
81263dba | 384 | (void) setpri(pp); |
83be5fac | 385 | pp->p_pri = pp->p_usrpri; |
054016e1 | 386 | } |
83be5fac | 387 | } |
287d9996 BJ |
388 | /* |
389 | * If trapped user-mode, give it a profiling tick. | |
390 | */ | |
f403d99f BJ |
391 | if (USERMODE(ps) && u.u_prof.pr_scale) { |
392 | u.u_procp->p_flag |= SOWEUPC; | |
393 | aston(); | |
83be5fac | 394 | } |
83be5fac BJ |
395 | } |
396 | ||
397 | /* | |
964bcfb1 | 398 | * Timeout is called to arrange that |
0a34b6fd | 399 | * fun(arg) is called in tim/hz seconds. |
83be5fac | 400 | * An entry is sorted into the callout |
964bcfb1 | 401 | * structure. The time in each structure |
0a34b6fd | 402 | * entry is the number of hz's more |
83be5fac BJ |
403 | * than the previous entry. |
404 | * In this way, decrementing the | |
405 | * first entry has the effect of | |
406 | * updating all entries. | |
407 | * | |
408 | * The panic is there because there is nothing | |
409 | * intelligent to be done if an entry won't fit. | |
410 | */ | |
411 | timeout(fun, arg, tim) | |
4512b9a4 BJ |
412 | int (*fun)(); |
413 | caddr_t arg; | |
83be5fac | 414 | { |
0a34b6fd | 415 | register struct callout *p1, *p2, *p3; |
83be5fac BJ |
416 | register int t; |
417 | int s; | |
418 | ||
419 | t = tim; | |
420 | p1 = &callout[0]; | |
421 | s = spl7(); | |
964bcfb1 | 422 | while (p1->c_func != 0 && p1->c_time <= t) { |
83be5fac BJ |
423 | t -= p1->c_time; |
424 | p1++; | |
425 | } | |
83be5fac BJ |
426 | p1->c_time -= t; |
427 | p2 = p1; | |
0a34b6fd | 428 | p3 = callout+(ncallout-2); |
964bcfb1 | 429 | while (p2->c_func != 0) { |
72559ec9 | 430 | if (p2 >= p3) |
f403d99f | 431 | panic("timeout"); |
83be5fac | 432 | p2++; |
72559ec9 | 433 | } |
964bcfb1 | 434 | while (p2 >= p1) { |
83be5fac BJ |
435 | (p2+1)->c_time = p2->c_time; |
436 | (p2+1)->c_func = p2->c_func; | |
437 | (p2+1)->c_arg = p2->c_arg; | |
438 | p2--; | |
439 | } | |
440 | p1->c_time = t; | |
441 | p1->c_func = fun; | |
442 | p1->c_arg = arg; | |
443 | splx(s); | |
444 | } |