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