Home | History | Annotate | Line # | Download | only in kern
kern_time.c revision 1.36.10.1
      1  1.36.10.1    itojun /*	$NetBSD: kern_time.c,v 1.36.10.1 1999/11/30 13:34:43 itojun Exp $	*/
      2        1.9       cgd 
      3        1.1       cgd /*
      4        1.8       cgd  * Copyright (c) 1982, 1986, 1989, 1993
      5        1.8       cgd  *	The Regents of the University of California.  All rights reserved.
      6        1.1       cgd  *
      7        1.1       cgd  * Redistribution and use in source and binary forms, with or without
      8        1.1       cgd  * modification, are permitted provided that the following conditions
      9        1.1       cgd  * are met:
     10        1.1       cgd  * 1. Redistributions of source code must retain the above copyright
     11        1.1       cgd  *    notice, this list of conditions and the following disclaimer.
     12        1.1       cgd  * 2. Redistributions in binary form must reproduce the above copyright
     13        1.1       cgd  *    notice, this list of conditions and the following disclaimer in the
     14        1.1       cgd  *    documentation and/or other materials provided with the distribution.
     15        1.1       cgd  * 3. All advertising materials mentioning features or use of this software
     16        1.1       cgd  *    must display the following acknowledgement:
     17        1.1       cgd  *	This product includes software developed by the University of
     18        1.1       cgd  *	California, Berkeley and its contributors.
     19        1.1       cgd  * 4. Neither the name of the University nor the names of its contributors
     20        1.1       cgd  *    may be used to endorse or promote products derived from this software
     21        1.1       cgd  *    without specific prior written permission.
     22        1.1       cgd  *
     23        1.1       cgd  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     24        1.1       cgd  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     25        1.1       cgd  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     26        1.1       cgd  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     27        1.1       cgd  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     28        1.1       cgd  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     29        1.1       cgd  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     30        1.1       cgd  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     31        1.1       cgd  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     32        1.1       cgd  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     33        1.1       cgd  * SUCH DAMAGE.
     34        1.1       cgd  *
     35       1.33      fvdl  *	@(#)kern_time.c	8.4 (Berkeley) 5/26/95
     36        1.1       cgd  */
     37       1.31   thorpej 
     38       1.31   thorpej #include "fs_nfs.h"
     39       1.34   thorpej #include "opt_nfsserver.h"
     40        1.1       cgd 
     41        1.5   mycroft #include <sys/param.h>
     42        1.5   mycroft #include <sys/resourcevar.h>
     43        1.5   mycroft #include <sys/kernel.h>
     44        1.8       cgd #include <sys/systm.h>
     45        1.5   mycroft #include <sys/proc.h>
     46        1.8       cgd #include <sys/vnode.h>
     47       1.17  christos #include <sys/signalvar.h>
     48       1.25     perry #include <sys/syslog.h>
     49        1.1       cgd 
     50       1.11       cgd #include <sys/mount.h>
     51       1.11       cgd #include <sys/syscallargs.h>
     52       1.19  christos 
     53  1.36.10.1    itojun #include <vm/vm.h>
     54  1.36.10.1    itojun #include <uvm/uvm_extern.h>
     55  1.36.10.1    itojun 
     56       1.26   thorpej #if defined(NFS) || defined(NFSSERVER)
     57       1.20      fvdl #include <nfs/rpcv2.h>
     58       1.20      fvdl #include <nfs/nfsproto.h>
     59       1.19  christos #include <nfs/nfs_var.h>
     60       1.19  christos #endif
     61       1.17  christos 
     62        1.5   mycroft #include <machine/cpu.h>
     63        1.1       cgd 
     64       1.29       tls static int	settime __P((struct timeval *));
     65       1.23       cgd 
     66       1.23       cgd /*
     67        1.1       cgd  * Time of day and interval timer support.
     68        1.1       cgd  *
     69        1.1       cgd  * These routines provide the kernel entry points to get and set
     70        1.1       cgd  * the time-of-day and per-process interval timers.  Subroutines
     71        1.1       cgd  * here provide support for adding and subtracting timeval structures
     72        1.1       cgd  * and decrementing interval timers, optionally reloading the interval
     73        1.1       cgd  * timers when they expire.
     74        1.1       cgd  */
     75        1.1       cgd 
     76       1.22       jtc /* This function is used by clock_settime and settimeofday */
     77       1.29       tls static int
     78       1.22       jtc settime(tv)
     79       1.22       jtc 	struct timeval *tv;
     80       1.22       jtc {
     81       1.22       jtc 	struct timeval delta;
     82       1.22       jtc 	int s;
     83       1.22       jtc 
     84       1.22       jtc 	/* WHAT DO WE DO ABOUT PENDING REAL-TIME TIMEOUTS??? */
     85       1.22       jtc 	s = splclock();
     86       1.22       jtc 	timersub(tv, &time, &delta);
     87       1.29       tls 	if ((delta.tv_sec < 0 || delta.tv_usec < 0) && securelevel > 1)
     88       1.29       tls 		return (EPERM);
     89       1.29       tls #ifdef notyet
     90       1.29       tls 	if ((delta.tv_sec < 86400) && securelevel > 0)
     91       1.29       tls 		return (EPERM);
     92       1.29       tls #endif
     93       1.22       jtc 	time = *tv;
     94       1.22       jtc 	(void) splsoftclock();
     95       1.22       jtc 	timeradd(&boottime, &delta, &boottime);
     96       1.22       jtc 	timeradd(&runtime, &delta, &runtime);
     97       1.26   thorpej #	if defined(NFS) || defined(NFSSERVER)
     98       1.22       jtc 		nqnfs_lease_updatetime(delta.tv_sec);
     99       1.22       jtc #	endif
    100       1.22       jtc 	splx(s);
    101       1.22       jtc 	resettodr();
    102       1.29       tls 	return (0);
    103       1.22       jtc }
    104       1.22       jtc 
    105       1.22       jtc /* ARGSUSED */
    106       1.22       jtc int
    107       1.22       jtc sys_clock_gettime(p, v, retval)
    108       1.22       jtc 	struct proc *p;
    109       1.22       jtc 	void *v;
    110       1.22       jtc 	register_t *retval;
    111       1.22       jtc {
    112       1.22       jtc 	register struct sys_clock_gettime_args /* {
    113       1.22       jtc 		syscallarg(clockid_t) clock_id;
    114       1.23       cgd 		syscallarg(struct timespec *) tp;
    115       1.23       cgd 	} */ *uap = v;
    116       1.22       jtc 	clockid_t clock_id;
    117       1.22       jtc 	struct timeval atv;
    118       1.22       jtc 	struct timespec ats;
    119       1.22       jtc 
    120       1.22       jtc 	clock_id = SCARG(uap, clock_id);
    121       1.22       jtc 	if (clock_id != CLOCK_REALTIME)
    122       1.22       jtc 		return (EINVAL);
    123       1.22       jtc 
    124       1.22       jtc 	microtime(&atv);
    125       1.22       jtc 	TIMEVAL_TO_TIMESPEC(&atv,&ats);
    126       1.22       jtc 
    127       1.24       cgd 	return copyout(&ats, SCARG(uap, tp), sizeof(ats));
    128       1.22       jtc }
    129       1.22       jtc 
    130       1.22       jtc /* ARGSUSED */
    131       1.22       jtc int
    132       1.22       jtc sys_clock_settime(p, v, retval)
    133       1.22       jtc 	struct proc *p;
    134       1.22       jtc 	void *v;
    135       1.22       jtc 	register_t *retval;
    136       1.22       jtc {
    137       1.22       jtc 	register struct sys_clock_settime_args /* {
    138       1.22       jtc 		syscallarg(clockid_t) clock_id;
    139       1.23       cgd 		syscallarg(const struct timespec *) tp;
    140       1.23       cgd 	} */ *uap = v;
    141       1.22       jtc 	clockid_t clock_id;
    142       1.22       jtc 	struct timeval atv;
    143       1.22       jtc 	struct timespec ats;
    144       1.22       jtc 	int error;
    145       1.22       jtc 
    146       1.22       jtc 	if ((error = suser(p->p_ucred, &p->p_acflag)) != 0)
    147       1.22       jtc 		return (error);
    148       1.22       jtc 
    149       1.22       jtc 	clock_id = SCARG(uap, clock_id);
    150       1.22       jtc 	if (clock_id != CLOCK_REALTIME)
    151       1.22       jtc 		return (EINVAL);
    152       1.22       jtc 
    153       1.24       cgd 	if ((error = copyin(SCARG(uap, tp), &ats, sizeof(ats))) != 0)
    154       1.23       cgd 		return (error);
    155       1.22       jtc 
    156       1.22       jtc 	TIMESPEC_TO_TIMEVAL(&atv,&ats);
    157       1.29       tls 	if ((error = settime(&atv)))
    158       1.29       tls 		return (error);
    159       1.22       jtc 
    160       1.22       jtc 	return 0;
    161       1.22       jtc }
    162       1.22       jtc 
    163       1.22       jtc int
    164       1.22       jtc sys_clock_getres(p, v, retval)
    165       1.22       jtc 	struct proc *p;
    166       1.22       jtc 	void *v;
    167       1.22       jtc 	register_t *retval;
    168       1.22       jtc {
    169       1.22       jtc 	register struct sys_clock_getres_args /* {
    170       1.22       jtc 		syscallarg(clockid_t) clock_id;
    171       1.23       cgd 		syscallarg(struct timespec *) tp;
    172       1.23       cgd 	} */ *uap = v;
    173       1.22       jtc 	clockid_t clock_id;
    174       1.22       jtc 	struct timespec ts;
    175       1.22       jtc 	int error = 0;
    176       1.22       jtc 
    177       1.22       jtc 	clock_id = SCARG(uap, clock_id);
    178       1.22       jtc 	if (clock_id != CLOCK_REALTIME)
    179       1.22       jtc 		return (EINVAL);
    180       1.22       jtc 
    181       1.22       jtc 	if (SCARG(uap, tp)) {
    182       1.22       jtc 		ts.tv_sec = 0;
    183       1.22       jtc 		ts.tv_nsec = 1000000000 / hz;
    184       1.22       jtc 
    185       1.35     perry 		error = copyout(&ts, SCARG(uap, tp), sizeof(ts));
    186       1.22       jtc 	}
    187       1.22       jtc 
    188       1.22       jtc 	return error;
    189       1.22       jtc }
    190       1.22       jtc 
    191       1.27       jtc /* ARGSUSED */
    192       1.27       jtc int
    193       1.27       jtc sys_nanosleep(p, v, retval)
    194       1.27       jtc 	struct proc *p;
    195       1.27       jtc 	void *v;
    196       1.27       jtc 	register_t *retval;
    197       1.27       jtc {
    198       1.27       jtc 	static int nanowait;
    199       1.27       jtc 	register struct sys_nanosleep_args/* {
    200       1.27       jtc 		syscallarg(struct timespec *) rqtp;
    201       1.27       jtc 		syscallarg(struct timespec *) rmtp;
    202       1.27       jtc 	} */ *uap = v;
    203       1.27       jtc 	struct timespec rqt;
    204       1.27       jtc 	struct timespec rmt;
    205       1.27       jtc 	struct timeval atv, utv;
    206       1.27       jtc 	int error, s, timo;
    207       1.27       jtc 
    208       1.27       jtc 	error = copyin((caddr_t)SCARG(uap, rqtp), (caddr_t)&rqt,
    209       1.27       jtc 		       sizeof(struct timespec));
    210       1.27       jtc 	if (error)
    211       1.27       jtc 		return (error);
    212       1.27       jtc 
    213       1.27       jtc 	TIMESPEC_TO_TIMEVAL(&atv,&rqt)
    214       1.27       jtc 	if (itimerfix(&atv))
    215       1.27       jtc 		return (EINVAL);
    216       1.27       jtc 
    217       1.27       jtc 	s = splclock();
    218       1.27       jtc 	timeradd(&atv,&time,&atv);
    219       1.27       jtc 	timo = hzto(&atv);
    220       1.27       jtc 	/*
    221       1.27       jtc 	 * Avoid inadvertantly sleeping forever
    222       1.27       jtc 	 */
    223       1.27       jtc 	if (timo == 0)
    224       1.27       jtc 		timo = 1;
    225       1.27       jtc 	splx(s);
    226       1.27       jtc 
    227       1.27       jtc 	error = tsleep(&nanowait, PWAIT | PCATCH, "nanosleep", timo);
    228       1.27       jtc 	if (error == ERESTART)
    229       1.27       jtc 		error = EINTR;
    230       1.27       jtc 	if (error == EWOULDBLOCK)
    231       1.27       jtc 		error = 0;
    232       1.27       jtc 
    233       1.27       jtc 	if (SCARG(uap, rmtp)) {
    234       1.28       jtc 		int error;
    235       1.28       jtc 
    236       1.27       jtc 		s = splclock();
    237       1.27       jtc 		utv = time;
    238       1.27       jtc 		splx(s);
    239       1.27       jtc 
    240       1.27       jtc 		timersub(&atv, &utv, &utv);
    241       1.27       jtc 		if (utv.tv_sec < 0)
    242       1.27       jtc 			timerclear(&utv);
    243       1.27       jtc 
    244       1.27       jtc 		TIMEVAL_TO_TIMESPEC(&utv,&rmt);
    245       1.27       jtc 		error = copyout((caddr_t)&rmt, (caddr_t)SCARG(uap,rmtp),
    246       1.28       jtc 			sizeof(rmt));
    247       1.28       jtc 		if (error)
    248       1.28       jtc 			return (error);
    249       1.27       jtc 	}
    250       1.27       jtc 
    251       1.27       jtc 	return error;
    252       1.27       jtc }
    253       1.22       jtc 
    254        1.1       cgd /* ARGSUSED */
    255        1.3    andrew int
    256       1.16   mycroft sys_gettimeofday(p, v, retval)
    257        1.1       cgd 	struct proc *p;
    258       1.15   thorpej 	void *v;
    259       1.15   thorpej 	register_t *retval;
    260       1.15   thorpej {
    261       1.16   mycroft 	register struct sys_gettimeofday_args /* {
    262       1.11       cgd 		syscallarg(struct timeval *) tp;
    263       1.11       cgd 		syscallarg(struct timezone *) tzp;
    264       1.15   thorpej 	} */ *uap = v;
    265        1.1       cgd 	struct timeval atv;
    266        1.1       cgd 	int error = 0;
    267       1.25     perry 	struct timezone tzfake;
    268        1.1       cgd 
    269       1.11       cgd 	if (SCARG(uap, tp)) {
    270        1.1       cgd 		microtime(&atv);
    271       1.35     perry 		error = copyout(&atv, SCARG(uap, tp), sizeof(atv));
    272       1.17  christos 		if (error)
    273        1.1       cgd 			return (error);
    274        1.1       cgd 	}
    275       1.25     perry 	if (SCARG(uap, tzp)) {
    276       1.25     perry 		/*
    277       1.32   mycroft 		 * NetBSD has no kernel notion of time zone, so we just
    278       1.25     perry 		 * fake up a timezone struct and return it if demanded.
    279       1.25     perry 		 */
    280       1.25     perry 		tzfake.tz_minuteswest = 0;
    281       1.25     perry 		tzfake.tz_dsttime = 0;
    282       1.35     perry 		error = copyout(&tzfake, SCARG(uap, tzp), sizeof(tzfake));
    283       1.25     perry 	}
    284        1.1       cgd 	return (error);
    285        1.1       cgd }
    286        1.1       cgd 
    287        1.1       cgd /* ARGSUSED */
    288        1.3    andrew int
    289       1.16   mycroft sys_settimeofday(p, v, retval)
    290        1.1       cgd 	struct proc *p;
    291       1.15   thorpej 	void *v;
    292       1.15   thorpej 	register_t *retval;
    293       1.15   thorpej {
    294       1.16   mycroft 	struct sys_settimeofday_args /* {
    295       1.24       cgd 		syscallarg(const struct timeval *) tv;
    296       1.24       cgd 		syscallarg(const struct timezone *) tzp;
    297       1.15   thorpej 	} */ *uap = v;
    298       1.22       jtc 	struct timeval atv;
    299        1.1       cgd 	struct timezone atz;
    300       1.22       jtc 	int error;
    301        1.1       cgd 
    302       1.17  christos 	if ((error = suser(p->p_ucred, &p->p_acflag)) != 0)
    303        1.1       cgd 		return (error);
    304        1.8       cgd 	/* Verify all parameters before changing time. */
    305       1.24       cgd 	if (SCARG(uap, tv) && (error = copyin(SCARG(uap, tv),
    306       1.24       cgd 	    &atv, sizeof(atv))))
    307        1.8       cgd 		return (error);
    308       1.25     perry 	/* XXX since we don't use tz, probably no point in doing copyin. */
    309       1.24       cgd 	if (SCARG(uap, tzp) && (error = copyin(SCARG(uap, tzp),
    310       1.24       cgd 	    &atz, sizeof(atz))))
    311        1.8       cgd 		return (error);
    312       1.22       jtc 	if (SCARG(uap, tv))
    313       1.29       tls 		if ((error = settime(&atv)))
    314       1.29       tls 			return (error);
    315       1.25     perry 	/*
    316       1.32   mycroft 	 * NetBSD has no kernel notion of time zone, and only an
    317       1.25     perry 	 * obsolete program would try to set it, so we log a warning.
    318       1.25     perry 	 */
    319       1.11       cgd 	if (SCARG(uap, tzp))
    320       1.25     perry 		log(LOG_WARNING, "pid %d attempted to set the "
    321       1.32   mycroft 		    "(obsolete) kernel time zone\n", p->p_pid);
    322        1.8       cgd 	return (0);
    323        1.1       cgd }
    324        1.1       cgd 
    325        1.1       cgd int	tickdelta;			/* current clock skew, us. per tick */
    326        1.1       cgd long	timedelta;			/* unapplied time correction, us. */
    327        1.1       cgd long	bigadj = 1000000;		/* use 10x skew above bigadj us. */
    328        1.1       cgd 
    329        1.1       cgd /* ARGSUSED */
    330        1.3    andrew int
    331       1.16   mycroft sys_adjtime(p, v, retval)
    332        1.1       cgd 	struct proc *p;
    333       1.15   thorpej 	void *v;
    334       1.15   thorpej 	register_t *retval;
    335       1.15   thorpej {
    336       1.16   mycroft 	register struct sys_adjtime_args /* {
    337       1.24       cgd 		syscallarg(const struct timeval *) delta;
    338       1.11       cgd 		syscallarg(struct timeval *) olddelta;
    339       1.15   thorpej 	} */ *uap = v;
    340        1.8       cgd 	struct timeval atv;
    341        1.8       cgd 	register long ndelta, ntickdelta, odelta;
    342        1.1       cgd 	int s, error;
    343        1.1       cgd 
    344       1.17  christos 	if ((error = suser(p->p_ucred, &p->p_acflag)) != 0)
    345        1.1       cgd 		return (error);
    346       1.17  christos 
    347       1.24       cgd 	error = copyin(SCARG(uap, delta), &atv, sizeof(struct timeval));
    348       1.17  christos 	if (error)
    349        1.1       cgd 		return (error);
    350  1.36.10.1    itojun 	if (SCARG(uap, olddelta) != NULL &&
    351  1.36.10.1    itojun 	    uvm_useracc((caddr_t)SCARG(uap, olddelta), sizeof(struct timeval),
    352  1.36.10.1    itojun 	     B_WRITE) == FALSE)
    353  1.36.10.1    itojun 		return (EFAULT);
    354        1.8       cgd 
    355        1.8       cgd 	/*
    356        1.8       cgd 	 * Compute the total correction and the rate at which to apply it.
    357        1.8       cgd 	 * Round the adjustment down to a whole multiple of the per-tick
    358        1.8       cgd 	 * delta, so that after some number of incremental changes in
    359        1.8       cgd 	 * hardclock(), tickdelta will become zero, lest the correction
    360        1.8       cgd 	 * overshoot and start taking us away from the desired final time.
    361        1.8       cgd 	 */
    362        1.1       cgd 	ndelta = atv.tv_sec * 1000000 + atv.tv_usec;
    363        1.8       cgd 	if (ndelta > bigadj)
    364        1.8       cgd 		ntickdelta = 10 * tickadj;
    365        1.8       cgd 	else
    366        1.8       cgd 		ntickdelta = tickadj;
    367        1.8       cgd 	if (ndelta % ntickdelta)
    368        1.8       cgd 		ndelta = ndelta / ntickdelta * ntickdelta;
    369        1.8       cgd 
    370        1.8       cgd 	/*
    371        1.8       cgd 	 * To make hardclock()'s job easier, make the per-tick delta negative
    372        1.8       cgd 	 * if we want time to run slower; then hardclock can simply compute
    373        1.8       cgd 	 * tick + tickdelta, and subtract tickdelta from timedelta.
    374        1.8       cgd 	 */
    375        1.8       cgd 	if (ndelta < 0)
    376        1.8       cgd 		ntickdelta = -ntickdelta;
    377        1.1       cgd 	s = splclock();
    378        1.8       cgd 	odelta = timedelta;
    379        1.1       cgd 	timedelta = ndelta;
    380        1.8       cgd 	tickdelta = ntickdelta;
    381        1.1       cgd 	splx(s);
    382        1.1       cgd 
    383       1.11       cgd 	if (SCARG(uap, olddelta)) {
    384        1.8       cgd 		atv.tv_sec = odelta / 1000000;
    385        1.8       cgd 		atv.tv_usec = odelta % 1000000;
    386       1.24       cgd 		(void) copyout(&atv, SCARG(uap, olddelta),
    387        1.8       cgd 		    sizeof(struct timeval));
    388        1.8       cgd 	}
    389        1.1       cgd 	return (0);
    390        1.1       cgd }
    391        1.1       cgd 
    392        1.1       cgd /*
    393        1.1       cgd  * Get value of an interval timer.  The process virtual and
    394        1.1       cgd  * profiling virtual time timers are kept in the p_stats area, since
    395        1.1       cgd  * they can be swapped out.  These are kept internally in the
    396        1.1       cgd  * way they are specified externally: in time until they expire.
    397        1.1       cgd  *
    398        1.1       cgd  * The real time interval timer is kept in the process table slot
    399        1.1       cgd  * for the process, and its value (it_value) is kept as an
    400        1.1       cgd  * absolute time rather than as a delta, so that it is easy to keep
    401        1.1       cgd  * periodic real-time signals from drifting.
    402        1.1       cgd  *
    403        1.1       cgd  * Virtual time timers are processed in the hardclock() routine of
    404        1.1       cgd  * kern_clock.c.  The real time timer is processed by a timeout
    405        1.1       cgd  * routine, called from the softclock() routine.  Since a callout
    406        1.1       cgd  * may be delayed in real time due to interrupt processing in the system,
    407        1.1       cgd  * it is possible for the real time timeout routine (realitexpire, given below),
    408        1.1       cgd  * to be delayed in real time past when it is supposed to occur.  It
    409        1.1       cgd  * does not suffice, therefore, to reload the real timer .it_value from the
    410        1.1       cgd  * real time timers .it_interval.  Rather, we compute the next time in
    411        1.1       cgd  * absolute time the timer should go off.
    412        1.1       cgd  */
    413        1.1       cgd /* ARGSUSED */
    414        1.3    andrew int
    415       1.16   mycroft sys_getitimer(p, v, retval)
    416        1.1       cgd 	struct proc *p;
    417       1.15   thorpej 	void *v;
    418       1.15   thorpej 	register_t *retval;
    419       1.15   thorpej {
    420       1.16   mycroft 	register struct sys_getitimer_args /* {
    421       1.30   mycroft 		syscallarg(int) which;
    422       1.11       cgd 		syscallarg(struct itimerval *) itv;
    423       1.15   thorpej 	} */ *uap = v;
    424       1.30   mycroft 	int which = SCARG(uap, which);
    425        1.1       cgd 	struct itimerval aitv;
    426        1.1       cgd 	int s;
    427        1.1       cgd 
    428       1.30   mycroft 	if ((u_int)which > ITIMER_PROF)
    429        1.1       cgd 		return (EINVAL);
    430        1.1       cgd 	s = splclock();
    431       1.30   mycroft 	if (which == ITIMER_REAL) {
    432        1.1       cgd 		/*
    433       1.12   mycroft 		 * Convert from absolute to relative time in .it_value
    434        1.1       cgd 		 * part of real time timer.  If time for real time timer
    435        1.1       cgd 		 * has passed return 0, else return difference between
    436        1.1       cgd 		 * current time and time for the timer to go off.
    437        1.1       cgd 		 */
    438        1.1       cgd 		aitv = p->p_realtimer;
    439       1.36   thorpej 		if (timerisset(&aitv.it_value)) {
    440        1.1       cgd 			if (timercmp(&aitv.it_value, &time, <))
    441        1.1       cgd 				timerclear(&aitv.it_value);
    442        1.1       cgd 			else
    443       1.14   mycroft 				timersub(&aitv.it_value, &time, &aitv.it_value);
    444       1.36   thorpej 		}
    445        1.1       cgd 	} else
    446       1.30   mycroft 		aitv = p->p_stats->p_timer[which];
    447        1.1       cgd 	splx(s);
    448       1.35     perry 	return (copyout(&aitv, SCARG(uap, itv), sizeof(struct itimerval)));
    449        1.1       cgd }
    450        1.1       cgd 
    451        1.1       cgd /* ARGSUSED */
    452        1.3    andrew int
    453       1.16   mycroft sys_setitimer(p, v, retval)
    454        1.1       cgd 	struct proc *p;
    455       1.17  christos 	register void *v;
    456       1.15   thorpej 	register_t *retval;
    457       1.15   thorpej {
    458       1.16   mycroft 	register struct sys_setitimer_args /* {
    459       1.30   mycroft 		syscallarg(int) which;
    460       1.24       cgd 		syscallarg(const struct itimerval *) itv;
    461       1.11       cgd 		syscallarg(struct itimerval *) oitv;
    462       1.15   thorpej 	} */ *uap = v;
    463       1.30   mycroft 	int which = SCARG(uap, which);
    464       1.21       cgd 	struct sys_getitimer_args getargs;
    465        1.1       cgd 	struct itimerval aitv;
    466       1.24       cgd 	register const struct itimerval *itvp;
    467        1.1       cgd 	int s, error;
    468        1.1       cgd 
    469       1.30   mycroft 	if ((u_int)which > ITIMER_PROF)
    470        1.1       cgd 		return (EINVAL);
    471       1.11       cgd 	itvp = SCARG(uap, itv);
    472       1.24       cgd 	if (itvp && (error = copyin(itvp, &aitv, sizeof(struct itimerval))))
    473        1.1       cgd 		return (error);
    474       1.21       cgd 	if (SCARG(uap, oitv) != NULL) {
    475       1.30   mycroft 		SCARG(&getargs, which) = which;
    476       1.21       cgd 		SCARG(&getargs, itv) = SCARG(uap, oitv);
    477       1.23       cgd 		if ((error = sys_getitimer(p, &getargs, retval)) != 0)
    478       1.21       cgd 			return (error);
    479       1.21       cgd 	}
    480        1.1       cgd 	if (itvp == 0)
    481        1.1       cgd 		return (0);
    482        1.1       cgd 	if (itimerfix(&aitv.it_value) || itimerfix(&aitv.it_interval))
    483        1.1       cgd 		return (EINVAL);
    484        1.1       cgd 	s = splclock();
    485       1.30   mycroft 	if (which == ITIMER_REAL) {
    486        1.7   mycroft 		untimeout(realitexpire, p);
    487        1.1       cgd 		if (timerisset(&aitv.it_value)) {
    488       1.14   mycroft 			timeradd(&aitv.it_value, &time, &aitv.it_value);
    489        1.7   mycroft 			timeout(realitexpire, p, hzto(&aitv.it_value));
    490        1.1       cgd 		}
    491        1.1       cgd 		p->p_realtimer = aitv;
    492        1.1       cgd 	} else
    493       1.30   mycroft 		p->p_stats->p_timer[which] = aitv;
    494        1.1       cgd 	splx(s);
    495        1.1       cgd 	return (0);
    496        1.1       cgd }
    497        1.1       cgd 
    498        1.1       cgd /*
    499        1.1       cgd  * Real interval timer expired:
    500        1.1       cgd  * send process whose timer expired an alarm signal.
    501        1.1       cgd  * If time is not set up to reload, then just return.
    502        1.1       cgd  * Else compute next time timer should go off which is > current time.
    503        1.1       cgd  * This is where delay in processing this timeout causes multiple
    504        1.1       cgd  * SIGALRM calls to be compressed into one.
    505        1.1       cgd  */
    506        1.3    andrew void
    507        1.6       cgd realitexpire(arg)
    508        1.6       cgd 	void *arg;
    509        1.6       cgd {
    510        1.1       cgd 	register struct proc *p;
    511        1.1       cgd 	int s;
    512        1.1       cgd 
    513        1.6       cgd 	p = (struct proc *)arg;
    514        1.1       cgd 	psignal(p, SIGALRM);
    515        1.1       cgd 	if (!timerisset(&p->p_realtimer.it_interval)) {
    516        1.1       cgd 		timerclear(&p->p_realtimer.it_value);
    517        1.1       cgd 		return;
    518        1.1       cgd 	}
    519        1.1       cgd 	for (;;) {
    520        1.1       cgd 		s = splclock();
    521       1.14   mycroft 		timeradd(&p->p_realtimer.it_value,
    522       1.14   mycroft 		    &p->p_realtimer.it_interval, &p->p_realtimer.it_value);
    523        1.1       cgd 		if (timercmp(&p->p_realtimer.it_value, &time, >)) {
    524        1.7   mycroft 			timeout(realitexpire, p,
    525        1.1       cgd 			    hzto(&p->p_realtimer.it_value));
    526        1.1       cgd 			splx(s);
    527        1.1       cgd 			return;
    528        1.1       cgd 		}
    529        1.1       cgd 		splx(s);
    530        1.1       cgd 	}
    531        1.1       cgd }
    532        1.1       cgd 
    533        1.1       cgd /*
    534        1.1       cgd  * Check that a proposed value to load into the .it_value or
    535        1.1       cgd  * .it_interval part of an interval timer is acceptable, and
    536        1.1       cgd  * fix it to have at least minimal value (i.e. if it is less
    537        1.1       cgd  * than the resolution of the clock, round it up.)
    538        1.1       cgd  */
    539        1.3    andrew int
    540        1.1       cgd itimerfix(tv)
    541        1.1       cgd 	struct timeval *tv;
    542        1.1       cgd {
    543        1.1       cgd 
    544        1.1       cgd 	if (tv->tv_sec < 0 || tv->tv_sec > 100000000 ||
    545        1.1       cgd 	    tv->tv_usec < 0 || tv->tv_usec >= 1000000)
    546        1.1       cgd 		return (EINVAL);
    547        1.1       cgd 	if (tv->tv_sec == 0 && tv->tv_usec != 0 && tv->tv_usec < tick)
    548        1.1       cgd 		tv->tv_usec = tick;
    549        1.1       cgd 	return (0);
    550        1.1       cgd }
    551        1.1       cgd 
    552        1.1       cgd /*
    553        1.1       cgd  * Decrement an interval timer by a specified number
    554        1.1       cgd  * of microseconds, which must be less than a second,
    555        1.1       cgd  * i.e. < 1000000.  If the timer expires, then reload
    556        1.1       cgd  * it.  In this case, carry over (usec - old value) to
    557        1.8       cgd  * reduce the value reloaded into the timer so that
    558        1.1       cgd  * the timer does not drift.  This routine assumes
    559        1.1       cgd  * that it is called in a context where the timers
    560        1.1       cgd  * on which it is operating cannot change in value.
    561        1.1       cgd  */
    562        1.3    andrew int
    563        1.1       cgd itimerdecr(itp, usec)
    564        1.1       cgd 	register struct itimerval *itp;
    565        1.1       cgd 	int usec;
    566        1.1       cgd {
    567        1.1       cgd 
    568        1.1       cgd 	if (itp->it_value.tv_usec < usec) {
    569        1.1       cgd 		if (itp->it_value.tv_sec == 0) {
    570        1.1       cgd 			/* expired, and already in next interval */
    571        1.1       cgd 			usec -= itp->it_value.tv_usec;
    572        1.1       cgd 			goto expire;
    573        1.1       cgd 		}
    574        1.1       cgd 		itp->it_value.tv_usec += 1000000;
    575        1.1       cgd 		itp->it_value.tv_sec--;
    576        1.1       cgd 	}
    577        1.1       cgd 	itp->it_value.tv_usec -= usec;
    578        1.1       cgd 	usec = 0;
    579        1.1       cgd 	if (timerisset(&itp->it_value))
    580        1.1       cgd 		return (1);
    581        1.1       cgd 	/* expired, exactly at end of interval */
    582        1.1       cgd expire:
    583        1.1       cgd 	if (timerisset(&itp->it_interval)) {
    584        1.1       cgd 		itp->it_value = itp->it_interval;
    585        1.1       cgd 		itp->it_value.tv_usec -= usec;
    586        1.1       cgd 		if (itp->it_value.tv_usec < 0) {
    587        1.1       cgd 			itp->it_value.tv_usec += 1000000;
    588        1.1       cgd 			itp->it_value.tv_sec--;
    589        1.1       cgd 		}
    590        1.1       cgd 	} else
    591        1.1       cgd 		itp->it_value.tv_usec = 0;		/* sec is already 0 */
    592        1.1       cgd 	return (0);
    593        1.1       cgd }
    594