xref: /original-bsd/sys/kern/kern_time.c (revision 7316b25a)
1dcae39bdSmckusick /*
28f6f57faSbostic  * Copyright (c) 1982, 1986, 1989, 1993
38f6f57faSbostic  *	The Regents of the University of California.  All rights reserved.
4dcae39bdSmckusick  *
5b383d302Sbostic  * %sccs.include.redist.c%
6014695a9Smckusick  *
7*7316b25aSmckusick  *	@(#)kern_time.c	8.4 (Berkeley) 05/26/95
8dcae39bdSmckusick  */
9db51853bSsam 
106e23d7a0Sbostic #include <sys/param.h>
116e23d7a0Sbostic #include <sys/resourcevar.h>
126e23d7a0Sbostic #include <sys/kernel.h>
136e23d7a0Sbostic #include <sys/systm.h>
146e23d7a0Sbostic #include <sys/proc.h>
156e23d7a0Sbostic #include <sys/vnode.h>
16ef678427Sroot 
17ab04d79bScgd #include <sys/mount.h>
18ab04d79bScgd #include <sys/syscallargs.h>
19ab04d79bScgd 
206e23d7a0Sbostic #include <machine/cpu.h>
2167a72975Skarels 
2272762883Sroot /*
2372762883Sroot  * Time of day and interval timer support.
2434eef8ebSroot  *
2534eef8ebSroot  * These routines provide the kernel entry points to get and set
2634eef8ebSroot  * the time-of-day and per-process interval timers.  Subroutines
2734eef8ebSroot  * here provide support for adding and subtracting timeval structures
2834eef8ebSroot  * and decrementing interval timers, optionally reloading the interval
2934eef8ebSroot  * timers when they expire.
3072762883Sroot  */
3172762883Sroot 
32d1ec48c2Skarels /* ARGSUSED */
33ab04d79bScgd int
gettimeofday(p,uap,retval)34d1ec48c2Skarels gettimeofday(p, uap, retval)
35d1ec48c2Skarels 	struct proc *p;
36ab04d79bScgd 	register struct gettimeofday_args /* {
37ab04d79bScgd 		syscallarg(struct timeval *) tp;
38ab04d79bScgd 		syscallarg(struct timezone *) tzp;
39ab04d79bScgd 	} */ *uap;
40ab04d79bScgd 	register_t *retval;
41d1ec48c2Skarels {
42ef678427Sroot 	struct timeval atv;
43d1ec48c2Skarels 	int error = 0;
44ef678427Sroot 
45ab04d79bScgd 	if (SCARG(uap, tp)) {
4670dbe469Skarels 		microtime(&atv);
47ab04d79bScgd 		if (error = copyout((caddr_t)&atv, (caddr_t)SCARG(uap, tp),
48d1ec48c2Skarels 		    sizeof (atv)))
492c51c3e4Skarels 			return (error);
502da4521eSbostic 	}
51ab04d79bScgd 	if (SCARG(uap, tzp))
52ab04d79bScgd 		error = copyout((caddr_t)&tz, (caddr_t)SCARG(uap, tzp),
532da4521eSbostic 		    sizeof (tz));
542c51c3e4Skarels 	return (error);
55ef678427Sroot }
56ef678427Sroot 
57187e1fb7Sbostic /* ARGSUSED */
58ab04d79bScgd int
settimeofday(p,uap,retval)59d1ec48c2Skarels settimeofday(p, uap, retval)
60d1ec48c2Skarels 	struct proc *p;
61ab04d79bScgd 	struct settimeofday_args /* {
62ab04d79bScgd 		syscallarg(struct timeval *) tv;
63ab04d79bScgd 		syscallarg(struct timezone *) tzp;
64ab04d79bScgd 	} */ *uap;
65ab04d79bScgd 	register_t *retval;
66d1ec48c2Skarels {
67e4223d7eStorek 	struct timeval atv, delta;
68ef678427Sroot 	struct timezone atz;
69d1ec48c2Skarels 	int error, s;
70ef678427Sroot 
710b0833e3Skarels 	if (error = suser(p->p_ucred, &p->p_acflag))
722c51c3e4Skarels 		return (error);
73e4223d7eStorek 	/* Verify all parameters before changing time. */
74ab04d79bScgd 	if (SCARG(uap, tv) && (error = copyin((caddr_t)SCARG(uap, tv),
75ab04d79bScgd 	    (caddr_t)&atv, sizeof(atv))))
762c51c3e4Skarels 		return (error);
77ab04d79bScgd 	if (SCARG(uap, tzp) && (error = copyin((caddr_t)SCARG(uap, tzp),
78ab04d79bScgd 	    (caddr_t)&atz, sizeof(atz))))
79e4223d7eStorek 		return (error);
80ab04d79bScgd 	if (SCARG(uap, tv)) {
81*7316b25aSmckusick 		/*
82*7316b25aSmckusick 		 * If the system is secure, we do not allow the time to be
83*7316b25aSmckusick 		 * set to an earlier value (it may be slowed using adjtime,
84*7316b25aSmckusick 		 * but not set back). This feature prevent interlopers from
85*7316b25aSmckusick 		 * setting arbitrary time stamps on files.
86*7316b25aSmckusick 		 */
87*7316b25aSmckusick 		if (securelevel > 0 && timercmp(&atv, &time, <))
88*7316b25aSmckusick 			return (EPERM);
89014695a9Smckusick 		/* WHAT DO WE DO ABOUT PENDING REAL-TIME TIMEOUTS??? */
90e4223d7eStorek 		s = splclock();
91e4223d7eStorek 		/* nb. delta.tv_usec may be < 0, but this is OK here */
92e4223d7eStorek 		delta.tv_sec = atv.tv_sec - time.tv_sec;
93e4223d7eStorek 		delta.tv_usec = atv.tv_usec - time.tv_usec;
94e4223d7eStorek 		time = atv;
95e4223d7eStorek 		(void) splsoftclock();
96e4223d7eStorek 		timevaladd(&boottime, &delta);
97e4223d7eStorek 		timevalfix(&boottime);
98e4223d7eStorek 		timevaladd(&runtime, &delta);
99e4223d7eStorek 		timevalfix(&runtime);
10096c192e5Smckusick #		ifdef NFS
10196c192e5Smckusick 			lease_updatetime(delta.tv_sec);
10296c192e5Smckusick #		endif
103e4223d7eStorek 		splx(s);
104014695a9Smckusick 		resettodr();
1052da4521eSbostic 	}
106ab04d79bScgd 	if (SCARG(uap, tzp))
1070228495eSsam 		tz = atz;
108e4223d7eStorek 	return (0);
109ef678427Sroot }
11072762883Sroot 
111a690062aSkarels extern	int tickadj;			/* "standard" clock skew, us./tick */
112a690062aSkarels int	tickdelta;			/* current clock skew, us. per tick */
113a690062aSkarels long	timedelta;			/* unapplied time correction, us. */
114a690062aSkarels long	bigadj = 1000000;		/* use 10x skew above bigadj us. */
1155d3ec6cbSkarels 
116d1ec48c2Skarels /* ARGSUSED */
117ab04d79bScgd int
adjtime(p,uap,retval)118d1ec48c2Skarels adjtime(p, uap, retval)
119d1ec48c2Skarels 	struct proc *p;
120ab04d79bScgd 	register struct adjtime_args /* {
121ab04d79bScgd 		syscallarg(struct timeval *) delta;
122ab04d79bScgd 		syscallarg(struct timeval *) olddelta;
123ab04d79bScgd 	} */ *uap;
124ab04d79bScgd 	register_t *retval;
125d1ec48c2Skarels {
126cbd24f66Storek 	struct timeval atv;
127cbd24f66Storek 	register long ndelta, ntickdelta, odelta;
128d1ec48c2Skarels 	int s, error;
1295d3ec6cbSkarels 
1300b0833e3Skarels 	if (error = suser(p->p_ucred, &p->p_acflag))
1312c51c3e4Skarels 		return (error);
132ab04d79bScgd 	if (error = copyin((caddr_t)SCARG(uap, delta), (caddr_t)&atv,
133ab04d79bScgd 	    sizeof(struct timeval)))
1342c51c3e4Skarels 		return (error);
135a690062aSkarels 
136cbd24f66Storek 	/*
137cbd24f66Storek 	 * Compute the total correction and the rate at which to apply it.
138cbd24f66Storek 	 * Round the adjustment down to a whole multiple of the per-tick
139cbd24f66Storek 	 * delta, so that after some number of incremental changes in
140cbd24f66Storek 	 * hardclock(), tickdelta will become zero, lest the correction
141cbd24f66Storek 	 * overshoot and start taking us away from the desired final time.
142cbd24f66Storek 	 */
143cbd24f66Storek 	ndelta = atv.tv_sec * 1000000 + atv.tv_usec;
144cbd24f66Storek 	if (ndelta > bigadj)
145cbd24f66Storek 		ntickdelta = 10 * tickadj;
146cbd24f66Storek 	else
147cbd24f66Storek 		ntickdelta = tickadj;
148cbd24f66Storek 	if (ndelta % ntickdelta)
149cbd24f66Storek 		ndelta = ndelta / ntickdelta * ntickdelta;
150cbd24f66Storek 
151cbd24f66Storek 	/*
152cbd24f66Storek 	 * To make hardclock()'s job easier, make the per-tick delta negative
153cbd24f66Storek 	 * if we want time to run slower; then hardclock can simply compute
154cbd24f66Storek 	 * tick + tickdelta, and subtract tickdelta from timedelta.
155cbd24f66Storek 	 */
156cbd24f66Storek 	if (ndelta < 0)
157cbd24f66Storek 		ntickdelta = -ntickdelta;
158e782b972Skarels 	s = splclock();
159cbd24f66Storek 	odelta = timedelta;
160a690062aSkarels 	timedelta = ndelta;
161cbd24f66Storek 	tickdelta = ntickdelta;
162a690062aSkarels 	splx(s);
163a690062aSkarels 
164ab04d79bScgd 	if (SCARG(uap, olddelta)) {
165cbd24f66Storek 		atv.tv_sec = odelta / 1000000;
166cbd24f66Storek 		atv.tv_usec = odelta % 1000000;
167ab04d79bScgd 		(void) copyout((caddr_t)&atv, (caddr_t)SCARG(uap, olddelta),
1685d3ec6cbSkarels 		    sizeof(struct timeval));
169cbd24f66Storek 	}
1702c51c3e4Skarels 	return (0);
1715d3ec6cbSkarels }
1725d3ec6cbSkarels 
17334eef8ebSroot /*
17434eef8ebSroot  * Get value of an interval timer.  The process virtual and
1750b0833e3Skarels  * profiling virtual time timers are kept in the p_stats area, since
17634eef8ebSroot  * they can be swapped out.  These are kept internally in the
17734eef8ebSroot  * way they are specified externally: in time until they expire.
17834eef8ebSroot  *
17934eef8ebSroot  * The real time interval timer is kept in the process table slot
18034eef8ebSroot  * for the process, and its value (it_value) is kept as an
18134eef8ebSroot  * absolute time rather than as a delta, so that it is easy to keep
18234eef8ebSroot  * periodic real-time signals from drifting.
18334eef8ebSroot  *
18434eef8ebSroot  * Virtual time timers are processed in the hardclock() routine of
18534eef8ebSroot  * kern_clock.c.  The real time timer is processed by a timeout
18634eef8ebSroot  * routine, called from the softclock() routine.  Since a callout
18734eef8ebSroot  * may be delayed in real time due to interrupt processing in the system,
18834eef8ebSroot  * it is possible for the real time timeout routine (realitexpire, given below),
18934eef8ebSroot  * to be delayed in real time past when it is supposed to occur.  It
19034eef8ebSroot  * does not suffice, therefore, to reload the real timer .it_value from the
19134eef8ebSroot  * real time timers .it_interval.  Rather, we compute the next time in
19234eef8ebSroot  * absolute time the timer should go off.
19334eef8ebSroot  */
194d1ec48c2Skarels /* ARGSUSED */
195ab04d79bScgd int
getitimer(p,uap,retval)196d1ec48c2Skarels getitimer(p, uap, retval)
197d1ec48c2Skarels 	struct proc *p;
198ab04d79bScgd 	register struct getitimer_args /* {
199ab04d79bScgd 		syscallarg(u_int) which;
200ab04d79bScgd 		syscallarg(struct itimerval *) itv;
201ab04d79bScgd 	} */ *uap;
202ab04d79bScgd 	register_t *retval;
203d1ec48c2Skarels {
2040ed3b3c8Sroot 	struct itimerval aitv;
205ef678427Sroot 	int s;
206ef678427Sroot 
207ab04d79bScgd 	if (SCARG(uap, which) > ITIMER_PROF)
2082c51c3e4Skarels 		return (EINVAL);
20970dbe469Skarels 	s = splclock();
210ab04d79bScgd 	if (SCARG(uap, which) == ITIMER_REAL) {
21134eef8ebSroot 		/*
212ab04d79bScgd 		 * Convert from absolute to relative time in .it_value
21334eef8ebSroot 		 * part of real time timer.  If time for real time timer
21434eef8ebSroot 		 * has passed return 0, else return difference between
21534eef8ebSroot 		 * current time and time for the timer to go off.
21634eef8ebSroot 		 */
217d1ec48c2Skarels 		aitv = p->p_realtimer;
2180ed3b3c8Sroot 		if (timerisset(&aitv.it_value))
2190ed3b3c8Sroot 			if (timercmp(&aitv.it_value, &time, <))
2200ed3b3c8Sroot 				timerclear(&aitv.it_value);
2210ed3b3c8Sroot 			else
222e4223d7eStorek 				timevalsub(&aitv.it_value,
223e4223d7eStorek 				    (struct timeval *)&time);
2240ed3b3c8Sroot 	} else
225ab04d79bScgd 		aitv = p->p_stats->p_timer[SCARG(uap, which)];
2260ed3b3c8Sroot 	splx(s);
227ab04d79bScgd 	return (copyout((caddr_t)&aitv, (caddr_t)SCARG(uap, itv),
228d1ec48c2Skarels 	    sizeof (struct itimerval)));
229ef678427Sroot }
230ef678427Sroot 
231d1ec48c2Skarels /* ARGSUSED */
232ab04d79bScgd int
setitimer(p,uap,retval)233d1ec48c2Skarels setitimer(p, uap, retval)
234d1ec48c2Skarels 	struct proc *p;
235ab04d79bScgd 	register struct setitimer_args /* {
236ab04d79bScgd 		syscallarg(u_int) which;
237ab04d79bScgd 		syscallarg(struct itimerval *) itv;
238ab04d79bScgd 		syscallarg(struct itimerval *) oitv;
239ab04d79bScgd 	} */ *uap;
240ab04d79bScgd 	register_t *retval;
241d1ec48c2Skarels {
2423468c2f1Smckusick 	struct itimerval aitv;
2433468c2f1Smckusick 	register struct itimerval *itvp;
244d1ec48c2Skarels 	int s, error;
245ef678427Sroot 
246ab04d79bScgd 	if (SCARG(uap, which) > ITIMER_PROF)
2472c51c3e4Skarels 		return (EINVAL);
248ab04d79bScgd 	itvp = SCARG(uap, itv);
249d1ec48c2Skarels 	if (itvp && (error = copyin((caddr_t)itvp, (caddr_t)&aitv,
2503468c2f1Smckusick 	    sizeof(struct itimerval))))
2512c51c3e4Skarels 		return (error);
252ab04d79bScgd 	if ((SCARG(uap, itv) = SCARG(uap, oitv)) &&
253ab04d79bScgd 	    (error = getitimer(p, uap, retval)))
2542c51c3e4Skarels 		return (error);
2553468c2f1Smckusick 	if (itvp == 0)
256d1ec48c2Skarels 		return (0);
257d1ec48c2Skarels 	if (itimerfix(&aitv.it_value) || itimerfix(&aitv.it_interval))
2582c51c3e4Skarels 		return (EINVAL);
25970dbe469Skarels 	s = splclock();
260ab04d79bScgd 	if (SCARG(uap, which) == ITIMER_REAL) {
261a11faa3dSroot 		untimeout(realitexpire, (caddr_t)p);
2620ed3b3c8Sroot 		if (timerisset(&aitv.it_value)) {
263e4223d7eStorek 			timevaladd(&aitv.it_value, (struct timeval *)&time);
264a11faa3dSroot 			timeout(realitexpire, (caddr_t)p, hzto(&aitv.it_value));
2650ed3b3c8Sroot 		}
2660ed3b3c8Sroot 		p->p_realtimer = aitv;
2670ed3b3c8Sroot 	} else
268ab04d79bScgd 		p->p_stats->p_timer[SCARG(uap, which)] = aitv;
269ef678427Sroot 	splx(s);
2702c51c3e4Skarels 	return (0);
271ef678427Sroot }
272ef678427Sroot 
27334eef8ebSroot /*
27434eef8ebSroot  * Real interval timer expired:
27534eef8ebSroot  * send process whose timer expired an alarm signal.
27634eef8ebSroot  * If time is not set up to reload, then just return.
27734eef8ebSroot  * Else compute next time timer should go off which is > current time.
27834eef8ebSroot  * This is where delay in processing this timeout causes multiple
27934eef8ebSroot  * SIGALRM calls to be compressed into one.
28034eef8ebSroot  */
281e4223d7eStorek void
realitexpire(arg)282e4223d7eStorek realitexpire(arg)
283e4223d7eStorek 	void *arg;
2840ed3b3c8Sroot {
285e4223d7eStorek 	register struct proc *p;
2860ed3b3c8Sroot 	int s;
2870ed3b3c8Sroot 
288e4223d7eStorek 	p = (struct proc *)arg;
2890ed3b3c8Sroot 	psignal(p, SIGALRM);
2900ed3b3c8Sroot 	if (!timerisset(&p->p_realtimer.it_interval)) {
2910ed3b3c8Sroot 		timerclear(&p->p_realtimer.it_value);
2920ed3b3c8Sroot 		return;
2930ed3b3c8Sroot 	}
2940ed3b3c8Sroot 	for (;;) {
29570dbe469Skarels 		s = splclock();
2960ed3b3c8Sroot 		timevaladd(&p->p_realtimer.it_value,
2970ed3b3c8Sroot 		    &p->p_realtimer.it_interval);
2980ed3b3c8Sroot 		if (timercmp(&p->p_realtimer.it_value, &time, >)) {
299a11faa3dSroot 			timeout(realitexpire, (caddr_t)p,
300a11faa3dSroot 			    hzto(&p->p_realtimer.it_value));
3010ed3b3c8Sroot 			splx(s);
3020ed3b3c8Sroot 			return;
3030ed3b3c8Sroot 		}
3040ed3b3c8Sroot 		splx(s);
3050ed3b3c8Sroot 	}
3060ed3b3c8Sroot }
3070ed3b3c8Sroot 
30834eef8ebSroot /*
30934eef8ebSroot  * Check that a proposed value to load into the .it_value or
31034eef8ebSroot  * .it_interval part of an interval timer is acceptable, and
31134eef8ebSroot  * fix it to have at least minimal value (i.e. if it is less
31234eef8ebSroot  * than the resolution of the clock, round it up.)
31334eef8ebSroot  */
314ab04d79bScgd int
itimerfix(tv)31572762883Sroot itimerfix(tv)
31672762883Sroot 	struct timeval *tv;
31772762883Sroot {
31872762883Sroot 
3190ed3b3c8Sroot 	if (tv->tv_sec < 0 || tv->tv_sec > 100000000 ||
3200ed3b3c8Sroot 	    tv->tv_usec < 0 || tv->tv_usec >= 1000000)
32172762883Sroot 		return (EINVAL);
32242312cf9Ssam 	if (tv->tv_sec == 0 && tv->tv_usec != 0 && tv->tv_usec < tick)
32372762883Sroot 		tv->tv_usec = tick;
32472762883Sroot 	return (0);
32572762883Sroot }
32672762883Sroot 
32734eef8ebSroot /*
32834eef8ebSroot  * Decrement an interval timer by a specified number
32934eef8ebSroot  * of microseconds, which must be less than a second,
33034eef8ebSroot  * i.e. < 1000000.  If the timer expires, then reload
33134eef8ebSroot  * it.  In this case, carry over (usec - old value) to
332e4223d7eStorek  * reduce the value reloaded into the timer so that
33334eef8ebSroot  * the timer does not drift.  This routine assumes
33434eef8ebSroot  * that it is called in a context where the timers
33534eef8ebSroot  * on which it is operating cannot change in value.
33634eef8ebSroot  */
337ab04d79bScgd int
itimerdecr(itp,usec)338ef678427Sroot itimerdecr(itp, usec)
339ef678427Sroot 	register struct itimerval *itp;
340ef678427Sroot 	int usec;
341ef678427Sroot {
342ef678427Sroot 
34372762883Sroot 	if (itp->it_value.tv_usec < usec) {
34472762883Sroot 		if (itp->it_value.tv_sec == 0) {
34534eef8ebSroot 			/* expired, and already in next interval */
34672762883Sroot 			usec -= itp->it_value.tv_usec;
347ef678427Sroot 			goto expire;
348ef678427Sroot 		}
34972762883Sroot 		itp->it_value.tv_usec += 1000000;
35072762883Sroot 		itp->it_value.tv_sec--;
35172762883Sroot 	}
35272762883Sroot 	itp->it_value.tv_usec -= usec;
35372762883Sroot 	usec = 0;
35472762883Sroot 	if (timerisset(&itp->it_value))
355ef678427Sroot 		return (1);
35634eef8ebSroot 	/* expired, exactly at end of interval */
357ef678427Sroot expire:
35872762883Sroot 	if (timerisset(&itp->it_interval)) {
35972762883Sroot 		itp->it_value = itp->it_interval;
36072762883Sroot 		itp->it_value.tv_usec -= usec;
36172762883Sroot 		if (itp->it_value.tv_usec < 0) {
36272762883Sroot 			itp->it_value.tv_usec += 1000000;
36372762883Sroot 			itp->it_value.tv_sec--;
36472762883Sroot 		}
36572762883Sroot 	} else
36634eef8ebSroot 		itp->it_value.tv_usec = 0;		/* sec is already 0 */
367ef678427Sroot 	return (0);
368ef678427Sroot }
369ef678427Sroot 
37034eef8ebSroot /*
37134eef8ebSroot  * Add and subtract routines for timevals.
37234eef8ebSroot  * N.B.: subtract routine doesn't deal with
37334eef8ebSroot  * results which are before the beginning,
37434eef8ebSroot  * it just gets very confused in this case.
37534eef8ebSroot  * Caveat emptor.
37634eef8ebSroot  */
37734eef8ebSroot timevaladd(t1, t2)
37834eef8ebSroot 	struct timeval *t1, *t2;
37934eef8ebSroot {
38034eef8ebSroot 
38134eef8ebSroot 	t1->tv_sec += t2->tv_sec;
38234eef8ebSroot 	t1->tv_usec += t2->tv_usec;
38334eef8ebSroot 	timevalfix(t1);
38434eef8ebSroot }
38534eef8ebSroot 
38634eef8ebSroot timevalsub(t1, t2)
38734eef8ebSroot 	struct timeval *t1, *t2;
38834eef8ebSroot {
38934eef8ebSroot 
39034eef8ebSroot 	t1->tv_sec -= t2->tv_sec;
39134eef8ebSroot 	t1->tv_usec -= t2->tv_usec;
39234eef8ebSroot 	timevalfix(t1);
39334eef8ebSroot }
39434eef8ebSroot 
39534eef8ebSroot timevalfix(t1)
39634eef8ebSroot 	struct timeval *t1;
39734eef8ebSroot {
39834eef8ebSroot 
39934eef8ebSroot 	if (t1->tv_usec < 0) {
40034eef8ebSroot 		t1->tv_sec--;
40134eef8ebSroot 		t1->tv_usec += 1000000;
40234eef8ebSroot 	}
40334eef8ebSroot 	if (t1->tv_usec >= 1000000) {
40434eef8ebSroot 		t1->tv_sec++;
40534eef8ebSroot 		t1->tv_usec -= 1000000;
40634eef8ebSroot 	}
40734eef8ebSroot }
408