xref: /csrg-svn/sys/kern/kern_clock.c (revision 1770)
1 /*	10/14/12	4.1	kern_clock.c	*/
2 
3 #include "../h/param.h"
4 #include "../h/systm.h"
5 #include "../h/dk.h"
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"
16 #include "../h/vlimit.h"
17 #include "../h/mtpr.h"
18 #include "../h/clock.h"
19 
20 #include "../conf/dh.h"
21 #include "../conf/dz.h"
22 
23 #define	SCHMAG	9/10
24 
25 /*
26  * Constant for decay filter for cpu usage.
27  */
28 double	ccpu = 0.95122942450071400909;		/* exp(-1/20) */
29 
30 /*
31  * Clock is called straight from
32  * the real time clock interrupt.
33  *
34  * Functions:
35  *	implement callouts
36  *	maintain user/system times
37  *	maintain date
38  *	profile
39  *	lightning bolt wakeup (every second)
40  *	alarm clock signals
41  *	jab the scheduler
42  */
43 #ifdef KPROF
44 unsigned short kcount[20000];
45 #endif
46 
47 /*
48  * We handle regular calls to the dh and dz silo input processors
49  * without using timeouts to save a little time.
50  */
51 int	rintvl = 0;		/* every 1/60'th of sec check receivers */
52 int	rcnt;
53 
54 clock(pc, ps)
55 caddr_t pc;
56 {
57 	register struct callo *p1, *p2;
58 	register struct proc *pp;
59 	register int s;
60 	int a, cpstate, i;
61 
62 	/*
63 	 * reprime clock
64 	 */
65 	clkreld();
66 
67 	/*
68 	 * callouts
69 	 * else update first non-zero time
70 	 */
71 
72 	if(callout[0].c_func == NULL)
73 		goto out;
74 	p2 = &callout[0];
75 	while(p2->c_time<=0 && p2->c_func!=NULL)
76 		p2++;
77 	p2->c_time--;
78 
79 	/*
80 	 * if ps is high, just return
81 	 */
82 	if (BASEPRI(ps))
83 		goto out;
84 
85 	/*
86 	 * callout
87 	 */
88 
89 	if(callout[0].c_time <= 0) {
90 		p1 = &callout[0];
91 		while(p1->c_func != 0 && p1->c_time <= 0) {
92 			(*p1->c_func)(p1->c_arg);
93 			p1++;
94 		}
95 		p2 = &callout[0];
96 		while(p2->c_func = p1->c_func) {
97 			p2->c_time = p1->c_time;
98 			p2->c_arg = p1->c_arg;
99 			p1++;
100 			p2++;
101 		}
102 	}
103 
104 	/*
105 	 * lightning bolt time-out
106 	 * and time of day
107 	 */
108 out:
109 
110 	/*
111 	 * In order to not take input character interrupts to use
112 	 * the input silo on DZ's we have to guarantee to echo
113 	 * characters regularly.  This means that we have to
114 	 * call the timer routines predictably.  Since blocking
115 	 * in these routines is at spl5(), we have to make spl5()
116 	 * really spl6() blocking off the clock to put this code
117 	 * here.  Note also that it is critical that we run spl5()
118 	 * (i.e. really spl6()) in the receiver interrupt routines
119 	 * so we can't enter them recursively and transpose characters.
120 	 */
121 	if (rcnt >= rintvl) {
122 #if NDH11 > 0
123 		dhtimer();
124 #endif
125 #if NDZ11 > 0
126 		dztimer();
127 #endif
128 		rcnt = 0;
129 	} else
130 		rcnt++;
131 	if (!noproc) {
132 		s = u.u_procp->p_rssize;
133 		u.u_vm.vm_idsrss += s;
134 		if (u.u_procp->p_textp) {
135 			register int xrss = u.u_procp->p_textp->x_rssize;
136 
137 			s += xrss;
138 			u.u_vm.vm_ixrss += xrss;
139 		}
140 		if (s > u.u_vm.vm_maxrss)
141 			u.u_vm.vm_maxrss = s;
142 		if ((u.u_vm.vm_utime+u.u_vm.vm_stime+1)/HZ > u.u_limit[LIM_CPU]) {
143 			psignal(u.u_procp, SIGXCPU);
144 			if (u.u_limit[LIM_CPU] < INFINITY - 5)
145 				u.u_limit[LIM_CPU] += 5;
146 		}
147 	}
148 	if (USERMODE(ps)) {
149 		u.u_vm.vm_utime++;
150 		if(u.u_procp->p_nice > NZERO)
151 			cpstate = CP_NICE;
152 		else
153 			cpstate = CP_USER;
154 	} else {
155 		cpstate = CP_SYS;
156 		if (noproc)
157 			cpstate = CP_IDLE;
158 		else
159 			u.u_vm.vm_stime++;
160 	}
161 	cp_time[cpstate]++;
162 	for (i = 0; i < DK_NDRIVE; i++)
163 		if (dk_busy&(1<<i))
164 			dk_time[i]++;
165 	if (!noproc) {
166 		pp = u.u_procp;
167 		pp->p_cpticks++;
168 		if(++pp->p_cpu == 0)
169 			pp->p_cpu--;
170 		if(pp->p_cpu % 16 == 0) {
171 			(void) setpri(pp);
172 			if (pp->p_pri >= PUSER)
173 				pp->p_pri = pp->p_usrpri;
174 		}
175 	}
176 	++lbolt;
177 	if (lbolt % (HZ/4) == 0) {
178 		vmpago();
179 		runrun++;
180 	}
181 	if (lbolt >= HZ) {
182 		extern int hangcnt;
183 
184 		if (BASEPRI(ps))
185 			return;
186 		lbolt -= HZ;
187 		++time;
188 		(void) spl1();
189 		/*
190 		 * machdep.c:unhang uses hangcnt to make sure uba
191 		 * doesn't forget to interrupt (this has been observed).
192 		 * This prevents an accumulation of < 5 second uba failures
193 		 * from summing to a uba reset.
194 		 */
195 		if (hangcnt)
196 			hangcnt--;
197 		runrun++;
198 		wakeup((caddr_t)&lbolt);
199 		for(pp = &proc[0]; pp < &proc[NPROC]; pp++)
200 		if (pp->p_stat && pp->p_stat!=SZOMB) {
201 			if(pp->p_time != 127)
202 				pp->p_time++;
203 			if(pp->p_clktim)
204 				if(--pp->p_clktim == 0)
205 					if (pp->p_flag & STIMO) {
206 						s = spl6();
207 						switch (pp->p_stat) {
208 
209 						case SSLEEP:
210 							setrun(pp);
211 							break;
212 
213 						case SSTOP:
214 							unsleep(pp);
215 							break;
216 						}
217 						pp->p_flag &= ~STIMO;
218 						splx(s);
219 					} else
220 						psignal(pp, SIGALRM);
221 			if(pp->p_stat==SSLEEP||pp->p_stat==SSTOP)
222 				if (pp->p_slptime != 127)
223 					pp->p_slptime++;
224 			if (pp->p_flag&SLOAD)
225 				pp->p_pctcpu = ccpu * pp->p_pctcpu +
226 				    (1.0 - ccpu) * (pp->p_cpticks/(float)HZ);
227 			pp->p_cpticks = 0;
228 			a = (pp->p_cpu & 0377)*SCHMAG + pp->p_nice - NZERO;
229 			if(a < 0)
230 				a = 0;
231 			if(a > 255)
232 				a = 255;
233 			pp->p_cpu = a;
234 			(void) setpri(pp);
235 			s = spl6();
236 			if(pp->p_pri >= PUSER) {
237 				if ((pp != u.u_procp || noproc) &&
238 				    pp->p_stat == SRUN &&
239 				    (pp->p_flag & SLOAD) &&
240 				    pp->p_pri != pp->p_usrpri) {
241 					remrq(pp);
242 					pp->p_pri = pp->p_usrpri;
243 					setrq(pp);
244 				} else
245 					pp->p_pri = pp->p_usrpri;
246 			}
247 			splx(s);
248 		}
249 		vmmeter();
250 		if(runin!=0) {
251 			runin = 0;
252 			wakeup((caddr_t)&runin);
253 		}
254 		/*
255 		 * If there are pages that have been cleaned,
256 		 * jolt the pageout daemon to process them.
257 		 * We do this here so that these pages will be
258 		 * freed if there is an abundance of memory and the
259 		 * daemon would not be awakened otherwise.
260 		 */
261 		if (bclnlist != NULL)
262 			wakeup((caddr_t)&proc[2]);
263 		if (USERMODE(ps)) {
264 			pp = u.u_procp;
265 #ifdef ERNIE
266 			if (pp->p_uid)
267 				if (pp->p_nice == NZERO && u.u_vm.vm_utime > 600 * HZ)
268 					pp->p_nice = NZERO+4;
269 			(void) setpri(pp);
270 			pp->p_pri = pp->p_usrpri;
271 #endif
272 		}
273 	}
274 	if (!BASEPRI(ps))
275 		unhang();
276 	if (USERMODE(ps)) {
277 		/*
278 		 * We do this last since it
279 		 * may block on a page fault in user space.
280 		 */
281 		if (u.u_prof.pr_scale)
282 			addupc(pc, &u.u_prof, 1);
283 	}
284 #ifdef KPROF
285 	else if (!noproc) {
286 		register int indx = ((int)pc & 0x7fffffff) / 4;
287 
288 		if (indx >= 0 && indx < 20000)
289 			if (++kcount[indx] == 0)
290 				--kcount[indx];
291 	}
292 #endif
293 }
294 
295 /*
296  * timeout is called to arrange that
297  * fun(arg) is called in tim/HZ seconds.
298  * An entry is sorted into the callout
299  * structure. The time in each structure
300  * entry is the number of HZ's more
301  * than the previous entry.
302  * In this way, decrementing the
303  * first entry has the effect of
304  * updating all entries.
305  *
306  * The panic is there because there is nothing
307  * intelligent to be done if an entry won't fit.
308  */
309 timeout(fun, arg, tim)
310 int (*fun)();
311 caddr_t arg;
312 {
313 	register struct callo *p1, *p2;
314 	register int t;
315 	int s;
316 
317 	t = tim;
318 	p1 = &callout[0];
319 	s = spl7();
320 	while(p1->c_func != 0 && p1->c_time <= t) {
321 		t -= p1->c_time;
322 		p1++;
323 	}
324 	if (p1 >= &callout[NCALL-1])
325 		panic("Timeout table overflow");
326 	p1->c_time -= t;
327 	p2 = p1;
328 	while(p2->c_func != 0)
329 		p2++;
330 	while(p2 >= p1) {
331 		(p2+1)->c_time = p2->c_time;
332 		(p2+1)->c_func = p2->c_func;
333 		(p2+1)->c_arg = p2->c_arg;
334 		p2--;
335 	}
336 	p1->c_time = t;
337 	p1->c_func = fun;
338 	p1->c_arg = arg;
339 	splx(s);
340 }
341