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 34d2d3e875SBruce Evans * $Id: kern_time.c,v 1.10 1995/06/29 07:07:00 davidg 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); 111df8bae1dSRodney W. Grimes if (uap->tzp && 112df8bae1dSRodney W. Grimes (error = copyin((caddr_t)uap->tzp, (caddr_t)&atz, sizeof(atz)))) 113df8bae1dSRodney W. Grimes return (error); 114df8bae1dSRodney W. Grimes if (uap->tv) { 115df8bae1dSRodney W. Grimes /* WHAT DO WE DO ABOUT PENDING REAL-TIME TIMEOUTS??? */ 116df8bae1dSRodney W. Grimes s = splclock(); 117df8bae1dSRodney W. Grimes /* nb. delta.tv_usec may be < 0, but this is OK here */ 118df8bae1dSRodney W. Grimes delta.tv_sec = atv.tv_sec - time.tv_sec; 119df8bae1dSRodney W. Grimes delta.tv_usec = atv.tv_usec - time.tv_usec; 120df8bae1dSRodney W. Grimes time = atv; 121df8bae1dSRodney W. Grimes (void) splsoftclock(); 122df8bae1dSRodney W. Grimes timevaladd(&boottime, &delta); 123df8bae1dSRodney W. Grimes timevalfix(&boottime); 124df8bae1dSRodney W. Grimes timevaladd(&runtime, &delta); 125df8bae1dSRodney W. Grimes timevalfix(&runtime); 126df8bae1dSRodney W. Grimes LEASE_UPDATETIME(delta.tv_sec); 127df8bae1dSRodney W. Grimes splx(s); 128df8bae1dSRodney W. Grimes resettodr(); 129df8bae1dSRodney W. Grimes } 130df8bae1dSRodney W. Grimes if (uap->tzp) 131df8bae1dSRodney W. Grimes tz = atz; 132df8bae1dSRodney W. Grimes return (0); 133df8bae1dSRodney W. Grimes } 134df8bae1dSRodney W. Grimes 135df8bae1dSRodney W. Grimes extern int tickadj; /* "standard" clock skew, us./tick */ 136df8bae1dSRodney W. Grimes int tickdelta; /* current clock skew, us. per tick */ 137df8bae1dSRodney W. Grimes long timedelta; /* unapplied time correction, us. */ 138df8bae1dSRodney W. Grimes long bigadj = 1000000; /* use 10x skew above bigadj us. */ 139df8bae1dSRodney W. Grimes 140d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 141df8bae1dSRodney W. Grimes struct adjtime_args { 142df8bae1dSRodney W. Grimes struct timeval *delta; 143df8bae1dSRodney W. Grimes struct timeval *olddelta; 144df8bae1dSRodney W. Grimes }; 145d2d3e875SBruce Evans #endif 146df8bae1dSRodney W. Grimes /* ARGSUSED */ 14726f9a767SRodney W. Grimes int 148df8bae1dSRodney W. Grimes adjtime(p, uap, retval) 149df8bae1dSRodney W. Grimes struct proc *p; 150df8bae1dSRodney W. Grimes register struct adjtime_args *uap; 151df8bae1dSRodney W. Grimes int *retval; 152df8bae1dSRodney W. Grimes { 153df8bae1dSRodney W. Grimes struct timeval atv; 154df8bae1dSRodney W. Grimes register long ndelta, ntickdelta, odelta; 155df8bae1dSRodney W. Grimes int s, error; 156df8bae1dSRodney W. Grimes 157bb56ec4aSPoul-Henning Kamp if ((error = suser(p->p_ucred, &p->p_acflag))) 158df8bae1dSRodney W. Grimes return (error); 159bb56ec4aSPoul-Henning Kamp if ((error = 160bb56ec4aSPoul-Henning Kamp copyin((caddr_t)uap->delta, (caddr_t)&atv, sizeof(struct timeval)))) 161df8bae1dSRodney W. Grimes return (error); 162df8bae1dSRodney W. Grimes 163df8bae1dSRodney W. Grimes /* 164df8bae1dSRodney W. Grimes * Compute the total correction and the rate at which to apply it. 165df8bae1dSRodney W. Grimes * Round the adjustment down to a whole multiple of the per-tick 166df8bae1dSRodney W. Grimes * delta, so that after some number of incremental changes in 167df8bae1dSRodney W. Grimes * hardclock(), tickdelta will become zero, lest the correction 168df8bae1dSRodney W. Grimes * overshoot and start taking us away from the desired final time. 169df8bae1dSRodney W. Grimes */ 170df8bae1dSRodney W. Grimes ndelta = atv.tv_sec * 1000000 + atv.tv_usec; 171df8bae1dSRodney W. Grimes if (ndelta > bigadj) 172df8bae1dSRodney W. Grimes ntickdelta = 10 * tickadj; 173df8bae1dSRodney W. Grimes else 174df8bae1dSRodney W. Grimes ntickdelta = tickadj; 175df8bae1dSRodney W. Grimes if (ndelta % ntickdelta) 176df8bae1dSRodney W. Grimes ndelta = ndelta / ntickdelta * ntickdelta; 177df8bae1dSRodney W. Grimes 178df8bae1dSRodney W. Grimes /* 179df8bae1dSRodney W. Grimes * To make hardclock()'s job easier, make the per-tick delta negative 180df8bae1dSRodney W. Grimes * if we want time to run slower; then hardclock can simply compute 181df8bae1dSRodney W. Grimes * tick + tickdelta, and subtract tickdelta from timedelta. 182df8bae1dSRodney W. Grimes */ 183df8bae1dSRodney W. Grimes if (ndelta < 0) 184df8bae1dSRodney W. Grimes ntickdelta = -ntickdelta; 185df8bae1dSRodney W. Grimes s = splclock(); 186df8bae1dSRodney W. Grimes odelta = timedelta; 187df8bae1dSRodney W. Grimes timedelta = ndelta; 188df8bae1dSRodney W. Grimes tickdelta = ntickdelta; 189df8bae1dSRodney W. Grimes splx(s); 190df8bae1dSRodney W. Grimes 191df8bae1dSRodney W. Grimes if (uap->olddelta) { 192df8bae1dSRodney W. Grimes atv.tv_sec = odelta / 1000000; 193df8bae1dSRodney W. Grimes atv.tv_usec = odelta % 1000000; 194df8bae1dSRodney W. Grimes (void) copyout((caddr_t)&atv, (caddr_t)uap->olddelta, 195df8bae1dSRodney W. Grimes sizeof(struct timeval)); 196df8bae1dSRodney W. Grimes } 197df8bae1dSRodney W. Grimes return (0); 198df8bae1dSRodney W. Grimes } 199df8bae1dSRodney W. Grimes 200df8bae1dSRodney W. Grimes /* 201df8bae1dSRodney W. Grimes * Get value of an interval timer. The process virtual and 202df8bae1dSRodney W. Grimes * profiling virtual time timers are kept in the p_stats area, since 203df8bae1dSRodney W. Grimes * they can be swapped out. These are kept internally in the 204df8bae1dSRodney W. Grimes * way they are specified externally: in time until they expire. 205df8bae1dSRodney W. Grimes * 206df8bae1dSRodney W. Grimes * The real time interval timer is kept in the process table slot 207df8bae1dSRodney W. Grimes * for the process, and its value (it_value) is kept as an 208df8bae1dSRodney W. Grimes * absolute time rather than as a delta, so that it is easy to keep 209df8bae1dSRodney W. Grimes * periodic real-time signals from drifting. 210df8bae1dSRodney W. Grimes * 211df8bae1dSRodney W. Grimes * Virtual time timers are processed in the hardclock() routine of 212df8bae1dSRodney W. Grimes * kern_clock.c. The real time timer is processed by a timeout 213df8bae1dSRodney W. Grimes * routine, called from the softclock() routine. Since a callout 214df8bae1dSRodney W. Grimes * may be delayed in real time due to interrupt processing in the system, 215df8bae1dSRodney W. Grimes * it is possible for the real time timeout routine (realitexpire, given below), 216df8bae1dSRodney W. Grimes * to be delayed in real time past when it is supposed to occur. It 217df8bae1dSRodney W. Grimes * does not suffice, therefore, to reload the real timer .it_value from the 218df8bae1dSRodney W. Grimes * real time timers .it_interval. Rather, we compute the next time in 219df8bae1dSRodney W. Grimes * absolute time the timer should go off. 220df8bae1dSRodney W. Grimes */ 221d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 222df8bae1dSRodney W. Grimes struct getitimer_args { 223df8bae1dSRodney W. Grimes u_int which; 224df8bae1dSRodney W. Grimes struct itimerval *itv; 225df8bae1dSRodney W. Grimes }; 226d2d3e875SBruce Evans #endif 227df8bae1dSRodney W. Grimes /* ARGSUSED */ 22826f9a767SRodney W. Grimes int 229df8bae1dSRodney W. Grimes getitimer(p, uap, retval) 230df8bae1dSRodney W. Grimes struct proc *p; 231df8bae1dSRodney W. Grimes register struct getitimer_args *uap; 232df8bae1dSRodney W. Grimes int *retval; 233df8bae1dSRodney W. Grimes { 234df8bae1dSRodney W. Grimes struct itimerval aitv; 235df8bae1dSRodney W. Grimes int s; 236df8bae1dSRodney W. Grimes 237df8bae1dSRodney W. Grimes if (uap->which > ITIMER_PROF) 238df8bae1dSRodney W. Grimes return (EINVAL); 239df8bae1dSRodney W. Grimes s = splclock(); 240df8bae1dSRodney W. Grimes if (uap->which == ITIMER_REAL) { 241df8bae1dSRodney W. Grimes /* 242df8bae1dSRodney W. Grimes * Convert from absoulte to relative time in .it_value 243df8bae1dSRodney W. Grimes * part of real time timer. If time for real time timer 244df8bae1dSRodney W. Grimes * has passed return 0, else return difference between 245df8bae1dSRodney W. Grimes * current time and time for the timer to go off. 246df8bae1dSRodney W. Grimes */ 247df8bae1dSRodney W. Grimes aitv = p->p_realtimer; 248df8bae1dSRodney W. Grimes if (timerisset(&aitv.it_value)) 249df8bae1dSRodney W. Grimes if (timercmp(&aitv.it_value, &time, <)) 250df8bae1dSRodney W. Grimes timerclear(&aitv.it_value); 251df8bae1dSRodney W. Grimes else 252df8bae1dSRodney W. Grimes timevalsub(&aitv.it_value, 253df8bae1dSRodney W. Grimes (struct timeval *)&time); 254df8bae1dSRodney W. Grimes } else 255df8bae1dSRodney W. Grimes aitv = p->p_stats->p_timer[uap->which]; 256df8bae1dSRodney W. Grimes splx(s); 257df8bae1dSRodney W. Grimes return (copyout((caddr_t)&aitv, (caddr_t)uap->itv, 258df8bae1dSRodney W. Grimes sizeof (struct itimerval))); 259df8bae1dSRodney W. Grimes } 260df8bae1dSRodney W. Grimes 261d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 262df8bae1dSRodney W. Grimes struct setitimer_args { 263df8bae1dSRodney W. Grimes u_int which; 264df8bae1dSRodney W. Grimes struct itimerval *itv, *oitv; 265df8bae1dSRodney W. Grimes }; 266d2d3e875SBruce Evans #endif 267df8bae1dSRodney W. Grimes /* ARGSUSED */ 26826f9a767SRodney W. Grimes int 269df8bae1dSRodney W. Grimes setitimer(p, uap, retval) 270df8bae1dSRodney W. Grimes struct proc *p; 271df8bae1dSRodney W. Grimes register struct setitimer_args *uap; 272df8bae1dSRodney W. Grimes int *retval; 273df8bae1dSRodney W. Grimes { 274df8bae1dSRodney W. Grimes struct itimerval aitv; 275df8bae1dSRodney W. Grimes register struct itimerval *itvp; 276df8bae1dSRodney W. Grimes int s, error; 277df8bae1dSRodney W. Grimes 278df8bae1dSRodney W. Grimes if (uap->which > ITIMER_PROF) 279df8bae1dSRodney W. Grimes return (EINVAL); 280df8bae1dSRodney W. Grimes itvp = uap->itv; 281df8bae1dSRodney W. Grimes if (itvp && (error = copyin((caddr_t)itvp, (caddr_t)&aitv, 282df8bae1dSRodney W. Grimes sizeof(struct itimerval)))) 283df8bae1dSRodney W. Grimes return (error); 284df8bae1dSRodney W. Grimes if ((uap->itv = uap->oitv) && (error = getitimer(p, uap, retval))) 285df8bae1dSRodney W. Grimes return (error); 286df8bae1dSRodney W. Grimes if (itvp == 0) 287df8bae1dSRodney W. Grimes return (0); 288df8bae1dSRodney W. Grimes if (itimerfix(&aitv.it_value) || itimerfix(&aitv.it_interval)) 289df8bae1dSRodney W. Grimes return (EINVAL); 290df8bae1dSRodney W. Grimes s = splclock(); 291df8bae1dSRodney W. Grimes if (uap->which == ITIMER_REAL) { 292df8bae1dSRodney W. Grimes untimeout(realitexpire, (caddr_t)p); 293df8bae1dSRodney W. Grimes if (timerisset(&aitv.it_value)) { 294df8bae1dSRodney W. Grimes timevaladd(&aitv.it_value, (struct timeval *)&time); 295df8bae1dSRodney W. Grimes timeout(realitexpire, (caddr_t)p, hzto(&aitv.it_value)); 296df8bae1dSRodney W. Grimes } 297df8bae1dSRodney W. Grimes p->p_realtimer = aitv; 298df8bae1dSRodney W. Grimes } else 299df8bae1dSRodney W. Grimes p->p_stats->p_timer[uap->which] = aitv; 300df8bae1dSRodney W. Grimes splx(s); 301df8bae1dSRodney W. Grimes return (0); 302df8bae1dSRodney W. Grimes } 303df8bae1dSRodney W. Grimes 304df8bae1dSRodney W. Grimes /* 305df8bae1dSRodney W. Grimes * Real interval timer expired: 306df8bae1dSRodney W. Grimes * send process whose timer expired an alarm signal. 307df8bae1dSRodney W. Grimes * If time is not set up to reload, then just return. 308df8bae1dSRodney W. Grimes * Else compute next time timer should go off which is > current time. 309df8bae1dSRodney W. Grimes * This is where delay in processing this timeout causes multiple 310df8bae1dSRodney W. Grimes * SIGALRM calls to be compressed into one. 3119207f00aSBruce Evans * hzto() always adds 1 to allow for the time until the next clock 3129207f00aSBruce Evans * interrupt being strictly less than 1 clock tick, but we don't want 3139207f00aSBruce Evans * that here since we want to appear to be in sync with the clock 3149207f00aSBruce Evans * interrupt even when we're delayed. 315df8bae1dSRodney W. Grimes */ 316df8bae1dSRodney W. Grimes void 317df8bae1dSRodney W. Grimes realitexpire(arg) 318df8bae1dSRodney W. Grimes void *arg; 319df8bae1dSRodney W. Grimes { 320df8bae1dSRodney W. Grimes register struct proc *p; 321df8bae1dSRodney W. Grimes int s; 322df8bae1dSRodney W. Grimes 323df8bae1dSRodney W. Grimes p = (struct proc *)arg; 324df8bae1dSRodney W. Grimes psignal(p, SIGALRM); 325df8bae1dSRodney W. Grimes if (!timerisset(&p->p_realtimer.it_interval)) { 326df8bae1dSRodney W. Grimes timerclear(&p->p_realtimer.it_value); 327df8bae1dSRodney W. Grimes return; 328df8bae1dSRodney W. Grimes } 329df8bae1dSRodney W. Grimes for (;;) { 330df8bae1dSRodney W. Grimes s = splclock(); 331df8bae1dSRodney W. Grimes timevaladd(&p->p_realtimer.it_value, 332df8bae1dSRodney W. Grimes &p->p_realtimer.it_interval); 333df8bae1dSRodney W. Grimes if (timercmp(&p->p_realtimer.it_value, &time, >)) { 334df8bae1dSRodney W. Grimes timeout(realitexpire, (caddr_t)p, 3359207f00aSBruce Evans hzto(&p->p_realtimer.it_value) - 1); 336df8bae1dSRodney W. Grimes splx(s); 337df8bae1dSRodney W. Grimes return; 338df8bae1dSRodney W. Grimes } 339df8bae1dSRodney W. Grimes splx(s); 340df8bae1dSRodney W. Grimes } 341df8bae1dSRodney W. Grimes } 342df8bae1dSRodney W. Grimes 343df8bae1dSRodney W. Grimes /* 344df8bae1dSRodney W. Grimes * Check that a proposed value to load into the .it_value or 345df8bae1dSRodney W. Grimes * .it_interval part of an interval timer is acceptable, and 346df8bae1dSRodney W. Grimes * fix it to have at least minimal value (i.e. if it is less 347df8bae1dSRodney W. Grimes * than the resolution of the clock, round it up.) 348df8bae1dSRodney W. Grimes */ 34926f9a767SRodney W. Grimes int 350df8bae1dSRodney W. Grimes itimerfix(tv) 351df8bae1dSRodney W. Grimes struct timeval *tv; 352df8bae1dSRodney W. Grimes { 353df8bae1dSRodney W. Grimes 354df8bae1dSRodney W. Grimes if (tv->tv_sec < 0 || tv->tv_sec > 100000000 || 355df8bae1dSRodney W. Grimes tv->tv_usec < 0 || tv->tv_usec >= 1000000) 356df8bae1dSRodney W. Grimes return (EINVAL); 357df8bae1dSRodney W. Grimes if (tv->tv_sec == 0 && tv->tv_usec != 0 && tv->tv_usec < tick) 358df8bae1dSRodney W. Grimes tv->tv_usec = tick; 359df8bae1dSRodney W. Grimes return (0); 360df8bae1dSRodney W. Grimes } 361df8bae1dSRodney W. Grimes 362df8bae1dSRodney W. Grimes /* 363df8bae1dSRodney W. Grimes * Decrement an interval timer by a specified number 364df8bae1dSRodney W. Grimes * of microseconds, which must be less than a second, 365df8bae1dSRodney W. Grimes * i.e. < 1000000. If the timer expires, then reload 366df8bae1dSRodney W. Grimes * it. In this case, carry over (usec - old value) to 367df8bae1dSRodney W. Grimes * reduce the value reloaded into the timer so that 368df8bae1dSRodney W. Grimes * the timer does not drift. This routine assumes 369df8bae1dSRodney W. Grimes * that it is called in a context where the timers 370df8bae1dSRodney W. Grimes * on which it is operating cannot change in value. 371df8bae1dSRodney W. Grimes */ 37226f9a767SRodney W. Grimes int 373df8bae1dSRodney W. Grimes itimerdecr(itp, usec) 374df8bae1dSRodney W. Grimes register struct itimerval *itp; 375df8bae1dSRodney W. Grimes int usec; 376df8bae1dSRodney W. Grimes { 377df8bae1dSRodney W. Grimes 378df8bae1dSRodney W. Grimes if (itp->it_value.tv_usec < usec) { 379df8bae1dSRodney W. Grimes if (itp->it_value.tv_sec == 0) { 380df8bae1dSRodney W. Grimes /* expired, and already in next interval */ 381df8bae1dSRodney W. Grimes usec -= itp->it_value.tv_usec; 382df8bae1dSRodney W. Grimes goto expire; 383df8bae1dSRodney W. Grimes } 384df8bae1dSRodney W. Grimes itp->it_value.tv_usec += 1000000; 385df8bae1dSRodney W. Grimes itp->it_value.tv_sec--; 386df8bae1dSRodney W. Grimes } 387df8bae1dSRodney W. Grimes itp->it_value.tv_usec -= usec; 388df8bae1dSRodney W. Grimes usec = 0; 389df8bae1dSRodney W. Grimes if (timerisset(&itp->it_value)) 390df8bae1dSRodney W. Grimes return (1); 391df8bae1dSRodney W. Grimes /* expired, exactly at end of interval */ 392df8bae1dSRodney W. Grimes expire: 393df8bae1dSRodney W. Grimes if (timerisset(&itp->it_interval)) { 394df8bae1dSRodney W. Grimes itp->it_value = itp->it_interval; 395df8bae1dSRodney W. Grimes itp->it_value.tv_usec -= usec; 396df8bae1dSRodney W. Grimes if (itp->it_value.tv_usec < 0) { 397df8bae1dSRodney W. Grimes itp->it_value.tv_usec += 1000000; 398df8bae1dSRodney W. Grimes itp->it_value.tv_sec--; 399df8bae1dSRodney W. Grimes } 400df8bae1dSRodney W. Grimes } else 401df8bae1dSRodney W. Grimes itp->it_value.tv_usec = 0; /* sec is already 0 */ 402df8bae1dSRodney W. Grimes return (0); 403df8bae1dSRodney W. Grimes } 404df8bae1dSRodney W. Grimes 405df8bae1dSRodney W. Grimes /* 406df8bae1dSRodney W. Grimes * Add and subtract routines for timevals. 407df8bae1dSRodney W. Grimes * N.B.: subtract routine doesn't deal with 408df8bae1dSRodney W. Grimes * results which are before the beginning, 409df8bae1dSRodney W. Grimes * it just gets very confused in this case. 410df8bae1dSRodney W. Grimes * Caveat emptor. 411df8bae1dSRodney W. Grimes */ 41226f9a767SRodney W. Grimes void 413df8bae1dSRodney W. Grimes timevaladd(t1, t2) 414df8bae1dSRodney W. Grimes struct timeval *t1, *t2; 415df8bae1dSRodney W. Grimes { 416df8bae1dSRodney W. Grimes 417df8bae1dSRodney W. Grimes t1->tv_sec += t2->tv_sec; 418df8bae1dSRodney W. Grimes t1->tv_usec += t2->tv_usec; 419df8bae1dSRodney W. Grimes timevalfix(t1); 420df8bae1dSRodney W. Grimes } 421df8bae1dSRodney W. Grimes 42226f9a767SRodney W. Grimes void 423df8bae1dSRodney W. Grimes timevalsub(t1, t2) 424df8bae1dSRodney W. Grimes struct timeval *t1, *t2; 425df8bae1dSRodney W. Grimes { 426df8bae1dSRodney W. Grimes 427df8bae1dSRodney W. Grimes t1->tv_sec -= t2->tv_sec; 428df8bae1dSRodney W. Grimes t1->tv_usec -= t2->tv_usec; 429df8bae1dSRodney W. Grimes timevalfix(t1); 430df8bae1dSRodney W. Grimes } 431df8bae1dSRodney W. Grimes 43226f9a767SRodney W. Grimes void 433df8bae1dSRodney W. Grimes timevalfix(t1) 434df8bae1dSRodney W. Grimes struct timeval *t1; 435df8bae1dSRodney W. Grimes { 436df8bae1dSRodney W. Grimes 437df8bae1dSRodney W. Grimes if (t1->tv_usec < 0) { 438df8bae1dSRodney W. Grimes t1->tv_sec--; 439df8bae1dSRodney W. Grimes t1->tv_usec += 1000000; 440df8bae1dSRodney W. Grimes } 441df8bae1dSRodney W. Grimes if (t1->tv_usec >= 1000000) { 442df8bae1dSRodney W. Grimes t1->tv_sec++; 443df8bae1dSRodney W. Grimes t1->tv_usec -= 1000000; 444df8bae1dSRodney W. Grimes } 445df8bae1dSRodney W. Grimes } 446