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 34797f2d22SPoul-Henning Kamp * $Id: kern_time.c,v 1.4 1994/09/25 19:33:45 phk Exp $ 35df8bae1dSRodney W. Grimes */ 36df8bae1dSRodney W. Grimes 37df8bae1dSRodney W. Grimes #include <sys/param.h> 38df8bae1dSRodney W. Grimes #include <sys/resourcevar.h> 39797f2d22SPoul-Henning Kamp #include <sys/signalvar.h> 40df8bae1dSRodney W. Grimes #include <sys/kernel.h> 41df8bae1dSRodney W. Grimes #include <sys/systm.h> 42df8bae1dSRodney W. Grimes #include <sys/proc.h> 43df8bae1dSRodney W. Grimes #include <sys/vnode.h> 44df8bae1dSRodney W. Grimes 45df8bae1dSRodney W. Grimes #include <machine/cpu.h> 46df8bae1dSRodney W. Grimes 47df8bae1dSRodney W. Grimes /* 48df8bae1dSRodney W. Grimes * Time of day and interval timer support. 49df8bae1dSRodney W. Grimes * 50df8bae1dSRodney W. Grimes * These routines provide the kernel entry points to get and set 51df8bae1dSRodney W. Grimes * the time-of-day and per-process interval timers. Subroutines 52df8bae1dSRodney W. Grimes * here provide support for adding and subtracting timeval structures 53df8bae1dSRodney W. Grimes * and decrementing interval timers, optionally reloading the interval 54df8bae1dSRodney W. Grimes * timers when they expire. 55df8bae1dSRodney W. Grimes */ 56df8bae1dSRodney W. Grimes 57df8bae1dSRodney W. Grimes struct gettimeofday_args { 58df8bae1dSRodney W. Grimes struct timeval *tp; 59df8bae1dSRodney W. Grimes struct timezone *tzp; 60df8bae1dSRodney W. Grimes }; 61df8bae1dSRodney W. Grimes /* ARGSUSED */ 6226f9a767SRodney W. Grimes int 63df8bae1dSRodney W. Grimes gettimeofday(p, uap, retval) 64df8bae1dSRodney W. Grimes struct proc *p; 65df8bae1dSRodney W. Grimes register struct gettimeofday_args *uap; 66df8bae1dSRodney W. Grimes int *retval; 67df8bae1dSRodney W. Grimes { 68df8bae1dSRodney W. Grimes struct timeval atv; 69df8bae1dSRodney W. Grimes int error = 0; 70df8bae1dSRodney W. Grimes 71df8bae1dSRodney W. Grimes if (uap->tp) { 72df8bae1dSRodney W. Grimes microtime(&atv); 73bb56ec4aSPoul-Henning Kamp if ((error = copyout((caddr_t)&atv, (caddr_t)uap->tp, 74bb56ec4aSPoul-Henning Kamp sizeof (atv)))) 75df8bae1dSRodney W. Grimes return (error); 76df8bae1dSRodney W. Grimes } 77df8bae1dSRodney W. Grimes if (uap->tzp) 78df8bae1dSRodney W. Grimes error = copyout((caddr_t)&tz, (caddr_t)uap->tzp, 79df8bae1dSRodney W. Grimes sizeof (tz)); 80df8bae1dSRodney W. Grimes return (error); 81df8bae1dSRodney W. Grimes } 82df8bae1dSRodney W. Grimes 83df8bae1dSRodney W. Grimes struct settimeofday_args { 84df8bae1dSRodney W. Grimes struct timeval *tv; 85df8bae1dSRodney W. Grimes struct timezone *tzp; 86df8bae1dSRodney W. Grimes }; 87df8bae1dSRodney W. Grimes /* ARGSUSED */ 8826f9a767SRodney W. Grimes int 89df8bae1dSRodney W. Grimes settimeofday(p, uap, retval) 90df8bae1dSRodney W. Grimes struct proc *p; 91df8bae1dSRodney W. Grimes struct settimeofday_args *uap; 92df8bae1dSRodney W. Grimes int *retval; 93df8bae1dSRodney W. Grimes { 94df8bae1dSRodney W. Grimes struct timeval atv, delta; 95df8bae1dSRodney W. Grimes struct timezone atz; 96df8bae1dSRodney W. Grimes int error, s; 97df8bae1dSRodney W. Grimes 98bb56ec4aSPoul-Henning Kamp if ((error = suser(p->p_ucred, &p->p_acflag))) 99df8bae1dSRodney W. Grimes return (error); 100df8bae1dSRodney W. Grimes /* Verify all parameters before changing time. */ 101df8bae1dSRodney W. Grimes if (uap->tv && 102df8bae1dSRodney W. Grimes (error = copyin((caddr_t)uap->tv, (caddr_t)&atv, sizeof(atv)))) 103df8bae1dSRodney W. Grimes return (error); 104df8bae1dSRodney W. Grimes if (uap->tzp && 105df8bae1dSRodney W. Grimes (error = copyin((caddr_t)uap->tzp, (caddr_t)&atz, sizeof(atz)))) 106df8bae1dSRodney W. Grimes return (error); 107df8bae1dSRodney W. Grimes if (uap->tv) { 108df8bae1dSRodney W. Grimes /* WHAT DO WE DO ABOUT PENDING REAL-TIME TIMEOUTS??? */ 109df8bae1dSRodney W. Grimes s = splclock(); 110df8bae1dSRodney W. Grimes /* nb. delta.tv_usec may be < 0, but this is OK here */ 111df8bae1dSRodney W. Grimes delta.tv_sec = atv.tv_sec - time.tv_sec; 112df8bae1dSRodney W. Grimes delta.tv_usec = atv.tv_usec - time.tv_usec; 113df8bae1dSRodney W. Grimes time = atv; 114df8bae1dSRodney W. Grimes (void) splsoftclock(); 115df8bae1dSRodney W. Grimes timevaladd(&boottime, &delta); 116df8bae1dSRodney W. Grimes timevalfix(&boottime); 117df8bae1dSRodney W. Grimes timevaladd(&runtime, &delta); 118df8bae1dSRodney W. Grimes timevalfix(&runtime); 119df8bae1dSRodney W. Grimes LEASE_UPDATETIME(delta.tv_sec); 120df8bae1dSRodney W. Grimes splx(s); 121df8bae1dSRodney W. Grimes resettodr(); 122df8bae1dSRodney W. Grimes } 123df8bae1dSRodney W. Grimes if (uap->tzp) 124df8bae1dSRodney W. Grimes tz = atz; 125df8bae1dSRodney W. Grimes return (0); 126df8bae1dSRodney W. Grimes } 127df8bae1dSRodney W. Grimes 128df8bae1dSRodney W. Grimes extern int tickadj; /* "standard" clock skew, us./tick */ 129df8bae1dSRodney W. Grimes int tickdelta; /* current clock skew, us. per tick */ 130df8bae1dSRodney W. Grimes long timedelta; /* unapplied time correction, us. */ 131df8bae1dSRodney W. Grimes long bigadj = 1000000; /* use 10x skew above bigadj us. */ 132df8bae1dSRodney W. Grimes 133df8bae1dSRodney W. Grimes struct adjtime_args { 134df8bae1dSRodney W. Grimes struct timeval *delta; 135df8bae1dSRodney W. Grimes struct timeval *olddelta; 136df8bae1dSRodney W. Grimes }; 137df8bae1dSRodney W. Grimes /* ARGSUSED */ 13826f9a767SRodney W. Grimes int 139df8bae1dSRodney W. Grimes adjtime(p, uap, retval) 140df8bae1dSRodney W. Grimes struct proc *p; 141df8bae1dSRodney W. Grimes register struct adjtime_args *uap; 142df8bae1dSRodney W. Grimes int *retval; 143df8bae1dSRodney W. Grimes { 144df8bae1dSRodney W. Grimes struct timeval atv; 145df8bae1dSRodney W. Grimes register long ndelta, ntickdelta, odelta; 146df8bae1dSRodney W. Grimes int s, error; 147df8bae1dSRodney W. Grimes 148bb56ec4aSPoul-Henning Kamp if ((error = suser(p->p_ucred, &p->p_acflag))) 149df8bae1dSRodney W. Grimes return (error); 150bb56ec4aSPoul-Henning Kamp if ((error = 151bb56ec4aSPoul-Henning Kamp copyin((caddr_t)uap->delta, (caddr_t)&atv, sizeof(struct timeval)))) 152df8bae1dSRodney W. Grimes return (error); 153df8bae1dSRodney W. Grimes 154df8bae1dSRodney W. Grimes /* 155df8bae1dSRodney W. Grimes * Compute the total correction and the rate at which to apply it. 156df8bae1dSRodney W. Grimes * Round the adjustment down to a whole multiple of the per-tick 157df8bae1dSRodney W. Grimes * delta, so that after some number of incremental changes in 158df8bae1dSRodney W. Grimes * hardclock(), tickdelta will become zero, lest the correction 159df8bae1dSRodney W. Grimes * overshoot and start taking us away from the desired final time. 160df8bae1dSRodney W. Grimes */ 161df8bae1dSRodney W. Grimes ndelta = atv.tv_sec * 1000000 + atv.tv_usec; 162df8bae1dSRodney W. Grimes if (ndelta > bigadj) 163df8bae1dSRodney W. Grimes ntickdelta = 10 * tickadj; 164df8bae1dSRodney W. Grimes else 165df8bae1dSRodney W. Grimes ntickdelta = tickadj; 166df8bae1dSRodney W. Grimes if (ndelta % ntickdelta) 167df8bae1dSRodney W. Grimes ndelta = ndelta / ntickdelta * ntickdelta; 168df8bae1dSRodney W. Grimes 169df8bae1dSRodney W. Grimes /* 170df8bae1dSRodney W. Grimes * To make hardclock()'s job easier, make the per-tick delta negative 171df8bae1dSRodney W. Grimes * if we want time to run slower; then hardclock can simply compute 172df8bae1dSRodney W. Grimes * tick + tickdelta, and subtract tickdelta from timedelta. 173df8bae1dSRodney W. Grimes */ 174df8bae1dSRodney W. Grimes if (ndelta < 0) 175df8bae1dSRodney W. Grimes ntickdelta = -ntickdelta; 176df8bae1dSRodney W. Grimes s = splclock(); 177df8bae1dSRodney W. Grimes odelta = timedelta; 178df8bae1dSRodney W. Grimes timedelta = ndelta; 179df8bae1dSRodney W. Grimes tickdelta = ntickdelta; 180df8bae1dSRodney W. Grimes splx(s); 181df8bae1dSRodney W. Grimes 182df8bae1dSRodney W. Grimes if (uap->olddelta) { 183df8bae1dSRodney W. Grimes atv.tv_sec = odelta / 1000000; 184df8bae1dSRodney W. Grimes atv.tv_usec = odelta % 1000000; 185df8bae1dSRodney W. Grimes (void) copyout((caddr_t)&atv, (caddr_t)uap->olddelta, 186df8bae1dSRodney W. Grimes sizeof(struct timeval)); 187df8bae1dSRodney W. Grimes } 188df8bae1dSRodney W. Grimes return (0); 189df8bae1dSRodney W. Grimes } 190df8bae1dSRodney W. Grimes 191df8bae1dSRodney W. Grimes /* 192df8bae1dSRodney W. Grimes * Get value of an interval timer. The process virtual and 193df8bae1dSRodney W. Grimes * profiling virtual time timers are kept in the p_stats area, since 194df8bae1dSRodney W. Grimes * they can be swapped out. These are kept internally in the 195df8bae1dSRodney W. Grimes * way they are specified externally: in time until they expire. 196df8bae1dSRodney W. Grimes * 197df8bae1dSRodney W. Grimes * The real time interval timer is kept in the process table slot 198df8bae1dSRodney W. Grimes * for the process, and its value (it_value) is kept as an 199df8bae1dSRodney W. Grimes * absolute time rather than as a delta, so that it is easy to keep 200df8bae1dSRodney W. Grimes * periodic real-time signals from drifting. 201df8bae1dSRodney W. Grimes * 202df8bae1dSRodney W. Grimes * Virtual time timers are processed in the hardclock() routine of 203df8bae1dSRodney W. Grimes * kern_clock.c. The real time timer is processed by a timeout 204df8bae1dSRodney W. Grimes * routine, called from the softclock() routine. Since a callout 205df8bae1dSRodney W. Grimes * may be delayed in real time due to interrupt processing in the system, 206df8bae1dSRodney W. Grimes * it is possible for the real time timeout routine (realitexpire, given below), 207df8bae1dSRodney W. Grimes * to be delayed in real time past when it is supposed to occur. It 208df8bae1dSRodney W. Grimes * does not suffice, therefore, to reload the real timer .it_value from the 209df8bae1dSRodney W. Grimes * real time timers .it_interval. Rather, we compute the next time in 210df8bae1dSRodney W. Grimes * absolute time the timer should go off. 211df8bae1dSRodney W. Grimes */ 212df8bae1dSRodney W. Grimes struct getitimer_args { 213df8bae1dSRodney W. Grimes u_int which; 214df8bae1dSRodney W. Grimes struct itimerval *itv; 215df8bae1dSRodney W. Grimes }; 216df8bae1dSRodney W. Grimes /* ARGSUSED */ 21726f9a767SRodney W. Grimes int 218df8bae1dSRodney W. Grimes getitimer(p, uap, retval) 219df8bae1dSRodney W. Grimes struct proc *p; 220df8bae1dSRodney W. Grimes register struct getitimer_args *uap; 221df8bae1dSRodney W. Grimes int *retval; 222df8bae1dSRodney W. Grimes { 223df8bae1dSRodney W. Grimes struct itimerval aitv; 224df8bae1dSRodney W. Grimes int s; 225df8bae1dSRodney W. Grimes 226df8bae1dSRodney W. Grimes if (uap->which > ITIMER_PROF) 227df8bae1dSRodney W. Grimes return (EINVAL); 228df8bae1dSRodney W. Grimes s = splclock(); 229df8bae1dSRodney W. Grimes if (uap->which == ITIMER_REAL) { 230df8bae1dSRodney W. Grimes /* 231df8bae1dSRodney W. Grimes * Convert from absoulte to relative time in .it_value 232df8bae1dSRodney W. Grimes * part of real time timer. If time for real time timer 233df8bae1dSRodney W. Grimes * has passed return 0, else return difference between 234df8bae1dSRodney W. Grimes * current time and time for the timer to go off. 235df8bae1dSRodney W. Grimes */ 236df8bae1dSRodney W. Grimes aitv = p->p_realtimer; 237df8bae1dSRodney W. Grimes if (timerisset(&aitv.it_value)) 238df8bae1dSRodney W. Grimes if (timercmp(&aitv.it_value, &time, <)) 239df8bae1dSRodney W. Grimes timerclear(&aitv.it_value); 240df8bae1dSRodney W. Grimes else 241df8bae1dSRodney W. Grimes timevalsub(&aitv.it_value, 242df8bae1dSRodney W. Grimes (struct timeval *)&time); 243df8bae1dSRodney W. Grimes } else 244df8bae1dSRodney W. Grimes aitv = p->p_stats->p_timer[uap->which]; 245df8bae1dSRodney W. Grimes splx(s); 246df8bae1dSRodney W. Grimes return (copyout((caddr_t)&aitv, (caddr_t)uap->itv, 247df8bae1dSRodney W. Grimes sizeof (struct itimerval))); 248df8bae1dSRodney W. Grimes } 249df8bae1dSRodney W. Grimes 250df8bae1dSRodney W. Grimes struct setitimer_args { 251df8bae1dSRodney W. Grimes u_int which; 252df8bae1dSRodney W. Grimes struct itimerval *itv, *oitv; 253df8bae1dSRodney W. Grimes }; 254df8bae1dSRodney W. Grimes /* ARGSUSED */ 25526f9a767SRodney W. Grimes int 256df8bae1dSRodney W. Grimes setitimer(p, uap, retval) 257df8bae1dSRodney W. Grimes struct proc *p; 258df8bae1dSRodney W. Grimes register struct setitimer_args *uap; 259df8bae1dSRodney W. Grimes int *retval; 260df8bae1dSRodney W. Grimes { 261df8bae1dSRodney W. Grimes struct itimerval aitv; 262df8bae1dSRodney W. Grimes register struct itimerval *itvp; 263df8bae1dSRodney W. Grimes int s, error; 264df8bae1dSRodney W. Grimes 265df8bae1dSRodney W. Grimes if (uap->which > ITIMER_PROF) 266df8bae1dSRodney W. Grimes return (EINVAL); 267df8bae1dSRodney W. Grimes itvp = uap->itv; 268df8bae1dSRodney W. Grimes if (itvp && (error = copyin((caddr_t)itvp, (caddr_t)&aitv, 269df8bae1dSRodney W. Grimes sizeof(struct itimerval)))) 270df8bae1dSRodney W. Grimes return (error); 271df8bae1dSRodney W. Grimes if ((uap->itv = uap->oitv) && (error = getitimer(p, uap, retval))) 272df8bae1dSRodney W. Grimes return (error); 273df8bae1dSRodney W. Grimes if (itvp == 0) 274df8bae1dSRodney W. Grimes return (0); 275df8bae1dSRodney W. Grimes if (itimerfix(&aitv.it_value) || itimerfix(&aitv.it_interval)) 276df8bae1dSRodney W. Grimes return (EINVAL); 277df8bae1dSRodney W. Grimes s = splclock(); 278df8bae1dSRodney W. Grimes if (uap->which == ITIMER_REAL) { 279df8bae1dSRodney W. Grimes untimeout(realitexpire, (caddr_t)p); 280df8bae1dSRodney W. Grimes if (timerisset(&aitv.it_value)) { 281df8bae1dSRodney W. Grimes timevaladd(&aitv.it_value, (struct timeval *)&time); 282df8bae1dSRodney W. Grimes timeout(realitexpire, (caddr_t)p, hzto(&aitv.it_value)); 283df8bae1dSRodney W. Grimes } 284df8bae1dSRodney W. Grimes p->p_realtimer = aitv; 285df8bae1dSRodney W. Grimes } else 286df8bae1dSRodney W. Grimes p->p_stats->p_timer[uap->which] = aitv; 287df8bae1dSRodney W. Grimes splx(s); 288df8bae1dSRodney W. Grimes return (0); 289df8bae1dSRodney W. Grimes } 290df8bae1dSRodney W. Grimes 291df8bae1dSRodney W. Grimes /* 292df8bae1dSRodney W. Grimes * Real interval timer expired: 293df8bae1dSRodney W. Grimes * send process whose timer expired an alarm signal. 294df8bae1dSRodney W. Grimes * If time is not set up to reload, then just return. 295df8bae1dSRodney W. Grimes * Else compute next time timer should go off which is > current time. 296df8bae1dSRodney W. Grimes * This is where delay in processing this timeout causes multiple 297df8bae1dSRodney W. Grimes * SIGALRM calls to be compressed into one. 298df8bae1dSRodney W. Grimes */ 299df8bae1dSRodney W. Grimes void 300df8bae1dSRodney W. Grimes realitexpire(arg) 301df8bae1dSRodney W. Grimes void *arg; 302df8bae1dSRodney W. Grimes { 303df8bae1dSRodney W. Grimes register struct proc *p; 304df8bae1dSRodney W. Grimes int s; 305df8bae1dSRodney W. Grimes 306df8bae1dSRodney W. Grimes p = (struct proc *)arg; 307df8bae1dSRodney W. Grimes psignal(p, SIGALRM); 308df8bae1dSRodney W. Grimes if (!timerisset(&p->p_realtimer.it_interval)) { 309df8bae1dSRodney W. Grimes timerclear(&p->p_realtimer.it_value); 310df8bae1dSRodney W. Grimes return; 311df8bae1dSRodney W. Grimes } 312df8bae1dSRodney W. Grimes for (;;) { 313df8bae1dSRodney W. Grimes s = splclock(); 314df8bae1dSRodney W. Grimes timevaladd(&p->p_realtimer.it_value, 315df8bae1dSRodney W. Grimes &p->p_realtimer.it_interval); 316df8bae1dSRodney W. Grimes if (timercmp(&p->p_realtimer.it_value, &time, >)) { 317df8bae1dSRodney W. Grimes timeout(realitexpire, (caddr_t)p, 318df8bae1dSRodney W. Grimes hzto(&p->p_realtimer.it_value)); 319df8bae1dSRodney W. Grimes splx(s); 320df8bae1dSRodney W. Grimes return; 321df8bae1dSRodney W. Grimes } 322df8bae1dSRodney W. Grimes splx(s); 323df8bae1dSRodney W. Grimes } 324df8bae1dSRodney W. Grimes } 325df8bae1dSRodney W. Grimes 326df8bae1dSRodney W. Grimes /* 327df8bae1dSRodney W. Grimes * Check that a proposed value to load into the .it_value or 328df8bae1dSRodney W. Grimes * .it_interval part of an interval timer is acceptable, and 329df8bae1dSRodney W. Grimes * fix it to have at least minimal value (i.e. if it is less 330df8bae1dSRodney W. Grimes * than the resolution of the clock, round it up.) 331df8bae1dSRodney W. Grimes */ 33226f9a767SRodney W. Grimes int 333df8bae1dSRodney W. Grimes itimerfix(tv) 334df8bae1dSRodney W. Grimes struct timeval *tv; 335df8bae1dSRodney W. Grimes { 336df8bae1dSRodney W. Grimes 337df8bae1dSRodney W. Grimes if (tv->tv_sec < 0 || tv->tv_sec > 100000000 || 338df8bae1dSRodney W. Grimes tv->tv_usec < 0 || tv->tv_usec >= 1000000) 339df8bae1dSRodney W. Grimes return (EINVAL); 340df8bae1dSRodney W. Grimes if (tv->tv_sec == 0 && tv->tv_usec != 0 && tv->tv_usec < tick) 341df8bae1dSRodney W. Grimes tv->tv_usec = tick; 342df8bae1dSRodney W. Grimes return (0); 343df8bae1dSRodney W. Grimes } 344df8bae1dSRodney W. Grimes 345df8bae1dSRodney W. Grimes /* 346df8bae1dSRodney W. Grimes * Decrement an interval timer by a specified number 347df8bae1dSRodney W. Grimes * of microseconds, which must be less than a second, 348df8bae1dSRodney W. Grimes * i.e. < 1000000. If the timer expires, then reload 349df8bae1dSRodney W. Grimes * it. In this case, carry over (usec - old value) to 350df8bae1dSRodney W. Grimes * reduce the value reloaded into the timer so that 351df8bae1dSRodney W. Grimes * the timer does not drift. This routine assumes 352df8bae1dSRodney W. Grimes * that it is called in a context where the timers 353df8bae1dSRodney W. Grimes * on which it is operating cannot change in value. 354df8bae1dSRodney W. Grimes */ 35526f9a767SRodney W. Grimes int 356df8bae1dSRodney W. Grimes itimerdecr(itp, usec) 357df8bae1dSRodney W. Grimes register struct itimerval *itp; 358df8bae1dSRodney W. Grimes int usec; 359df8bae1dSRodney W. Grimes { 360df8bae1dSRodney W. Grimes 361df8bae1dSRodney W. Grimes if (itp->it_value.tv_usec < usec) { 362df8bae1dSRodney W. Grimes if (itp->it_value.tv_sec == 0) { 363df8bae1dSRodney W. Grimes /* expired, and already in next interval */ 364df8bae1dSRodney W. Grimes usec -= itp->it_value.tv_usec; 365df8bae1dSRodney W. Grimes goto expire; 366df8bae1dSRodney W. Grimes } 367df8bae1dSRodney W. Grimes itp->it_value.tv_usec += 1000000; 368df8bae1dSRodney W. Grimes itp->it_value.tv_sec--; 369df8bae1dSRodney W. Grimes } 370df8bae1dSRodney W. Grimes itp->it_value.tv_usec -= usec; 371df8bae1dSRodney W. Grimes usec = 0; 372df8bae1dSRodney W. Grimes if (timerisset(&itp->it_value)) 373df8bae1dSRodney W. Grimes return (1); 374df8bae1dSRodney W. Grimes /* expired, exactly at end of interval */ 375df8bae1dSRodney W. Grimes expire: 376df8bae1dSRodney W. Grimes if (timerisset(&itp->it_interval)) { 377df8bae1dSRodney W. Grimes itp->it_value = itp->it_interval; 378df8bae1dSRodney W. Grimes itp->it_value.tv_usec -= usec; 379df8bae1dSRodney W. Grimes if (itp->it_value.tv_usec < 0) { 380df8bae1dSRodney W. Grimes itp->it_value.tv_usec += 1000000; 381df8bae1dSRodney W. Grimes itp->it_value.tv_sec--; 382df8bae1dSRodney W. Grimes } 383df8bae1dSRodney W. Grimes } else 384df8bae1dSRodney W. Grimes itp->it_value.tv_usec = 0; /* sec is already 0 */ 385df8bae1dSRodney W. Grimes return (0); 386df8bae1dSRodney W. Grimes } 387df8bae1dSRodney W. Grimes 388df8bae1dSRodney W. Grimes /* 389df8bae1dSRodney W. Grimes * Add and subtract routines for timevals. 390df8bae1dSRodney W. Grimes * N.B.: subtract routine doesn't deal with 391df8bae1dSRodney W. Grimes * results which are before the beginning, 392df8bae1dSRodney W. Grimes * it just gets very confused in this case. 393df8bae1dSRodney W. Grimes * Caveat emptor. 394df8bae1dSRodney W. Grimes */ 39526f9a767SRodney W. Grimes void 396df8bae1dSRodney W. Grimes timevaladd(t1, t2) 397df8bae1dSRodney W. Grimes struct timeval *t1, *t2; 398df8bae1dSRodney W. Grimes { 399df8bae1dSRodney W. Grimes 400df8bae1dSRodney W. Grimes t1->tv_sec += t2->tv_sec; 401df8bae1dSRodney W. Grimes t1->tv_usec += t2->tv_usec; 402df8bae1dSRodney W. Grimes timevalfix(t1); 403df8bae1dSRodney W. Grimes } 404df8bae1dSRodney W. Grimes 40526f9a767SRodney W. Grimes void 406df8bae1dSRodney W. Grimes timevalsub(t1, t2) 407df8bae1dSRodney W. Grimes struct timeval *t1, *t2; 408df8bae1dSRodney W. Grimes { 409df8bae1dSRodney W. Grimes 410df8bae1dSRodney W. Grimes t1->tv_sec -= t2->tv_sec; 411df8bae1dSRodney W. Grimes t1->tv_usec -= t2->tv_usec; 412df8bae1dSRodney W. Grimes timevalfix(t1); 413df8bae1dSRodney W. Grimes } 414df8bae1dSRodney W. Grimes 41526f9a767SRodney W. Grimes void 416df8bae1dSRodney W. Grimes timevalfix(t1) 417df8bae1dSRodney W. Grimes struct timeval *t1; 418df8bae1dSRodney W. Grimes { 419df8bae1dSRodney W. Grimes 420df8bae1dSRodney W. Grimes if (t1->tv_usec < 0) { 421df8bae1dSRodney W. Grimes t1->tv_sec--; 422df8bae1dSRodney W. Grimes t1->tv_usec += 1000000; 423df8bae1dSRodney W. Grimes } 424df8bae1dSRodney W. Grimes if (t1->tv_usec >= 1000000) { 425df8bae1dSRodney W. Grimes t1->tv_sec++; 426df8bae1dSRodney W. Grimes t1->tv_usec -= 1000000; 427df8bae1dSRodney W. Grimes } 428df8bae1dSRodney W. Grimes } 429