kern_time.c revision 90836
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 3450477Speter * $FreeBSD: head/sys/kern/kern_time.c 90836 2002-02-18 08:40:28Z phk $ 351541Srgrimes */ 361541Srgrimes 371541Srgrimes#include <sys/param.h> 3848274Speter#include <sys/systm.h> 3976166Smarkm#include <sys/lock.h> 4076166Smarkm#include <sys/mutex.h> 4112221Sbde#include <sys/sysproto.h> 421541Srgrimes#include <sys/resourcevar.h> 433308Sphk#include <sys/signalvar.h> 441541Srgrimes#include <sys/kernel.h> 451541Srgrimes#include <sys/systm.h> 4625583Speter#include <sys/sysent.h> 471541Srgrimes#include <sys/proc.h> 4825656Speter#include <sys/time.h> 4958377Sphk#include <sys/timetc.h> 501541Srgrimes#include <sys/vnode.h> 5176166Smarkm 5226335Speter#include <vm/vm.h> 5326335Speter#include <vm/vm_extern.h> 541541Srgrimes 559369Sdgstruct timezone tz; 569369Sdg 578876Srgrimes/* 581541Srgrimes * Time of day and interval timer support. 591541Srgrimes * 601541Srgrimes * These routines provide the kernel entry points to get and set 611541Srgrimes * the time-of-day and per-process interval timers. Subroutines 621541Srgrimes * here provide support for adding and subtracting timeval structures 631541Srgrimes * and decrementing interval timers, optionally reloading the interval 641541Srgrimes * timers when they expire. 651541Srgrimes */ 661541Srgrimes 6783366Sjulianstatic int nanosleep1 __P((struct thread *td, struct timespec *rqt, 6828773Sbde struct timespec *rmt)); 6983969Srwatsonstatic int settime __P((struct proc *, struct timeval *)); 7013016Sbdestatic void timevalfix __P((struct timeval *)); 7130994Sphkstatic void no_lease_updatetime __P((int)); 7213016Sbde 7330739Sphkstatic void 7430739Sphkno_lease_updatetime(deltat) 7530739Sphk int deltat; 7630739Sphk{ 7730739Sphk} 7830739Sphk 7930739Sphkvoid (*lease_updatetime) __P((int)) = no_lease_updatetime; 8030739Sphk 8125583Speterstatic int 8283969Srwatsonsettime(p, tv) 8383969Srwatson struct proc *p; 8425583Speter struct timeval *tv; 8525583Speter{ 8645433Snsayer struct timeval delta, tv1, tv2; 8745438Snsayer static struct timeval maxtime, laststep; 8833690Sphk struct timespec ts; 8925583Speter int s; 9025583Speter 9125656Speter s = splclock(); 9233818Sbde microtime(&tv1); 9335029Sphk delta = *tv; 9435029Sphk timevalsub(&delta, &tv1); 9525583Speter 9625583Speter /* 9733818Sbde * If the system is secure, we do not allow the time to be 9845433Snsayer * set to a value earlier than 1 second less than the highest 9945433Snsayer * time we have yet seen. The worst a miscreant can do in 10045433Snsayer * this circumstance is "freeze" time. He couldn't go 10145433Snsayer * back to the past. 10245438Snsayer * 10345438Snsayer * We similarly do not allow the clock to be stepped more 10445438Snsayer * than one second, nor more than once per second. This allows 10545438Snsayer * a miscreant to make the clock march double-time, but no worse. 10625583Speter */ 10783969Srwatson if (securelevel_gt(p->p_ucred, 1) != 0) { 10845433Snsayer if (delta.tv_sec < 0 || delta.tv_usec < 0) { 10945437Smjacob /* 11045438Snsayer * Update maxtime to latest time we've seen. 11145437Smjacob */ 11245437Smjacob if (tv1.tv_sec > maxtime.tv_sec) 11345437Smjacob maxtime = tv1; 11445437Smjacob tv2 = *tv; 11545437Smjacob timevalsub(&tv2, &maxtime); 11645437Smjacob if (tv2.tv_sec < -1) { 11745437Smjacob tv->tv_sec = maxtime.tv_sec - 1; 11845433Snsayer printf("Time adjustment clamped to -1 second\n"); 11945433Snsayer } 12045437Smjacob } else { 12145438Snsayer if (tv1.tv_sec == laststep.tv_sec) { 12245438Snsayer splx(s); 12345438Snsayer return (EPERM); 12445438Snsayer } 12545438Snsayer if (delta.tv_sec > 1) { 12645438Snsayer tv->tv_sec = tv1.tv_sec + 1; 12745438Snsayer printf("Time adjustment clamped to +1 second\n"); 12845438Snsayer } 12945438Snsayer laststep = *tv; 13045433Snsayer } 13133818Sbde } 13233818Sbde 13333690Sphk ts.tv_sec = tv->tv_sec; 13433690Sphk ts.tv_nsec = tv->tv_usec * 1000; 13558377Sphk tc_setclock(&ts); 13625583Speter (void) splsoftclock(); 13725583Speter lease_updatetime(delta.tv_sec); 13825583Speter splx(s); 13925583Speter resettodr(); 14025583Speter return (0); 14125583Speter} 14225583Speter 14312221Sbde#ifndef _SYS_SYSPROTO_H_ 14425583Speterstruct clock_gettime_args { 14525583Speter clockid_t clock_id; 14625583Speter struct timespec *tp; 14725583Speter}; 14825583Speter#endif 14925656Speter 15082746Sdillon/* 15182746Sdillon * MPSAFE 15282746Sdillon */ 15325583Speter/* ARGSUSED */ 15425583Speterint 15583366Sjulianclock_gettime(td, uap) 15683366Sjulian struct thread *td; 15725583Speter struct clock_gettime_args *uap; 15825583Speter{ 15925583Speter struct timespec ats; 16025583Speter 16125656Speter if (SCARG(uap, clock_id) != CLOCK_REALTIME) 16225583Speter return (EINVAL); 16382746Sdillon mtx_lock(&Giant); 16433690Sphk nanotime(&ats); 16582746Sdillon mtx_unlock(&Giant); 16625656Speter return (copyout(&ats, SCARG(uap, tp), sizeof(ats))); 16725583Speter} 16825583Speter 16925583Speter#ifndef _SYS_SYSPROTO_H_ 17025583Speterstruct clock_settime_args { 17125583Speter clockid_t clock_id; 17225583Speter const struct timespec *tp; 17325583Speter}; 17425583Speter#endif 17525656Speter 17682746Sdillon/* 17782746Sdillon * MPSAFE 17882746Sdillon */ 17925583Speter/* ARGSUSED */ 18025583Speterint 18183366Sjulianclock_settime(td, uap) 18283366Sjulian struct thread *td; 18325583Speter struct clock_settime_args *uap; 18425583Speter{ 18525583Speter struct timeval atv; 18625583Speter struct timespec ats; 18725583Speter int error; 18825583Speter 18982746Sdillon mtx_lock(&Giant); 19083366Sjulian if ((error = suser_td(td)) != 0) 19182746Sdillon goto done2; 19282746Sdillon if (SCARG(uap, clock_id) != CLOCK_REALTIME) { 19382746Sdillon error = EINVAL; 19482746Sdillon goto done2; 19582746Sdillon } 19625583Speter if ((error = copyin(SCARG(uap, tp), &ats, sizeof(ats))) != 0) 19782746Sdillon goto done2; 19882746Sdillon if (ats.tv_nsec < 0 || ats.tv_nsec >= 1000000000) { 19982746Sdillon error = EINVAL; 20082746Sdillon goto done2; 20182746Sdillon } 20234901Sphk /* XXX Don't convert nsec->usec and back */ 20325583Speter TIMESPEC_TO_TIMEVAL(&atv, &ats); 20483969Srwatson error = settime(td->td_proc, &atv); 20582746Sdillondone2: 20682746Sdillon mtx_unlock(&Giant); 20782746Sdillon return (error); 20825583Speter} 20925583Speter 21025583Speter#ifndef _SYS_SYSPROTO_H_ 21125583Speterstruct clock_getres_args { 21225583Speter clockid_t clock_id; 21325583Speter struct timespec *tp; 21425583Speter}; 21525583Speter#endif 21625656Speter 21725583Speterint 21883366Sjulianclock_getres(td, uap) 21983366Sjulian struct thread *td; 22025583Speter struct clock_getres_args *uap; 22125583Speter{ 22225583Speter struct timespec ts; 22325656Speter int error; 22425583Speter 22525656Speter if (SCARG(uap, clock_id) != CLOCK_REALTIME) 22625583Speter return (EINVAL); 22725656Speter error = 0; 22825583Speter if (SCARG(uap, tp)) { 22925583Speter ts.tv_sec = 0; 23036810Sphk ts.tv_nsec = 1000000000 / timecounter->tc_frequency; 23125656Speter error = copyout(&ts, SCARG(uap, tp), sizeof(ts)); 23225583Speter } 23325656Speter return (error); 23425583Speter} 23525583Speter 23626335Speterstatic int nanowait; 23725656Speter 23826335Speterstatic int 23983366Sjuliannanosleep1(td, rqt, rmt) 24083366Sjulian struct thread *td; 24126335Speter struct timespec *rqt, *rmt; 24225583Speter{ 24335045Sphk struct timespec ts, ts2, ts3; 24435042Sphk struct timeval tv; 24535042Sphk int error; 24625583Speter 24728773Sbde if (rqt->tv_nsec < 0 || rqt->tv_nsec >= 1000000000) 24825656Speter return (EINVAL); 24943301Sdillon if (rqt->tv_sec < 0 || (rqt->tv_sec == 0 && rqt->tv_nsec == 0)) 25028773Sbde return (0); 25136119Sphk getnanouptime(&ts); 25235029Sphk timespecadd(&ts, rqt); 25335042Sphk TIMESPEC_TO_TIMEVAL(&tv, rqt); 25435042Sphk for (;;) { 25535042Sphk error = tsleep(&nanowait, PWAIT | PCATCH, "nanslp", 25635042Sphk tvtohz(&tv)); 25736119Sphk getnanouptime(&ts2); 25835042Sphk if (error != EWOULDBLOCK) { 25935042Sphk if (error == ERESTART) 26035042Sphk error = EINTR; 26135042Sphk if (rmt != NULL) { 26235042Sphk timespecsub(&ts, &ts2); 26335042Sphk if (ts.tv_sec < 0) 26435042Sphk timespecclear(&ts); 26535042Sphk *rmt = ts; 26635042Sphk } 26735042Sphk return (error); 26835042Sphk } 26935029Sphk if (timespeccmp(&ts2, &ts, >=)) 27035042Sphk return (0); 27135045Sphk ts3 = ts; 27235045Sphk timespecsub(&ts3, &ts2); 27335045Sphk TIMESPEC_TO_TIMEVAL(&tv, &ts3); 27426335Speter } 27526335Speter} 27625583Speter 27726335Speter#ifndef _SYS_SYSPROTO_H_ 27826335Speterstruct nanosleep_args { 27926335Speter struct timespec *rqtp; 28026335Speter struct timespec *rmtp; 28126335Speter}; 28226335Speter#endif 28326335Speter 28482746Sdillon/* 28582746Sdillon * MPSAFE 28682746Sdillon */ 28726335Speter/* ARGSUSED */ 28826335Speterint 28983366Sjuliannanosleep(td, uap) 29083366Sjulian struct thread *td; 29126335Speter struct nanosleep_args *uap; 29226335Speter{ 29326335Speter struct timespec rmt, rqt; 29482746Sdillon int error; 29526335Speter 29626335Speter error = copyin(SCARG(uap, rqtp), &rqt, sizeof(rqt)); 29726335Speter if (error) 29826335Speter return (error); 29982746Sdillon 30082746Sdillon mtx_lock(&Giant); 30182746Sdillon if (SCARG(uap, rmtp)) { 30252644Sphk if (!useracc((caddr_t)SCARG(uap, rmtp), sizeof(rmt), 30382746Sdillon VM_PROT_WRITE)) { 30482746Sdillon error = EFAULT; 30582746Sdillon goto done2; 30682746Sdillon } 30782746Sdillon } 30883366Sjulian error = nanosleep1(td, &rqt, &rmt); 30935043Speter if (error && SCARG(uap, rmtp)) { 31082746Sdillon int error2; 31182746Sdillon 31225656Speter error2 = copyout(&rmt, SCARG(uap, rmtp), sizeof(rmt)); 31326335Speter if (error2) /* XXX shouldn't happen, did useracc() above */ 31482746Sdillon error = error2; 31525583Speter } 31682746Sdillondone2: 31782746Sdillon mtx_unlock(&Giant); 31825656Speter return (error); 31925583Speter} 32025583Speter 32126335Speter#ifndef _SYS_SYSPROTO_H_ 3221541Srgrimesstruct gettimeofday_args { 3231541Srgrimes struct timeval *tp; 3241541Srgrimes struct timezone *tzp; 3251541Srgrimes}; 32612221Sbde#endif 32782746Sdillon/* 32882746Sdillon * MPSAFE 32982746Sdillon */ 3301541Srgrimes/* ARGSUSED */ 3311549Srgrimesint 33283366Sjuliangettimeofday(td, uap) 33383366Sjulian struct thread *td; 3341541Srgrimes register struct gettimeofday_args *uap; 3351541Srgrimes{ 3361541Srgrimes struct timeval atv; 3371541Srgrimes int error = 0; 3381541Srgrimes 3391541Srgrimes if (uap->tp) { 3401541Srgrimes microtime(&atv); 34190836Sphk error = copyout((caddr_t)&atv, (caddr_t)uap->tp, sizeof (atv)); 3421541Srgrimes } 34390836Sphk if (error == 0 && uap->tzp != NULL) { 34490836Sphk mtx_lock(&Giant); 3451541Srgrimes error = copyout((caddr_t)&tz, (caddr_t)uap->tzp, 3461541Srgrimes sizeof (tz)); 34790836Sphk mtx_unlock(&Giant); 34882746Sdillon } 3491541Srgrimes return (error); 3501541Srgrimes} 3511541Srgrimes 35212221Sbde#ifndef _SYS_SYSPROTO_H_ 3531541Srgrimesstruct settimeofday_args { 3541541Srgrimes struct timeval *tv; 3551541Srgrimes struct timezone *tzp; 3561541Srgrimes}; 35712221Sbde#endif 35882746Sdillon/* 35982746Sdillon * MPSAFE 36082746Sdillon */ 3611541Srgrimes/* ARGSUSED */ 3621549Srgrimesint 36383366Sjuliansettimeofday(td, uap) 36483366Sjulian struct thread *td; 3651541Srgrimes struct settimeofday_args *uap; 3661541Srgrimes{ 36725656Speter struct timeval atv; 3681541Srgrimes struct timezone atz; 36982746Sdillon int error = 0; 3701541Srgrimes 37182746Sdillon mtx_lock(&Giant); 37282746Sdillon 37383366Sjulian if ((error = suser_td(td))) 37482746Sdillon goto done2; 3751541Srgrimes /* Verify all parameters before changing time. */ 37625656Speter if (uap->tv) { 37725656Speter if ((error = copyin((caddr_t)uap->tv, (caddr_t)&atv, 37882746Sdillon sizeof(atv)))) { 37982746Sdillon goto done2; 38082746Sdillon } 38182746Sdillon if (atv.tv_usec < 0 || atv.tv_usec >= 1000000) { 38282746Sdillon error = EINVAL; 38382746Sdillon goto done2; 38482746Sdillon } 38525656Speter } 3861541Srgrimes if (uap->tzp && 38782746Sdillon (error = copyin((caddr_t)uap->tzp, (caddr_t)&atz, sizeof(atz)))) { 38882746Sdillon goto done2; 38982746Sdillon } 39083969Srwatson if (uap->tv && (error = settime(td->td_proc, &atv))) 39182746Sdillon goto done2; 3921541Srgrimes if (uap->tzp) 3931541Srgrimes tz = atz; 39482746Sdillondone2: 39582746Sdillon mtx_unlock(&Giant); 39682746Sdillon return (error); 3971541Srgrimes} 3981541Srgrimes 3991541Srgrimesint tickdelta; /* current clock skew, us. per tick */ 4001541Srgrimeslong timedelta; /* unapplied time correction, us. */ 40112819Sphkstatic long bigadj = 1000000; /* use 10x skew above bigadj us. */ 4021541Srgrimes 40312221Sbde#ifndef _SYS_SYSPROTO_H_ 4041541Srgrimesstruct adjtime_args { 4051541Srgrimes struct timeval *delta; 4061541Srgrimes struct timeval *olddelta; 4071541Srgrimes}; 40812221Sbde#endif 40982746Sdillon/* 41082746Sdillon * MPSAFE 41182746Sdillon */ 4121541Srgrimes/* ARGSUSED */ 4131549Srgrimesint 41483366Sjulianadjtime(td, uap) 41583366Sjulian struct thread *td; 4161541Srgrimes register struct adjtime_args *uap; 4171541Srgrimes{ 4181541Srgrimes struct timeval atv; 4191541Srgrimes register long ndelta, ntickdelta, odelta; 4201541Srgrimes int s, error; 4211541Srgrimes 42282746Sdillon mtx_lock(&Giant); 42382746Sdillon 42483366Sjulian if ((error = suser_td(td))) 42582746Sdillon goto done2; 42682746Sdillon error = copyin((caddr_t)uap->delta, (caddr_t)&atv, 42782746Sdillon sizeof(struct timeval)); 42882746Sdillon if (error) 42982746Sdillon goto done2; 4301541Srgrimes 4311541Srgrimes /* 4321541Srgrimes * Compute the total correction and the rate at which to apply it. 4331541Srgrimes * Round the adjustment down to a whole multiple of the per-tick 4341541Srgrimes * delta, so that after some number of incremental changes in 4351541Srgrimes * hardclock(), tickdelta will become zero, lest the correction 4361541Srgrimes * overshoot and start taking us away from the desired final time. 4371541Srgrimes */ 4381541Srgrimes ndelta = atv.tv_sec * 1000000 + atv.tv_usec; 43917123Sbde if (ndelta > bigadj || ndelta < -bigadj) 4401541Srgrimes ntickdelta = 10 * tickadj; 4411541Srgrimes else 4421541Srgrimes ntickdelta = tickadj; 4431541Srgrimes if (ndelta % ntickdelta) 4441541Srgrimes ndelta = ndelta / ntickdelta * ntickdelta; 4451541Srgrimes 4461541Srgrimes /* 4471541Srgrimes * To make hardclock()'s job easier, make the per-tick delta negative 4481541Srgrimes * if we want time to run slower; then hardclock can simply compute 4491541Srgrimes * tick + tickdelta, and subtract tickdelta from timedelta. 4501541Srgrimes */ 4511541Srgrimes if (ndelta < 0) 4521541Srgrimes ntickdelta = -ntickdelta; 4531541Srgrimes s = splclock(); 4541541Srgrimes odelta = timedelta; 4551541Srgrimes timedelta = ndelta; 4561541Srgrimes tickdelta = ntickdelta; 4571541Srgrimes splx(s); 4581541Srgrimes 4591541Srgrimes if (uap->olddelta) { 4601541Srgrimes atv.tv_sec = odelta / 1000000; 4611541Srgrimes atv.tv_usec = odelta % 1000000; 4621541Srgrimes (void) copyout((caddr_t)&atv, (caddr_t)uap->olddelta, 4631541Srgrimes sizeof(struct timeval)); 4641541Srgrimes } 46582746Sdillondone2: 46682746Sdillon mtx_unlock(&Giant); 46782746Sdillon return (error); 4681541Srgrimes} 4691541Srgrimes 4701541Srgrimes/* 4711541Srgrimes * Get value of an interval timer. The process virtual and 4721541Srgrimes * profiling virtual time timers are kept in the p_stats area, since 4731541Srgrimes * they can be swapped out. These are kept internally in the 4741541Srgrimes * way they are specified externally: in time until they expire. 4751541Srgrimes * 4761541Srgrimes * The real time interval timer is kept in the process table slot 4771541Srgrimes * for the process, and its value (it_value) is kept as an 4781541Srgrimes * absolute time rather than as a delta, so that it is easy to keep 4791541Srgrimes * periodic real-time signals from drifting. 4801541Srgrimes * 4811541Srgrimes * Virtual time timers are processed in the hardclock() routine of 4821541Srgrimes * kern_clock.c. The real time timer is processed by a timeout 4831541Srgrimes * routine, called from the softclock() routine. Since a callout 4841541Srgrimes * may be delayed in real time due to interrupt processing in the system, 4851541Srgrimes * it is possible for the real time timeout routine (realitexpire, given below), 4861541Srgrimes * to be delayed in real time past when it is supposed to occur. It 4871541Srgrimes * does not suffice, therefore, to reload the real timer .it_value from the 4881541Srgrimes * real time timers .it_interval. Rather, we compute the next time in 4891541Srgrimes * absolute time the timer should go off. 4901541Srgrimes */ 49112221Sbde#ifndef _SYS_SYSPROTO_H_ 4921541Srgrimesstruct getitimer_args { 4931541Srgrimes u_int which; 4941541Srgrimes struct itimerval *itv; 4951541Srgrimes}; 49612221Sbde#endif 49782746Sdillon/* 49882746Sdillon * MPSAFE 49982746Sdillon */ 5001541Srgrimes/* ARGSUSED */ 5011549Srgrimesint 50283366Sjuliangetitimer(td, uap) 50383366Sjulian struct thread *td; 5041541Srgrimes register struct getitimer_args *uap; 5051541Srgrimes{ 50683366Sjulian struct proc *p = td->td_proc; 50734961Sphk struct timeval ctv; 5081541Srgrimes struct itimerval aitv; 5091541Srgrimes int s; 51082746Sdillon int error; 5111541Srgrimes 5121541Srgrimes if (uap->which > ITIMER_PROF) 5131541Srgrimes return (EINVAL); 51482746Sdillon 51582746Sdillon mtx_lock(&Giant); 51682746Sdillon 51734961Sphk s = splclock(); /* XXX still needed ? */ 5181541Srgrimes if (uap->which == ITIMER_REAL) { 5191541Srgrimes /* 52036128Sbde * Convert from absolute to relative time in .it_value 5211541Srgrimes * part of real time timer. If time for real time timer 5221541Srgrimes * has passed return 0, else return difference between 5231541Srgrimes * current time and time for the timer to go off. 5241541Srgrimes */ 5251541Srgrimes aitv = p->p_realtimer; 52635058Sphk if (timevalisset(&aitv.it_value)) { 52736119Sphk getmicrouptime(&ctv); 52835058Sphk if (timevalcmp(&aitv.it_value, &ctv, <)) 52935058Sphk timevalclear(&aitv.it_value); 5301541Srgrimes else 53134961Sphk timevalsub(&aitv.it_value, &ctv); 53234961Sphk } 53382746Sdillon } else { 5341541Srgrimes aitv = p->p_stats->p_timer[uap->which]; 53582746Sdillon } 5361541Srgrimes splx(s); 53782746Sdillon error = copyout((caddr_t)&aitv, (caddr_t)uap->itv, 53882746Sdillon sizeof (struct itimerval)); 53982746Sdillon mtx_unlock(&Giant); 54082746Sdillon return(error); 5411541Srgrimes} 5421541Srgrimes 54312221Sbde#ifndef _SYS_SYSPROTO_H_ 5441541Srgrimesstruct setitimer_args { 5451541Srgrimes u_int which; 5461541Srgrimes struct itimerval *itv, *oitv; 5471541Srgrimes}; 54812221Sbde#endif 54982746Sdillon/* 55082746Sdillon * MPSAFE 55182746Sdillon */ 5521541Srgrimes/* ARGSUSED */ 5531549Srgrimesint 55483366Sjuliansetitimer(td, uap) 55583366Sjulian struct thread *td; 5561541Srgrimes register struct setitimer_args *uap; 5571541Srgrimes{ 55883366Sjulian struct proc *p = td->td_proc; 5591541Srgrimes struct itimerval aitv; 56034961Sphk struct timeval ctv; 5611541Srgrimes register struct itimerval *itvp; 56282746Sdillon int s, error = 0; 5631541Srgrimes 5641541Srgrimes if (uap->which > ITIMER_PROF) 5651541Srgrimes return (EINVAL); 5661541Srgrimes itvp = uap->itv; 5671541Srgrimes if (itvp && (error = copyin((caddr_t)itvp, (caddr_t)&aitv, 5681541Srgrimes sizeof(struct itimerval)))) 5691541Srgrimes return (error); 57082746Sdillon 57182746Sdillon mtx_lock(&Giant); 57282746Sdillon 57312381Sbde if ((uap->itv = uap->oitv) && 57483366Sjulian (error = getitimer(td, (struct getitimer_args *)uap))) { 57582746Sdillon goto done2; 57682746Sdillon } 57782746Sdillon if (itvp == 0) { 57882746Sdillon error = 0; 57982746Sdillon goto done2; 58082746Sdillon } 58182746Sdillon if (itimerfix(&aitv.it_value)) { 58282746Sdillon error = EINVAL; 58382746Sdillon goto done2; 58482746Sdillon } 58582746Sdillon if (!timevalisset(&aitv.it_value)) { 58635058Sphk timevalclear(&aitv.it_interval); 58782746Sdillon } else if (itimerfix(&aitv.it_interval)) { 58882746Sdillon error = EINVAL; 58982746Sdillon goto done2; 59082746Sdillon } 59134961Sphk s = splclock(); /* XXX: still needed ? */ 5921541Srgrimes if (uap->which == ITIMER_REAL) { 59335058Sphk if (timevalisset(&p->p_realtimer.it_value)) 59469286Sjake callout_stop(&p->p_itcallout); 59535058Sphk if (timevalisset(&aitv.it_value)) 59669286Sjake callout_reset(&p->p_itcallout, tvtohz(&aitv.it_value), 59769286Sjake realitexpire, p); 59836119Sphk getmicrouptime(&ctv); 59935044Sphk timevaladd(&aitv.it_value, &ctv); 6001541Srgrimes p->p_realtimer = aitv; 60182746Sdillon } else { 6021541Srgrimes p->p_stats->p_timer[uap->which] = aitv; 60382746Sdillon } 6041541Srgrimes splx(s); 60582746Sdillondone2: 60682746Sdillon mtx_unlock(&Giant); 60782746Sdillon return (error); 6081541Srgrimes} 6091541Srgrimes 6101541Srgrimes/* 6111541Srgrimes * Real interval timer expired: 6121541Srgrimes * send process whose timer expired an alarm signal. 6131541Srgrimes * If time is not set up to reload, then just return. 6141541Srgrimes * Else compute next time timer should go off which is > current time. 6151541Srgrimes * This is where delay in processing this timeout causes multiple 6161541Srgrimes * SIGALRM calls to be compressed into one. 61736127Sbde * tvtohz() always adds 1 to allow for the time until the next clock 6189327Sbde * interrupt being strictly less than 1 clock tick, but we don't want 6199327Sbde * that here since we want to appear to be in sync with the clock 6209327Sbde * interrupt even when we're delayed. 6211541Srgrimes */ 6221541Srgrimesvoid 6231541Srgrimesrealitexpire(arg) 6241541Srgrimes void *arg; 6251541Srgrimes{ 6261541Srgrimes register struct proc *p; 62735044Sphk struct timeval ctv, ntv; 6281541Srgrimes int s; 6291541Srgrimes 6301541Srgrimes p = (struct proc *)arg; 63173916Sjhb PROC_LOCK(p); 6321541Srgrimes psignal(p, SIGALRM); 63335058Sphk if (!timevalisset(&p->p_realtimer.it_interval)) { 63435058Sphk timevalclear(&p->p_realtimer.it_value); 63573916Sjhb PROC_UNLOCK(p); 6361541Srgrimes return; 6371541Srgrimes } 6381541Srgrimes for (;;) { 63934961Sphk s = splclock(); /* XXX: still neeeded ? */ 6401541Srgrimes timevaladd(&p->p_realtimer.it_value, 6411541Srgrimes &p->p_realtimer.it_interval); 64236119Sphk getmicrouptime(&ctv); 64335058Sphk if (timevalcmp(&p->p_realtimer.it_value, &ctv, >)) { 64435044Sphk ntv = p->p_realtimer.it_value; 64535044Sphk timevalsub(&ntv, &ctv); 64669286Sjake callout_reset(&p->p_itcallout, tvtohz(&ntv) - 1, 64769286Sjake realitexpire, p); 6481541Srgrimes splx(s); 64973916Sjhb PROC_UNLOCK(p); 6501541Srgrimes return; 6511541Srgrimes } 6521541Srgrimes splx(s); 6531541Srgrimes } 65473916Sjhb /*NOTREACHED*/ 6551541Srgrimes} 6561541Srgrimes 6571541Srgrimes/* 6581541Srgrimes * Check that a proposed value to load into the .it_value or 6591541Srgrimes * .it_interval part of an interval timer is acceptable, and 6601541Srgrimes * fix it to have at least minimal value (i.e. if it is less 6611541Srgrimes * than the resolution of the clock, round it up.) 6621541Srgrimes */ 6631549Srgrimesint 6641541Srgrimesitimerfix(tv) 6651541Srgrimes struct timeval *tv; 6661541Srgrimes{ 6671541Srgrimes 6681541Srgrimes if (tv->tv_sec < 0 || tv->tv_sec > 100000000 || 6691541Srgrimes tv->tv_usec < 0 || tv->tv_usec >= 1000000) 6701541Srgrimes return (EINVAL); 6711541Srgrimes if (tv->tv_sec == 0 && tv->tv_usec != 0 && tv->tv_usec < tick) 6721541Srgrimes tv->tv_usec = tick; 6731541Srgrimes return (0); 6741541Srgrimes} 6751541Srgrimes 6761541Srgrimes/* 6771541Srgrimes * Decrement an interval timer by a specified number 6781541Srgrimes * of microseconds, which must be less than a second, 6791541Srgrimes * i.e. < 1000000. If the timer expires, then reload 6801541Srgrimes * it. In this case, carry over (usec - old value) to 6811541Srgrimes * reduce the value reloaded into the timer so that 6821541Srgrimes * the timer does not drift. This routine assumes 6831541Srgrimes * that it is called in a context where the timers 6841541Srgrimes * on which it is operating cannot change in value. 6851541Srgrimes */ 6861549Srgrimesint 6871541Srgrimesitimerdecr(itp, usec) 6881541Srgrimes register struct itimerval *itp; 6891541Srgrimes int usec; 6901541Srgrimes{ 6911541Srgrimes 6921541Srgrimes if (itp->it_value.tv_usec < usec) { 6931541Srgrimes if (itp->it_value.tv_sec == 0) { 6941541Srgrimes /* expired, and already in next interval */ 6951541Srgrimes usec -= itp->it_value.tv_usec; 6961541Srgrimes goto expire; 6971541Srgrimes } 6981541Srgrimes itp->it_value.tv_usec += 1000000; 6991541Srgrimes itp->it_value.tv_sec--; 7001541Srgrimes } 7011541Srgrimes itp->it_value.tv_usec -= usec; 7021541Srgrimes usec = 0; 70335058Sphk if (timevalisset(&itp->it_value)) 7041541Srgrimes return (1); 7051541Srgrimes /* expired, exactly at end of interval */ 7061541Srgrimesexpire: 70735058Sphk if (timevalisset(&itp->it_interval)) { 7081541Srgrimes itp->it_value = itp->it_interval; 7091541Srgrimes itp->it_value.tv_usec -= usec; 7101541Srgrimes if (itp->it_value.tv_usec < 0) { 7111541Srgrimes itp->it_value.tv_usec += 1000000; 7121541Srgrimes itp->it_value.tv_sec--; 7131541Srgrimes } 7141541Srgrimes } else 7151541Srgrimes itp->it_value.tv_usec = 0; /* sec is already 0 */ 7161541Srgrimes return (0); 7171541Srgrimes} 7181541Srgrimes 7191541Srgrimes/* 7201541Srgrimes * Add and subtract routines for timevals. 7211541Srgrimes * N.B.: subtract routine doesn't deal with 7221541Srgrimes * results which are before the beginning, 7231541Srgrimes * it just gets very confused in this case. 7241541Srgrimes * Caveat emptor. 7251541Srgrimes */ 7261549Srgrimesvoid 7271541Srgrimestimevaladd(t1, t2) 7281541Srgrimes struct timeval *t1, *t2; 7291541Srgrimes{ 7301541Srgrimes 7311541Srgrimes t1->tv_sec += t2->tv_sec; 7321541Srgrimes t1->tv_usec += t2->tv_usec; 7331541Srgrimes timevalfix(t1); 7341541Srgrimes} 7351541Srgrimes 7361549Srgrimesvoid 7371541Srgrimestimevalsub(t1, t2) 7381541Srgrimes struct timeval *t1, *t2; 7391541Srgrimes{ 7401541Srgrimes 7411541Srgrimes t1->tv_sec -= t2->tv_sec; 7421541Srgrimes t1->tv_usec -= t2->tv_usec; 7431541Srgrimes timevalfix(t1); 7441541Srgrimes} 7451541Srgrimes 74612819Sphkstatic void 7471541Srgrimestimevalfix(t1) 7481541Srgrimes struct timeval *t1; 7491541Srgrimes{ 7501541Srgrimes 7511541Srgrimes if (t1->tv_usec < 0) { 7521541Srgrimes t1->tv_sec--; 7531541Srgrimes t1->tv_usec += 1000000; 7541541Srgrimes } 7551541Srgrimes if (t1->tv_usec >= 1000000) { 7561541Srgrimes t1->tv_sec++; 7571541Srgrimes t1->tv_usec -= 1000000; 7581541Srgrimes } 7591541Srgrimes} 760