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