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