xref: /csrg-svn/sys/kern/kern_clock.c (revision 370)
1*370Sbill /*	10/14/12	3.15	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"
16*370Sbill #include "../h/limit.h"
179Sbill 
189Sbill #define	SCHMAG	9/10
199Sbill 
209Sbill 
219Sbill /*
229Sbill  * clock is called straight from
239Sbill  * the real time clock interrupt.
249Sbill  *
259Sbill  * Functions:
269Sbill  *	implement callouts
279Sbill  *	maintain user/system times
289Sbill  *	maintain date
299Sbill  *	profile
309Sbill  *	lightning bolt wakeup (every second)
319Sbill  *	alarm clock signals
329Sbill  *	jab the scheduler
339Sbill  */
349Sbill #ifdef KPROF
35104Sbill unsigned short kcount[20000];
369Sbill #endif
379Sbill 
38115Sbill /*
39115Sbill  * We handle regular calls to the dh and dz silo input processors
40115Sbill  * without using timeouts to save a little time.
41115Sbill  */
42142Sbill int	rintvl = 0;		/* every 1/60'th of sec check receivers */
43115Sbill int	rcnt;
44115Sbill 
459Sbill clock(pc, ps)
469Sbill caddr_t pc;
479Sbill {
489Sbill 	register struct callo *p1, *p2;
499Sbill 	register struct proc *pp;
509Sbill 	register int s;
51305Sbill 	int a, cpstate;
529Sbill 
539Sbill 	/*
549Sbill 	 * reprime clock
559Sbill 	 */
569Sbill 	clkreld();
579Sbill 
589Sbill 	/*
599Sbill 	 * callouts
609Sbill 	 * else update first non-zero time
619Sbill 	 */
629Sbill 
639Sbill 	if(callout[0].c_func == NULL)
649Sbill 		goto out;
659Sbill 	p2 = &callout[0];
669Sbill 	while(p2->c_time<=0 && p2->c_func!=NULL)
679Sbill 		p2++;
689Sbill 	p2->c_time--;
699Sbill 
709Sbill 	/*
719Sbill 	 * if ps is high, just return
729Sbill 	 */
739Sbill 	if (BASEPRI(ps))
749Sbill 		goto out;
759Sbill 
769Sbill 	/*
779Sbill 	 * callout
789Sbill 	 */
799Sbill 
809Sbill 	if(callout[0].c_time <= 0) {
819Sbill 		p1 = &callout[0];
829Sbill 		while(p1->c_func != 0 && p1->c_time <= 0) {
839Sbill 			(*p1->c_func)(p1->c_arg);
849Sbill 			p1++;
859Sbill 		}
869Sbill 		p2 = &callout[0];
879Sbill 		while(p2->c_func = p1->c_func) {
889Sbill 			p2->c_time = p1->c_time;
899Sbill 			p2->c_arg = p1->c_arg;
909Sbill 			p1++;
919Sbill 			p2++;
929Sbill 		}
939Sbill 	}
949Sbill 
959Sbill 	/*
969Sbill 	 * lightning bolt time-out
979Sbill 	 * and time of day
989Sbill 	 */
999Sbill out:
100138Sbill 
101138Sbill 	/*
102138Sbill 	 * In order to not take input character interrupts to use
103138Sbill 	 * the input silo on DZ's we have to guarantee to echo
104138Sbill 	 * characters regularly.  This means that we have to
105138Sbill 	 * call the timer routines predictably.  Since blocking
106138Sbill 	 * in these routines is at spl5(), we have to make spl5()
107138Sbill 	 * really spl6() blocking off the clock to put this code
108138Sbill 	 * here.  Note also that it is critical that we run spl5()
109138Sbill 	 * (i.e. really spl6()) in the receiver interrupt routines
110138Sbill 	 * so we can't enter them recursively and transpose characters.
111138Sbill 	 */
112138Sbill 	if (rcnt >= rintvl) {
113138Sbill 		dhtimer();
114138Sbill 		dztimer();
115138Sbill 		rcnt = 0;
116138Sbill 	} else
117138Sbill 		rcnt++;
1189Sbill 	if (!noproc) {
1199Sbill 		s = u.u_procp->p_rssize;
1209Sbill 		u.u_vm.vm_idsrss += s;
1219Sbill 		if (u.u_procp->p_textp) {
1229Sbill 			register int xrss = u.u_procp->p_textp->x_rssize;
1239Sbill 
1249Sbill 			s += xrss;
1259Sbill 			u.u_vm.vm_ixrss += xrss;
1269Sbill 		}
1279Sbill 		if (s > u.u_vm.vm_maxrss)
1289Sbill 			u.u_vm.vm_maxrss = s;
1299Sbill 	}
1309Sbill 	if (USERMODE(ps)) {
1319Sbill 		u.u_vm.vm_utime++;
1329Sbill 		if(u.u_procp->p_nice > NZERO)
133305Sbill 			cpstate = CP_NICE;
134305Sbill 		else
135305Sbill 			cpstate = CP_USER;
1369Sbill 	} else {
137305Sbill 		cpstate = CP_SYS;
1389Sbill 		if (noproc)
139305Sbill 			cpstate = CP_IDLE;
1409Sbill 		else
1419Sbill 			u.u_vm.vm_stime++;
1429Sbill 	}
143305Sbill 	dk_time[cpstate][dk_busy&(DK_NSTATES-1)]++;
1449Sbill 	if (!noproc) {
1459Sbill 		pp = u.u_procp;
1469Sbill 		if(++pp->p_cpu == 0)
1479Sbill 			pp->p_cpu--;
1489Sbill 		if(pp->p_cpu % 16 == 0) {
149125Sbill 			(void) setpri(pp);
1509Sbill 			if (pp->p_pri >= PUSER)
1519Sbill 				pp->p_pri = pp->p_usrpri;
1529Sbill 		}
1539Sbill 	}
1549Sbill 	++lbolt;
1559Sbill 	if (lbolt % (HZ/4) == 0) {
1569Sbill 		vmpago();
1579Sbill 		runrun++;
1589Sbill 	}
1599Sbill 	if (lbolt >= HZ) {
1609Sbill 		if (BASEPRI(ps))
1619Sbill 			return;
1629Sbill 		lbolt -= HZ;
1639Sbill 		++time;
164125Sbill 		(void) spl1();
1659Sbill 		runrun++;
1669Sbill 		wakeup((caddr_t)&lbolt);
1679Sbill 		for(pp = &proc[0]; pp < &proc[NPROC]; pp++)
1689Sbill 		if (pp->p_stat && pp->p_stat<SZOMB) {
1699Sbill 			if(pp->p_time != 127)
1709Sbill 				pp->p_time++;
1719Sbill 			if(pp->p_clktim)
1729Sbill 				if(--pp->p_clktim == 0)
173101Sbill 					if (pp->p_flag & STIMO) {
174101Sbill 						s = spl6();
175204Sbill 						switch (pp->p_stat) {
176204Sbill 
177204Sbill 						case SSLEEP:
178101Sbill 							setrun(pp);
179204Sbill 							break;
180204Sbill 
181204Sbill 						case SSTOP:
182204Sbill 							unsleep(pp);
183204Sbill 							break;
184204Sbill 						}
185101Sbill 						pp->p_flag &= ~STIMO;
186101Sbill 						splx(s);
187101Sbill 					} else
188166Sbill 						psignal(pp, SIGALRM);
1899Sbill 			if(pp->p_stat==SSLEEP||pp->p_stat==SSTOP)
1909Sbill 				if (pp->p_slptime != 127)
1919Sbill 					pp->p_slptime++;
1929Sbill 			if(pp->p_flag&SLOAD) {
1939Sbill 				ave(pp->p_aveflt, pp->p_faults, 5);
1949Sbill 				pp->p_faults = 0;
1959Sbill 			}
1969Sbill 			a = (pp->p_cpu & 0377)*SCHMAG + pp->p_nice - NZERO;
1979Sbill 			if(a < 0)
1989Sbill 				a = 0;
1999Sbill 			if(a > 255)
2009Sbill 				a = 255;
2019Sbill 			pp->p_cpu = a;
202125Sbill 			(void) setpri(pp);
2039Sbill 			s = spl6();
2049Sbill 			if(pp->p_pri >= PUSER) {
2059Sbill 				if ((pp != u.u_procp || noproc) &&
2069Sbill 				    pp->p_stat == SRUN &&
2079Sbill 				    (pp->p_flag & SLOAD) &&
2089Sbill 				    pp->p_pri != pp->p_usrpri) {
2099Sbill 					remrq(pp);
2109Sbill 					pp->p_pri = pp->p_usrpri;
2119Sbill 					setrq(pp);
2129Sbill 				} else
2139Sbill 					pp->p_pri = pp->p_usrpri;
2149Sbill 			}
2159Sbill 			splx(s);
2169Sbill 		}
2179Sbill 		vmmeter();
2189Sbill 		if(runin!=0) {
2199Sbill 			runin = 0;
2209Sbill 			wakeup((caddr_t)&runin);
2219Sbill 		}
2229Sbill 		/*
2239Sbill 		 * If there are pages that have been cleaned,
2249Sbill 		 * jolt the pageout daemon to process them.
2259Sbill 		 * We do this here so that these pages will be
2269Sbill 		 * freed if there is an abundance of memory and the
2279Sbill 		 * daemon would not be awakened otherwise.
2289Sbill 		 */
2299Sbill 		if (bclnlist != NULL)
2309Sbill 			wakeup((caddr_t)&proc[2]);
2319Sbill 		if (USERMODE(ps)) {
2329Sbill 			pp = u.u_procp;
233362Sbill #ifdef ERNIE
2349Sbill 			if (pp->p_uid)
2359Sbill 				if (pp->p_nice == NZERO && u.u_vm.vm_utime > 600 * HZ)
2369Sbill 					pp->p_nice = NZERO+4;
237125Sbill 			(void) setpri(pp);
2389Sbill 			pp->p_pri = pp->p_usrpri;
239362Sbill #endif
240362Sbill 			if (u.u_vm.vm_utime+u.u_vm.vm_stime > u.u_limit[LIM_CPU])
241362Sbill 				psignal(pp, SIGXCPU);
2429Sbill 		}
2439Sbill 	}
244277Sbill 	if (!BASEPRI(ps))
245277Sbill 		unhang();
2469Sbill 	if (USERMODE(ps)) {
2479Sbill 		/*
2489Sbill 		 * We do this last since it
2499Sbill 		 * may block on a page fault in user space.
2509Sbill 		 */
2519Sbill 		if (u.u_prof.pr_scale)
2529Sbill 			addupc(pc, &u.u_prof, 1);
2539Sbill 	}
2549Sbill #ifdef KPROF
2559Sbill 	else if (!noproc) {
256104Sbill 		register int indx = ((int)pc & 0x7fffffff) / 4;
2579Sbill 
2589Sbill 		if (indx >= 0 && indx < 20000)
259104Sbill 			if (++kcount[indx] == 0)
260104Sbill 				--kcount[indx];
2619Sbill 	}
2629Sbill #endif
2639Sbill }
2649Sbill 
2659Sbill /*
2669Sbill  * timeout is called to arrange that
2679Sbill  * fun(arg) is called in tim/HZ seconds.
2689Sbill  * An entry is sorted into the callout
2699Sbill  * structure. The time in each structure
2709Sbill  * entry is the number of HZ's more
2719Sbill  * than the previous entry.
2729Sbill  * In this way, decrementing the
2739Sbill  * first entry has the effect of
2749Sbill  * updating all entries.
2759Sbill  *
2769Sbill  * The panic is there because there is nothing
2779Sbill  * intelligent to be done if an entry won't fit.
2789Sbill  */
2799Sbill timeout(fun, arg, tim)
2809Sbill int (*fun)();
2819Sbill caddr_t arg;
2829Sbill {
2839Sbill 	register struct callo *p1, *p2;
2849Sbill 	register int t;
2859Sbill 	int s;
2869Sbill 
2879Sbill 	t = tim;
2889Sbill 	p1 = &callout[0];
2899Sbill 	s = spl7();
2909Sbill 	while(p1->c_func != 0 && p1->c_time <= t) {
2919Sbill 		t -= p1->c_time;
2929Sbill 		p1++;
2939Sbill 	}
2949Sbill 	if (p1 >= &callout[NCALL-1])
2959Sbill 		panic("Timeout table overflow");
2969Sbill 	p1->c_time -= t;
2979Sbill 	p2 = p1;
2989Sbill 	while(p2->c_func != 0)
2999Sbill 		p2++;
3009Sbill 	while(p2 >= p1) {
3019Sbill 		(p2+1)->c_time = p2->c_time;
3029Sbill 		(p2+1)->c_func = p2->c_func;
3039Sbill 		(p2+1)->c_arg = p2->c_arg;
3049Sbill 		p2--;
3059Sbill 	}
3069Sbill 	p1->c_time = t;
3079Sbill 	p1->c_func = fun;
3089Sbill 	p1->c_arg = arg;
3099Sbill 	splx(s);
3109Sbill }
311