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