Commit | Line | Data |
---|---|---|
0a34b6fd | 1 | /* kern_clock.c 4.14 %G% */ |
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 BJ |
24 | #define SCHMAG 9/10 |
25 | ||
26 | ||
27 | /* | |
f403d99f | 28 | * Hardclock is called straight from |
83be5fac | 29 | * the real time clock interrupt. |
f403d99f BJ |
30 | * We limit the work we do at real clock interrupt time to: |
31 | * reloading clock | |
32 | * decrementing time to callouts | |
33 | * recording cpu time usage | |
4512b9a4 | 34 | * modifying priority of current process |
f403d99f BJ |
35 | * arrange for soft clock interrupt |
36 | * kernel pc profiling | |
83be5fac | 37 | * |
f403d99f | 38 | * At softclock interrupt time we: |
83be5fac | 39 | * implement callouts |
83be5fac | 40 | * maintain date |
83be5fac BJ |
41 | * lightning bolt wakeup (every second) |
42 | * alarm clock signals | |
43 | * jab the scheduler | |
f403d99f BJ |
44 | * |
45 | * On the vax softclock interrupts are implemented by | |
46 | * software interrupts. Note that we may have multiple softclock | |
47 | * interrupts compressed into one (due to excessive interrupt load), | |
48 | * but that hardclock interrupts should never be lost. | |
83be5fac | 49 | */ |
83be5fac | 50 | |
260ea681 | 51 | /*ARGSUSED*/ |
f403d99f | 52 | hardclock(pc, ps) |
4512b9a4 | 53 | caddr_t pc; |
83be5fac | 54 | { |
0a34b6fd | 55 | register struct callout *p1; |
83be5fac | 56 | register struct proc *pp; |
f403d99f | 57 | register int s, cpstate; |
83be5fac BJ |
58 | |
59 | /* | |
60 | * reprime clock | |
61 | */ | |
62 | clkreld(); | |
63 | ||
64 | /* | |
f403d99f | 65 | * update callout times |
83be5fac | 66 | */ |
83be5fac BJ |
67 | if(callout[0].c_func == NULL) |
68 | goto out; | |
f403d99f BJ |
69 | p1 = &callout[0]; |
70 | while(p1->c_time<=0 && p1->c_func!=NULL) | |
71 | p1++; | |
72 | p1->c_time--; | |
83be5fac | 73 | out: |
5da67d35 BJ |
74 | |
75 | /* | |
f403d99f | 76 | * Maintain iostat and per-process cpu statistics |
5da67d35 | 77 | */ |
83be5fac BJ |
78 | if (!noproc) { |
79 | s = u.u_procp->p_rssize; | |
80 | u.u_vm.vm_idsrss += s; | |
81 | if (u.u_procp->p_textp) { | |
82 | register int xrss = u.u_procp->p_textp->x_rssize; | |
83 | ||
84 | s += xrss; | |
85 | u.u_vm.vm_ixrss += xrss; | |
86 | } | |
87 | if (s > u.u_vm.vm_maxrss) | |
88 | u.u_vm.vm_maxrss = s; | |
0a34b6fd | 89 | if ((u.u_vm.vm_utime+u.u_vm.vm_stime+1)/hz > u.u_limit[LIM_CPU]) { |
39f2f769 BJ |
90 | psignal(u.u_procp, SIGXCPU); |
91 | if (u.u_limit[LIM_CPU] < INFINITY - 5) | |
92 | u.u_limit[LIM_CPU] += 5; | |
93 | } | |
83be5fac | 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]++; | |
83be5fac BJ |
112 | if (!noproc) { |
113 | pp = u.u_procp; | |
dd808ba3 | 114 | pp->p_cpticks++; |
83be5fac BJ |
115 | if(++pp->p_cpu == 0) |
116 | pp->p_cpu--; | |
117 | if(pp->p_cpu % 16 == 0) { | |
81263dba | 118 | (void) setpri(pp); |
83be5fac BJ |
119 | if (pp->p_pri >= PUSER) |
120 | pp->p_pri = pp->p_usrpri; | |
121 | } | |
122 | } | |
123 | ++lbolt; | |
e5a79c70 BJ |
124 | #if VAX780 |
125 | if (cpu == VAX_780 && !BASEPRI(ps)) | |
f403d99f BJ |
126 | unhang(); |
127 | #endif | |
128 | setsoftclock(); | |
129 | } | |
130 | ||
131 | /* | |
132 | * Constant for decay filter for cpu usage. | |
133 | */ | |
134 | double ccpu = 0.95122942450071400909; /* exp(-1/20) */ | |
135 | ||
136 | /* | |
137 | * Software clock interrupt. | |
138 | * This routine is blocked by spl1(), | |
139 | * which doesn't block device interrupts! | |
140 | */ | |
260ea681 | 141 | /*ARGSUSED*/ |
f403d99f | 142 | softclock(pc, ps) |
4512b9a4 | 143 | caddr_t pc; |
f403d99f | 144 | { |
0a34b6fd | 145 | register struct callout *p1, *p2; |
f403d99f BJ |
146 | register struct proc *pp; |
147 | register int a, s; | |
148 | ||
149 | /* | |
150 | * callout | |
151 | */ | |
152 | if(callout[0].c_time <= 0) { | |
153 | p1 = &callout[0]; | |
154 | while(p1->c_func != 0 && p1->c_time <= 0) { | |
155 | (*p1->c_func)(p1->c_arg); | |
156 | p1++; | |
157 | } | |
158 | p2 = &callout[0]; | |
159 | while(p2->c_func = p1->c_func) { | |
160 | p2->c_time = p1->c_time; | |
161 | p2->c_arg = p1->c_arg; | |
162 | p1++; | |
163 | p2++; | |
164 | } | |
165 | } | |
166 | ||
167 | /* | |
168 | * Drain silos. | |
169 | */ | |
3b90686d | 170 | #if NDH > 0 |
f403d99f BJ |
171 | s = spl5(); dhtimer(); splx(s); |
172 | #endif | |
3b90686d | 173 | #if NDZ > 0 |
f403d99f BJ |
174 | s = spl5(); dztimer(); splx(s); |
175 | #endif | |
176 | ||
4512b9a4 BJ |
177 | /* |
178 | * If idling and processes are waiting to swap in, | |
179 | * check on them. | |
180 | */ | |
181 | if (noproc && runin) { | |
182 | runin = 0; | |
183 | wakeup((caddr_t)&runin); | |
184 | } | |
185 | ||
f403d99f BJ |
186 | /* |
187 | * Run paging daemon and reschedule every 1/4 sec. | |
188 | */ | |
0a34b6fd | 189 | if (lbolt % (hz/4) == 0) { |
83be5fac BJ |
190 | vmpago(); |
191 | runrun++; | |
f403d99f | 192 | aston(); |
83be5fac | 193 | } |
f403d99f BJ |
194 | |
195 | /* | |
196 | * Lightning bolt every second: | |
197 | * sleep timeouts | |
198 | * process priority recomputation | |
199 | * process %cpu averaging | |
200 | * virtual memory metering | |
201 | * kick swapper if processes want in | |
202 | */ | |
0a34b6fd | 203 | if (lbolt >= hz) { |
83be5fac BJ |
204 | if (BASEPRI(ps)) |
205 | return; | |
0a34b6fd | 206 | lbolt -= hz; |
83be5fac | 207 | ++time; |
83be5fac | 208 | wakeup((caddr_t)&lbolt); |
86fd527f | 209 | for(pp = proc; pp < procNPROC; pp++) |
8418f526 | 210 | if (pp->p_stat && pp->p_stat!=SZOMB) { |
83be5fac BJ |
211 | if(pp->p_time != 127) |
212 | pp->p_time++; | |
213 | if(pp->p_clktim) | |
214 | if(--pp->p_clktim == 0) | |
8add37d7 BJ |
215 | if (pp->p_flag & STIMO) { |
216 | s = spl6(); | |
daac5944 BJ |
217 | switch (pp->p_stat) { |
218 | ||
219 | case SSLEEP: | |
8add37d7 | 220 | setrun(pp); |
daac5944 BJ |
221 | break; |
222 | ||
223 | case SSTOP: | |
224 | unsleep(pp); | |
225 | break; | |
226 | } | |
8add37d7 BJ |
227 | pp->p_flag &= ~STIMO; |
228 | splx(s); | |
229 | } else | |
cccb9ee6 | 230 | psignal(pp, SIGALRM); |
83be5fac BJ |
231 | if(pp->p_stat==SSLEEP||pp->p_stat==SSTOP) |
232 | if (pp->p_slptime != 127) | |
233 | pp->p_slptime++; | |
dd808ba3 BJ |
234 | if (pp->p_flag&SLOAD) |
235 | pp->p_pctcpu = ccpu * pp->p_pctcpu + | |
0a34b6fd | 236 | (1.0 - ccpu) * (pp->p_cpticks/(float)hz); |
dd808ba3 | 237 | pp->p_cpticks = 0; |
83be5fac BJ |
238 | a = (pp->p_cpu & 0377)*SCHMAG + pp->p_nice - NZERO; |
239 | if(a < 0) | |
240 | a = 0; | |
241 | if(a > 255) | |
242 | a = 255; | |
243 | pp->p_cpu = a; | |
81263dba | 244 | (void) setpri(pp); |
83be5fac BJ |
245 | s = spl6(); |
246 | if(pp->p_pri >= PUSER) { | |
247 | if ((pp != u.u_procp || noproc) && | |
248 | pp->p_stat == SRUN && | |
249 | (pp->p_flag & SLOAD) && | |
250 | pp->p_pri != pp->p_usrpri) { | |
251 | remrq(pp); | |
252 | pp->p_pri = pp->p_usrpri; | |
253 | setrq(pp); | |
254 | } else | |
255 | pp->p_pri = pp->p_usrpri; | |
256 | } | |
257 | splx(s); | |
258 | } | |
259 | vmmeter(); | |
260 | if(runin!=0) { | |
261 | runin = 0; | |
262 | wakeup((caddr_t)&runin); | |
263 | } | |
264 | /* | |
265 | * If there are pages that have been cleaned, | |
266 | * jolt the pageout daemon to process them. | |
267 | * We do this here so that these pages will be | |
268 | * freed if there is an abundance of memory and the | |
269 | * daemon would not be awakened otherwise. | |
270 | */ | |
271 | if (bclnlist != NULL) | |
272 | wakeup((caddr_t)&proc[2]); | |
83be5fac BJ |
273 | if (USERMODE(ps)) { |
274 | pp = u.u_procp; | |
275 | if (pp->p_uid) | |
0a34b6fd | 276 | if (pp->p_nice == NZERO && u.u_vm.vm_utime > 600 * hz) |
83be5fac | 277 | pp->p_nice = NZERO+4; |
81263dba | 278 | (void) setpri(pp); |
83be5fac | 279 | pp->p_pri = pp->p_usrpri; |
054016e1 | 280 | } |
83be5fac | 281 | } |
f403d99f BJ |
282 | if (USERMODE(ps) && u.u_prof.pr_scale) { |
283 | u.u_procp->p_flag |= SOWEUPC; | |
284 | aston(); | |
83be5fac | 285 | } |
83be5fac BJ |
286 | } |
287 | ||
288 | /* | |
289 | * timeout is called to arrange that | |
0a34b6fd | 290 | * fun(arg) is called in tim/hz seconds. |
83be5fac BJ |
291 | * An entry is sorted into the callout |
292 | * structure. The time in each structure | |
0a34b6fd | 293 | * entry is the number of hz's more |
83be5fac BJ |
294 | * than the previous entry. |
295 | * In this way, decrementing the | |
296 | * first entry has the effect of | |
297 | * updating all entries. | |
298 | * | |
299 | * The panic is there because there is nothing | |
300 | * intelligent to be done if an entry won't fit. | |
301 | */ | |
302 | timeout(fun, arg, tim) | |
4512b9a4 BJ |
303 | int (*fun)(); |
304 | caddr_t arg; | |
83be5fac | 305 | { |
0a34b6fd | 306 | register struct callout *p1, *p2, *p3; |
83be5fac BJ |
307 | register int t; |
308 | int s; | |
309 | ||
310 | t = tim; | |
311 | p1 = &callout[0]; | |
312 | s = spl7(); | |
313 | while(p1->c_func != 0 && p1->c_time <= t) { | |
314 | t -= p1->c_time; | |
315 | p1++; | |
316 | } | |
83be5fac BJ |
317 | p1->c_time -= t; |
318 | p2 = p1; | |
0a34b6fd | 319 | p3 = callout+(ncallout-2); |
72559ec9 BJ |
320 | while(p2->c_func != 0) { |
321 | if (p2 >= p3) | |
f403d99f | 322 | panic("timeout"); |
83be5fac | 323 | p2++; |
72559ec9 | 324 | } |
83be5fac BJ |
325 | while(p2 >= p1) { |
326 | (p2+1)->c_time = p2->c_time; | |
327 | (p2+1)->c_func = p2->c_func; | |
328 | (p2+1)->c_arg = p2->c_arg; | |
329 | p2--; | |
330 | } | |
331 | p1->c_time = t; | |
332 | p1->c_func = fun; | |
333 | p1->c_arg = arg; | |
334 | splx(s); | |
335 | } |