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