1df8bae1dSRodney W. Grimes /* 2df8bae1dSRodney W. Grimes * Copyright (c) 1982, 1986, 1989, 1993 3df8bae1dSRodney W. Grimes * The Regents of the University of California. All rights reserved. 4df8bae1dSRodney W. Grimes * 5df8bae1dSRodney W. Grimes * Redistribution and use in source and binary forms, with or without 6df8bae1dSRodney W. Grimes * modification, are permitted provided that the following conditions 7df8bae1dSRodney W. Grimes * are met: 8df8bae1dSRodney W. Grimes * 1. Redistributions of source code must retain the above copyright 9df8bae1dSRodney W. Grimes * notice, this list of conditions and the following disclaimer. 10df8bae1dSRodney W. Grimes * 2. Redistributions in binary form must reproduce the above copyright 11df8bae1dSRodney W. Grimes * notice, this list of conditions and the following disclaimer in the 12df8bae1dSRodney W. Grimes * documentation and/or other materials provided with the distribution. 13df8bae1dSRodney W. Grimes * 3. All advertising materials mentioning features or use of this software 14df8bae1dSRodney W. Grimes * must display the following acknowledgement: 15df8bae1dSRodney W. Grimes * This product includes software developed by the University of 16df8bae1dSRodney W. Grimes * California, Berkeley and its contributors. 17df8bae1dSRodney W. Grimes * 4. Neither the name of the University nor the names of its contributors 18df8bae1dSRodney W. Grimes * may be used to endorse or promote products derived from this software 19df8bae1dSRodney W. Grimes * without specific prior written permission. 20df8bae1dSRodney W. Grimes * 21df8bae1dSRodney W. Grimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22df8bae1dSRodney W. Grimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23df8bae1dSRodney W. Grimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24df8bae1dSRodney W. Grimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25df8bae1dSRodney W. Grimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26df8bae1dSRodney W. Grimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27df8bae1dSRodney W. Grimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28df8bae1dSRodney W. Grimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29df8bae1dSRodney W. Grimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30df8bae1dSRodney W. Grimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31df8bae1dSRodney W. Grimes * SUCH DAMAGE. 32df8bae1dSRodney W. Grimes * 33df8bae1dSRodney W. Grimes * @(#)kern_time.c 8.1 (Berkeley) 6/10/93 3487b6de2bSPoul-Henning Kamp * $Id: kern_time.c,v 1.12 1995/11/19 00:59:22 bde Exp $ 35df8bae1dSRodney W. Grimes */ 36df8bae1dSRodney W. Grimes 37df8bae1dSRodney W. Grimes #include <sys/param.h> 38d2d3e875SBruce Evans #include <sys/sysproto.h> 39df8bae1dSRodney W. Grimes #include <sys/resourcevar.h> 40797f2d22SPoul-Henning Kamp #include <sys/signalvar.h> 41df8bae1dSRodney W. Grimes #include <sys/kernel.h> 42df8bae1dSRodney W. Grimes #include <sys/systm.h> 43df8bae1dSRodney W. Grimes #include <sys/proc.h> 44df8bae1dSRodney W. Grimes #include <sys/vnode.h> 45df8bae1dSRodney W. Grimes 46df8bae1dSRodney W. Grimes #include <machine/cpu.h> 47df8bae1dSRodney W. Grimes 48ac7e6123SDavid Greenman struct timezone tz; 49ac7e6123SDavid Greenman 50df8bae1dSRodney W. Grimes /* 51df8bae1dSRodney W. Grimes * Time of day and interval timer support. 52df8bae1dSRodney W. Grimes * 53df8bae1dSRodney W. Grimes * These routines provide the kernel entry points to get and set 54df8bae1dSRodney W. Grimes * the time-of-day and per-process interval timers. Subroutines 55df8bae1dSRodney W. Grimes * here provide support for adding and subtracting timeval structures 56df8bae1dSRodney W. Grimes * and decrementing interval timers, optionally reloading the interval 57df8bae1dSRodney W. Grimes * timers when they expire. 58df8bae1dSRodney W. Grimes */ 59df8bae1dSRodney W. Grimes 60d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 61df8bae1dSRodney W. Grimes struct gettimeofday_args { 62df8bae1dSRodney W. Grimes struct timeval *tp; 63df8bae1dSRodney W. Grimes struct timezone *tzp; 64df8bae1dSRodney W. Grimes }; 65d2d3e875SBruce Evans #endif 66df8bae1dSRodney W. Grimes /* ARGSUSED */ 6726f9a767SRodney W. Grimes int 68df8bae1dSRodney W. Grimes gettimeofday(p, uap, retval) 69df8bae1dSRodney W. Grimes struct proc *p; 70df8bae1dSRodney W. Grimes register struct gettimeofday_args *uap; 71df8bae1dSRodney W. Grimes int *retval; 72df8bae1dSRodney W. Grimes { 73df8bae1dSRodney W. Grimes struct timeval atv; 74df8bae1dSRodney W. Grimes int error = 0; 75df8bae1dSRodney W. Grimes 76df8bae1dSRodney W. Grimes if (uap->tp) { 77df8bae1dSRodney W. Grimes microtime(&atv); 78bb56ec4aSPoul-Henning Kamp if ((error = copyout((caddr_t)&atv, (caddr_t)uap->tp, 79bb56ec4aSPoul-Henning Kamp sizeof (atv)))) 80df8bae1dSRodney W. Grimes return (error); 81df8bae1dSRodney W. Grimes } 82df8bae1dSRodney W. Grimes if (uap->tzp) 83df8bae1dSRodney W. Grimes error = copyout((caddr_t)&tz, (caddr_t)uap->tzp, 84df8bae1dSRodney W. Grimes sizeof (tz)); 85df8bae1dSRodney W. Grimes return (error); 86df8bae1dSRodney W. Grimes } 87df8bae1dSRodney W. Grimes 88d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 89df8bae1dSRodney W. Grimes struct settimeofday_args { 90df8bae1dSRodney W. Grimes struct timeval *tv; 91df8bae1dSRodney W. Grimes struct timezone *tzp; 92df8bae1dSRodney W. Grimes }; 93d2d3e875SBruce Evans #endif 94df8bae1dSRodney W. Grimes /* ARGSUSED */ 9526f9a767SRodney W. Grimes int 96df8bae1dSRodney W. Grimes settimeofday(p, uap, retval) 97df8bae1dSRodney W. Grimes struct proc *p; 98df8bae1dSRodney W. Grimes struct settimeofday_args *uap; 99df8bae1dSRodney W. Grimes int *retval; 100df8bae1dSRodney W. Grimes { 101df8bae1dSRodney W. Grimes struct timeval atv, delta; 102df8bae1dSRodney W. Grimes struct timezone atz; 103df8bae1dSRodney W. Grimes int error, s; 104df8bae1dSRodney W. Grimes 105bb56ec4aSPoul-Henning Kamp if ((error = suser(p->p_ucred, &p->p_acflag))) 106df8bae1dSRodney W. Grimes return (error); 107df8bae1dSRodney W. Grimes /* Verify all parameters before changing time. */ 108df8bae1dSRodney W. Grimes if (uap->tv && 109df8bae1dSRodney W. Grimes (error = copyin((caddr_t)uap->tv, (caddr_t)&atv, sizeof(atv)))) 110df8bae1dSRodney W. Grimes return (error); 1110808c591SBruce Evans if (atv.tv_usec < 0 || atv.tv_usec >= 1000000) 1120808c591SBruce Evans return (EINVAL); 113df8bae1dSRodney W. Grimes if (uap->tzp && 114df8bae1dSRodney W. Grimes (error = copyin((caddr_t)uap->tzp, (caddr_t)&atz, sizeof(atz)))) 115df8bae1dSRodney W. Grimes return (error); 116df8bae1dSRodney W. Grimes if (uap->tv) { 117df8bae1dSRodney W. Grimes /* WHAT DO WE DO ABOUT PENDING REAL-TIME TIMEOUTS??? */ 118df8bae1dSRodney W. Grimes s = splclock(); 119df8bae1dSRodney W. Grimes /* nb. delta.tv_usec may be < 0, but this is OK here */ 120df8bae1dSRodney W. Grimes delta.tv_sec = atv.tv_sec - time.tv_sec; 121df8bae1dSRodney W. Grimes delta.tv_usec = atv.tv_usec - time.tv_usec; 1220808c591SBruce Evans time = atv; /* XXX should avoid skew in tv_usec */ 123df8bae1dSRodney W. Grimes (void) splsoftclock(); 1240808c591SBruce Evans timevalfix(&delta); 125df8bae1dSRodney W. Grimes timevaladd(&boottime, &delta); 126df8bae1dSRodney W. Grimes timevaladd(&runtime, &delta); 127df8bae1dSRodney W. Grimes LEASE_UPDATETIME(delta.tv_sec); 128df8bae1dSRodney W. Grimes splx(s); 129df8bae1dSRodney W. Grimes resettodr(); 130df8bae1dSRodney W. Grimes } 131df8bae1dSRodney W. Grimes if (uap->tzp) 132df8bae1dSRodney W. Grimes tz = atz; 133df8bae1dSRodney W. Grimes return (0); 134df8bae1dSRodney W. Grimes } 135df8bae1dSRodney W. Grimes 136df8bae1dSRodney W. Grimes extern int tickadj; /* "standard" clock skew, us./tick */ 137df8bae1dSRodney W. Grimes int tickdelta; /* current clock skew, us. per tick */ 138df8bae1dSRodney W. Grimes long timedelta; /* unapplied time correction, us. */ 13987b6de2bSPoul-Henning Kamp static long bigadj = 1000000; /* use 10x skew above bigadj us. */ 140df8bae1dSRodney W. Grimes 141d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 142df8bae1dSRodney W. Grimes struct adjtime_args { 143df8bae1dSRodney W. Grimes struct timeval *delta; 144df8bae1dSRodney W. Grimes struct timeval *olddelta; 145df8bae1dSRodney W. Grimes }; 146d2d3e875SBruce Evans #endif 147df8bae1dSRodney W. Grimes /* ARGSUSED */ 14826f9a767SRodney W. Grimes int 149df8bae1dSRodney W. Grimes adjtime(p, uap, retval) 150df8bae1dSRodney W. Grimes struct proc *p; 151df8bae1dSRodney W. Grimes register struct adjtime_args *uap; 152df8bae1dSRodney W. Grimes int *retval; 153df8bae1dSRodney W. Grimes { 154df8bae1dSRodney W. Grimes struct timeval atv; 155df8bae1dSRodney W. Grimes register long ndelta, ntickdelta, odelta; 156df8bae1dSRodney W. Grimes int s, error; 157df8bae1dSRodney W. Grimes 158bb56ec4aSPoul-Henning Kamp if ((error = suser(p->p_ucred, &p->p_acflag))) 159df8bae1dSRodney W. Grimes return (error); 160bb56ec4aSPoul-Henning Kamp if ((error = 161bb56ec4aSPoul-Henning Kamp copyin((caddr_t)uap->delta, (caddr_t)&atv, sizeof(struct timeval)))) 162df8bae1dSRodney W. Grimes return (error); 163df8bae1dSRodney W. Grimes 164df8bae1dSRodney W. Grimes /* 165df8bae1dSRodney W. Grimes * Compute the total correction and the rate at which to apply it. 166df8bae1dSRodney W. Grimes * Round the adjustment down to a whole multiple of the per-tick 167df8bae1dSRodney W. Grimes * delta, so that after some number of incremental changes in 168df8bae1dSRodney W. Grimes * hardclock(), tickdelta will become zero, lest the correction 169df8bae1dSRodney W. Grimes * overshoot and start taking us away from the desired final time. 170df8bae1dSRodney W. Grimes */ 171df8bae1dSRodney W. Grimes ndelta = atv.tv_sec * 1000000 + atv.tv_usec; 172df8bae1dSRodney W. Grimes if (ndelta > bigadj) 173df8bae1dSRodney W. Grimes ntickdelta = 10 * tickadj; 174df8bae1dSRodney W. Grimes else 175df8bae1dSRodney W. Grimes ntickdelta = tickadj; 176df8bae1dSRodney W. Grimes if (ndelta % ntickdelta) 177df8bae1dSRodney W. Grimes ndelta = ndelta / ntickdelta * ntickdelta; 178df8bae1dSRodney W. Grimes 179df8bae1dSRodney W. Grimes /* 180df8bae1dSRodney W. Grimes * To make hardclock()'s job easier, make the per-tick delta negative 181df8bae1dSRodney W. Grimes * if we want time to run slower; then hardclock can simply compute 182df8bae1dSRodney W. Grimes * tick + tickdelta, and subtract tickdelta from timedelta. 183df8bae1dSRodney W. Grimes */ 184df8bae1dSRodney W. Grimes if (ndelta < 0) 185df8bae1dSRodney W. Grimes ntickdelta = -ntickdelta; 186df8bae1dSRodney W. Grimes s = splclock(); 187df8bae1dSRodney W. Grimes odelta = timedelta; 188df8bae1dSRodney W. Grimes timedelta = ndelta; 189df8bae1dSRodney W. Grimes tickdelta = ntickdelta; 190df8bae1dSRodney W. Grimes splx(s); 191df8bae1dSRodney W. Grimes 192df8bae1dSRodney W. Grimes if (uap->olddelta) { 193df8bae1dSRodney W. Grimes atv.tv_sec = odelta / 1000000; 194df8bae1dSRodney W. Grimes atv.tv_usec = odelta % 1000000; 195df8bae1dSRodney W. Grimes (void) copyout((caddr_t)&atv, (caddr_t)uap->olddelta, 196df8bae1dSRodney W. Grimes sizeof(struct timeval)); 197df8bae1dSRodney W. Grimes } 198df8bae1dSRodney W. Grimes return (0); 199df8bae1dSRodney W. Grimes } 200df8bae1dSRodney W. Grimes 201df8bae1dSRodney W. Grimes /* 202df8bae1dSRodney W. Grimes * Get value of an interval timer. The process virtual and 203df8bae1dSRodney W. Grimes * profiling virtual time timers are kept in the p_stats area, since 204df8bae1dSRodney W. Grimes * they can be swapped out. These are kept internally in the 205df8bae1dSRodney W. Grimes * way they are specified externally: in time until they expire. 206df8bae1dSRodney W. Grimes * 207df8bae1dSRodney W. Grimes * The real time interval timer is kept in the process table slot 208df8bae1dSRodney W. Grimes * for the process, and its value (it_value) is kept as an 209df8bae1dSRodney W. Grimes * absolute time rather than as a delta, so that it is easy to keep 210df8bae1dSRodney W. Grimes * periodic real-time signals from drifting. 211df8bae1dSRodney W. Grimes * 212df8bae1dSRodney W. Grimes * Virtual time timers are processed in the hardclock() routine of 213df8bae1dSRodney W. Grimes * kern_clock.c. The real time timer is processed by a timeout 214df8bae1dSRodney W. Grimes * routine, called from the softclock() routine. Since a callout 215df8bae1dSRodney W. Grimes * may be delayed in real time due to interrupt processing in the system, 216df8bae1dSRodney W. Grimes * it is possible for the real time timeout routine (realitexpire, given below), 217df8bae1dSRodney W. Grimes * to be delayed in real time past when it is supposed to occur. It 218df8bae1dSRodney W. Grimes * does not suffice, therefore, to reload the real timer .it_value from the 219df8bae1dSRodney W. Grimes * real time timers .it_interval. Rather, we compute the next time in 220df8bae1dSRodney W. Grimes * absolute time the timer should go off. 221df8bae1dSRodney W. Grimes */ 222d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 223df8bae1dSRodney W. Grimes struct getitimer_args { 224df8bae1dSRodney W. Grimes u_int which; 225df8bae1dSRodney W. Grimes struct itimerval *itv; 226df8bae1dSRodney W. Grimes }; 227d2d3e875SBruce Evans #endif 228df8bae1dSRodney W. Grimes /* ARGSUSED */ 22926f9a767SRodney W. Grimes int 230df8bae1dSRodney W. Grimes getitimer(p, uap, retval) 231df8bae1dSRodney W. Grimes struct proc *p; 232df8bae1dSRodney W. Grimes register struct getitimer_args *uap; 233df8bae1dSRodney W. Grimes int *retval; 234df8bae1dSRodney W. Grimes { 235df8bae1dSRodney W. Grimes struct itimerval aitv; 236df8bae1dSRodney W. Grimes int s; 237df8bae1dSRodney W. Grimes 238df8bae1dSRodney W. Grimes if (uap->which > ITIMER_PROF) 239df8bae1dSRodney W. Grimes return (EINVAL); 240df8bae1dSRodney W. Grimes s = splclock(); 241df8bae1dSRodney W. Grimes if (uap->which == ITIMER_REAL) { 242df8bae1dSRodney W. Grimes /* 243df8bae1dSRodney W. Grimes * Convert from absoulte to relative time in .it_value 244df8bae1dSRodney W. Grimes * part of real time timer. If time for real time timer 245df8bae1dSRodney W. Grimes * has passed return 0, else return difference between 246df8bae1dSRodney W. Grimes * current time and time for the timer to go off. 247df8bae1dSRodney W. Grimes */ 248df8bae1dSRodney W. Grimes aitv = p->p_realtimer; 249df8bae1dSRodney W. Grimes if (timerisset(&aitv.it_value)) 250df8bae1dSRodney W. Grimes if (timercmp(&aitv.it_value, &time, <)) 251df8bae1dSRodney W. Grimes timerclear(&aitv.it_value); 252df8bae1dSRodney W. Grimes else 253df8bae1dSRodney W. Grimes timevalsub(&aitv.it_value, 254df8bae1dSRodney W. Grimes (struct timeval *)&time); 255df8bae1dSRodney W. Grimes } else 256df8bae1dSRodney W. Grimes aitv = p->p_stats->p_timer[uap->which]; 257df8bae1dSRodney W. Grimes splx(s); 258df8bae1dSRodney W. Grimes return (copyout((caddr_t)&aitv, (caddr_t)uap->itv, 259df8bae1dSRodney W. Grimes sizeof (struct itimerval))); 260df8bae1dSRodney W. Grimes } 261df8bae1dSRodney W. Grimes 262d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 263df8bae1dSRodney W. Grimes struct setitimer_args { 264df8bae1dSRodney W. Grimes u_int which; 265df8bae1dSRodney W. Grimes struct itimerval *itv, *oitv; 266df8bae1dSRodney W. Grimes }; 267d2d3e875SBruce Evans #endif 268df8bae1dSRodney W. Grimes /* ARGSUSED */ 26926f9a767SRodney W. Grimes int 270df8bae1dSRodney W. Grimes setitimer(p, uap, retval) 271df8bae1dSRodney W. Grimes struct proc *p; 272df8bae1dSRodney W. Grimes register struct setitimer_args *uap; 273df8bae1dSRodney W. Grimes int *retval; 274df8bae1dSRodney W. Grimes { 275df8bae1dSRodney W. Grimes struct itimerval aitv; 276df8bae1dSRodney W. Grimes register struct itimerval *itvp; 277df8bae1dSRodney W. Grimes int s, error; 278df8bae1dSRodney W. Grimes 279df8bae1dSRodney W. Grimes if (uap->which > ITIMER_PROF) 280df8bae1dSRodney W. Grimes return (EINVAL); 281df8bae1dSRodney W. Grimes itvp = uap->itv; 282df8bae1dSRodney W. Grimes if (itvp && (error = copyin((caddr_t)itvp, (caddr_t)&aitv, 283df8bae1dSRodney W. Grimes sizeof(struct itimerval)))) 284df8bae1dSRodney W. Grimes return (error); 2850808c591SBruce Evans if ((uap->itv = uap->oitv) && 2860808c591SBruce Evans (error = getitimer(p, (struct getitimer_args *)uap, retval))) 287df8bae1dSRodney W. Grimes return (error); 288df8bae1dSRodney W. Grimes if (itvp == 0) 289df8bae1dSRodney W. Grimes return (0); 290df8bae1dSRodney W. Grimes if (itimerfix(&aitv.it_value) || itimerfix(&aitv.it_interval)) 291df8bae1dSRodney W. Grimes return (EINVAL); 292df8bae1dSRodney W. Grimes s = splclock(); 293df8bae1dSRodney W. Grimes if (uap->which == ITIMER_REAL) { 294df8bae1dSRodney W. Grimes untimeout(realitexpire, (caddr_t)p); 295df8bae1dSRodney W. Grimes if (timerisset(&aitv.it_value)) { 296df8bae1dSRodney W. Grimes timevaladd(&aitv.it_value, (struct timeval *)&time); 297df8bae1dSRodney W. Grimes timeout(realitexpire, (caddr_t)p, hzto(&aitv.it_value)); 298df8bae1dSRodney W. Grimes } 299df8bae1dSRodney W. Grimes p->p_realtimer = aitv; 300df8bae1dSRodney W. Grimes } else 301df8bae1dSRodney W. Grimes p->p_stats->p_timer[uap->which] = aitv; 302df8bae1dSRodney W. Grimes splx(s); 303df8bae1dSRodney W. Grimes return (0); 304df8bae1dSRodney W. Grimes } 305df8bae1dSRodney W. Grimes 306df8bae1dSRodney W. Grimes /* 307df8bae1dSRodney W. Grimes * Real interval timer expired: 308df8bae1dSRodney W. Grimes * send process whose timer expired an alarm signal. 309df8bae1dSRodney W. Grimes * If time is not set up to reload, then just return. 310df8bae1dSRodney W. Grimes * Else compute next time timer should go off which is > current time. 311df8bae1dSRodney W. Grimes * This is where delay in processing this timeout causes multiple 312df8bae1dSRodney W. Grimes * SIGALRM calls to be compressed into one. 3139207f00aSBruce Evans * hzto() always adds 1 to allow for the time until the next clock 3149207f00aSBruce Evans * interrupt being strictly less than 1 clock tick, but we don't want 3159207f00aSBruce Evans * that here since we want to appear to be in sync with the clock 3169207f00aSBruce Evans * interrupt even when we're delayed. 317df8bae1dSRodney W. Grimes */ 318df8bae1dSRodney W. Grimes void 319df8bae1dSRodney W. Grimes realitexpire(arg) 320df8bae1dSRodney W. Grimes void *arg; 321df8bae1dSRodney W. Grimes { 322df8bae1dSRodney W. Grimes register struct proc *p; 323df8bae1dSRodney W. Grimes int s; 324df8bae1dSRodney W. Grimes 325df8bae1dSRodney W. Grimes p = (struct proc *)arg; 326df8bae1dSRodney W. Grimes psignal(p, SIGALRM); 327df8bae1dSRodney W. Grimes if (!timerisset(&p->p_realtimer.it_interval)) { 328df8bae1dSRodney W. Grimes timerclear(&p->p_realtimer.it_value); 329df8bae1dSRodney W. Grimes return; 330df8bae1dSRodney W. Grimes } 331df8bae1dSRodney W. Grimes for (;;) { 332df8bae1dSRodney W. Grimes s = splclock(); 333df8bae1dSRodney W. Grimes timevaladd(&p->p_realtimer.it_value, 334df8bae1dSRodney W. Grimes &p->p_realtimer.it_interval); 335df8bae1dSRodney W. Grimes if (timercmp(&p->p_realtimer.it_value, &time, >)) { 336df8bae1dSRodney W. Grimes timeout(realitexpire, (caddr_t)p, 3379207f00aSBruce Evans hzto(&p->p_realtimer.it_value) - 1); 338df8bae1dSRodney W. Grimes splx(s); 339df8bae1dSRodney W. Grimes return; 340df8bae1dSRodney W. Grimes } 341df8bae1dSRodney W. Grimes splx(s); 342df8bae1dSRodney W. Grimes } 343df8bae1dSRodney W. Grimes } 344df8bae1dSRodney W. Grimes 345df8bae1dSRodney W. Grimes /* 346df8bae1dSRodney W. Grimes * Check that a proposed value to load into the .it_value or 347df8bae1dSRodney W. Grimes * .it_interval part of an interval timer is acceptable, and 348df8bae1dSRodney W. Grimes * fix it to have at least minimal value (i.e. if it is less 349df8bae1dSRodney W. Grimes * than the resolution of the clock, round it up.) 350df8bae1dSRodney W. Grimes */ 35126f9a767SRodney W. Grimes int 352df8bae1dSRodney W. Grimes itimerfix(tv) 353df8bae1dSRodney W. Grimes struct timeval *tv; 354df8bae1dSRodney W. Grimes { 355df8bae1dSRodney W. Grimes 356df8bae1dSRodney W. Grimes if (tv->tv_sec < 0 || tv->tv_sec > 100000000 || 357df8bae1dSRodney W. Grimes tv->tv_usec < 0 || tv->tv_usec >= 1000000) 358df8bae1dSRodney W. Grimes return (EINVAL); 359df8bae1dSRodney W. Grimes if (tv->tv_sec == 0 && tv->tv_usec != 0 && tv->tv_usec < tick) 360df8bae1dSRodney W. Grimes tv->tv_usec = tick; 361df8bae1dSRodney W. Grimes return (0); 362df8bae1dSRodney W. Grimes } 363df8bae1dSRodney W. Grimes 364df8bae1dSRodney W. Grimes /* 365df8bae1dSRodney W. Grimes * Decrement an interval timer by a specified number 366df8bae1dSRodney W. Grimes * of microseconds, which must be less than a second, 367df8bae1dSRodney W. Grimes * i.e. < 1000000. If the timer expires, then reload 368df8bae1dSRodney W. Grimes * it. In this case, carry over (usec - old value) to 369df8bae1dSRodney W. Grimes * reduce the value reloaded into the timer so that 370df8bae1dSRodney W. Grimes * the timer does not drift. This routine assumes 371df8bae1dSRodney W. Grimes * that it is called in a context where the timers 372df8bae1dSRodney W. Grimes * on which it is operating cannot change in value. 373df8bae1dSRodney W. Grimes */ 37426f9a767SRodney W. Grimes int 375df8bae1dSRodney W. Grimes itimerdecr(itp, usec) 376df8bae1dSRodney W. Grimes register struct itimerval *itp; 377df8bae1dSRodney W. Grimes int usec; 378df8bae1dSRodney W. Grimes { 379df8bae1dSRodney W. Grimes 380df8bae1dSRodney W. Grimes if (itp->it_value.tv_usec < usec) { 381df8bae1dSRodney W. Grimes if (itp->it_value.tv_sec == 0) { 382df8bae1dSRodney W. Grimes /* expired, and already in next interval */ 383df8bae1dSRodney W. Grimes usec -= itp->it_value.tv_usec; 384df8bae1dSRodney W. Grimes goto expire; 385df8bae1dSRodney W. Grimes } 386df8bae1dSRodney W. Grimes itp->it_value.tv_usec += 1000000; 387df8bae1dSRodney W. Grimes itp->it_value.tv_sec--; 388df8bae1dSRodney W. Grimes } 389df8bae1dSRodney W. Grimes itp->it_value.tv_usec -= usec; 390df8bae1dSRodney W. Grimes usec = 0; 391df8bae1dSRodney W. Grimes if (timerisset(&itp->it_value)) 392df8bae1dSRodney W. Grimes return (1); 393df8bae1dSRodney W. Grimes /* expired, exactly at end of interval */ 394df8bae1dSRodney W. Grimes expire: 395df8bae1dSRodney W. Grimes if (timerisset(&itp->it_interval)) { 396df8bae1dSRodney W. Grimes itp->it_value = itp->it_interval; 397df8bae1dSRodney W. Grimes itp->it_value.tv_usec -= usec; 398df8bae1dSRodney W. Grimes if (itp->it_value.tv_usec < 0) { 399df8bae1dSRodney W. Grimes itp->it_value.tv_usec += 1000000; 400df8bae1dSRodney W. Grimes itp->it_value.tv_sec--; 401df8bae1dSRodney W. Grimes } 402df8bae1dSRodney W. Grimes } else 403df8bae1dSRodney W. Grimes itp->it_value.tv_usec = 0; /* sec is already 0 */ 404df8bae1dSRodney W. Grimes return (0); 405df8bae1dSRodney W. Grimes } 406df8bae1dSRodney W. Grimes 407df8bae1dSRodney W. Grimes /* 408df8bae1dSRodney W. Grimes * Add and subtract routines for timevals. 409df8bae1dSRodney W. Grimes * N.B.: subtract routine doesn't deal with 410df8bae1dSRodney W. Grimes * results which are before the beginning, 411df8bae1dSRodney W. Grimes * it just gets very confused in this case. 412df8bae1dSRodney W. Grimes * Caveat emptor. 413df8bae1dSRodney W. Grimes */ 41426f9a767SRodney W. Grimes void 415df8bae1dSRodney W. Grimes timevaladd(t1, t2) 416df8bae1dSRodney W. Grimes struct timeval *t1, *t2; 417df8bae1dSRodney W. Grimes { 418df8bae1dSRodney W. Grimes 419df8bae1dSRodney W. Grimes t1->tv_sec += t2->tv_sec; 420df8bae1dSRodney W. Grimes t1->tv_usec += t2->tv_usec; 421df8bae1dSRodney W. Grimes timevalfix(t1); 422df8bae1dSRodney W. Grimes } 423df8bae1dSRodney W. Grimes 42426f9a767SRodney W. Grimes void 425df8bae1dSRodney W. Grimes timevalsub(t1, t2) 426df8bae1dSRodney W. Grimes struct timeval *t1, *t2; 427df8bae1dSRodney W. Grimes { 428df8bae1dSRodney W. Grimes 429df8bae1dSRodney W. Grimes t1->tv_sec -= t2->tv_sec; 430df8bae1dSRodney W. Grimes t1->tv_usec -= t2->tv_usec; 431df8bae1dSRodney W. Grimes timevalfix(t1); 432df8bae1dSRodney W. Grimes } 433df8bae1dSRodney W. Grimes 43487b6de2bSPoul-Henning Kamp static void 435df8bae1dSRodney W. Grimes timevalfix(t1) 436df8bae1dSRodney W. Grimes struct timeval *t1; 437df8bae1dSRodney W. Grimes { 438df8bae1dSRodney W. Grimes 439df8bae1dSRodney W. Grimes if (t1->tv_usec < 0) { 440df8bae1dSRodney W. Grimes t1->tv_sec--; 441df8bae1dSRodney W. Grimes t1->tv_usec += 1000000; 442df8bae1dSRodney W. Grimes } 443df8bae1dSRodney W. Grimes if (t1->tv_usec >= 1000000) { 444df8bae1dSRodney W. Grimes t1->tv_sec++; 445df8bae1dSRodney W. Grimes t1->tv_usec -= 1000000; 446df8bae1dSRodney W. Grimes } 447df8bae1dSRodney W. Grimes } 448