xref: /csrg-svn/sys/kern/kern_clock.c (revision 928)
1*928Sbill /*	10/14/12	3.19	kern_clock.c	*/
29Sbill 
39Sbill #include "../h/param.h"
49Sbill #include "../h/systm.h"
5329Sbill #include "../h/dk.h"
69Sbill #include "../h/callo.h"
79Sbill #include "../h/seg.h"
89Sbill #include "../h/dir.h"
99Sbill #include "../h/user.h"
109Sbill #include "../h/proc.h"
119Sbill #include "../h/reg.h"
129Sbill #include "../h/psl.h"
139Sbill #include "../h/vm.h"
149Sbill #include "../h/buf.h"
159Sbill #include "../h/text.h"
16877Sbill #include "../h/vlimit.h"
17877Sbill #include "../h/mtpr.h"
18877Sbill #include "../h/clock.h"
199Sbill 
209Sbill #define	SCHMAG	9/10
219Sbill 
229Sbill 
239Sbill /*
249Sbill  * clock is called straight from
259Sbill  * the real time clock interrupt.
269Sbill  *
279Sbill  * Functions:
289Sbill  *	implement callouts
299Sbill  *	maintain user/system times
309Sbill  *	maintain date
319Sbill  *	profile
329Sbill  *	lightning bolt wakeup (every second)
339Sbill  *	alarm clock signals
349Sbill  *	jab the scheduler
359Sbill  */
369Sbill #ifdef KPROF
37104Sbill unsigned short kcount[20000];
389Sbill #endif
399Sbill 
40115Sbill /*
41115Sbill  * We handle regular calls to the dh and dz silo input processors
42115Sbill  * without using timeouts to save a little time.
43115Sbill  */
44142Sbill int	rintvl = 0;		/* every 1/60'th of sec check receivers */
45115Sbill int	rcnt;
46115Sbill 
479Sbill clock(pc, ps)
489Sbill caddr_t pc;
499Sbill {
509Sbill 	register struct callo *p1, *p2;
519Sbill 	register struct proc *pp;
529Sbill 	register int s;
53305Sbill 	int a, cpstate;
549Sbill 
559Sbill 	/*
569Sbill 	 * reprime clock
579Sbill 	 */
589Sbill 	clkreld();
599Sbill 
609Sbill 	/*
619Sbill 	 * callouts
629Sbill 	 * else update first non-zero time
639Sbill 	 */
649Sbill 
659Sbill 	if(callout[0].c_func == NULL)
669Sbill 		goto out;
679Sbill 	p2 = &callout[0];
689Sbill 	while(p2->c_time<=0 && p2->c_func!=NULL)
699Sbill 		p2++;
709Sbill 	p2->c_time--;
719Sbill 
729Sbill 	/*
739Sbill 	 * if ps is high, just return
749Sbill 	 */
759Sbill 	if (BASEPRI(ps))
769Sbill 		goto out;
779Sbill 
789Sbill 	/*
799Sbill 	 * callout
809Sbill 	 */
819Sbill 
829Sbill 	if(callout[0].c_time <= 0) {
839Sbill 		p1 = &callout[0];
849Sbill 		while(p1->c_func != 0 && p1->c_time <= 0) {
859Sbill 			(*p1->c_func)(p1->c_arg);
869Sbill 			p1++;
879Sbill 		}
889Sbill 		p2 = &callout[0];
899Sbill 		while(p2->c_func = p1->c_func) {
909Sbill 			p2->c_time = p1->c_time;
919Sbill 			p2->c_arg = p1->c_arg;
929Sbill 			p1++;
939Sbill 			p2++;
949Sbill 		}
959Sbill 	}
969Sbill 
979Sbill 	/*
989Sbill 	 * lightning bolt time-out
999Sbill 	 * and time of day
1009Sbill 	 */
1019Sbill out:
102138Sbill 
103138Sbill 	/*
104138Sbill 	 * In order to not take input character interrupts to use
105138Sbill 	 * the input silo on DZ's we have to guarantee to echo
106138Sbill 	 * characters regularly.  This means that we have to
107138Sbill 	 * call the timer routines predictably.  Since blocking
108138Sbill 	 * in these routines is at spl5(), we have to make spl5()
109138Sbill 	 * really spl6() blocking off the clock to put this code
110138Sbill 	 * here.  Note also that it is critical that we run spl5()
111138Sbill 	 * (i.e. really spl6()) in the receiver interrupt routines
112138Sbill 	 * so we can't enter them recursively and transpose characters.
113138Sbill 	 */
114138Sbill 	if (rcnt >= rintvl) {
115138Sbill 		dhtimer();
116138Sbill 		dztimer();
117138Sbill 		rcnt = 0;
118138Sbill 	} else
119138Sbill 		rcnt++;
1209Sbill 	if (!noproc) {
1219Sbill 		s = u.u_procp->p_rssize;
1229Sbill 		u.u_vm.vm_idsrss += s;
1239Sbill 		if (u.u_procp->p_textp) {
1249Sbill 			register int xrss = u.u_procp->p_textp->x_rssize;
1259Sbill 
1269Sbill 			s += xrss;
1279Sbill 			u.u_vm.vm_ixrss += xrss;
1289Sbill 		}
1299Sbill 		if (s > u.u_vm.vm_maxrss)
1309Sbill 			u.u_vm.vm_maxrss = s;
131375Sbill 		if ((u.u_vm.vm_utime+u.u_vm.vm_stime+1)/HZ > u.u_limit[LIM_CPU]) {
132375Sbill 			psignal(u.u_procp, SIGXCPU);
133375Sbill 			if (u.u_limit[LIM_CPU] < INFINITY - 5)
134375Sbill 				u.u_limit[LIM_CPU] += 5;
135375Sbill 		}
1369Sbill 	}
1379Sbill 	if (USERMODE(ps)) {
1389Sbill 		u.u_vm.vm_utime++;
1399Sbill 		if(u.u_procp->p_nice > NZERO)
140305Sbill 			cpstate = CP_NICE;
141305Sbill 		else
142305Sbill 			cpstate = CP_USER;
1439Sbill 	} else {
144305Sbill 		cpstate = CP_SYS;
1459Sbill 		if (noproc)
146305Sbill 			cpstate = CP_IDLE;
1479Sbill 		else
1489Sbill 			u.u_vm.vm_stime++;
1499Sbill 	}
150305Sbill 	dk_time[cpstate][dk_busy&(DK_NSTATES-1)]++;
1519Sbill 	if (!noproc) {
1529Sbill 		pp = u.u_procp;
1539Sbill 		if(++pp->p_cpu == 0)
1549Sbill 			pp->p_cpu--;
1559Sbill 		if(pp->p_cpu % 16 == 0) {
156125Sbill 			(void) setpri(pp);
1579Sbill 			if (pp->p_pri >= PUSER)
1589Sbill 				pp->p_pri = pp->p_usrpri;
1599Sbill 		}
1609Sbill 	}
1619Sbill 	++lbolt;
1629Sbill 	if (lbolt % (HZ/4) == 0) {
1639Sbill 		vmpago();
1649Sbill 		runrun++;
1659Sbill 	}
1669Sbill 	if (lbolt >= HZ) {
167877Sbill 		extern int hangcnt;
168877Sbill 
1699Sbill 		if (BASEPRI(ps))
1709Sbill 			return;
1719Sbill 		lbolt -= HZ;
1729Sbill 		++time;
173125Sbill 		(void) spl1();
174877Sbill 		/*
175877Sbill 		 * machdep.c:unhang uses hangcnt to make sure uba
176877Sbill 		 * doesn't forget to interrupt (this has been observed).
177877Sbill 		 * This prevents an accumulation of < 5 second uba failures
178877Sbill 		 * from summing to a uba reset.
179877Sbill 		 */
180877Sbill 		if (hangcnt)
181877Sbill 			hangcnt--;
1829Sbill 		runrun++;
1839Sbill 		wakeup((caddr_t)&lbolt);
1849Sbill 		for(pp = &proc[0]; pp < &proc[NPROC]; pp++)
185*928Sbill 		if (pp->p_stat && pp->p_stat!=SZOMB) {
1869Sbill 			if(pp->p_time != 127)
1879Sbill 				pp->p_time++;
1889Sbill 			if(pp->p_clktim)
1899Sbill 				if(--pp->p_clktim == 0)
190101Sbill 					if (pp->p_flag & STIMO) {
191101Sbill 						s = spl6();
192204Sbill 						switch (pp->p_stat) {
193204Sbill 
194204Sbill 						case SSLEEP:
195101Sbill 							setrun(pp);
196204Sbill 							break;
197204Sbill 
198204Sbill 						case SSTOP:
199204Sbill 							unsleep(pp);
200204Sbill 							break;
201204Sbill 						}
202101Sbill 						pp->p_flag &= ~STIMO;
203101Sbill 						splx(s);
204101Sbill 					} else
205166Sbill 						psignal(pp, SIGALRM);
2069Sbill 			if(pp->p_stat==SSLEEP||pp->p_stat==SSTOP)
2079Sbill 				if (pp->p_slptime != 127)
2089Sbill 					pp->p_slptime++;
2099Sbill 			if(pp->p_flag&SLOAD) {
2109Sbill 				ave(pp->p_aveflt, pp->p_faults, 5);
2119Sbill 				pp->p_faults = 0;
2129Sbill 			}
2139Sbill 			a = (pp->p_cpu & 0377)*SCHMAG + pp->p_nice - NZERO;
2149Sbill 			if(a < 0)
2159Sbill 				a = 0;
2169Sbill 			if(a > 255)
2179Sbill 				a = 255;
2189Sbill 			pp->p_cpu = a;
219125Sbill 			(void) setpri(pp);
2209Sbill 			s = spl6();
2219Sbill 			if(pp->p_pri >= PUSER) {
2229Sbill 				if ((pp != u.u_procp || noproc) &&
2239Sbill 				    pp->p_stat == SRUN &&
2249Sbill 				    (pp->p_flag & SLOAD) &&
2259Sbill 				    pp->p_pri != pp->p_usrpri) {
2269Sbill 					remrq(pp);
2279Sbill 					pp->p_pri = pp->p_usrpri;
2289Sbill 					setrq(pp);
2299Sbill 				} else
2309Sbill 					pp->p_pri = pp->p_usrpri;
2319Sbill 			}
2329Sbill 			splx(s);
2339Sbill 		}
2349Sbill 		vmmeter();
2359Sbill 		if(runin!=0) {
2369Sbill 			runin = 0;
2379Sbill 			wakeup((caddr_t)&runin);
2389Sbill 		}
2399Sbill 		/*
2409Sbill 		 * If there are pages that have been cleaned,
2419Sbill 		 * jolt the pageout daemon to process them.
2429Sbill 		 * We do this here so that these pages will be
2439Sbill 		 * freed if there is an abundance of memory and the
2449Sbill 		 * daemon would not be awakened otherwise.
2459Sbill 		 */
2469Sbill 		if (bclnlist != NULL)
2479Sbill 			wakeup((caddr_t)&proc[2]);
2489Sbill 		if (USERMODE(ps)) {
2499Sbill 			pp = u.u_procp;
250362Sbill #ifdef ERNIE
2519Sbill 			if (pp->p_uid)
2529Sbill 				if (pp->p_nice == NZERO && u.u_vm.vm_utime > 600 * HZ)
2539Sbill 					pp->p_nice = NZERO+4;
254125Sbill 			(void) setpri(pp);
2559Sbill 			pp->p_pri = pp->p_usrpri;
256362Sbill #endif
2579Sbill 		}
2589Sbill 	}
259277Sbill 	if (!BASEPRI(ps))
260277Sbill 		unhang();
2619Sbill 	if (USERMODE(ps)) {
2629Sbill 		/*
2639Sbill 		 * We do this last since it
2649Sbill 		 * may block on a page fault in user space.
2659Sbill 		 */
2669Sbill 		if (u.u_prof.pr_scale)
2679Sbill 			addupc(pc, &u.u_prof, 1);
2689Sbill 	}
2699Sbill #ifdef KPROF
2709Sbill 	else if (!noproc) {
271104Sbill 		register int indx = ((int)pc & 0x7fffffff) / 4;
2729Sbill 
2739Sbill 		if (indx >= 0 && indx < 20000)
274104Sbill 			if (++kcount[indx] == 0)
275104Sbill 				--kcount[indx];
2769Sbill 	}
2779Sbill #endif
2789Sbill }
2799Sbill 
2809Sbill /*
2819Sbill  * timeout is called to arrange that
2829Sbill  * fun(arg) is called in tim/HZ seconds.
2839Sbill  * An entry is sorted into the callout
2849Sbill  * structure. The time in each structure
2859Sbill  * entry is the number of HZ's more
2869Sbill  * than the previous entry.
2879Sbill  * In this way, decrementing the
2889Sbill  * first entry has the effect of
2899Sbill  * updating all entries.
2909Sbill  *
2919Sbill  * The panic is there because there is nothing
2929Sbill  * intelligent to be done if an entry won't fit.
2939Sbill  */
2949Sbill timeout(fun, arg, tim)
2959Sbill int (*fun)();
2969Sbill caddr_t arg;
2979Sbill {
2989Sbill 	register struct callo *p1, *p2;
2999Sbill 	register int t;
3009Sbill 	int s;
3019Sbill 
3029Sbill 	t = tim;
3039Sbill 	p1 = &callout[0];
3049Sbill 	s = spl7();
3059Sbill 	while(p1->c_func != 0 && p1->c_time <= t) {
3069Sbill 		t -= p1->c_time;
3079Sbill 		p1++;
3089Sbill 	}
3099Sbill 	if (p1 >= &callout[NCALL-1])
3109Sbill 		panic("Timeout table overflow");
3119Sbill 	p1->c_time -= t;
3129Sbill 	p2 = p1;
3139Sbill 	while(p2->c_func != 0)
3149Sbill 		p2++;
3159Sbill 	while(p2 >= p1) {
3169Sbill 		(p2+1)->c_time = p2->c_time;
3179Sbill 		(p2+1)->c_func = p2->c_func;
3189Sbill 		(p2+1)->c_arg = p2->c_arg;
3199Sbill 		p2--;
3209Sbill 	}
3219Sbill 	p1->c_time = t;
3229Sbill 	p1->c_func = fun;
3239Sbill 	p1->c_arg = arg;
3249Sbill 	splx(s);
3259Sbill }
326