kern_time.c revision 35058
11541Srgrimes/*
21541Srgrimes * Copyright (c) 1982, 1986, 1989, 1993
31541Srgrimes *	The Regents of the University of California.  All rights reserved.
41541Srgrimes *
51541Srgrimes * Redistribution and use in source and binary forms, with or without
61541Srgrimes * modification, are permitted provided that the following conditions
71541Srgrimes * are met:
81541Srgrimes * 1. Redistributions of source code must retain the above copyright
91541Srgrimes *    notice, this list of conditions and the following disclaimer.
101541Srgrimes * 2. Redistributions in binary form must reproduce the above copyright
111541Srgrimes *    notice, this list of conditions and the following disclaimer in the
121541Srgrimes *    documentation and/or other materials provided with the distribution.
131541Srgrimes * 3. All advertising materials mentioning features or use of this software
141541Srgrimes *    must display the following acknowledgement:
151541Srgrimes *	This product includes software developed by the University of
161541Srgrimes *	California, Berkeley and its contributors.
171541Srgrimes * 4. Neither the name of the University nor the names of its contributors
181541Srgrimes *    may be used to endorse or promote products derived from this software
191541Srgrimes *    without specific prior written permission.
201541Srgrimes *
211541Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
221541Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
231541Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
241541Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
251541Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
261541Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
271541Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
281541Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
291541Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
301541Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
311541Srgrimes * SUCH DAMAGE.
321541Srgrimes *
331541Srgrimes *	@(#)kern_time.c	8.1 (Berkeley) 6/10/93
3435058Sphk * $Id: kern_time.c,v 1.51 1998/04/05 12:10:41 phk Exp $
351541Srgrimes */
361541Srgrimes
371541Srgrimes#include <sys/param.h>
3812221Sbde#include <sys/sysproto.h>
391541Srgrimes#include <sys/resourcevar.h>
403308Sphk#include <sys/signalvar.h>
411541Srgrimes#include <sys/kernel.h>
421541Srgrimes#include <sys/systm.h>
4325583Speter#include <sys/sysent.h>
441541Srgrimes#include <sys/proc.h>
4525656Speter#include <sys/time.h>
461541Srgrimes#include <sys/vnode.h>
4726335Speter#include <vm/vm.h>
4826335Speter#include <vm/vm_extern.h>
491541Srgrimes
509369Sdgstruct timezone tz;
519369Sdg
528876Srgrimes/*
531541Srgrimes * Time of day and interval timer support.
541541Srgrimes *
551541Srgrimes * These routines provide the kernel entry points to get and set
561541Srgrimes * the time-of-day and per-process interval timers.  Subroutines
571541Srgrimes * here provide support for adding and subtracting timeval structures
581541Srgrimes * and decrementing interval timers, optionally reloading the interval
591541Srgrimes * timers when they expire.
601541Srgrimes */
611541Srgrimes
6228773Sbdestatic int	nanosleep1 __P((struct proc *p, struct timespec *rqt,
6328773Sbde		    struct timespec *rmt));
6425656Speterstatic int	settime __P((struct timeval *));
6513016Sbdestatic void	timevalfix __P((struct timeval *));
6630994Sphkstatic void	no_lease_updatetime __P((int));
6713016Sbde
6830739Sphkstatic void
6930739Sphkno_lease_updatetime(deltat)
7030739Sphk	int deltat;
7130739Sphk{
7230739Sphk}
7330739Sphk
7430739Sphkvoid (*lease_updatetime) __P((int))  = no_lease_updatetime;
7530739Sphk
7625583Speterstatic int
7725583Spetersettime(tv)
7825583Speter	struct timeval *tv;
7925583Speter{
8033818Sbde	struct timeval delta, tv1;
8133690Sphk	struct timespec ts;
8225583Speter	struct proc *p;
8325583Speter	int s;
8425583Speter
8525656Speter	s = splclock();
8633818Sbde	microtime(&tv1);
8735029Sphk	delta = *tv;
8835029Sphk	timevalsub(&delta, &tv1);
8925583Speter
9025583Speter	/*
9133818Sbde	 * If the system is secure, we do not allow the time to be
9233818Sbde	 * set to an earlier value (it may be slowed using adjtime,
9333818Sbde	 * but not set back). This feature prevent interlopers from
9433818Sbde	 * setting arbitrary time stamps on files.
9525583Speter	 */
9633818Sbde	if (delta.tv_sec < 0 && securelevel > 1) {
9733818Sbde		splx(s);
9833818Sbde		return (EPERM);
9933818Sbde	}
10033818Sbde
10133690Sphk	ts.tv_sec = tv->tv_sec;
10233690Sphk	ts.tv_nsec = tv->tv_usec * 1000;
10333690Sphk	set_timecounter(&ts);
10425583Speter	(void) splsoftclock();
10525583Speter	lease_updatetime(delta.tv_sec);
10625583Speter	splx(s);
10725583Speter	resettodr();
10825583Speter	return (0);
10925583Speter}
11025583Speter
11112221Sbde#ifndef _SYS_SYSPROTO_H_
11225583Speterstruct clock_gettime_args {
11325583Speter	clockid_t clock_id;
11425583Speter	struct	timespec *tp;
11525583Speter};
11625583Speter#endif
11725656Speter
11825583Speter/* ARGSUSED */
11925583Speterint
12030994Sphkclock_gettime(p, uap)
12125583Speter	struct proc *p;
12225583Speter	struct clock_gettime_args *uap;
12325583Speter{
12425583Speter	struct timespec ats;
12525583Speter
12625656Speter	if (SCARG(uap, clock_id) != CLOCK_REALTIME)
12725583Speter		return (EINVAL);
12833690Sphk	nanotime(&ats);
12925656Speter	return (copyout(&ats, SCARG(uap, tp), sizeof(ats)));
13025583Speter}
13125583Speter
13225583Speter#ifndef _SYS_SYSPROTO_H_
13325583Speterstruct clock_settime_args {
13425583Speter	clockid_t clock_id;
13525583Speter	const struct	timespec *tp;
13625583Speter};
13725583Speter#endif
13825656Speter
13925583Speter/* ARGSUSED */
14025583Speterint
14130994Sphkclock_settime(p, uap)
14225583Speter	struct proc *p;
14325583Speter	struct clock_settime_args *uap;
14425583Speter{
14525583Speter	struct timeval atv;
14625583Speter	struct timespec ats;
14725583Speter	int error;
14825583Speter
14925583Speter	if ((error = suser(p->p_ucred, &p->p_acflag)) != 0)
15025583Speter		return (error);
15125656Speter	if (SCARG(uap, clock_id) != CLOCK_REALTIME)
15225583Speter		return (EINVAL);
15325583Speter	if ((error = copyin(SCARG(uap, tp), &ats, sizeof(ats))) != 0)
15425583Speter		return (error);
15527855Sbde	if (ats.tv_nsec < 0 || ats.tv_nsec >= 1000000000)
15625656Speter		return (EINVAL);
15734901Sphk	/* XXX Don't convert nsec->usec and back */
15825583Speter	TIMESPEC_TO_TIMEVAL(&atv, &ats);
15925583Speter	if ((error = settime(&atv)))
16025583Speter		return (error);
16125656Speter	return (0);
16225583Speter}
16325583Speter
16425583Speter#ifndef _SYS_SYSPROTO_H_
16525583Speterstruct clock_getres_args {
16625583Speter	clockid_t clock_id;
16725583Speter	struct	timespec *tp;
16825583Speter};
16925583Speter#endif
17025656Speter
17125583Speterint
17230994Sphkclock_getres(p, uap)
17325583Speter	struct proc *p;
17425583Speter	struct clock_getres_args *uap;
17525583Speter{
17625583Speter	struct timespec ts;
17725656Speter	int error;
17825583Speter
17925656Speter	if (SCARG(uap, clock_id) != CLOCK_REALTIME)
18025583Speter		return (EINVAL);
18125656Speter	error = 0;
18225583Speter	if (SCARG(uap, tp)) {
18325583Speter		ts.tv_sec = 0;
18433690Sphk		ts.tv_nsec = 1000000000 / timecounter->frequency;
18525656Speter		error = copyout(&ts, SCARG(uap, tp), sizeof(ts));
18625583Speter	}
18725656Speter	return (error);
18825583Speter}
18925583Speter
19026335Speterstatic int nanowait;
19125656Speter
19226335Speterstatic int
19326335Speternanosleep1(p, rqt, rmt)
19425583Speter	struct proc *p;
19526335Speter	struct timespec *rqt, *rmt;
19625583Speter{
19735045Sphk	struct timespec ts, ts2, ts3;
19835042Sphk	struct timeval tv;
19935042Sphk	int error;
20025583Speter
20128773Sbde	if (rqt->tv_nsec < 0 || rqt->tv_nsec >= 1000000000)
20225656Speter		return (EINVAL);
20328773Sbde	if (rqt->tv_sec < 0 || rqt->tv_sec == 0 && rqt->tv_nsec == 0)
20428773Sbde		return (0);
20535029Sphk	getnanoruntime(&ts);
20635029Sphk	timespecadd(&ts, rqt);
20735042Sphk	TIMESPEC_TO_TIMEVAL(&tv, rqt);
20835042Sphk	for (;;) {
20935042Sphk		error = tsleep(&nanowait, PWAIT | PCATCH, "nanslp",
21035042Sphk		    tvtohz(&tv));
21135029Sphk		getnanoruntime(&ts2);
21235042Sphk		if (error != EWOULDBLOCK) {
21335042Sphk			if (error == ERESTART)
21435042Sphk				error = EINTR;
21535042Sphk			if (rmt != NULL) {
21635042Sphk				timespecsub(&ts, &ts2);
21735042Sphk				if (ts.tv_sec < 0)
21835042Sphk					timespecclear(&ts);
21935042Sphk				*rmt = ts;
22035042Sphk			}
22135042Sphk			return (error);
22235042Sphk		}
22335029Sphk		if (timespeccmp(&ts2, &ts, >=))
22435042Sphk			return (0);
22535045Sphk		ts3 = ts;
22635045Sphk		timespecsub(&ts3, &ts2);
22735045Sphk		TIMESPEC_TO_TIMEVAL(&tv, &ts3);
22826335Speter	}
22926335Speter}
23025583Speter
23126335Speter#ifndef _SYS_SYSPROTO_H_
23226335Speterstruct nanosleep_args {
23326335Speter	struct	timespec *rqtp;
23426335Speter	struct	timespec *rmtp;
23526335Speter};
23626335Speter#endif
23726335Speter
23826335Speter/* ARGSUSED */
23926335Speterint
24030994Sphknanosleep(p, uap)
24126335Speter	struct proc *p;
24226335Speter	struct nanosleep_args *uap;
24326335Speter{
24426335Speter	struct timespec rmt, rqt;
24526335Speter	int error, error2;
24626335Speter
24726335Speter	error = copyin(SCARG(uap, rqtp), &rqt, sizeof(rqt));
24826335Speter	if (error)
24926335Speter		return (error);
25026336Speter	if (SCARG(uap, rmtp))
25126336Speter		if (!useracc((caddr_t)SCARG(uap, rmtp), sizeof(rmt), B_WRITE))
25226336Speter			return (EFAULT);
25326335Speter	error = nanosleep1(p, &rqt, &rmt);
25435043Speter	if (error && SCARG(uap, rmtp)) {
25525656Speter		error2 = copyout(&rmt, SCARG(uap, rmtp), sizeof(rmt));
25626335Speter		if (error2)	/* XXX shouldn't happen, did useracc() above */
25725656Speter			return (error2);
25825583Speter	}
25925656Speter	return (error);
26025583Speter}
26125583Speter
26226335Speter#ifndef _SYS_SYSPROTO_H_
26326335Speterstruct signanosleep_args {
26426335Speter	struct	timespec *rqtp;
26526335Speter	struct	timespec *rmtp;
26626335Speter	sigset_t *mask;
26726335Speter};
26826335Speter#endif
26925583Speter
27026335Speter/* ARGSUSED */
27126335Speterint
27230994Sphksignanosleep(p, uap)
27326335Speter	struct proc *p;
27426335Speter	struct signanosleep_args *uap;
27526335Speter{
27626335Speter	struct timespec rmt, rqt;
27726335Speter	int error, error2;
27826335Speter	sigset_t mask;
27926335Speter
28026335Speter	error = copyin(SCARG(uap, rqtp), &rqt, sizeof(rqt));
28126335Speter	if (error)
28226335Speter		return (error);
28326336Speter	if (SCARG(uap, rmtp))
28426336Speter		if (!useracc((caddr_t)SCARG(uap, rmtp), sizeof(rmt), B_WRITE))
28526336Speter			return (EFAULT);
28626335Speter	error = copyin(SCARG(uap, mask), &mask, sizeof(mask));
28726335Speter	if (error)
28826335Speter		return (error);
28926335Speter
29030440Speter	/* change mask for sleep */
29126335Speter	p->p_sigmask = mask &~ sigcantmask;
29226335Speter
29326335Speter	error = nanosleep1(p, &rqt, &rmt);
29426335Speter
29535043Speter	if (error && SCARG(uap, rmtp)) {
29626335Speter		error2 = copyout(&rmt, SCARG(uap, rmtp), sizeof(rmt));
29726335Speter		if (error2)	/* XXX shouldn't happen, did useracc() above */
29826335Speter			return (error2);
29926335Speter	}
30026335Speter	return (error);
30126335Speter}
30226335Speter
30325583Speter#ifndef _SYS_SYSPROTO_H_
3041541Srgrimesstruct gettimeofday_args {
3051541Srgrimes	struct	timeval *tp;
3061541Srgrimes	struct	timezone *tzp;
3071541Srgrimes};
30812221Sbde#endif
3091541Srgrimes/* ARGSUSED */
3101549Srgrimesint
31130994Sphkgettimeofday(p, uap)
3121541Srgrimes	struct proc *p;
3131541Srgrimes	register struct gettimeofday_args *uap;
3141541Srgrimes{
3151541Srgrimes	struct timeval atv;
3161541Srgrimes	int error = 0;
3171541Srgrimes
3181541Srgrimes	if (uap->tp) {
3191541Srgrimes		microtime(&atv);
3203098Sphk		if ((error = copyout((caddr_t)&atv, (caddr_t)uap->tp,
3213098Sphk		    sizeof (atv))))
3221541Srgrimes			return (error);
3231541Srgrimes	}
3241541Srgrimes	if (uap->tzp)
3251541Srgrimes		error = copyout((caddr_t)&tz, (caddr_t)uap->tzp,
3261541Srgrimes		    sizeof (tz));
3271541Srgrimes	return (error);
3281541Srgrimes}
3291541Srgrimes
33012221Sbde#ifndef _SYS_SYSPROTO_H_
3311541Srgrimesstruct settimeofday_args {
3321541Srgrimes	struct	timeval *tv;
3331541Srgrimes	struct	timezone *tzp;
3341541Srgrimes};
33512221Sbde#endif
3361541Srgrimes/* ARGSUSED */
3371549Srgrimesint
33830994Sphksettimeofday(p, uap)
3391541Srgrimes	struct proc *p;
3401541Srgrimes	struct settimeofday_args *uap;
3411541Srgrimes{
34225656Speter	struct timeval atv;
3431541Srgrimes	struct timezone atz;
34425656Speter	int error;
3451541Srgrimes
3463098Sphk	if ((error = suser(p->p_ucred, &p->p_acflag)))
3471541Srgrimes		return (error);
3481541Srgrimes	/* Verify all parameters before changing time. */
34925656Speter	if (uap->tv) {
35025656Speter		if ((error = copyin((caddr_t)uap->tv, (caddr_t)&atv,
35125656Speter		    sizeof(atv))))
35225656Speter			return (error);
35325656Speter		if (atv.tv_usec < 0 || atv.tv_usec >= 1000000)
35425656Speter			return (EINVAL);
35525656Speter	}
3561541Srgrimes	if (uap->tzp &&
3571541Srgrimes	    (error = copyin((caddr_t)uap->tzp, (caddr_t)&atz, sizeof(atz))))
3581541Srgrimes		return (error);
35925583Speter	if (uap->tv && (error = settime(&atv)))
36025583Speter		return (error);
3611541Srgrimes	if (uap->tzp)
3621541Srgrimes		tz = atz;
3631541Srgrimes	return (0);
3641541Srgrimes}
3651541Srgrimes
3661541Srgrimesint	tickdelta;			/* current clock skew, us. per tick */
3671541Srgrimeslong	timedelta;			/* unapplied time correction, us. */
36812819Sphkstatic long	bigadj = 1000000;	/* use 10x skew above bigadj us. */
3691541Srgrimes
37012221Sbde#ifndef _SYS_SYSPROTO_H_
3711541Srgrimesstruct adjtime_args {
3721541Srgrimes	struct timeval *delta;
3731541Srgrimes	struct timeval *olddelta;
3741541Srgrimes};
37512221Sbde#endif
3761541Srgrimes/* ARGSUSED */
3771549Srgrimesint
37830994Sphkadjtime(p, uap)
3791541Srgrimes	struct proc *p;
3801541Srgrimes	register struct adjtime_args *uap;
3811541Srgrimes{
3821541Srgrimes	struct timeval atv;
3831541Srgrimes	register long ndelta, ntickdelta, odelta;
3841541Srgrimes	int s, error;
3851541Srgrimes
3863098Sphk	if ((error = suser(p->p_ucred, &p->p_acflag)))
3871541Srgrimes		return (error);
3883098Sphk	if ((error =
3893098Sphk	    copyin((caddr_t)uap->delta, (caddr_t)&atv, sizeof(struct timeval))))
3901541Srgrimes		return (error);
3911541Srgrimes
3921541Srgrimes	/*
3931541Srgrimes	 * Compute the total correction and the rate at which to apply it.
3941541Srgrimes	 * Round the adjustment down to a whole multiple of the per-tick
3951541Srgrimes	 * delta, so that after some number of incremental changes in
3961541Srgrimes	 * hardclock(), tickdelta will become zero, lest the correction
3971541Srgrimes	 * overshoot and start taking us away from the desired final time.
3981541Srgrimes	 */
3991541Srgrimes	ndelta = atv.tv_sec * 1000000 + atv.tv_usec;
40017123Sbde	if (ndelta > bigadj || ndelta < -bigadj)
4011541Srgrimes		ntickdelta = 10 * tickadj;
4021541Srgrimes	else
4031541Srgrimes		ntickdelta = tickadj;
4041541Srgrimes	if (ndelta % ntickdelta)
4051541Srgrimes		ndelta = ndelta / ntickdelta * ntickdelta;
4061541Srgrimes
4071541Srgrimes	/*
4081541Srgrimes	 * To make hardclock()'s job easier, make the per-tick delta negative
4091541Srgrimes	 * if we want time to run slower; then hardclock can simply compute
4101541Srgrimes	 * tick + tickdelta, and subtract tickdelta from timedelta.
4111541Srgrimes	 */
4121541Srgrimes	if (ndelta < 0)
4131541Srgrimes		ntickdelta = -ntickdelta;
4141541Srgrimes	s = splclock();
4151541Srgrimes	odelta = timedelta;
4161541Srgrimes	timedelta = ndelta;
4171541Srgrimes	tickdelta = ntickdelta;
4181541Srgrimes	splx(s);
4191541Srgrimes
4201541Srgrimes	if (uap->olddelta) {
4211541Srgrimes		atv.tv_sec = odelta / 1000000;
4221541Srgrimes		atv.tv_usec = odelta % 1000000;
4231541Srgrimes		(void) copyout((caddr_t)&atv, (caddr_t)uap->olddelta,
4241541Srgrimes		    sizeof(struct timeval));
4251541Srgrimes	}
4261541Srgrimes	return (0);
4271541Srgrimes}
4281541Srgrimes
4291541Srgrimes/*
4301541Srgrimes * Get value of an interval timer.  The process virtual and
4311541Srgrimes * profiling virtual time timers are kept in the p_stats area, since
4321541Srgrimes * they can be swapped out.  These are kept internally in the
4331541Srgrimes * way they are specified externally: in time until they expire.
4341541Srgrimes *
4351541Srgrimes * The real time interval timer is kept in the process table slot
4361541Srgrimes * for the process, and its value (it_value) is kept as an
4371541Srgrimes * absolute time rather than as a delta, so that it is easy to keep
4381541Srgrimes * periodic real-time signals from drifting.
4391541Srgrimes *
4401541Srgrimes * Virtual time timers are processed in the hardclock() routine of
4411541Srgrimes * kern_clock.c.  The real time timer is processed by a timeout
4421541Srgrimes * routine, called from the softclock() routine.  Since a callout
4431541Srgrimes * may be delayed in real time due to interrupt processing in the system,
4441541Srgrimes * it is possible for the real time timeout routine (realitexpire, given below),
4451541Srgrimes * to be delayed in real time past when it is supposed to occur.  It
4461541Srgrimes * does not suffice, therefore, to reload the real timer .it_value from the
4471541Srgrimes * real time timers .it_interval.  Rather, we compute the next time in
4481541Srgrimes * absolute time the timer should go off.
4491541Srgrimes */
45012221Sbde#ifndef _SYS_SYSPROTO_H_
4511541Srgrimesstruct getitimer_args {
4521541Srgrimes	u_int	which;
4531541Srgrimes	struct	itimerval *itv;
4541541Srgrimes};
45512221Sbde#endif
4561541Srgrimes/* ARGSUSED */
4571549Srgrimesint
45830994Sphkgetitimer(p, uap)
4591541Srgrimes	struct proc *p;
4601541Srgrimes	register struct getitimer_args *uap;
4611541Srgrimes{
46234961Sphk	struct timeval ctv;
4631541Srgrimes	struct itimerval aitv;
4641541Srgrimes	int s;
4651541Srgrimes
4661541Srgrimes	if (uap->which > ITIMER_PROF)
4671541Srgrimes		return (EINVAL);
46834961Sphk	s = splclock(); /* XXX still needed ? */
4691541Srgrimes	if (uap->which == ITIMER_REAL) {
4701541Srgrimes		/*
4711541Srgrimes		 * Convert from absoulte to relative time in .it_value
4721541Srgrimes		 * part of real time timer.  If time for real time timer
4731541Srgrimes		 * has passed return 0, else return difference between
4741541Srgrimes		 * current time and time for the timer to go off.
4751541Srgrimes		 */
4761541Srgrimes		aitv = p->p_realtimer;
47735058Sphk		if (timevalisset(&aitv.it_value)) {
47835044Sphk			getmicroruntime(&ctv);
47935058Sphk			if (timevalcmp(&aitv.it_value, &ctv, <))
48035058Sphk				timevalclear(&aitv.it_value);
4811541Srgrimes			else
48234961Sphk				timevalsub(&aitv.it_value, &ctv);
48334961Sphk		}
4841541Srgrimes	} else
4851541Srgrimes		aitv = p->p_stats->p_timer[uap->which];
4861541Srgrimes	splx(s);
4871541Srgrimes	return (copyout((caddr_t)&aitv, (caddr_t)uap->itv,
4881541Srgrimes	    sizeof (struct itimerval)));
4891541Srgrimes}
4901541Srgrimes
49112221Sbde#ifndef _SYS_SYSPROTO_H_
4921541Srgrimesstruct setitimer_args {
4931541Srgrimes	u_int	which;
4941541Srgrimes	struct	itimerval *itv, *oitv;
4951541Srgrimes};
49612221Sbde#endif
4971541Srgrimes/* ARGSUSED */
4981549Srgrimesint
49930994Sphksetitimer(p, uap)
5001541Srgrimes	struct proc *p;
5011541Srgrimes	register struct setitimer_args *uap;
5021541Srgrimes{
5031541Srgrimes	struct itimerval aitv;
50434961Sphk	struct timeval ctv;
5051541Srgrimes	register struct itimerval *itvp;
5061541Srgrimes	int s, error;
5071541Srgrimes
5081541Srgrimes	if (uap->which > ITIMER_PROF)
5091541Srgrimes		return (EINVAL);
5101541Srgrimes	itvp = uap->itv;
5111541Srgrimes	if (itvp && (error = copyin((caddr_t)itvp, (caddr_t)&aitv,
5121541Srgrimes	    sizeof(struct itimerval))))
5131541Srgrimes		return (error);
51412381Sbde	if ((uap->itv = uap->oitv) &&
51530994Sphk	    (error = getitimer(p, (struct getitimer_args *)uap)))
5161541Srgrimes		return (error);
5171541Srgrimes	if (itvp == 0)
5181541Srgrimes		return (0);
51928213Sache	if (itimerfix(&aitv.it_value))
5201541Srgrimes		return (EINVAL);
52135058Sphk	if (!timevalisset(&aitv.it_value))
52235058Sphk		timevalclear(&aitv.it_interval);
52328213Sache	else if (itimerfix(&aitv.it_interval))
52428213Sache		return (EINVAL);
52534961Sphk	s = splclock(); /* XXX: still needed ? */
5261541Srgrimes	if (uap->which == ITIMER_REAL) {
52735058Sphk		if (timevalisset(&p->p_realtimer.it_value))
52829680Sgibbs			untimeout(realitexpire, (caddr_t)p, p->p_ithandle);
52935058Sphk		if (timevalisset(&aitv.it_value))
53029680Sgibbs			p->p_ithandle = timeout(realitexpire, (caddr_t)p,
53135033Sphk						tvtohz(&aitv.it_value));
53235044Sphk		getmicroruntime(&ctv);
53335044Sphk		timevaladd(&aitv.it_value, &ctv);
5341541Srgrimes		p->p_realtimer = aitv;
5351541Srgrimes	} else
5361541Srgrimes		p->p_stats->p_timer[uap->which] = aitv;
5371541Srgrimes	splx(s);
5381541Srgrimes	return (0);
5391541Srgrimes}
5401541Srgrimes
5411541Srgrimes/*
5421541Srgrimes * Real interval timer expired:
5431541Srgrimes * send process whose timer expired an alarm signal.
5441541Srgrimes * If time is not set up to reload, then just return.
5451541Srgrimes * Else compute next time timer should go off which is > current time.
5461541Srgrimes * This is where delay in processing this timeout causes multiple
5471541Srgrimes * SIGALRM calls to be compressed into one.
5489327Sbde * hzto() always adds 1 to allow for the time until the next clock
5499327Sbde * interrupt being strictly less than 1 clock tick, but we don't want
5509327Sbde * that here since we want to appear to be in sync with the clock
5519327Sbde * interrupt even when we're delayed.
5521541Srgrimes */
5531541Srgrimesvoid
5541541Srgrimesrealitexpire(arg)
5551541Srgrimes	void *arg;
5561541Srgrimes{
5571541Srgrimes	register struct proc *p;
55835044Sphk	struct timeval ctv, ntv;
5591541Srgrimes	int s;
5601541Srgrimes
5611541Srgrimes	p = (struct proc *)arg;
5621541Srgrimes	psignal(p, SIGALRM);
56335058Sphk	if (!timevalisset(&p->p_realtimer.it_interval)) {
56435058Sphk		timevalclear(&p->p_realtimer.it_value);
5651541Srgrimes		return;
5661541Srgrimes	}
5671541Srgrimes	for (;;) {
56834961Sphk		s = splclock(); /* XXX: still neeeded ? */
5691541Srgrimes		timevaladd(&p->p_realtimer.it_value,
5701541Srgrimes		    &p->p_realtimer.it_interval);
57135044Sphk		getmicroruntime(&ctv);
57235058Sphk		if (timevalcmp(&p->p_realtimer.it_value, &ctv, >)) {
57335044Sphk			ntv = p->p_realtimer.it_value;
57435044Sphk			timevalsub(&ntv, &ctv);
57529680Sgibbs			p->p_ithandle =
57635044Sphk			    timeout(realitexpire, (caddr_t)p, tvtohz(&ntv));
5771541Srgrimes			splx(s);
5781541Srgrimes			return;
5791541Srgrimes		}
5801541Srgrimes		splx(s);
5811541Srgrimes	}
5821541Srgrimes}
5831541Srgrimes
5841541Srgrimes/*
5851541Srgrimes * Check that a proposed value to load into the .it_value or
5861541Srgrimes * .it_interval part of an interval timer is acceptable, and
5871541Srgrimes * fix it to have at least minimal value (i.e. if it is less
5881541Srgrimes * than the resolution of the clock, round it up.)
5891541Srgrimes */
5901549Srgrimesint
5911541Srgrimesitimerfix(tv)
5921541Srgrimes	struct timeval *tv;
5931541Srgrimes{
5941541Srgrimes
5951541Srgrimes	if (tv->tv_sec < 0 || tv->tv_sec > 100000000 ||
5961541Srgrimes	    tv->tv_usec < 0 || tv->tv_usec >= 1000000)
5971541Srgrimes		return (EINVAL);
5981541Srgrimes	if (tv->tv_sec == 0 && tv->tv_usec != 0 && tv->tv_usec < tick)
5991541Srgrimes		tv->tv_usec = tick;
6001541Srgrimes	return (0);
6011541Srgrimes}
6021541Srgrimes
6031541Srgrimes/*
6041541Srgrimes * Decrement an interval timer by a specified number
6051541Srgrimes * of microseconds, which must be less than a second,
6061541Srgrimes * i.e. < 1000000.  If the timer expires, then reload
6071541Srgrimes * it.  In this case, carry over (usec - old value) to
6081541Srgrimes * reduce the value reloaded into the timer so that
6091541Srgrimes * the timer does not drift.  This routine assumes
6101541Srgrimes * that it is called in a context where the timers
6111541Srgrimes * on which it is operating cannot change in value.
6121541Srgrimes */
6131549Srgrimesint
6141541Srgrimesitimerdecr(itp, usec)
6151541Srgrimes	register struct itimerval *itp;
6161541Srgrimes	int usec;
6171541Srgrimes{
6181541Srgrimes
6191541Srgrimes	if (itp->it_value.tv_usec < usec) {
6201541Srgrimes		if (itp->it_value.tv_sec == 0) {
6211541Srgrimes			/* expired, and already in next interval */
6221541Srgrimes			usec -= itp->it_value.tv_usec;
6231541Srgrimes			goto expire;
6241541Srgrimes		}
6251541Srgrimes		itp->it_value.tv_usec += 1000000;
6261541Srgrimes		itp->it_value.tv_sec--;
6271541Srgrimes	}
6281541Srgrimes	itp->it_value.tv_usec -= usec;
6291541Srgrimes	usec = 0;
63035058Sphk	if (timevalisset(&itp->it_value))
6311541Srgrimes		return (1);
6321541Srgrimes	/* expired, exactly at end of interval */
6331541Srgrimesexpire:
63435058Sphk	if (timevalisset(&itp->it_interval)) {
6351541Srgrimes		itp->it_value = itp->it_interval;
6361541Srgrimes		itp->it_value.tv_usec -= usec;
6371541Srgrimes		if (itp->it_value.tv_usec < 0) {
6381541Srgrimes			itp->it_value.tv_usec += 1000000;
6391541Srgrimes			itp->it_value.tv_sec--;
6401541Srgrimes		}
6411541Srgrimes	} else
6421541Srgrimes		itp->it_value.tv_usec = 0;		/* sec is already 0 */
6431541Srgrimes	return (0);
6441541Srgrimes}
6451541Srgrimes
6461541Srgrimes/*
6471541Srgrimes * Add and subtract routines for timevals.
6481541Srgrimes * N.B.: subtract routine doesn't deal with
6491541Srgrimes * results which are before the beginning,
6501541Srgrimes * it just gets very confused in this case.
6511541Srgrimes * Caveat emptor.
6521541Srgrimes */
6531549Srgrimesvoid
6541541Srgrimestimevaladd(t1, t2)
6551541Srgrimes	struct timeval *t1, *t2;
6561541Srgrimes{
6571541Srgrimes
6581541Srgrimes	t1->tv_sec += t2->tv_sec;
6591541Srgrimes	t1->tv_usec += t2->tv_usec;
6601541Srgrimes	timevalfix(t1);
6611541Srgrimes}
6621541Srgrimes
6631549Srgrimesvoid
6641541Srgrimestimevalsub(t1, t2)
6651541Srgrimes	struct timeval *t1, *t2;
6661541Srgrimes{
6671541Srgrimes
6681541Srgrimes	t1->tv_sec -= t2->tv_sec;
6691541Srgrimes	t1->tv_usec -= t2->tv_usec;
6701541Srgrimes	timevalfix(t1);
6711541Srgrimes}
6721541Srgrimes
67312819Sphkstatic void
6741541Srgrimestimevalfix(t1)
6751541Srgrimes	struct timeval *t1;
6761541Srgrimes{
6771541Srgrimes
6781541Srgrimes	if (t1->tv_usec < 0) {
6791541Srgrimes		t1->tv_sec--;
6801541Srgrimes		t1->tv_usec += 1000000;
6811541Srgrimes	}
6821541Srgrimes	if (t1->tv_usec >= 1000000) {
6831541Srgrimes		t1->tv_sec++;
6841541Srgrimes		t1->tv_usec -= 1000000;
6851541Srgrimes	}
6861541Srgrimes}
687