xref: /csrg-svn/sys/kern/kern_time.c (revision 17356)
1*17356Skarels /*	kern_time.c	6.4	84/11/14	*/
27424Sroot 
39757Ssam #include "../machine/reg.h"
49757Ssam 
517093Sbloom #include "param.h"
617093Sbloom #include "dir.h"		/* XXX */
717093Sbloom #include "user.h"
817093Sbloom #include "kernel.h"
917093Sbloom #include "inode.h"
1017093Sbloom #include "proc.h"
117424Sroot 
128103Sroot /*
138103Sroot  * Time of day and interval timer support.
148146Sroot  *
158146Sroot  * These routines provide the kernel entry points to get and set
168146Sroot  * the time-of-day and per-process interval timers.  Subroutines
178146Sroot  * here provide support for adding and subtracting timeval structures
188146Sroot  * and decrementing interval timers, optionally reloading the interval
198146Sroot  * timers when they expire.
208103Sroot  */
218103Sroot 
228034Sroot gettimeofday()
237424Sroot {
248034Sroot 	register struct a {
258034Sroot 		struct	timeval *tp;
268034Sroot 		struct	timezone *tzp;
278034Sroot 	} *uap = (struct a *)u.u_ap;
288034Sroot 	struct timeval atv;
298103Sroot 	int s;
307500Sroot 
318103Sroot 	s = spl7(); atv = time; splx(s);
329998Ssam 	u.u_error = copyout((caddr_t)&atv, (caddr_t)uap->tp, sizeof (atv));
339998Ssam 	if (u.u_error)
348034Sroot 		return;
358034Sroot 	if (uap->tzp == 0)
368034Sroot 		return;
378103Sroot 	/* SHOULD HAVE PER-PROCESS TIMEZONE */
389998Ssam 	u.u_error = copyout((caddr_t)&tz, (caddr_t)uap->tzp, sizeof (tz));
397500Sroot }
407500Sroot 
418034Sroot settimeofday()
427500Sroot {
438034Sroot 	register struct a {
448103Sroot 		struct	timeval *tv;
458103Sroot 		struct	timezone *tzp;
468034Sroot 	} *uap = (struct a *)u.u_ap;
478034Sroot 	struct timeval atv;
488034Sroot 	struct timezone atz;
497500Sroot 
509998Ssam 	u.u_error = copyin((caddr_t)uap->tv, (caddr_t)&atv,
519998Ssam 		sizeof (struct timeval));
529998Ssam 	if (u.u_error)
538034Sroot 		return;
548103Sroot 	setthetime(&atv);
558103Sroot 	if (uap->tzp && suser()) {
569998Ssam 		u.u_error = copyin((caddr_t)uap->tzp, (caddr_t)&atz,
579998Ssam 			sizeof (atz));
5816576Ssam 		if (u.u_error == 0)
5916576Ssam 			tz = atz;
608034Sroot 	}
617500Sroot }
627500Sroot 
638103Sroot setthetime(tv)
648103Sroot 	struct timeval *tv;
658103Sroot {
668103Sroot 	int s;
678103Sroot 
688103Sroot 	if (!suser())
698103Sroot 		return;
708146Sroot /* WHAT DO WE DO ABOUT PENDING REAL-TIME TIMEOUTS??? */
718103Sroot 	boottime.tv_sec += tv->tv_sec - time.tv_sec;
728103Sroot 	s = spl7(); time = *tv; splx(s);
739007Sroot 	resettodr();
748103Sroot }
758103Sroot 
76*17356Skarels int adjtimedelta;
77*17356Skarels 
78*17356Skarels adjtime()
79*17356Skarels {
80*17356Skarels 	register struct a {
81*17356Skarels 		struct timeval *delta;
82*17356Skarels 		struct timeval *olddelta;
83*17356Skarels 	} *uap = (struct a *)u.u_ap;
84*17356Skarels 
85*17356Skarels 	struct timeval atv, oatv;
86*17356Skarels 
87*17356Skarels 	if (!suser())
88*17356Skarels 		return;
89*17356Skarels 	u.u_error = copyin((caddr_t)uap->delta, (caddr_t)&atv,
90*17356Skarels 		sizeof (struct timeval));
91*17356Skarels 	if (u.u_error)
92*17356Skarels 		return;
93*17356Skarels 	if (uap->olddelta) {
94*17356Skarels 		oatv.tv_sec = adjtimedelta / 1000000;
95*17356Skarels 		oatv.tv_usec = adjtimedelta % 1000000;
96*17356Skarels 		(void) copyout((caddr_t)&oatv, (caddr_t)uap->olddelta,
97*17356Skarels 			sizeof (struct timeval));
98*17356Skarels 	}
99*17356Skarels 	adjtimedelta = atv.tv_sec * 1000000 + atv.tv_usec;
100*17356Skarels }
101*17356Skarels 
1028146Sroot /*
1038146Sroot  * Get value of an interval timer.  The process virtual and
1048146Sroot  * profiling virtual time timers are kept in the u. area, since
1058146Sroot  * they can be swapped out.  These are kept internally in the
1068146Sroot  * way they are specified externally: in time until they expire.
1078146Sroot  *
1088146Sroot  * The real time interval timer is kept in the process table slot
1098146Sroot  * for the process, and its value (it_value) is kept as an
1108146Sroot  * absolute time rather than as a delta, so that it is easy to keep
1118146Sroot  * periodic real-time signals from drifting.
1128146Sroot  *
1138146Sroot  * Virtual time timers are processed in the hardclock() routine of
1148146Sroot  * kern_clock.c.  The real time timer is processed by a timeout
1158146Sroot  * routine, called from the softclock() routine.  Since a callout
1168146Sroot  * may be delayed in real time due to interrupt processing in the system,
1178146Sroot  * it is possible for the real time timeout routine (realitexpire, given below),
1188146Sroot  * to be delayed in real time past when it is supposed to occur.  It
1198146Sroot  * does not suffice, therefore, to reload the real timer .it_value from the
1208146Sroot  * real time timers .it_interval.  Rather, we compute the next time in
1218146Sroot  * absolute time the timer should go off.
1228146Sroot  */
1238034Sroot getitimer()
1248034Sroot {
1257424Sroot 	register struct a {
1268034Sroot 		u_int	which;
1278034Sroot 		struct	itimerval *itv;
1288034Sroot 	} *uap = (struct a *)u.u_ap;
1298114Sroot 	struct itimerval aitv;
1308034Sroot 	int s;
1317424Sroot 
1328034Sroot 	if (uap->which > 2) {
1338034Sroot 		u.u_error = EINVAL;
1348034Sroot 		return;
1357424Sroot 	}
1368034Sroot 	s = spl7();
1378114Sroot 	if (uap->which == ITIMER_REAL) {
1388146Sroot 		/*
1398146Sroot 		 * Convert from absoulte to relative time in .it_value
1408146Sroot 		 * part of real time timer.  If time for real time timer
1418146Sroot 		 * has passed return 0, else return difference between
1428146Sroot 		 * current time and time for the timer to go off.
1438146Sroot 		 */
1448114Sroot 		aitv = u.u_procp->p_realtimer;
1458114Sroot 		if (timerisset(&aitv.it_value))
1468114Sroot 			if (timercmp(&aitv.it_value, &time, <))
1478114Sroot 				timerclear(&aitv.it_value);
1488114Sroot 			else
1498114Sroot 				timevalsub(&aitv.it_value, &time);
1508114Sroot 	} else
1518114Sroot 		aitv = u.u_timer[uap->which];
1528114Sroot 	splx(s);
1539998Ssam 	u.u_error = copyout((caddr_t)&aitv, (caddr_t)uap->itv,
1549998Ssam 	    sizeof (struct itimerval));
1558034Sroot 	splx(s);
1567424Sroot }
1577424Sroot 
1588034Sroot setitimer()
1597424Sroot {
1607424Sroot 	register struct a {
1618034Sroot 		u_int	which;
1628103Sroot 		struct	itimerval *itv, *oitv;
1638034Sroot 	} *uap = (struct a *)u.u_ap;
1648034Sroot 	struct itimerval aitv;
1658034Sroot 	int s;
1668114Sroot 	register struct proc *p = u.u_procp;
1677424Sroot 
1688034Sroot 	if (uap->which > 2) {
1698034Sroot 		u.u_error = EINVAL;
1708103Sroot 		return;
1717424Sroot 	}
1729998Ssam 	u.u_error = copyin((caddr_t)uap->itv, (caddr_t)&aitv,
1739998Ssam 	    sizeof (struct itimerval));
1749998Ssam 	if (u.u_error)
1758103Sroot 		return;
1768103Sroot 	if (uap->oitv) {
1778103Sroot 		uap->itv = uap->oitv;
1788103Sroot 		getitimer();
1798103Sroot 	}
1808103Sroot 	if (itimerfix(&aitv.it_value) || itimerfix(&aitv.it_interval)) {
1818103Sroot 		u.u_error = EINVAL;
1828103Sroot 		return;
1838103Sroot 	}
1848103Sroot 	s = spl7();
1858114Sroot 	if (uap->which == ITIMER_REAL) {
1868625Sroot 		untimeout(realitexpire, (caddr_t)p);
1878114Sroot 		if (timerisset(&aitv.it_value)) {
1888114Sroot 			timevaladd(&aitv.it_value, &time);
1898625Sroot 			timeout(realitexpire, (caddr_t)p, hzto(&aitv.it_value));
1908114Sroot 		}
1918114Sroot 		p->p_realtimer = aitv;
1928114Sroot 	} else
1938103Sroot 		u.u_timer[uap->which] = aitv;
1948034Sroot 	splx(s);
1957424Sroot }
1967424Sroot 
1978146Sroot /*
1988146Sroot  * Real interval timer expired:
1998146Sroot  * send process whose timer expired an alarm signal.
2008146Sroot  * If time is not set up to reload, then just return.
2018146Sroot  * Else compute next time timer should go off which is > current time.
2028146Sroot  * This is where delay in processing this timeout causes multiple
2038146Sroot  * SIGALRM calls to be compressed into one.
2048146Sroot  */
2058146Sroot realitexpire(p)
2068114Sroot 	register struct proc *p;
2078114Sroot {
2088114Sroot 	int s;
2098114Sroot 
2108114Sroot 	psignal(p, SIGALRM);
2118114Sroot 	if (!timerisset(&p->p_realtimer.it_interval)) {
2128114Sroot 		timerclear(&p->p_realtimer.it_value);
2138114Sroot 		return;
2148114Sroot 	}
2158114Sroot 	for (;;) {
2168114Sroot 		s = spl7();
2178114Sroot 		timevaladd(&p->p_realtimer.it_value,
2188114Sroot 		    &p->p_realtimer.it_interval);
2198114Sroot 		if (timercmp(&p->p_realtimer.it_value, &time, >)) {
2208625Sroot 			timeout(realitexpire, (caddr_t)p,
2218625Sroot 			    hzto(&p->p_realtimer.it_value));
2228114Sroot 			splx(s);
2238114Sroot 			return;
2248114Sroot 		}
2258114Sroot 		splx(s);
2268114Sroot 	}
2278114Sroot }
2288114Sroot 
2298146Sroot /*
2308146Sroot  * Check that a proposed value to load into the .it_value or
2318146Sroot  * .it_interval part of an interval timer is acceptable, and
2328146Sroot  * fix it to have at least minimal value (i.e. if it is less
2338146Sroot  * than the resolution of the clock, round it up.)
2348146Sroot  */
2358103Sroot itimerfix(tv)
2368103Sroot 	struct timeval *tv;
2377424Sroot {
2388034Sroot 
2398114Sroot 	if (tv->tv_sec < 0 || tv->tv_sec > 100000000 ||
2408114Sroot 	    tv->tv_usec < 0 || tv->tv_usec >= 1000000)
2418103Sroot 		return (EINVAL);
24212970Ssam 	if (tv->tv_sec == 0 && tv->tv_usec != 0 && tv->tv_usec < tick)
2438103Sroot 		tv->tv_usec = tick;
2448103Sroot 	return (0);
2458034Sroot }
2468034Sroot 
2478146Sroot /*
2488146Sroot  * Decrement an interval timer by a specified number
2498146Sroot  * of microseconds, which must be less than a second,
2508146Sroot  * i.e. < 1000000.  If the timer expires, then reload
2518146Sroot  * it.  In this case, carry over (usec - old value) to
2528146Sroot  * reducint the value reloaded into the timer so that
2538146Sroot  * the timer does not drift.  This routine assumes
2548146Sroot  * that it is called in a context where the timers
2558146Sroot  * on which it is operating cannot change in value.
2568146Sroot  */
2578034Sroot itimerdecr(itp, usec)
2588034Sroot 	register struct itimerval *itp;
2598034Sroot 	int usec;
2608034Sroot {
2618034Sroot 
2628103Sroot 	if (itp->it_value.tv_usec < usec) {
2638103Sroot 		if (itp->it_value.tv_sec == 0) {
2648146Sroot 			/* expired, and already in next interval */
2658103Sroot 			usec -= itp->it_value.tv_usec;
2668034Sroot 			goto expire;
2678103Sroot 		}
2688103Sroot 		itp->it_value.tv_usec += 1000000;
2698103Sroot 		itp->it_value.tv_sec--;
2708034Sroot 	}
2718103Sroot 	itp->it_value.tv_usec -= usec;
2728103Sroot 	usec = 0;
2738103Sroot 	if (timerisset(&itp->it_value))
2748034Sroot 		return (1);
2758146Sroot 	/* expired, exactly at end of interval */
2768034Sroot expire:
2778103Sroot 	if (timerisset(&itp->it_interval)) {
2788103Sroot 		itp->it_value = itp->it_interval;
2798103Sroot 		itp->it_value.tv_usec -= usec;
2808103Sroot 		if (itp->it_value.tv_usec < 0) {
2818103Sroot 			itp->it_value.tv_usec += 1000000;
2828103Sroot 			itp->it_value.tv_sec--;
2838103Sroot 		}
2848103Sroot 	} else
2858146Sroot 		itp->it_value.tv_usec = 0;		/* sec is already 0 */
2868034Sroot 	return (0);
2878034Sroot }
2888034Sroot 
2898146Sroot /*
2908146Sroot  * Add and subtract routines for timevals.
2918146Sroot  * N.B.: subtract routine doesn't deal with
2928146Sroot  * results which are before the beginning,
2938146Sroot  * it just gets very confused in this case.
2948146Sroot  * Caveat emptor.
2958146Sroot  */
2968146Sroot timevaladd(t1, t2)
2978146Sroot 	struct timeval *t1, *t2;
2988146Sroot {
2998146Sroot 
3008146Sroot 	t1->tv_sec += t2->tv_sec;
3018146Sroot 	t1->tv_usec += t2->tv_usec;
3028146Sroot 	timevalfix(t1);
3038146Sroot }
3048146Sroot 
3058146Sroot timevalsub(t1, t2)
3068146Sroot 	struct timeval *t1, *t2;
3078146Sroot {
3088146Sroot 
3098146Sroot 	t1->tv_sec -= t2->tv_sec;
3108146Sroot 	t1->tv_usec -= t2->tv_usec;
3118146Sroot 	timevalfix(t1);
3128146Sroot }
3138146Sroot 
3148146Sroot timevalfix(t1)
3158146Sroot 	struct timeval *t1;
3168146Sroot {
3178146Sroot 
3188146Sroot 	if (t1->tv_usec < 0) {
3198146Sroot 		t1->tv_sec--;
3208146Sroot 		t1->tv_usec += 1000000;
3218146Sroot 	}
3228146Sroot 	if (t1->tv_usec >= 1000000) {
3238146Sroot 		t1->tv_sec++;
3248146Sroot 		t1->tv_usec -= 1000000;
3258146Sroot 	}
3268146Sroot }
327