kern_time.c revision 35029
11541Srgrimes/* 21541Srgrimes * Copyright (c) 1982, 1986, 1989, 1993 31541Srgrimes * The Regents of the University of California. All rights reserved. 41541Srgrimes * 51541Srgrimes * Redistribution and use in source and binary forms, with or without 61541Srgrimes * modification, are permitted provided that the following conditions 71541Srgrimes * are met: 81541Srgrimes * 1. Redistributions of source code must retain the above copyright 91541Srgrimes * notice, this list of conditions and the following disclaimer. 101541Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 111541Srgrimes * notice, this list of conditions and the following disclaimer in the 121541Srgrimes * documentation and/or other materials provided with the distribution. 131541Srgrimes * 3. All advertising materials mentioning features or use of this software 141541Srgrimes * must display the following acknowledgement: 151541Srgrimes * This product includes software developed by the University of 161541Srgrimes * California, Berkeley and its contributors. 171541Srgrimes * 4. Neither the name of the University nor the names of its contributors 181541Srgrimes * may be used to endorse or promote products derived from this software 191541Srgrimes * without specific prior written permission. 201541Srgrimes * 211541Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 221541Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 231541Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 241541Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 251541Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 261541Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 271541Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 281541Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 291541Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 301541Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 311541Srgrimes * SUCH DAMAGE. 321541Srgrimes * 331541Srgrimes * @(#)kern_time.c 8.1 (Berkeley) 6/10/93 3435029Sphk * $Id: kern_time.c,v 1.44 1998/03/30 09:50:23 phk Exp $ 351541Srgrimes */ 361541Srgrimes 371541Srgrimes#include <sys/param.h> 3812221Sbde#include <sys/sysproto.h> 391541Srgrimes#include <sys/resourcevar.h> 403308Sphk#include <sys/signalvar.h> 411541Srgrimes#include <sys/kernel.h> 421541Srgrimes#include <sys/systm.h> 4325583Speter#include <sys/sysent.h> 441541Srgrimes#include <sys/proc.h> 4525656Speter#include <sys/time.h> 461541Srgrimes#include <sys/vnode.h> 4726335Speter#include <vm/vm.h> 4826335Speter#include <vm/vm_extern.h> 491541Srgrimes 509369Sdgstruct timezone tz; 519369Sdg 528876Srgrimes/* 531541Srgrimes * Time of day and interval timer support. 541541Srgrimes * 551541Srgrimes * These routines provide the kernel entry points to get and set 561541Srgrimes * the time-of-day and per-process interval timers. Subroutines 571541Srgrimes * here provide support for adding and subtracting timeval structures 581541Srgrimes * and decrementing interval timers, optionally reloading the interval 591541Srgrimes * timers when they expire. 601541Srgrimes */ 611541Srgrimes 6228773Sbdestatic int nanosleep1 __P((struct proc *p, struct timespec *rqt, 6328773Sbde struct timespec *rmt)); 6425656Speterstatic int settime __P((struct timeval *)); 6513016Sbdestatic void timevalfix __P((struct timeval *)); 6630994Sphkstatic void no_lease_updatetime __P((int)); 6713016Sbde 6830739Sphkstatic void 6930739Sphkno_lease_updatetime(deltat) 7030739Sphk int deltat; 7130739Sphk{ 7230739Sphk} 7330739Sphk 7430739Sphkvoid (*lease_updatetime) __P((int)) = no_lease_updatetime; 7530739Sphk 7625583Speterstatic int 7725583Spetersettime(tv) 7825583Speter struct timeval *tv; 7925583Speter{ 8033818Sbde struct timeval delta, tv1; 8133690Sphk struct timespec ts; 8225583Speter struct proc *p; 8325583Speter int s; 8425583Speter 8525656Speter s = splclock(); 8633818Sbde microtime(&tv1); 8735029Sphk delta = *tv; 8835029Sphk timevalsub(&delta, &tv1); 8925583Speter 9025583Speter /* 9133818Sbde * If the system is secure, we do not allow the time to be 9233818Sbde * set to an earlier value (it may be slowed using adjtime, 9333818Sbde * but not set back). This feature prevent interlopers from 9433818Sbde * setting arbitrary time stamps on files. 9525583Speter */ 9633818Sbde if (delta.tv_sec < 0 && securelevel > 1) { 9733818Sbde splx(s); 9833818Sbde return (EPERM); 9933818Sbde } 10033818Sbde 10133690Sphk ts.tv_sec = tv->tv_sec; 10233690Sphk ts.tv_nsec = tv->tv_usec * 1000; 10333690Sphk set_timecounter(&ts); 10425583Speter (void) splsoftclock(); 10526335Speter for (p = allproc.lh_first; p != 0; p = p->p_list.le_next) { 10625583Speter if (timerisset(&p->p_realtimer.it_value)) 10725583Speter timevaladd(&p->p_realtimer.it_value, &delta); 10826335Speter } 10925583Speter lease_updatetime(delta.tv_sec); 11025583Speter splx(s); 11125583Speter resettodr(); 11225583Speter return (0); 11325583Speter} 11425583Speter 11512221Sbde#ifndef _SYS_SYSPROTO_H_ 11625583Speterstruct clock_gettime_args { 11725583Speter clockid_t clock_id; 11825583Speter struct timespec *tp; 11925583Speter}; 12025583Speter#endif 12125656Speter 12225583Speter/* ARGSUSED */ 12325583Speterint 12430994Sphkclock_gettime(p, uap) 12525583Speter struct proc *p; 12625583Speter struct clock_gettime_args *uap; 12725583Speter{ 12825583Speter struct timespec ats; 12925583Speter 13025656Speter if (SCARG(uap, clock_id) != CLOCK_REALTIME) 13125583Speter return (EINVAL); 13233690Sphk nanotime(&ats); 13325656Speter return (copyout(&ats, SCARG(uap, tp), sizeof(ats))); 13425583Speter} 13525583Speter 13625583Speter#ifndef _SYS_SYSPROTO_H_ 13725583Speterstruct clock_settime_args { 13825583Speter clockid_t clock_id; 13925583Speter const struct timespec *tp; 14025583Speter}; 14125583Speter#endif 14225656Speter 14325583Speter/* ARGSUSED */ 14425583Speterint 14530994Sphkclock_settime(p, uap) 14625583Speter struct proc *p; 14725583Speter struct clock_settime_args *uap; 14825583Speter{ 14925583Speter struct timeval atv; 15025583Speter struct timespec ats; 15125583Speter int error; 15225583Speter 15325583Speter if ((error = suser(p->p_ucred, &p->p_acflag)) != 0) 15425583Speter return (error); 15525656Speter if (SCARG(uap, clock_id) != CLOCK_REALTIME) 15625583Speter return (EINVAL); 15725583Speter if ((error = copyin(SCARG(uap, tp), &ats, sizeof(ats))) != 0) 15825583Speter return (error); 15927855Sbde if (ats.tv_nsec < 0 || ats.tv_nsec >= 1000000000) 16025656Speter return (EINVAL); 16134901Sphk /* XXX Don't convert nsec->usec and back */ 16225583Speter TIMESPEC_TO_TIMEVAL(&atv, &ats); 16325583Speter if ((error = settime(&atv))) 16425583Speter return (error); 16525656Speter return (0); 16625583Speter} 16725583Speter 16825583Speter#ifndef _SYS_SYSPROTO_H_ 16925583Speterstruct clock_getres_args { 17025583Speter clockid_t clock_id; 17125583Speter struct timespec *tp; 17225583Speter}; 17325583Speter#endif 17425656Speter 17525583Speterint 17630994Sphkclock_getres(p, uap) 17725583Speter struct proc *p; 17825583Speter struct clock_getres_args *uap; 17925583Speter{ 18025583Speter struct timespec ts; 18125656Speter int error; 18225583Speter 18325656Speter if (SCARG(uap, clock_id) != CLOCK_REALTIME) 18425583Speter return (EINVAL); 18525656Speter error = 0; 18625583Speter if (SCARG(uap, tp)) { 18725583Speter ts.tv_sec = 0; 18833690Sphk ts.tv_nsec = 1000000000 / timecounter->frequency; 18925656Speter error = copyout(&ts, SCARG(uap, tp), sizeof(ts)); 19025583Speter } 19125656Speter return (error); 19225583Speter} 19325583Speter 19426335Speterstatic int nanowait; 19525656Speter 19626335Speterstatic int 19726335Speternanosleep1(p, rqt, rmt) 19825583Speter struct proc *p; 19926335Speter struct timespec *rqt, *rmt; 20025583Speter{ 20135029Sphk struct timespec ts, ts2; 20235029Sphk int error, timo; 20325583Speter 20428773Sbde if (rqt->tv_nsec < 0 || rqt->tv_nsec >= 1000000000) 20525656Speter return (EINVAL); 20628773Sbde if (rqt->tv_sec < 0 || rqt->tv_sec == 0 && rqt->tv_nsec == 0) 20728773Sbde return (0); 20825583Speter 20935029Sphk getnanoruntime(&ts); 21035029Sphk timespecadd(&ts, rqt); 21135029Sphk error = 0; 21235029Sphk while (1) { 21335029Sphk getnanoruntime(&ts2); 21435029Sphk if (timespeccmp(&ts2, &ts, >=)) 21535029Sphk break; 21635029Sphk else if (ts2.tv_sec + 60 * 60 * 24 * hz < ts.tv_sec) 21735029Sphk timo = 60 * 60 * 24 * hz; 21835029Sphk else if (ts2.tv_sec + 2 < ts.tv_sec) { 21935029Sphk /* Leave one second for the difference in tv_nsec */ 22035029Sphk timo = ts.tv_sec - ts2.tv_sec - 1; 22135029Sphk timo *= hz; 22235029Sphk } else { 22335029Sphk timo = (ts.tv_sec - ts2.tv_sec) * 1000000000; 22435029Sphk timo += ts.tv_nsec - ts2.tv_nsec; 22535029Sphk timo /= (1000000000 / hz); 22635029Sphk timo ++; 22728171Sache } 22828171Sache error = tsleep(&nanowait, PWAIT | PCATCH, "nanslp", timo); 22935029Sphk if (error == ERESTART) { 23028171Sache error = EINTR; 23135029Sphk break; 23228171Sache } 23326335Speter } 23435029Sphk if (rmt) { 23535029Sphk *rmt = ts; 23635029Sphk timespecsub(rmt, &ts2); 23735029Sphk } 23835029Sphk return(error); 23926335Speter} 24025583Speter 24126335Speter#ifndef _SYS_SYSPROTO_H_ 24226335Speterstruct nanosleep_args { 24326335Speter struct timespec *rqtp; 24426335Speter struct timespec *rmtp; 24526335Speter}; 24626335Speter#endif 24726335Speter 24826335Speter/* ARGSUSED */ 24926335Speterint 25030994Sphknanosleep(p, uap) 25126335Speter struct proc *p; 25226335Speter struct nanosleep_args *uap; 25326335Speter{ 25426335Speter struct timespec rmt, rqt; 25526335Speter int error, error2; 25626335Speter 25726335Speter error = copyin(SCARG(uap, rqtp), &rqt, sizeof(rqt)); 25826335Speter if (error) 25926335Speter return (error); 26026336Speter if (SCARG(uap, rmtp)) 26126336Speter if (!useracc((caddr_t)SCARG(uap, rmtp), sizeof(rmt), B_WRITE)) 26226336Speter return (EFAULT); 26326335Speter error = nanosleep1(p, &rqt, &rmt); 26426335Speter if (SCARG(uap, rmtp)) { 26525656Speter error2 = copyout(&rmt, SCARG(uap, rmtp), sizeof(rmt)); 26626335Speter if (error2) /* XXX shouldn't happen, did useracc() above */ 26725656Speter return (error2); 26825583Speter } 26925656Speter return (error); 27025583Speter} 27125583Speter 27226335Speter#ifndef _SYS_SYSPROTO_H_ 27326335Speterstruct signanosleep_args { 27426335Speter struct timespec *rqtp; 27526335Speter struct timespec *rmtp; 27626335Speter sigset_t *mask; 27726335Speter}; 27826335Speter#endif 27925583Speter 28026335Speter/* ARGSUSED */ 28126335Speterint 28230994Sphksignanosleep(p, uap) 28326335Speter struct proc *p; 28426335Speter struct signanosleep_args *uap; 28526335Speter{ 28626335Speter struct timespec rmt, rqt; 28726335Speter int error, error2; 28826335Speter sigset_t mask; 28926335Speter 29026335Speter error = copyin(SCARG(uap, rqtp), &rqt, sizeof(rqt)); 29126335Speter if (error) 29226335Speter return (error); 29326336Speter if (SCARG(uap, rmtp)) 29426336Speter if (!useracc((caddr_t)SCARG(uap, rmtp), sizeof(rmt), B_WRITE)) 29526336Speter return (EFAULT); 29626335Speter error = copyin(SCARG(uap, mask), &mask, sizeof(mask)); 29726335Speter if (error) 29826335Speter return (error); 29926335Speter 30030440Speter /* change mask for sleep */ 30126335Speter p->p_sigmask = mask &~ sigcantmask; 30226335Speter 30326335Speter error = nanosleep1(p, &rqt, &rmt); 30426335Speter 30526335Speter if (SCARG(uap, rmtp)) { 30626335Speter error2 = copyout(&rmt, SCARG(uap, rmtp), sizeof(rmt)); 30726335Speter if (error2) /* XXX shouldn't happen, did useracc() above */ 30826335Speter return (error2); 30926335Speter } 31026335Speter return (error); 31126335Speter} 31226335Speter 31325583Speter#ifndef _SYS_SYSPROTO_H_ 3141541Srgrimesstruct gettimeofday_args { 3151541Srgrimes struct timeval *tp; 3161541Srgrimes struct timezone *tzp; 3171541Srgrimes}; 31812221Sbde#endif 3191541Srgrimes/* ARGSUSED */ 3201549Srgrimesint 32130994Sphkgettimeofday(p, uap) 3221541Srgrimes struct proc *p; 3231541Srgrimes register struct gettimeofday_args *uap; 3241541Srgrimes{ 3251541Srgrimes struct timeval atv; 3261541Srgrimes int error = 0; 3271541Srgrimes 3281541Srgrimes if (uap->tp) { 3291541Srgrimes microtime(&atv); 3303098Sphk if ((error = copyout((caddr_t)&atv, (caddr_t)uap->tp, 3313098Sphk sizeof (atv)))) 3321541Srgrimes return (error); 3331541Srgrimes } 3341541Srgrimes if (uap->tzp) 3351541Srgrimes error = copyout((caddr_t)&tz, (caddr_t)uap->tzp, 3361541Srgrimes sizeof (tz)); 3371541Srgrimes return (error); 3381541Srgrimes} 3391541Srgrimes 34012221Sbde#ifndef _SYS_SYSPROTO_H_ 3411541Srgrimesstruct settimeofday_args { 3421541Srgrimes struct timeval *tv; 3431541Srgrimes struct timezone *tzp; 3441541Srgrimes}; 34512221Sbde#endif 3461541Srgrimes/* ARGSUSED */ 3471549Srgrimesint 34830994Sphksettimeofday(p, uap) 3491541Srgrimes struct proc *p; 3501541Srgrimes struct settimeofday_args *uap; 3511541Srgrimes{ 35225656Speter struct timeval atv; 3531541Srgrimes struct timezone atz; 35425656Speter int error; 3551541Srgrimes 3563098Sphk if ((error = suser(p->p_ucred, &p->p_acflag))) 3571541Srgrimes return (error); 3581541Srgrimes /* Verify all parameters before changing time. */ 35925656Speter if (uap->tv) { 36025656Speter if ((error = copyin((caddr_t)uap->tv, (caddr_t)&atv, 36125656Speter sizeof(atv)))) 36225656Speter return (error); 36325656Speter if (atv.tv_usec < 0 || atv.tv_usec >= 1000000) 36425656Speter return (EINVAL); 36525656Speter } 3661541Srgrimes if (uap->tzp && 3671541Srgrimes (error = copyin((caddr_t)uap->tzp, (caddr_t)&atz, sizeof(atz)))) 3681541Srgrimes return (error); 36925583Speter if (uap->tv && (error = settime(&atv))) 37025583Speter return (error); 3711541Srgrimes if (uap->tzp) 3721541Srgrimes tz = atz; 3731541Srgrimes return (0); 3741541Srgrimes} 3751541Srgrimes 3761541Srgrimesint tickdelta; /* current clock skew, us. per tick */ 3771541Srgrimeslong timedelta; /* unapplied time correction, us. */ 37812819Sphkstatic long bigadj = 1000000; /* use 10x skew above bigadj us. */ 3791541Srgrimes 38012221Sbde#ifndef _SYS_SYSPROTO_H_ 3811541Srgrimesstruct adjtime_args { 3821541Srgrimes struct timeval *delta; 3831541Srgrimes struct timeval *olddelta; 3841541Srgrimes}; 38512221Sbde#endif 3861541Srgrimes/* ARGSUSED */ 3871549Srgrimesint 38830994Sphkadjtime(p, uap) 3891541Srgrimes struct proc *p; 3901541Srgrimes register struct adjtime_args *uap; 3911541Srgrimes{ 3921541Srgrimes struct timeval atv; 3931541Srgrimes register long ndelta, ntickdelta, odelta; 3941541Srgrimes int s, error; 3951541Srgrimes 3963098Sphk if ((error = suser(p->p_ucred, &p->p_acflag))) 3971541Srgrimes return (error); 3983098Sphk if ((error = 3993098Sphk copyin((caddr_t)uap->delta, (caddr_t)&atv, sizeof(struct timeval)))) 4001541Srgrimes return (error); 4011541Srgrimes 4021541Srgrimes /* 4031541Srgrimes * Compute the total correction and the rate at which to apply it. 4041541Srgrimes * Round the adjustment down to a whole multiple of the per-tick 4051541Srgrimes * delta, so that after some number of incremental changes in 4061541Srgrimes * hardclock(), tickdelta will become zero, lest the correction 4071541Srgrimes * overshoot and start taking us away from the desired final time. 4081541Srgrimes */ 4091541Srgrimes ndelta = atv.tv_sec * 1000000 + atv.tv_usec; 41017123Sbde if (ndelta > bigadj || ndelta < -bigadj) 4111541Srgrimes ntickdelta = 10 * tickadj; 4121541Srgrimes else 4131541Srgrimes ntickdelta = tickadj; 4141541Srgrimes if (ndelta % ntickdelta) 4151541Srgrimes ndelta = ndelta / ntickdelta * ntickdelta; 4161541Srgrimes 4171541Srgrimes /* 4181541Srgrimes * To make hardclock()'s job easier, make the per-tick delta negative 4191541Srgrimes * if we want time to run slower; then hardclock can simply compute 4201541Srgrimes * tick + tickdelta, and subtract tickdelta from timedelta. 4211541Srgrimes */ 4221541Srgrimes if (ndelta < 0) 4231541Srgrimes ntickdelta = -ntickdelta; 4241541Srgrimes s = splclock(); 4251541Srgrimes odelta = timedelta; 4261541Srgrimes timedelta = ndelta; 4271541Srgrimes tickdelta = ntickdelta; 4281541Srgrimes splx(s); 4291541Srgrimes 4301541Srgrimes if (uap->olddelta) { 4311541Srgrimes atv.tv_sec = odelta / 1000000; 4321541Srgrimes atv.tv_usec = odelta % 1000000; 4331541Srgrimes (void) copyout((caddr_t)&atv, (caddr_t)uap->olddelta, 4341541Srgrimes sizeof(struct timeval)); 4351541Srgrimes } 4361541Srgrimes return (0); 4371541Srgrimes} 4381541Srgrimes 4391541Srgrimes/* 4401541Srgrimes * Get value of an interval timer. The process virtual and 4411541Srgrimes * profiling virtual time timers are kept in the p_stats area, since 4421541Srgrimes * they can be swapped out. These are kept internally in the 4431541Srgrimes * way they are specified externally: in time until they expire. 4441541Srgrimes * 4451541Srgrimes * The real time interval timer is kept in the process table slot 4461541Srgrimes * for the process, and its value (it_value) is kept as an 4471541Srgrimes * absolute time rather than as a delta, so that it is easy to keep 4481541Srgrimes * periodic real-time signals from drifting. 4491541Srgrimes * 4501541Srgrimes * Virtual time timers are processed in the hardclock() routine of 4511541Srgrimes * kern_clock.c. The real time timer is processed by a timeout 4521541Srgrimes * routine, called from the softclock() routine. Since a callout 4531541Srgrimes * may be delayed in real time due to interrupt processing in the system, 4541541Srgrimes * it is possible for the real time timeout routine (realitexpire, given below), 4551541Srgrimes * to be delayed in real time past when it is supposed to occur. It 4561541Srgrimes * does not suffice, therefore, to reload the real timer .it_value from the 4571541Srgrimes * real time timers .it_interval. Rather, we compute the next time in 4581541Srgrimes * absolute time the timer should go off. 4591541Srgrimes */ 46012221Sbde#ifndef _SYS_SYSPROTO_H_ 4611541Srgrimesstruct getitimer_args { 4621541Srgrimes u_int which; 4631541Srgrimes struct itimerval *itv; 4641541Srgrimes}; 46512221Sbde#endif 4661541Srgrimes/* ARGSUSED */ 4671549Srgrimesint 46830994Sphkgetitimer(p, uap) 4691541Srgrimes struct proc *p; 4701541Srgrimes register struct getitimer_args *uap; 4711541Srgrimes{ 47234961Sphk struct timeval ctv; 4731541Srgrimes struct itimerval aitv; 4741541Srgrimes int s; 4751541Srgrimes 4761541Srgrimes if (uap->which > ITIMER_PROF) 4771541Srgrimes return (EINVAL); 47834961Sphk s = splclock(); /* XXX still needed ? */ 4791541Srgrimes if (uap->which == ITIMER_REAL) { 4801541Srgrimes /* 4811541Srgrimes * Convert from absoulte to relative time in .it_value 4821541Srgrimes * part of real time timer. If time for real time timer 4831541Srgrimes * has passed return 0, else return difference between 4841541Srgrimes * current time and time for the timer to go off. 4851541Srgrimes */ 4861541Srgrimes aitv = p->p_realtimer; 48734961Sphk if (timerisset(&aitv.it_value)) { 48834961Sphk getmicrotime(&ctv); 48934961Sphk if (timercmp(&aitv.it_value, &ctv, <)) 4901541Srgrimes timerclear(&aitv.it_value); 4911541Srgrimes else 49234961Sphk timevalsub(&aitv.it_value, &ctv); 49334961Sphk } 4941541Srgrimes } else 4951541Srgrimes aitv = p->p_stats->p_timer[uap->which]; 4961541Srgrimes splx(s); 4971541Srgrimes return (copyout((caddr_t)&aitv, (caddr_t)uap->itv, 4981541Srgrimes sizeof (struct itimerval))); 4991541Srgrimes} 5001541Srgrimes 50112221Sbde#ifndef _SYS_SYSPROTO_H_ 5021541Srgrimesstruct setitimer_args { 5031541Srgrimes u_int which; 5041541Srgrimes struct itimerval *itv, *oitv; 5051541Srgrimes}; 50612221Sbde#endif 5071541Srgrimes/* ARGSUSED */ 5081549Srgrimesint 50930994Sphksetitimer(p, uap) 5101541Srgrimes struct proc *p; 5111541Srgrimes register struct setitimer_args *uap; 5121541Srgrimes{ 5131541Srgrimes struct itimerval aitv; 51434961Sphk struct timeval ctv; 5151541Srgrimes register struct itimerval *itvp; 5161541Srgrimes int s, error; 5171541Srgrimes 5181541Srgrimes if (uap->which > ITIMER_PROF) 5191541Srgrimes return (EINVAL); 5201541Srgrimes itvp = uap->itv; 5211541Srgrimes if (itvp && (error = copyin((caddr_t)itvp, (caddr_t)&aitv, 5221541Srgrimes sizeof(struct itimerval)))) 5231541Srgrimes return (error); 52412381Sbde if ((uap->itv = uap->oitv) && 52530994Sphk (error = getitimer(p, (struct getitimer_args *)uap))) 5261541Srgrimes return (error); 5271541Srgrimes if (itvp == 0) 5281541Srgrimes return (0); 52928213Sache if (itimerfix(&aitv.it_value)) 5301541Srgrimes return (EINVAL); 53128213Sache if (!timerisset(&aitv.it_value)) 53228213Sache timerclear(&aitv.it_interval); 53328213Sache else if (itimerfix(&aitv.it_interval)) 53428213Sache return (EINVAL); 53534961Sphk s = splclock(); /* XXX: still needed ? */ 5361541Srgrimes if (uap->which == ITIMER_REAL) { 53729680Sgibbs if (timerisset(&p->p_realtimer.it_value)) 53829680Sgibbs untimeout(realitexpire, (caddr_t)p, p->p_ithandle); 5391541Srgrimes if (timerisset(&aitv.it_value)) { 54034961Sphk getmicrotime(&ctv); 54134961Sphk timevaladd(&aitv.it_value, &ctv); 54229680Sgibbs p->p_ithandle = timeout(realitexpire, (caddr_t)p, 54329680Sgibbs hzto(&aitv.it_value)); 5441541Srgrimes } 5451541Srgrimes p->p_realtimer = aitv; 5461541Srgrimes } else 5471541Srgrimes p->p_stats->p_timer[uap->which] = aitv; 5481541Srgrimes splx(s); 5491541Srgrimes return (0); 5501541Srgrimes} 5511541Srgrimes 5521541Srgrimes/* 5531541Srgrimes * Real interval timer expired: 5541541Srgrimes * send process whose timer expired an alarm signal. 5551541Srgrimes * If time is not set up to reload, then just return. 5561541Srgrimes * Else compute next time timer should go off which is > current time. 5571541Srgrimes * This is where delay in processing this timeout causes multiple 5581541Srgrimes * SIGALRM calls to be compressed into one. 5599327Sbde * hzto() always adds 1 to allow for the time until the next clock 5609327Sbde * interrupt being strictly less than 1 clock tick, but we don't want 5619327Sbde * that here since we want to appear to be in sync with the clock 5629327Sbde * interrupt even when we're delayed. 5631541Srgrimes */ 5641541Srgrimesvoid 5651541Srgrimesrealitexpire(arg) 5661541Srgrimes void *arg; 5671541Srgrimes{ 5681541Srgrimes register struct proc *p; 56934961Sphk struct timeval ctv; 5701541Srgrimes int s; 5711541Srgrimes 5721541Srgrimes p = (struct proc *)arg; 5731541Srgrimes psignal(p, SIGALRM); 5741541Srgrimes if (!timerisset(&p->p_realtimer.it_interval)) { 5751541Srgrimes timerclear(&p->p_realtimer.it_value); 5761541Srgrimes return; 5771541Srgrimes } 5781541Srgrimes for (;;) { 57934961Sphk s = splclock(); /* XXX: still neeeded ? */ 5801541Srgrimes timevaladd(&p->p_realtimer.it_value, 5811541Srgrimes &p->p_realtimer.it_interval); 58234961Sphk getmicrotime(&ctv); 58334961Sphk if (timercmp(&p->p_realtimer.it_value, &ctv, >)) { 58429680Sgibbs p->p_ithandle = 58529680Sgibbs timeout(realitexpire, (caddr_t)p, 58629680Sgibbs hzto(&p->p_realtimer.it_value) - 1); 5871541Srgrimes splx(s); 5881541Srgrimes return; 5891541Srgrimes } 5901541Srgrimes splx(s); 5911541Srgrimes } 5921541Srgrimes} 5931541Srgrimes 5941541Srgrimes/* 5951541Srgrimes * Check that a proposed value to load into the .it_value or 5961541Srgrimes * .it_interval part of an interval timer is acceptable, and 5971541Srgrimes * fix it to have at least minimal value (i.e. if it is less 5981541Srgrimes * than the resolution of the clock, round it up.) 5991541Srgrimes */ 6001549Srgrimesint 6011541Srgrimesitimerfix(tv) 6021541Srgrimes struct timeval *tv; 6031541Srgrimes{ 6041541Srgrimes 6051541Srgrimes if (tv->tv_sec < 0 || tv->tv_sec > 100000000 || 6061541Srgrimes tv->tv_usec < 0 || tv->tv_usec >= 1000000) 6071541Srgrimes return (EINVAL); 6081541Srgrimes if (tv->tv_sec == 0 && tv->tv_usec != 0 && tv->tv_usec < tick) 6091541Srgrimes tv->tv_usec = tick; 6101541Srgrimes return (0); 6111541Srgrimes} 6121541Srgrimes 6131541Srgrimes/* 6141541Srgrimes * Decrement an interval timer by a specified number 6151541Srgrimes * of microseconds, which must be less than a second, 6161541Srgrimes * i.e. < 1000000. If the timer expires, then reload 6171541Srgrimes * it. In this case, carry over (usec - old value) to 6181541Srgrimes * reduce the value reloaded into the timer so that 6191541Srgrimes * the timer does not drift. This routine assumes 6201541Srgrimes * that it is called in a context where the timers 6211541Srgrimes * on which it is operating cannot change in value. 6221541Srgrimes */ 6231549Srgrimesint 6241541Srgrimesitimerdecr(itp, usec) 6251541Srgrimes register struct itimerval *itp; 6261541Srgrimes int usec; 6271541Srgrimes{ 6281541Srgrimes 6291541Srgrimes if (itp->it_value.tv_usec < usec) { 6301541Srgrimes if (itp->it_value.tv_sec == 0) { 6311541Srgrimes /* expired, and already in next interval */ 6321541Srgrimes usec -= itp->it_value.tv_usec; 6331541Srgrimes goto expire; 6341541Srgrimes } 6351541Srgrimes itp->it_value.tv_usec += 1000000; 6361541Srgrimes itp->it_value.tv_sec--; 6371541Srgrimes } 6381541Srgrimes itp->it_value.tv_usec -= usec; 6391541Srgrimes usec = 0; 6401541Srgrimes if (timerisset(&itp->it_value)) 6411541Srgrimes return (1); 6421541Srgrimes /* expired, exactly at end of interval */ 6431541Srgrimesexpire: 6441541Srgrimes if (timerisset(&itp->it_interval)) { 6451541Srgrimes itp->it_value = itp->it_interval; 6461541Srgrimes itp->it_value.tv_usec -= usec; 6471541Srgrimes if (itp->it_value.tv_usec < 0) { 6481541Srgrimes itp->it_value.tv_usec += 1000000; 6491541Srgrimes itp->it_value.tv_sec--; 6501541Srgrimes } 6511541Srgrimes } else 6521541Srgrimes itp->it_value.tv_usec = 0; /* sec is already 0 */ 6531541Srgrimes return (0); 6541541Srgrimes} 6551541Srgrimes 6561541Srgrimes/* 6571541Srgrimes * Add and subtract routines for timevals. 6581541Srgrimes * N.B.: subtract routine doesn't deal with 6591541Srgrimes * results which are before the beginning, 6601541Srgrimes * it just gets very confused in this case. 6611541Srgrimes * Caveat emptor. 6621541Srgrimes */ 6631549Srgrimesvoid 6641541Srgrimestimevaladd(t1, t2) 6651541Srgrimes struct timeval *t1, *t2; 6661541Srgrimes{ 6671541Srgrimes 6681541Srgrimes t1->tv_sec += t2->tv_sec; 6691541Srgrimes t1->tv_usec += t2->tv_usec; 6701541Srgrimes timevalfix(t1); 6711541Srgrimes} 6721541Srgrimes 6731549Srgrimesvoid 6741541Srgrimestimevalsub(t1, t2) 6751541Srgrimes struct timeval *t1, *t2; 6761541Srgrimes{ 6771541Srgrimes 6781541Srgrimes t1->tv_sec -= t2->tv_sec; 6791541Srgrimes t1->tv_usec -= t2->tv_usec; 6801541Srgrimes timevalfix(t1); 6811541Srgrimes} 6821541Srgrimes 68312819Sphkstatic void 6841541Srgrimestimevalfix(t1) 6851541Srgrimes struct timeval *t1; 6861541Srgrimes{ 6871541Srgrimes 6881541Srgrimes if (t1->tv_usec < 0) { 6891541Srgrimes t1->tv_sec--; 6901541Srgrimes t1->tv_usec += 1000000; 6911541Srgrimes } 6921541Srgrimes if (t1->tv_usec >= 1000000) { 6931541Srgrimes t1->tv_sec++; 6941541Srgrimes t1->tv_usec -= 1000000; 6951541Srgrimes } 6961541Srgrimes} 697