kern_time.c revision 152029
1139804Simp/*- 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 * 4. Neither the name of the University nor the names of its contributors 141541Srgrimes * may be used to endorse or promote products derived from this software 151541Srgrimes * without specific prior written permission. 161541Srgrimes * 171541Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 181541Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 191541Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 201541Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 211541Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 221541Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 231541Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 241541Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 251541Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 261541Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 271541Srgrimes * SUCH DAMAGE. 281541Srgrimes * 291541Srgrimes * @(#)kern_time.c 8.1 (Berkeley) 6/10/93 301541Srgrimes */ 311541Srgrimes 32116182Sobrien#include <sys/cdefs.h> 33116182Sobrien__FBSDID("$FreeBSD: head/sys/kern/kern_time.c 152029 2005-11-04 09:41:00Z davidxu $"); 34116182Sobrien 35106369Srwatson#include "opt_mac.h" 36106369Srwatson 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> 45106369Srwatson#include <sys/mac.h> 46140483Sps#include <sys/syscallsubr.h> 4725583Speter#include <sys/sysent.h> 481541Srgrimes#include <sys/proc.h> 4925656Speter#include <sys/time.h> 50151576Sdavidxu#include <sys/timers.h> 5158377Sphk#include <sys/timetc.h> 521541Srgrimes#include <sys/vnode.h> 5376166Smarkm 5426335Speter#include <vm/vm.h> 5526335Speter#include <vm/vm_extern.h> 561541Srgrimes 57151576Sdavidxu#define MAX_CLOCKS (CLOCK_MONOTONIC+1) 58151576Sdavidxu 59110299Sphkint tz_minuteswest; 60110299Sphkint tz_dsttime; 619369Sdg 62151576Sdavidxustatic struct kclock posix_clocks[MAX_CLOCKS]; 63151576Sdavidxustatic uma_zone_t itimer_zone = NULL; 64151576Sdavidxu 658876Srgrimes/* 661541Srgrimes * Time of day and interval timer support. 671541Srgrimes * 681541Srgrimes * These routines provide the kernel entry points to get and set 691541Srgrimes * the time-of-day and per-process interval timers. Subroutines 701541Srgrimes * here provide support for adding and subtracting timeval structures 711541Srgrimes * and decrementing interval timers, optionally reloading the interval 721541Srgrimes * timers when they expire. 731541Srgrimes */ 741541Srgrimes 7594343Sjhbstatic int settime(struct thread *, struct timeval *); 7692723Salfredstatic void timevalfix(struct timeval *); 7792723Salfredstatic void no_lease_updatetime(int); 7813016Sbde 79151576Sdavidxustatic void itimer_start(void); 80151576Sdavidxustatic int itimer_init(void *, int, int); 81151576Sdavidxustatic void itimer_fini(void *, int); 82151576Sdavidxustatic void itimer_enter(struct itimer *); 83151576Sdavidxustatic void itimer_leave(struct itimer *); 84151576Sdavidxustatic struct itimer *itimer_find(struct proc *, timer_t, int); 85151576Sdavidxustatic void itimers_alloc(struct proc *); 86151576Sdavidxustatic int realtimer_create(struct itimer *); 87151576Sdavidxustatic int realtimer_gettime(struct itimer *, struct itimerspec *); 88151576Sdavidxustatic int realtimer_settime(struct itimer *, int, 89151576Sdavidxu struct itimerspec *, struct itimerspec *); 90151576Sdavidxustatic int realtimer_delete(struct itimer *); 91151869Sdavidxustatic void realtimer_clocktime(clockid_t, struct timespec *); 92151576Sdavidxustatic void realtimer_expire(void *); 93151576Sdavidxustatic void realtimer_event_hook(struct proc *, clockid_t, int event); 94151576Sdavidxustatic int kern_timer_create(struct thread *, clockid_t, 95151576Sdavidxu struct sigevent *, timer_t *, timer_t); 96151576Sdavidxustatic int kern_timer_delete(struct thread *, timer_t); 97151576Sdavidxu 98151576Sdavidxuint register_posix_clock(int, struct kclock *); 99151576Sdavidxuvoid itimer_fire(struct itimer *it); 100151869Sdavidxuint itimespecfix(struct timespec *ts); 101151576Sdavidxu 102151576Sdavidxu#define CLOCK_CALL(clock, call, arglist) \ 103151576Sdavidxu ((*posix_clocks[clock].call) arglist) 104151576Sdavidxu 105151576SdavidxuSYSINIT(posix_timer, SI_SUB_P1003_1B, SI_ORDER_FIRST+4, itimer_start, NULL); 106151576Sdavidxu 107151576Sdavidxu 10830739Sphkstatic void 10930739Sphkno_lease_updatetime(deltat) 11030739Sphk int deltat; 11130739Sphk{ 11230739Sphk} 11330739Sphk 11492723Salfredvoid (*lease_updatetime)(int) = no_lease_updatetime; 11530739Sphk 11625583Speterstatic int 117102074Sphksettime(struct thread *td, struct timeval *tv) 11825583Speter{ 11945433Snsayer struct timeval delta, tv1, tv2; 12045438Snsayer static struct timeval maxtime, laststep; 12133690Sphk struct timespec ts; 12225583Speter int s; 12325583Speter 12425656Speter s = splclock(); 12533818Sbde microtime(&tv1); 12635029Sphk delta = *tv; 12735029Sphk timevalsub(&delta, &tv1); 12825583Speter 12925583Speter /* 13033818Sbde * If the system is secure, we do not allow the time to be 13145433Snsayer * set to a value earlier than 1 second less than the highest 13245433Snsayer * time we have yet seen. The worst a miscreant can do in 13345433Snsayer * this circumstance is "freeze" time. He couldn't go 13445433Snsayer * back to the past. 13545438Snsayer * 13645438Snsayer * We similarly do not allow the clock to be stepped more 13745438Snsayer * than one second, nor more than once per second. This allows 13845438Snsayer * a miscreant to make the clock march double-time, but no worse. 13925583Speter */ 14094343Sjhb if (securelevel_gt(td->td_ucred, 1) != 0) { 14145433Snsayer if (delta.tv_sec < 0 || delta.tv_usec < 0) { 14245437Smjacob /* 14345438Snsayer * Update maxtime to latest time we've seen. 14445437Smjacob */ 14545437Smjacob if (tv1.tv_sec > maxtime.tv_sec) 14645437Smjacob maxtime = tv1; 14745437Smjacob tv2 = *tv; 14845437Smjacob timevalsub(&tv2, &maxtime); 14945437Smjacob if (tv2.tv_sec < -1) { 15045437Smjacob tv->tv_sec = maxtime.tv_sec - 1; 15145433Snsayer printf("Time adjustment clamped to -1 second\n"); 15245433Snsayer } 15345437Smjacob } else { 15445438Snsayer if (tv1.tv_sec == laststep.tv_sec) { 15545438Snsayer splx(s); 15645438Snsayer return (EPERM); 15745438Snsayer } 15845438Snsayer if (delta.tv_sec > 1) { 15945438Snsayer tv->tv_sec = tv1.tv_sec + 1; 16045438Snsayer printf("Time adjustment clamped to +1 second\n"); 16145438Snsayer } 16245438Snsayer laststep = *tv; 16345433Snsayer } 16433818Sbde } 16533818Sbde 16633690Sphk ts.tv_sec = tv->tv_sec; 16733690Sphk ts.tv_nsec = tv->tv_usec * 1000; 16894343Sjhb mtx_lock(&Giant); 16958377Sphk tc_setclock(&ts); 17025583Speter (void) splsoftclock(); 17125583Speter lease_updatetime(delta.tv_sec); 17225583Speter splx(s); 17325583Speter resettodr(); 17494343Sjhb mtx_unlock(&Giant); 17525583Speter return (0); 17625583Speter} 17725583Speter 17812221Sbde#ifndef _SYS_SYSPROTO_H_ 17925583Speterstruct clock_gettime_args { 18025583Speter clockid_t clock_id; 18125583Speter struct timespec *tp; 18225583Speter}; 18325583Speter#endif 18425656Speter 18582746Sdillon/* 18682746Sdillon * MPSAFE 18782746Sdillon */ 18825583Speter/* ARGSUSED */ 18925583Speterint 190102074Sphkclock_gettime(struct thread *td, struct clock_gettime_args *uap) 19125583Speter{ 19225583Speter struct timespec ats; 193151357Sps int error; 194151357Sps 195151357Sps error = kern_clock_gettime(td, uap->clock_id, &ats); 196151357Sps if (error == 0) 197151357Sps error = copyout(&ats, uap->tp, sizeof(ats)); 198151357Sps 199151357Sps return (error); 200151357Sps} 201151357Sps 202151357Spsint 203151357Spskern_clock_gettime(struct thread *td, clockid_t clock_id, struct timespec *ats) 204151357Sps{ 205130884Skbyanc struct timeval sys, user; 206136152Sjhb struct proc *p; 20725583Speter 208136152Sjhb p = td->td_proc; 209151357Sps switch (clock_id) { 210130654Skbyanc case CLOCK_REALTIME: 211151357Sps nanotime(ats); 212130654Skbyanc break; 213130654Skbyanc case CLOCK_VIRTUAL: 214136152Sjhb PROC_LOCK(p); 215136152Sjhb calcru(p, &user, &sys); 216136152Sjhb PROC_UNLOCK(p); 217151357Sps TIMEVAL_TO_TIMESPEC(&user, ats); 218130654Skbyanc break; 219130654Skbyanc case CLOCK_PROF: 220136152Sjhb PROC_LOCK(p); 221136152Sjhb calcru(p, &user, &sys); 222136152Sjhb PROC_UNLOCK(p); 223130884Skbyanc timevaladd(&user, &sys); 224151357Sps TIMEVAL_TO_TIMESPEC(&user, ats); 225130654Skbyanc break; 226130884Skbyanc case CLOCK_MONOTONIC: 227151357Sps nanouptime(ats); 228130884Skbyanc break; 229130654Skbyanc default: 230111315Sphk return (EINVAL); 231130654Skbyanc } 232151357Sps return (0); 23325583Speter} 23425583Speter 23525583Speter#ifndef _SYS_SYSPROTO_H_ 23625583Speterstruct clock_settime_args { 23725583Speter clockid_t clock_id; 23825583Speter const struct timespec *tp; 23925583Speter}; 24025583Speter#endif 24125656Speter 24282746Sdillon/* 24382746Sdillon * MPSAFE 24482746Sdillon */ 24525583Speter/* ARGSUSED */ 24625583Speterint 247102074Sphkclock_settime(struct thread *td, struct clock_settime_args *uap) 24825583Speter{ 24925583Speter struct timespec ats; 25025583Speter int error; 25125583Speter 252151357Sps if ((error = copyin(uap->tp, &ats, sizeof(ats))) != 0) 253151357Sps return (error); 254151357Sps return (kern_clock_settime(td, uap->clock_id, &ats)); 255151357Sps} 256151357Sps 257151357Spsint 258151357Spskern_clock_settime(struct thread *td, clockid_t clock_id, struct timespec *ats) 259151357Sps{ 260151357Sps struct timeval atv; 261151357Sps int error; 262151357Sps 263106369Srwatson#ifdef MAC 264106369Srwatson error = mac_check_system_settime(td->td_ucred); 265106369Srwatson if (error) 266106369Srwatson return (error); 267106369Srwatson#endif 26893593Sjhb if ((error = suser(td)) != 0) 26994343Sjhb return (error); 270151357Sps if (clock_id != CLOCK_REALTIME) 27194343Sjhb return (EINVAL); 272151357Sps if (ats->tv_nsec < 0 || ats->tv_nsec >= 1000000000) 27394343Sjhb return (EINVAL); 27434901Sphk /* XXX Don't convert nsec->usec and back */ 275151357Sps TIMESPEC_TO_TIMEVAL(&atv, ats); 27694343Sjhb error = settime(td, &atv); 27782746Sdillon return (error); 27825583Speter} 27925583Speter 28025583Speter#ifndef _SYS_SYSPROTO_H_ 28125583Speterstruct clock_getres_args { 28225583Speter clockid_t clock_id; 28325583Speter struct timespec *tp; 28425583Speter}; 28525583Speter#endif 28625656Speter 28725583Speterint 288102074Sphkclock_getres(struct thread *td, struct clock_getres_args *uap) 28925583Speter{ 29025583Speter struct timespec ts; 291151357Sps int error; 29225583Speter 293151357Sps if (uap->tp == NULL) 294151357Sps return (0); 295151357Sps 296151357Sps error = kern_clock_getres(td, uap->clock_id, &ts); 297151357Sps if (error == 0) 298151357Sps error = copyout(&ts, uap->tp, sizeof(ts)); 299151357Sps return (error); 300151357Sps} 301151357Sps 302151357Spsint 303151357Spskern_clock_getres(struct thread *td, clockid_t clock_id, struct timespec *ts) 304151357Sps{ 305151357Sps 306151357Sps ts->tv_sec = 0; 307151357Sps switch (clock_id) { 308130654Skbyanc case CLOCK_REALTIME: 309130654Skbyanc case CLOCK_MONOTONIC: 310103964Sbde /* 311103964Sbde * Round up the result of the division cheaply by adding 1. 312103964Sbde * Rounding up is especially important if rounding down 313103964Sbde * would give 0. Perfect rounding is unimportant. 314103964Sbde */ 315151357Sps ts->tv_nsec = 1000000000 / tc_getfrequency() + 1; 316130654Skbyanc break; 317130654Skbyanc case CLOCK_VIRTUAL: 318130654Skbyanc case CLOCK_PROF: 319130654Skbyanc /* Accurately round up here because we can do so cheaply. */ 320151357Sps ts->tv_nsec = (1000000000 + hz - 1) / hz; 321130654Skbyanc break; 322130654Skbyanc default: 323130654Skbyanc return (EINVAL); 324130654Skbyanc } 325151357Sps return (0); 32625583Speter} 32725583Speter 32826335Speterstatic int nanowait; 32925656Speter 330140481Spsint 331140481Spskern_nanosleep(struct thread *td, struct timespec *rqt, struct timespec *rmt) 33225583Speter{ 33335045Sphk struct timespec ts, ts2, ts3; 33435042Sphk struct timeval tv; 33535042Sphk int error; 33625583Speter 33728773Sbde if (rqt->tv_nsec < 0 || rqt->tv_nsec >= 1000000000) 33825656Speter return (EINVAL); 33943301Sdillon if (rqt->tv_sec < 0 || (rqt->tv_sec == 0 && rqt->tv_nsec == 0)) 34028773Sbde return (0); 34136119Sphk getnanouptime(&ts); 34235029Sphk timespecadd(&ts, rqt); 34335042Sphk TIMESPEC_TO_TIMEVAL(&tv, rqt); 34435042Sphk for (;;) { 34535042Sphk error = tsleep(&nanowait, PWAIT | PCATCH, "nanslp", 34635042Sphk tvtohz(&tv)); 34736119Sphk getnanouptime(&ts2); 34835042Sphk if (error != EWOULDBLOCK) { 34935042Sphk if (error == ERESTART) 35035042Sphk error = EINTR; 35135042Sphk if (rmt != NULL) { 35235042Sphk timespecsub(&ts, &ts2); 35335042Sphk if (ts.tv_sec < 0) 35435042Sphk timespecclear(&ts); 35535042Sphk *rmt = ts; 35635042Sphk } 35735042Sphk return (error); 35835042Sphk } 35935029Sphk if (timespeccmp(&ts2, &ts, >=)) 36035042Sphk return (0); 36135045Sphk ts3 = ts; 36235045Sphk timespecsub(&ts3, &ts2); 36335045Sphk TIMESPEC_TO_TIMEVAL(&tv, &ts3); 36426335Speter } 36526335Speter} 36625583Speter 36726335Speter#ifndef _SYS_SYSPROTO_H_ 36826335Speterstruct nanosleep_args { 36926335Speter struct timespec *rqtp; 37026335Speter struct timespec *rmtp; 37126335Speter}; 37226335Speter#endif 37326335Speter 37482746Sdillon/* 37582746Sdillon * MPSAFE 37682746Sdillon */ 37726335Speter/* ARGSUSED */ 37826335Speterint 379102074Sphknanosleep(struct thread *td, struct nanosleep_args *uap) 38026335Speter{ 38126335Speter struct timespec rmt, rqt; 38282746Sdillon int error; 38326335Speter 384107849Salfred error = copyin(uap->rqtp, &rqt, sizeof(rqt)); 38526335Speter if (error) 38626335Speter return (error); 38782746Sdillon 388109521Salfred if (uap->rmtp && 389109521Salfred !useracc((caddr_t)uap->rmtp, sizeof(rmt), VM_PROT_WRITE)) 390109521Salfred return (EFAULT); 391140481Sps error = kern_nanosleep(td, &rqt, &rmt); 392107849Salfred if (error && uap->rmtp) { 39382746Sdillon int error2; 39482746Sdillon 395107849Salfred error2 = copyout(&rmt, uap->rmtp, sizeof(rmt)); 396109521Salfred if (error2) 39782746Sdillon error = error2; 39825583Speter } 39925656Speter return (error); 40025583Speter} 40125583Speter 40226335Speter#ifndef _SYS_SYSPROTO_H_ 4031541Srgrimesstruct gettimeofday_args { 4041541Srgrimes struct timeval *tp; 4051541Srgrimes struct timezone *tzp; 4061541Srgrimes}; 40712221Sbde#endif 40882746Sdillon/* 40982746Sdillon * MPSAFE 41082746Sdillon */ 4111541Srgrimes/* ARGSUSED */ 4121549Srgrimesint 413102074Sphkgettimeofday(struct thread *td, struct gettimeofday_args *uap) 4141541Srgrimes{ 4151541Srgrimes struct timeval atv; 416110286Stjr struct timezone rtz; 4171541Srgrimes int error = 0; 4181541Srgrimes 4191541Srgrimes if (uap->tp) { 4201541Srgrimes microtime(&atv); 42199012Salfred error = copyout(&atv, uap->tp, sizeof (atv)); 4221541Srgrimes } 42390836Sphk if (error == 0 && uap->tzp != NULL) { 424110299Sphk rtz.tz_minuteswest = tz_minuteswest; 425110299Sphk rtz.tz_dsttime = tz_dsttime; 426110286Stjr error = copyout(&rtz, uap->tzp, sizeof (rtz)); 42782746Sdillon } 4281541Srgrimes return (error); 4291541Srgrimes} 4301541Srgrimes 43112221Sbde#ifndef _SYS_SYSPROTO_H_ 4321541Srgrimesstruct settimeofday_args { 4331541Srgrimes struct timeval *tv; 4341541Srgrimes struct timezone *tzp; 4351541Srgrimes}; 43612221Sbde#endif 43782746Sdillon/* 43882746Sdillon * MPSAFE 43982746Sdillon */ 4401541Srgrimes/* ARGSUSED */ 4411549Srgrimesint 442102074Sphksettimeofday(struct thread *td, struct settimeofday_args *uap) 4431541Srgrimes{ 444144445Sjhb struct timeval atv, *tvp; 445144445Sjhb struct timezone atz, *tzp; 446144445Sjhb int error; 4471541Srgrimes 448144445Sjhb if (uap->tv) { 449144445Sjhb error = copyin(uap->tv, &atv, sizeof(atv)); 450144445Sjhb if (error) 451144445Sjhb return (error); 452144445Sjhb tvp = &atv; 453144445Sjhb } else 454144445Sjhb tvp = NULL; 455144445Sjhb if (uap->tzp) { 456144445Sjhb error = copyin(uap->tzp, &atz, sizeof(atz)); 457144445Sjhb if (error) 458144445Sjhb return (error); 459144445Sjhb tzp = &atz; 460144445Sjhb } else 461144445Sjhb tzp = NULL; 462144445Sjhb return (kern_settimeofday(td, tvp, tzp)); 463144445Sjhb} 464144445Sjhb 465144445Sjhbint 466144445Sjhbkern_settimeofday(struct thread *td, struct timeval *tv, struct timezone *tzp) 467144445Sjhb{ 468144445Sjhb int error; 469144445Sjhb 470106369Srwatson#ifdef MAC 471106369Srwatson error = mac_check_system_settime(td->td_ucred); 472106369Srwatson if (error) 473106369Srwatson return (error); 474106369Srwatson#endif 475144445Sjhb error = suser(td); 476144445Sjhb if (error) 47794343Sjhb return (error); 4781541Srgrimes /* Verify all parameters before changing time. */ 479144445Sjhb if (tv) { 480144445Sjhb if (tv->tv_usec < 0 || tv->tv_usec >= 1000000) 48194343Sjhb return (EINVAL); 482144445Sjhb error = settime(td, tv); 48325656Speter } 484144445Sjhb if (tzp && error == 0) { 485144445Sjhb tz_minuteswest = tzp->tz_minuteswest; 486144445Sjhb tz_dsttime = tzp->tz_dsttime; 48782746Sdillon } 48882746Sdillon return (error); 4891541Srgrimes} 490144445Sjhb 49182746Sdillon/* 4921541Srgrimes * Get value of an interval timer. The process virtual and 4931541Srgrimes * profiling virtual time timers are kept in the p_stats area, since 4941541Srgrimes * they can be swapped out. These are kept internally in the 4951541Srgrimes * way they are specified externally: in time until they expire. 4961541Srgrimes * 4971541Srgrimes * The real time interval timer is kept in the process table slot 4981541Srgrimes * for the process, and its value (it_value) is kept as an 4991541Srgrimes * absolute time rather than as a delta, so that it is easy to keep 5001541Srgrimes * periodic real-time signals from drifting. 5011541Srgrimes * 5021541Srgrimes * Virtual time timers are processed in the hardclock() routine of 5031541Srgrimes * kern_clock.c. The real time timer is processed by a timeout 5041541Srgrimes * routine, called from the softclock() routine. Since a callout 5051541Srgrimes * may be delayed in real time due to interrupt processing in the system, 5061541Srgrimes * it is possible for the real time timeout routine (realitexpire, given below), 5071541Srgrimes * to be delayed in real time past when it is supposed to occur. It 5081541Srgrimes * does not suffice, therefore, to reload the real timer .it_value from the 5091541Srgrimes * real time timers .it_interval. Rather, we compute the next time in 5101541Srgrimes * absolute time the timer should go off. 5111541Srgrimes */ 51212221Sbde#ifndef _SYS_SYSPROTO_H_ 5131541Srgrimesstruct getitimer_args { 5141541Srgrimes u_int which; 5151541Srgrimes struct itimerval *itv; 5161541Srgrimes}; 51712221Sbde#endif 51882746Sdillon/* 51982746Sdillon * MPSAFE 52082746Sdillon */ 5211549Srgrimesint 522102074Sphkgetitimer(struct thread *td, struct getitimer_args *uap) 5231541Srgrimes{ 524141470Sjhb struct itimerval aitv; 525140832Ssobomax int error; 526140832Ssobomax 527140832Ssobomax error = kern_getitimer(td, uap->which, &aitv); 528140832Ssobomax if (error != 0) 529140832Ssobomax return (error); 530140832Ssobomax return (copyout(&aitv, uap->itv, sizeof (struct itimerval))); 531140832Ssobomax} 532140832Ssobomax 533140832Ssobomaxint 534140832Ssobomaxkern_getitimer(struct thread *td, u_int which, struct itimerval *aitv) 535140832Ssobomax{ 53683366Sjulian struct proc *p = td->td_proc; 53734961Sphk struct timeval ctv; 5381541Srgrimes 539140832Ssobomax if (which > ITIMER_PROF) 5401541Srgrimes return (EINVAL); 54182746Sdillon 542140832Ssobomax if (which == ITIMER_REAL) { 5431541Srgrimes /* 54436128Sbde * Convert from absolute to relative time in .it_value 5451541Srgrimes * part of real time timer. If time for real time timer 5461541Srgrimes * has passed return 0, else return difference between 5471541Srgrimes * current time and time for the timer to go off. 5481541Srgrimes */ 549111034Stjr PROC_LOCK(p); 550140832Ssobomax *aitv = p->p_realtimer; 551111034Stjr PROC_UNLOCK(p); 552140832Ssobomax if (timevalisset(&aitv->it_value)) { 55336119Sphk getmicrouptime(&ctv); 554140832Ssobomax if (timevalcmp(&aitv->it_value, &ctv, <)) 555140832Ssobomax timevalclear(&aitv->it_value); 5561541Srgrimes else 557140832Ssobomax timevalsub(&aitv->it_value, &ctv); 55834961Sphk } 55982746Sdillon } else { 560111034Stjr mtx_lock_spin(&sched_lock); 561140832Ssobomax *aitv = p->p_stats->p_timer[which]; 562111034Stjr mtx_unlock_spin(&sched_lock); 56382746Sdillon } 564140832Ssobomax return (0); 5651541Srgrimes} 5661541Srgrimes 56712221Sbde#ifndef _SYS_SYSPROTO_H_ 5681541Srgrimesstruct setitimer_args { 5691541Srgrimes u_int which; 5701541Srgrimes struct itimerval *itv, *oitv; 5711541Srgrimes}; 57212221Sbde#endif 573140832Ssobomax 57482746Sdillon/* 57582746Sdillon * MPSAFE 57682746Sdillon */ 5771549Srgrimesint 578102074Sphksetitimer(struct thread *td, struct setitimer_args *uap) 5791541Srgrimes{ 580141470Sjhb struct itimerval aitv, oitv; 581140832Ssobomax int error; 5821541Srgrimes 583111034Stjr if (uap->itv == NULL) { 584111034Stjr uap->itv = uap->oitv; 585111034Stjr return (getitimer(td, (struct getitimer_args *)uap)); 586111034Stjr } 587111034Stjr 588111034Stjr if ((error = copyin(uap->itv, &aitv, sizeof(struct itimerval)))) 5891541Srgrimes return (error); 590140832Ssobomax error = kern_setitimer(td, uap->which, &aitv, &oitv); 591140832Ssobomax if (error != 0 || uap->oitv == NULL) 592140832Ssobomax return (error); 593140832Ssobomax return (copyout(&oitv, uap->oitv, sizeof(struct itimerval))); 594140832Ssobomax} 595140832Ssobomax 596140832Ssobomaxint 597141470Sjhbkern_setitimer(struct thread *td, u_int which, struct itimerval *aitv, 598141470Sjhb struct itimerval *oitv) 599140832Ssobomax{ 600140832Ssobomax struct proc *p = td->td_proc; 601140832Ssobomax struct timeval ctv; 602140832Ssobomax 603141483Sjhb if (aitv == NULL) 604141483Sjhb return (kern_getitimer(td, which, oitv)); 605141483Sjhb 606140832Ssobomax if (which > ITIMER_PROF) 607111034Stjr return (EINVAL); 608140832Ssobomax if (itimerfix(&aitv->it_value)) 609111034Stjr return (EINVAL); 610140832Ssobomax if (!timevalisset(&aitv->it_value)) 611140832Ssobomax timevalclear(&aitv->it_interval); 612140832Ssobomax else if (itimerfix(&aitv->it_interval)) 613140832Ssobomax return (EINVAL); 61482746Sdillon 615140832Ssobomax if (which == ITIMER_REAL) { 616111034Stjr PROC_LOCK(p); 61735058Sphk if (timevalisset(&p->p_realtimer.it_value)) 61869286Sjake callout_stop(&p->p_itcallout); 619114980Sjhb getmicrouptime(&ctv); 620140832Ssobomax if (timevalisset(&aitv->it_value)) { 621140832Ssobomax callout_reset(&p->p_itcallout, tvtohz(&aitv->it_value), 62269286Sjake realitexpire, p); 623140832Ssobomax timevaladd(&aitv->it_value, &ctv); 624114980Sjhb } 625140832Ssobomax *oitv = p->p_realtimer; 626140832Ssobomax p->p_realtimer = *aitv; 627111034Stjr PROC_UNLOCK(p); 628140832Ssobomax if (timevalisset(&oitv->it_value)) { 629140832Ssobomax if (timevalcmp(&oitv->it_value, &ctv, <)) 630140832Ssobomax timevalclear(&oitv->it_value); 631111034Stjr else 632140832Ssobomax timevalsub(&oitv->it_value, &ctv); 633111034Stjr } 63482746Sdillon } else { 635111034Stjr mtx_lock_spin(&sched_lock); 636140832Ssobomax *oitv = p->p_stats->p_timer[which]; 637140832Ssobomax p->p_stats->p_timer[which] = *aitv; 638111034Stjr mtx_unlock_spin(&sched_lock); 63982746Sdillon } 640140832Ssobomax return (0); 6411541Srgrimes} 6421541Srgrimes 6431541Srgrimes/* 6441541Srgrimes * Real interval timer expired: 6451541Srgrimes * send process whose timer expired an alarm signal. 6461541Srgrimes * If time is not set up to reload, then just return. 6471541Srgrimes * Else compute next time timer should go off which is > current time. 6481541Srgrimes * This is where delay in processing this timeout causes multiple 6491541Srgrimes * SIGALRM calls to be compressed into one. 65036127Sbde * tvtohz() always adds 1 to allow for the time until the next clock 6519327Sbde * interrupt being strictly less than 1 clock tick, but we don't want 6529327Sbde * that here since we want to appear to be in sync with the clock 6539327Sbde * interrupt even when we're delayed. 6541541Srgrimes */ 6551541Srgrimesvoid 656102074Sphkrealitexpire(void *arg) 6571541Srgrimes{ 658102074Sphk struct proc *p; 65935044Sphk struct timeval ctv, ntv; 6601541Srgrimes 6611541Srgrimes p = (struct proc *)arg; 66273916Sjhb PROC_LOCK(p); 6631541Srgrimes psignal(p, SIGALRM); 66435058Sphk if (!timevalisset(&p->p_realtimer.it_interval)) { 66535058Sphk timevalclear(&p->p_realtimer.it_value); 666116123Sjhb if (p->p_flag & P_WEXIT) 667116123Sjhb wakeup(&p->p_itcallout); 66873916Sjhb PROC_UNLOCK(p); 6691541Srgrimes return; 6701541Srgrimes } 6711541Srgrimes for (;;) { 6721541Srgrimes timevaladd(&p->p_realtimer.it_value, 6731541Srgrimes &p->p_realtimer.it_interval); 67436119Sphk getmicrouptime(&ctv); 67535058Sphk if (timevalcmp(&p->p_realtimer.it_value, &ctv, >)) { 67635044Sphk ntv = p->p_realtimer.it_value; 67735044Sphk timevalsub(&ntv, &ctv); 67869286Sjake callout_reset(&p->p_itcallout, tvtohz(&ntv) - 1, 67969286Sjake realitexpire, p); 68073916Sjhb PROC_UNLOCK(p); 6811541Srgrimes return; 6821541Srgrimes } 6831541Srgrimes } 68473916Sjhb /*NOTREACHED*/ 6851541Srgrimes} 6861541Srgrimes 6871541Srgrimes/* 6881541Srgrimes * Check that a proposed value to load into the .it_value or 6891541Srgrimes * .it_interval part of an interval timer is acceptable, and 6901541Srgrimes * fix it to have at least minimal value (i.e. if it is less 6911541Srgrimes * than the resolution of the clock, round it up.) 6921541Srgrimes */ 6931549Srgrimesint 694102074Sphkitimerfix(struct timeval *tv) 6951541Srgrimes{ 6961541Srgrimes 697151576Sdavidxu if (tv->tv_sec < 0 || tv->tv_usec < 0 || tv->tv_usec >= 1000000) 6981541Srgrimes return (EINVAL); 6991541Srgrimes if (tv->tv_sec == 0 && tv->tv_usec != 0 && tv->tv_usec < tick) 7001541Srgrimes tv->tv_usec = tick; 7011541Srgrimes return (0); 7021541Srgrimes} 7031541Srgrimes 7041541Srgrimes/* 7051541Srgrimes * Decrement an interval timer by a specified number 7061541Srgrimes * of microseconds, which must be less than a second, 7071541Srgrimes * i.e. < 1000000. If the timer expires, then reload 7081541Srgrimes * it. In this case, carry over (usec - old value) to 7091541Srgrimes * reduce the value reloaded into the timer so that 7101541Srgrimes * the timer does not drift. This routine assumes 7111541Srgrimes * that it is called in a context where the timers 7121541Srgrimes * on which it is operating cannot change in value. 7131541Srgrimes */ 7141549Srgrimesint 715102074Sphkitimerdecr(struct itimerval *itp, int usec) 7161541Srgrimes{ 7171541Srgrimes 7181541Srgrimes if (itp->it_value.tv_usec < usec) { 7191541Srgrimes if (itp->it_value.tv_sec == 0) { 7201541Srgrimes /* expired, and already in next interval */ 7211541Srgrimes usec -= itp->it_value.tv_usec; 7221541Srgrimes goto expire; 7231541Srgrimes } 7241541Srgrimes itp->it_value.tv_usec += 1000000; 7251541Srgrimes itp->it_value.tv_sec--; 7261541Srgrimes } 7271541Srgrimes itp->it_value.tv_usec -= usec; 7281541Srgrimes usec = 0; 72935058Sphk if (timevalisset(&itp->it_value)) 7301541Srgrimes return (1); 7311541Srgrimes /* expired, exactly at end of interval */ 7321541Srgrimesexpire: 73335058Sphk if (timevalisset(&itp->it_interval)) { 7341541Srgrimes itp->it_value = itp->it_interval; 7351541Srgrimes itp->it_value.tv_usec -= usec; 7361541Srgrimes if (itp->it_value.tv_usec < 0) { 7371541Srgrimes itp->it_value.tv_usec += 1000000; 7381541Srgrimes itp->it_value.tv_sec--; 7391541Srgrimes } 7401541Srgrimes } else 7411541Srgrimes itp->it_value.tv_usec = 0; /* sec is already 0 */ 7421541Srgrimes return (0); 7431541Srgrimes} 7441541Srgrimes 7451541Srgrimes/* 7461541Srgrimes * Add and subtract routines for timevals. 7471541Srgrimes * N.B.: subtract routine doesn't deal with 7481541Srgrimes * results which are before the beginning, 7491541Srgrimes * it just gets very confused in this case. 7501541Srgrimes * Caveat emptor. 7511541Srgrimes */ 7521549Srgrimesvoid 753121523Salfredtimevaladd(struct timeval *t1, const struct timeval *t2) 7541541Srgrimes{ 7551541Srgrimes 7561541Srgrimes t1->tv_sec += t2->tv_sec; 7571541Srgrimes t1->tv_usec += t2->tv_usec; 7581541Srgrimes timevalfix(t1); 7591541Srgrimes} 7601541Srgrimes 7611549Srgrimesvoid 762121523Salfredtimevalsub(struct timeval *t1, const struct timeval *t2) 7631541Srgrimes{ 7641541Srgrimes 7651541Srgrimes t1->tv_sec -= t2->tv_sec; 7661541Srgrimes t1->tv_usec -= t2->tv_usec; 7671541Srgrimes timevalfix(t1); 7681541Srgrimes} 7691541Srgrimes 77012819Sphkstatic void 771102074Sphktimevalfix(struct timeval *t1) 7721541Srgrimes{ 7731541Srgrimes 7741541Srgrimes if (t1->tv_usec < 0) { 7751541Srgrimes t1->tv_sec--; 7761541Srgrimes t1->tv_usec += 1000000; 7771541Srgrimes } 7781541Srgrimes if (t1->tv_usec >= 1000000) { 7791541Srgrimes t1->tv_sec++; 7801541Srgrimes t1->tv_usec -= 1000000; 7811541Srgrimes } 7821541Srgrimes} 783108142Ssam 784108142Ssam/* 785108511Ssam * ratecheck(): simple time-based rate-limit checking. 786108142Ssam */ 787108142Ssamint 788108142Ssamratecheck(struct timeval *lasttime, const struct timeval *mininterval) 789108142Ssam{ 790108142Ssam struct timeval tv, delta; 791108142Ssam int rv = 0; 792108142Ssam 793108511Ssam getmicrouptime(&tv); /* NB: 10ms precision */ 794108511Ssam delta = tv; 795108511Ssam timevalsub(&delta, lasttime); 796108142Ssam 797108142Ssam /* 798108142Ssam * check for 0,0 is so that the message will be seen at least once, 799108142Ssam * even if interval is huge. 800108142Ssam */ 801108142Ssam if (timevalcmp(&delta, mininterval, >=) || 802108142Ssam (lasttime->tv_sec == 0 && lasttime->tv_usec == 0)) { 803108142Ssam *lasttime = tv; 804108142Ssam rv = 1; 805108142Ssam } 806108142Ssam 807108142Ssam return (rv); 808108142Ssam} 809108142Ssam 810108142Ssam/* 811108142Ssam * ppsratecheck(): packets (or events) per second limitation. 812108511Ssam * 813108511Ssam * Return 0 if the limit is to be enforced (e.g. the caller 814108511Ssam * should drop a packet because of the rate limitation). 815108511Ssam * 816111558Ssam * maxpps of 0 always causes zero to be returned. maxpps of -1 817111558Ssam * always causes 1 to be returned; this effectively defeats rate 818111558Ssam * limiting. 819111558Ssam * 820108511Ssam * Note that we maintain the struct timeval for compatibility 821108511Ssam * with other bsd systems. We reuse the storage and just monitor 822108511Ssam * clock ticks for minimal overhead. 823108142Ssam */ 824108142Ssamint 825108142Ssamppsratecheck(struct timeval *lasttime, int *curpps, int maxpps) 826108142Ssam{ 827108511Ssam int now; 828108142Ssam 829108142Ssam /* 830108511Ssam * Reset the last time and counter if this is the first call 831108511Ssam * or more than a second has passed since the last update of 832108511Ssam * lasttime. 833108142Ssam */ 834108511Ssam now = ticks; 835108511Ssam if (lasttime->tv_sec == 0 || (u_int)(now - lasttime->tv_sec) >= hz) { 836108511Ssam lasttime->tv_sec = now; 837108511Ssam *curpps = 1; 838111558Ssam return (maxpps != 0); 839108511Ssam } else { 840108511Ssam (*curpps)++; /* NB: ignore potential overflow */ 841108511Ssam return (maxpps < 0 || *curpps < maxpps); 842108511Ssam } 843108142Ssam} 844151576Sdavidxu 845151576Sdavidxustatic void 846151576Sdavidxuitimer_start(void) 847151576Sdavidxu{ 848151576Sdavidxu struct kclock rt_clock = { 849151576Sdavidxu .timer_create = realtimer_create, 850151576Sdavidxu .timer_delete = realtimer_delete, 851151576Sdavidxu .timer_settime = realtimer_settime, 852151576Sdavidxu .timer_gettime = realtimer_gettime, 853151576Sdavidxu .event_hook = realtimer_event_hook 854151576Sdavidxu }; 855151576Sdavidxu 856151576Sdavidxu itimer_zone = uma_zcreate("itimer", sizeof(struct itimer), 857151576Sdavidxu NULL, NULL, itimer_init, itimer_fini, UMA_ALIGN_PTR, 0); 858151576Sdavidxu register_posix_clock(CLOCK_REALTIME, &rt_clock); 859151576Sdavidxu register_posix_clock(CLOCK_MONOTONIC, &rt_clock); 860151576Sdavidxu} 861151576Sdavidxu 862151576Sdavidxuint 863151576Sdavidxuregister_posix_clock(int clockid, struct kclock *clk) 864151576Sdavidxu{ 865151576Sdavidxu if ((unsigned)clockid >= MAX_CLOCKS) { 866151576Sdavidxu printf("%s: invalid clockid\n", __func__); 867151576Sdavidxu return (0); 868151576Sdavidxu } 869151576Sdavidxu posix_clocks[clockid] = *clk; 870151576Sdavidxu return (1); 871151576Sdavidxu} 872151576Sdavidxu 873151576Sdavidxustatic int 874151576Sdavidxuitimer_init(void *mem, int size, int flags) 875151576Sdavidxu{ 876151576Sdavidxu struct itimer *it; 877151576Sdavidxu 878151576Sdavidxu it = (struct itimer *)mem; 879151576Sdavidxu mtx_init(&it->it_mtx, "itimer lock", NULL, MTX_DEF); 880151576Sdavidxu return (0); 881151576Sdavidxu} 882151576Sdavidxu 883151576Sdavidxustatic void 884151576Sdavidxuitimer_fini(void *mem, int size) 885151576Sdavidxu{ 886151576Sdavidxu struct itimer *it; 887151576Sdavidxu 888151576Sdavidxu it = (struct itimer *)mem; 889151576Sdavidxu mtx_destroy(&it->it_mtx); 890151576Sdavidxu} 891151576Sdavidxu 892151576Sdavidxustatic void 893151576Sdavidxuitimer_enter(struct itimer *it) 894151576Sdavidxu{ 895151576Sdavidxu 896151576Sdavidxu mtx_assert(&it->it_mtx, MA_OWNED); 897151576Sdavidxu it->it_usecount++; 898151576Sdavidxu} 899151576Sdavidxu 900151576Sdavidxustatic void 901151576Sdavidxuitimer_leave(struct itimer *it) 902151576Sdavidxu{ 903151576Sdavidxu 904151576Sdavidxu mtx_assert(&it->it_mtx, MA_OWNED); 905151576Sdavidxu KASSERT(it->it_usecount > 0, ("invalid it_usecount")); 906151576Sdavidxu 907151576Sdavidxu if (--it->it_usecount == 0 && (it->it_flags & ITF_WANTED) != 0) 908151576Sdavidxu wakeup(it); 909151576Sdavidxu} 910151576Sdavidxu 911151576Sdavidxu#ifndef _SYS_SYSPROTO_H_ 912151576Sdavidxustruct timer_create_args { 913151576Sdavidxu clockid_t clock_id; 914151576Sdavidxu struct sigevent * evp; 915151576Sdavidxu timer_t * timerid; 916151576Sdavidxu}; 917151576Sdavidxu#endif 918151576Sdavidxu 919151576Sdavidxuint 920151576Sdavidxutimer_create(struct thread *td, struct timer_create_args *uap) 921151576Sdavidxu{ 922151576Sdavidxu struct sigevent *evp1, ev; 923151576Sdavidxu timer_t id; 924151576Sdavidxu int error; 925151576Sdavidxu 926151576Sdavidxu if (uap->evp != NULL) { 927151576Sdavidxu error = copyin(uap->evp, &ev, sizeof(ev)); 928151576Sdavidxu if (error != 0) 929151576Sdavidxu return (error); 930151576Sdavidxu evp1 = &ev; 931151576Sdavidxu } else 932151576Sdavidxu evp1 = NULL; 933151576Sdavidxu 934151576Sdavidxu error = kern_timer_create(td, uap->clock_id, evp1, &id, -1); 935151576Sdavidxu 936151576Sdavidxu if (error == 0) { 937151576Sdavidxu error = copyout(&id, uap->timerid, sizeof(timer_t)); 938151576Sdavidxu if (error != 0) 939151576Sdavidxu kern_timer_delete(td, id); 940151576Sdavidxu } 941151576Sdavidxu return (error); 942151576Sdavidxu} 943151576Sdavidxu 944151576Sdavidxustatic int 945151576Sdavidxukern_timer_create(struct thread *td, clockid_t clock_id, 946151576Sdavidxu struct sigevent *evp, timer_t *timerid, timer_t preset_id) 947151576Sdavidxu{ 948151576Sdavidxu struct proc *p = td->td_proc; 949151576Sdavidxu struct itimer *it; 950151576Sdavidxu int id; 951151576Sdavidxu int error; 952151576Sdavidxu 953151576Sdavidxu if (clock_id < 0 || clock_id >= MAX_CLOCKS) 954151576Sdavidxu return (EINVAL); 955151576Sdavidxu 956151576Sdavidxu if (posix_clocks[clock_id].timer_create == NULL) 957151576Sdavidxu return (EINVAL); 958151576Sdavidxu 959151576Sdavidxu if (evp != NULL) { 960151576Sdavidxu if (evp->sigev_notify != SIGEV_NONE && 961151869Sdavidxu evp->sigev_notify != SIGEV_SIGNAL && 962151869Sdavidxu evp->sigev_notify != SIGEV_THREAD_ID) 963151576Sdavidxu return (EINVAL); 964151869Sdavidxu if ((evp->sigev_notify == SIGEV_SIGNAL || 965151869Sdavidxu evp->sigev_notify == SIGEV_THREAD_ID) && 966151576Sdavidxu !_SIG_VALID(evp->sigev_signo)) 967151576Sdavidxu return (EINVAL); 968151576Sdavidxu } 969151576Sdavidxu 970151585Sdavidxu if (p->p_itimers == NULL) 971151576Sdavidxu itimers_alloc(p); 972151576Sdavidxu 973151576Sdavidxu it = uma_zalloc(itimer_zone, M_WAITOK); 974151576Sdavidxu it->it_flags = 0; 975151576Sdavidxu it->it_usecount = 0; 976151576Sdavidxu it->it_active = 0; 977151869Sdavidxu timespecclear(&it->it_time.it_value); 978151869Sdavidxu timespecclear(&it->it_time.it_interval); 979151576Sdavidxu it->it_overrun = 0; 980151576Sdavidxu it->it_overrun_last = 0; 981151576Sdavidxu it->it_clockid = clock_id; 982151576Sdavidxu it->it_timerid = -1; 983151576Sdavidxu it->it_proc = p; 984151576Sdavidxu ksiginfo_init(&it->it_ksi); 985151576Sdavidxu it->it_ksi.ksi_flags |= KSI_INS | KSI_EXT; 986151576Sdavidxu error = CLOCK_CALL(clock_id, timer_create, (it)); 987151576Sdavidxu if (error != 0) 988151576Sdavidxu goto out; 989151576Sdavidxu 990151576Sdavidxu PROC_LOCK(p); 991151576Sdavidxu if (preset_id != -1) { 992151576Sdavidxu KASSERT(preset_id >= 0 && preset_id < 3, ("invalid preset_id")); 993151576Sdavidxu id = preset_id; 994151585Sdavidxu if (p->p_itimers->its_timers[id] != NULL) { 995151576Sdavidxu PROC_UNLOCK(p); 996151576Sdavidxu error = 0; 997151576Sdavidxu goto out; 998151576Sdavidxu } 999151576Sdavidxu } else { 1000151576Sdavidxu /* 1001151576Sdavidxu * Find a free timer slot, skipping those reserved 1002151576Sdavidxu * for setitimer(). 1003151576Sdavidxu */ 1004151576Sdavidxu for (id = 3; id < TIMER_MAX; id++) 1005151585Sdavidxu if (p->p_itimers->its_timers[id] == NULL) 1006151576Sdavidxu break; 1007151576Sdavidxu if (id == TIMER_MAX) { 1008151576Sdavidxu PROC_UNLOCK(p); 1009151576Sdavidxu error = EAGAIN; 1010151576Sdavidxu goto out; 1011151576Sdavidxu } 1012151576Sdavidxu } 1013151576Sdavidxu it->it_timerid = id; 1014151585Sdavidxu p->p_itimers->its_timers[id] = it; 1015151576Sdavidxu if (evp != NULL) 1016151576Sdavidxu it->it_sigev = *evp; 1017151576Sdavidxu else { 1018151576Sdavidxu it->it_sigev.sigev_notify = SIGEV_SIGNAL; 1019151576Sdavidxu switch (clock_id) { 1020151576Sdavidxu default: 1021151576Sdavidxu case CLOCK_REALTIME: 1022151576Sdavidxu it->it_sigev.sigev_signo = SIGALRM; 1023151576Sdavidxu break; 1024151576Sdavidxu case CLOCK_VIRTUAL: 1025151576Sdavidxu it->it_sigev.sigev_signo = SIGVTALRM; 1026151576Sdavidxu break; 1027151576Sdavidxu case CLOCK_PROF: 1028151576Sdavidxu it->it_sigev.sigev_signo = SIGPROF; 1029151576Sdavidxu break; 1030151576Sdavidxu } 1031152029Sdavidxu it->it_sigev.sigev_value.sival_int = id; 1032151576Sdavidxu } 1033151576Sdavidxu 1034151869Sdavidxu if (it->it_sigev.sigev_notify == SIGEV_SIGNAL || 1035151869Sdavidxu it->it_sigev.sigev_notify == SIGEV_THREAD_ID) { 1036151576Sdavidxu it->it_ksi.ksi_signo = it->it_sigev.sigev_signo; 1037151576Sdavidxu it->it_ksi.ksi_code = SI_TIMER; 1038151576Sdavidxu it->it_ksi.ksi_value = it->it_sigev.sigev_value; 1039151576Sdavidxu it->it_ksi.ksi_timerid = id; 1040151576Sdavidxu } 1041151576Sdavidxu PROC_UNLOCK(p); 1042151576Sdavidxu *timerid = id; 1043151576Sdavidxu return (0); 1044151576Sdavidxu 1045151576Sdavidxuout: 1046151576Sdavidxu ITIMER_LOCK(it); 1047151576Sdavidxu CLOCK_CALL(it->it_clockid, timer_delete, (it)); 1048151576Sdavidxu ITIMER_UNLOCK(it); 1049151576Sdavidxu uma_zfree(itimer_zone, it); 1050151576Sdavidxu return (error); 1051151576Sdavidxu} 1052151576Sdavidxu 1053151576Sdavidxu#ifndef _SYS_SYSPROTO_H_ 1054151576Sdavidxustruct timer_delete_args { 1055151576Sdavidxu timer_t timerid; 1056151576Sdavidxu}; 1057151576Sdavidxu#endif 1058151576Sdavidxu 1059151576Sdavidxuint 1060151576Sdavidxutimer_delete(struct thread *td, struct timer_delete_args *uap) 1061151576Sdavidxu{ 1062151576Sdavidxu return (kern_timer_delete(td, uap->timerid)); 1063151576Sdavidxu} 1064151576Sdavidxu 1065151576Sdavidxustatic struct itimer * 1066151576Sdavidxuitimer_find(struct proc *p, timer_t timerid, int include_deleting) 1067151576Sdavidxu{ 1068151576Sdavidxu struct itimer *it; 1069151576Sdavidxu 1070151576Sdavidxu PROC_LOCK_ASSERT(p, MA_OWNED); 1071151585Sdavidxu if ((p->p_itimers == NULL) || (timerid >= TIMER_MAX) || 1072151585Sdavidxu (it = p->p_itimers->its_timers[timerid]) == NULL) { 1073151576Sdavidxu return (NULL); 1074151576Sdavidxu } 1075151576Sdavidxu ITIMER_LOCK(it); 1076151576Sdavidxu if (!include_deleting && (it->it_flags & ITF_DELETING) != 0) { 1077151576Sdavidxu ITIMER_UNLOCK(it); 1078151576Sdavidxu it = NULL; 1079151576Sdavidxu } 1080151576Sdavidxu return (it); 1081151576Sdavidxu} 1082151576Sdavidxu 1083151576Sdavidxustatic int 1084151576Sdavidxukern_timer_delete(struct thread *td, timer_t timerid) 1085151576Sdavidxu{ 1086151576Sdavidxu struct proc *p = td->td_proc; 1087151576Sdavidxu struct itimer *it; 1088151576Sdavidxu 1089151576Sdavidxu PROC_LOCK(p); 1090151576Sdavidxu it = itimer_find(p, timerid, 0); 1091151576Sdavidxu if (it == NULL) { 1092151576Sdavidxu PROC_UNLOCK(p); 1093151576Sdavidxu return (EINVAL); 1094151576Sdavidxu } 1095151576Sdavidxu PROC_UNLOCK(p); 1096151576Sdavidxu 1097151576Sdavidxu it->it_flags |= ITF_DELETING; 1098151576Sdavidxu while (it->it_usecount > 0) { 1099151576Sdavidxu it->it_flags |= ITF_WANTED; 1100151576Sdavidxu msleep(it, &it->it_mtx, PPAUSE, "itimer", 0); 1101151576Sdavidxu } 1102151576Sdavidxu it->it_flags &= ~ITF_WANTED; 1103151576Sdavidxu CLOCK_CALL(it->it_clockid, timer_delete, (it)); 1104151576Sdavidxu ITIMER_UNLOCK(it); 1105151576Sdavidxu 1106151576Sdavidxu PROC_LOCK(p); 1107151576Sdavidxu if (KSI_ONQ(&it->it_ksi)) 1108151576Sdavidxu sigqueue_take(&it->it_ksi); 1109151585Sdavidxu p->p_itimers->its_timers[timerid] = NULL; 1110151576Sdavidxu PROC_UNLOCK(p); 1111151576Sdavidxu uma_zfree(itimer_zone, it); 1112151576Sdavidxu return (0); 1113151576Sdavidxu} 1114151576Sdavidxu 1115151576Sdavidxu#ifndef _SYS_SYSPROTO_H_ 1116151576Sdavidxustruct timer_settime_args { 1117151576Sdavidxu timer_t timerid; 1118151576Sdavidxu int flags; 1119151576Sdavidxu const struct itimerspec * value; 1120151576Sdavidxu struct itimerspec * ovalue; 1121151576Sdavidxu}; 1122151576Sdavidxu#endif 1123151576Sdavidxu 1124151576Sdavidxuint 1125151576Sdavidxutimer_settime(struct thread *td, struct timer_settime_args *uap) 1126151576Sdavidxu{ 1127151576Sdavidxu struct proc *p = td->td_proc; 1128151576Sdavidxu struct itimer *it; 1129151576Sdavidxu struct itimerspec val, oval, *ovalp; 1130151576Sdavidxu int error; 1131151576Sdavidxu 1132151576Sdavidxu error = copyin(uap->value, &val, sizeof(val)); 1133151576Sdavidxu if (error != 0) 1134151576Sdavidxu return (error); 1135151576Sdavidxu 1136151576Sdavidxu if (uap->ovalue != NULL) 1137151576Sdavidxu ovalp = &oval; 1138151576Sdavidxu else 1139151576Sdavidxu ovalp = NULL; 1140151576Sdavidxu 1141151576Sdavidxu PROC_LOCK(p); 1142151576Sdavidxu if (uap->timerid < 3 || 1143151576Sdavidxu (it = itimer_find(p, uap->timerid, 0)) == NULL) { 1144151576Sdavidxu PROC_UNLOCK(p); 1145151576Sdavidxu error = EINVAL; 1146151576Sdavidxu } else { 1147151576Sdavidxu PROC_UNLOCK(p); 1148151576Sdavidxu itimer_enter(it); 1149151576Sdavidxu error = CLOCK_CALL(it->it_clockid, timer_settime, 1150151576Sdavidxu (it, uap->flags, &val, ovalp)); 1151151576Sdavidxu itimer_leave(it); 1152151576Sdavidxu ITIMER_UNLOCK(it); 1153151576Sdavidxu } 1154151576Sdavidxu if (error == 0 && uap->ovalue != NULL) 1155151576Sdavidxu error = copyout(ovalp, uap->ovalue, sizeof(*ovalp)); 1156151576Sdavidxu return (error); 1157151576Sdavidxu} 1158151576Sdavidxu 1159151576Sdavidxu#ifndef _SYS_SYSPROTO_H_ 1160151576Sdavidxustruct timer_gettime_args { 1161151576Sdavidxu timer_t timerid; 1162151576Sdavidxu struct itimerspec * value; 1163151576Sdavidxu}; 1164151576Sdavidxu#endif 1165151576Sdavidxu 1166151576Sdavidxuint 1167151576Sdavidxutimer_gettime(struct thread *td, struct timer_gettime_args *uap) 1168151576Sdavidxu{ 1169151576Sdavidxu struct proc *p = td->td_proc; 1170151576Sdavidxu struct itimer *it; 1171151576Sdavidxu struct itimerspec val; 1172151576Sdavidxu int error; 1173151576Sdavidxu 1174151576Sdavidxu PROC_LOCK(p); 1175151576Sdavidxu if (uap->timerid < 3 || 1176151576Sdavidxu (it = itimer_find(p, uap->timerid, 0)) == NULL) { 1177151576Sdavidxu PROC_UNLOCK(p); 1178151576Sdavidxu error = EINVAL; 1179151576Sdavidxu } else { 1180151576Sdavidxu PROC_UNLOCK(p); 1181151576Sdavidxu itimer_enter(it); 1182151576Sdavidxu error = CLOCK_CALL(it->it_clockid, timer_gettime, 1183151576Sdavidxu (it, &val)); 1184151576Sdavidxu itimer_leave(it); 1185151576Sdavidxu ITIMER_UNLOCK(it); 1186151576Sdavidxu } 1187151576Sdavidxu if (error == 0) 1188151576Sdavidxu error = copyout(&val, uap->value, sizeof(val)); 1189151576Sdavidxu return (error); 1190151576Sdavidxu} 1191151576Sdavidxu 1192151576Sdavidxu#ifndef _SYS_SYSPROTO_H_ 1193151576Sdavidxustruct timer_getoverrun_args { 1194151576Sdavidxu timer_t timerid; 1195151576Sdavidxu}; 1196151576Sdavidxu#endif 1197151576Sdavidxu 1198151576Sdavidxuint 1199151576Sdavidxutimer_getoverrun(struct thread *td, struct timer_getoverrun_args *uap) 1200151576Sdavidxu{ 1201151576Sdavidxu struct proc *p = td->td_proc; 1202151576Sdavidxu struct itimer *it; 1203151576Sdavidxu int error ; 1204151576Sdavidxu 1205151576Sdavidxu PROC_LOCK(p); 1206151576Sdavidxu if (uap->timerid < 3 || 1207151576Sdavidxu (it = itimer_find(p, uap->timerid, 0)) == NULL) { 1208151576Sdavidxu PROC_UNLOCK(p); 1209151576Sdavidxu error = EINVAL; 1210151576Sdavidxu } else { 1211151576Sdavidxu td->td_retval[0] = it->it_overrun_last; 1212151576Sdavidxu ITIMER_UNLOCK(it); 1213151869Sdavidxu PROC_UNLOCK(p); 1214151576Sdavidxu error = 0; 1215151576Sdavidxu } 1216151576Sdavidxu return (error); 1217151576Sdavidxu} 1218151576Sdavidxu 1219151576Sdavidxustatic int 1220151576Sdavidxurealtimer_create(struct itimer *it) 1221151576Sdavidxu{ 1222151576Sdavidxu callout_init_mtx(&it->it_callout, &it->it_mtx, 0); 1223151576Sdavidxu return (0); 1224151576Sdavidxu} 1225151576Sdavidxu 1226151576Sdavidxustatic int 1227151576Sdavidxurealtimer_delete(struct itimer *it) 1228151576Sdavidxu{ 1229151576Sdavidxu mtx_assert(&it->it_mtx, MA_OWNED); 1230151576Sdavidxu callout_stop(&it->it_callout); 1231151576Sdavidxu return (0); 1232151576Sdavidxu} 1233151576Sdavidxu 1234151576Sdavidxustatic int 1235151576Sdavidxurealtimer_gettime(struct itimer *it, struct itimerspec *ovalue) 1236151576Sdavidxu{ 1237151869Sdavidxu struct timespec cts; 1238151576Sdavidxu 1239151576Sdavidxu mtx_assert(&it->it_mtx, MA_OWNED); 1240151576Sdavidxu 1241151869Sdavidxu realtimer_clocktime(it->it_clockid, &cts); 1242151869Sdavidxu *ovalue = it->it_time; 1243151576Sdavidxu if (ovalue->it_value.tv_sec != 0 || ovalue->it_value.tv_nsec != 0) { 1244151869Sdavidxu timespecsub(&ovalue->it_value, &cts); 1245151576Sdavidxu if (ovalue->it_value.tv_sec < 0 || 1246151576Sdavidxu (ovalue->it_value.tv_sec == 0 && 1247151576Sdavidxu ovalue->it_value.tv_nsec == 0)) { 1248151576Sdavidxu ovalue->it_value.tv_sec = 0; 1249151576Sdavidxu ovalue->it_value.tv_nsec = 1; 1250151576Sdavidxu } 1251151576Sdavidxu } 1252151576Sdavidxu return (0); 1253151576Sdavidxu} 1254151576Sdavidxu 1255151576Sdavidxustatic int 1256151576Sdavidxurealtimer_settime(struct itimer *it, int flags, 1257151576Sdavidxu struct itimerspec *value, struct itimerspec *ovalue) 1258151576Sdavidxu{ 1259151869Sdavidxu struct timespec cts, ts; 1260151869Sdavidxu struct timeval tv; 1261151869Sdavidxu struct itimerspec val; 1262151576Sdavidxu 1263151576Sdavidxu mtx_assert(&it->it_mtx, MA_OWNED); 1264151576Sdavidxu 1265151869Sdavidxu val = *value; 1266151869Sdavidxu if (itimespecfix(&val.it_value)) 1267151576Sdavidxu return (EINVAL); 1268151576Sdavidxu 1269151869Sdavidxu if (timespecisset(&val.it_value)) { 1270151869Sdavidxu if (itimespecfix(&val.it_interval)) 1271151576Sdavidxu return (EINVAL); 1272151576Sdavidxu } else { 1273151869Sdavidxu timespecclear(&val.it_interval); 1274151576Sdavidxu } 1275151576Sdavidxu 1276151576Sdavidxu if (ovalue != NULL) 1277151576Sdavidxu realtimer_gettime(it, ovalue); 1278151576Sdavidxu 1279151576Sdavidxu it->it_time = val; 1280151869Sdavidxu if (timespecisset(&val.it_value)) { 1281151869Sdavidxu realtimer_clocktime(it->it_clockid, &cts); 1282151869Sdavidxu ts = val.it_value; 1283151576Sdavidxu if ((flags & TIMER_ABSTIME) == 0) { 1284151576Sdavidxu /* Convert to absolute time. */ 1285151869Sdavidxu timespecadd(&it->it_time.it_value, &cts); 1286151576Sdavidxu } else { 1287151869Sdavidxu timespecsub(&ts, &cts); 1288151576Sdavidxu /* 1289151869Sdavidxu * We don't care if ts is negative, tztohz will 1290151576Sdavidxu * fix it. 1291151576Sdavidxu */ 1292151576Sdavidxu } 1293151869Sdavidxu TIMESPEC_TO_TIMEVAL(&tv, &ts); 1294151869Sdavidxu callout_reset(&it->it_callout, tvtohz(&tv), 1295151576Sdavidxu realtimer_expire, it); 1296151576Sdavidxu } else { 1297151576Sdavidxu callout_stop(&it->it_callout); 1298151576Sdavidxu } 1299151576Sdavidxu 1300151576Sdavidxu return (0); 1301151576Sdavidxu} 1302151576Sdavidxu 1303151576Sdavidxustatic void 1304151869Sdavidxurealtimer_clocktime(clockid_t id, struct timespec *ts) 1305151576Sdavidxu{ 1306151576Sdavidxu if (id == CLOCK_REALTIME) 1307151869Sdavidxu getnanotime(ts); 1308151576Sdavidxu else /* CLOCK_MONOTONIC */ 1309151869Sdavidxu getnanouptime(ts); 1310151576Sdavidxu} 1311151576Sdavidxu 1312151869Sdavidxuint 1313151869Sdavidxuitimer_accept(struct proc *p, timer_t timerid, ksiginfo_t *ksi) 1314151869Sdavidxu{ 1315151869Sdavidxu struct itimer *it; 1316151869Sdavidxu 1317151869Sdavidxu PROC_LOCK_ASSERT(p, MA_OWNED); 1318151869Sdavidxu it = itimer_find(p, timerid, 0); 1319151869Sdavidxu if (it != NULL) { 1320151869Sdavidxu ksi->ksi_overrun = it->it_overrun; 1321151869Sdavidxu it->it_overrun_last = it->it_overrun; 1322151869Sdavidxu it->it_overrun = 0; 1323151869Sdavidxu ITIMER_UNLOCK(it); 1324151869Sdavidxu return (0); 1325151869Sdavidxu } 1326151869Sdavidxu return (EINVAL); 1327151869Sdavidxu} 1328151869Sdavidxu 1329151869Sdavidxuint 1330151869Sdavidxuitimespecfix(struct timespec *ts) 1331151869Sdavidxu{ 1332151869Sdavidxu 1333151869Sdavidxu if (ts->tv_sec < 0 || ts->tv_nsec < 0 || ts->tv_nsec >= 1000000000) 1334151869Sdavidxu return (EINVAL); 1335151869Sdavidxu if (ts->tv_sec == 0 && ts->tv_nsec != 0 && ts->tv_nsec < tick * 1000) 1336151869Sdavidxu ts->tv_nsec = tick * 1000; 1337151869Sdavidxu return (0); 1338151869Sdavidxu} 1339151869Sdavidxu 1340151576Sdavidxustatic void 1341151576Sdavidxurealtimer_event_hook(struct proc *p, clockid_t clock_id, int event) 1342151576Sdavidxu{ 1343151576Sdavidxu struct itimers *its; 1344151576Sdavidxu struct itimer *it; 1345151576Sdavidxu int i; 1346151576Sdavidxu 1347151576Sdavidxu /* 1348151576Sdavidxu * Timer 0 (ITIMER_REAL) is XSI interval timer, according to POSIX 1349151576Sdavidxu * specification, it should be inherited by new process image. 1350151576Sdavidxu */ 1351151576Sdavidxu if (event == ITIMER_EV_EXEC) 1352151576Sdavidxu i = 1; 1353151576Sdavidxu else 1354151576Sdavidxu i = 0; 1355151585Sdavidxu its = p->p_itimers; 1356151576Sdavidxu for (; i < TIMER_MAX; i++) { 1357151576Sdavidxu if ((it = its->its_timers[i]) != NULL && 1358151576Sdavidxu it->it_clockid == clock_id) { 1359151576Sdavidxu ITIMER_LOCK(it); 1360151576Sdavidxu callout_stop(&it->it_callout); 1361151576Sdavidxu ITIMER_UNLOCK(it); 1362151576Sdavidxu } 1363151576Sdavidxu } 1364151576Sdavidxu} 1365151576Sdavidxu 1366151576Sdavidxu/* Timeout callback for realtime timer */ 1367151576Sdavidxustatic void 1368151576Sdavidxurealtimer_expire(void *arg) 1369151576Sdavidxu{ 1370151869Sdavidxu struct timespec cts, ts; 1371151869Sdavidxu struct timeval tv; 1372151576Sdavidxu struct itimer *it; 1373151576Sdavidxu struct proc *p; 1374151576Sdavidxu 1375151576Sdavidxu it = (struct itimer *)arg; 1376151576Sdavidxu p = it->it_proc; 1377151576Sdavidxu 1378151869Sdavidxu realtimer_clocktime(it->it_clockid, &cts); 1379151576Sdavidxu /* Only fire if time is reached. */ 1380151869Sdavidxu if (timespeccmp(&cts, &it->it_time.it_value, >=)) { 1381151869Sdavidxu if (timespecisset(&it->it_time.it_interval)) { 1382151869Sdavidxu timespecadd(&it->it_time.it_value, 1383151869Sdavidxu &it->it_time.it_interval); 1384151869Sdavidxu while (timespeccmp(&cts, &it->it_time.it_value, >=)) { 1385151576Sdavidxu it->it_overrun++; 1386151869Sdavidxu timespecadd(&it->it_time.it_value, 1387151869Sdavidxu &it->it_time.it_interval); 1388151576Sdavidxu } 1389151576Sdavidxu } else { 1390151576Sdavidxu /* single shot timer ? */ 1391151869Sdavidxu timespecclear(&it->it_time.it_value); 1392151576Sdavidxu } 1393151869Sdavidxu if (timespecisset(&it->it_time.it_value)) { 1394151869Sdavidxu ts = it->it_time.it_value; 1395151869Sdavidxu timespecsub(&ts, &cts); 1396151869Sdavidxu TIMESPEC_TO_TIMEVAL(&tv, &ts); 1397151869Sdavidxu callout_reset(&it->it_callout, tvtohz(&tv), 1398151576Sdavidxu realtimer_expire, it); 1399151576Sdavidxu } 1400151576Sdavidxu ITIMER_UNLOCK(it); 1401151576Sdavidxu itimer_fire(it); 1402151576Sdavidxu ITIMER_LOCK(it); 1403151869Sdavidxu } else if (timespecisset(&it->it_time.it_value)) { 1404151869Sdavidxu ts = it->it_time.it_value; 1405151869Sdavidxu timespecsub(&ts, &cts); 1406151869Sdavidxu TIMESPEC_TO_TIMEVAL(&tv, &ts); 1407151869Sdavidxu callout_reset(&it->it_callout, tvtohz(&tv), realtimer_expire, 1408151576Sdavidxu it); 1409151576Sdavidxu } 1410151576Sdavidxu} 1411151576Sdavidxu 1412151576Sdavidxuvoid 1413151576Sdavidxuitimer_fire(struct itimer *it) 1414151576Sdavidxu{ 1415151576Sdavidxu struct proc *p = it->it_proc; 1416151993Sdavidxu int ret; 1417151576Sdavidxu 1418151869Sdavidxu if (it->it_sigev.sigev_notify == SIGEV_SIGNAL || 1419151869Sdavidxu it->it_sigev.sigev_notify == SIGEV_THREAD_ID) { 1420151576Sdavidxu PROC_LOCK(p); 1421151993Sdavidxu if (!KSI_ONQ(&it->it_ksi)) { 1422151993Sdavidxu ret = psignal_event(p, &it->it_sigev, &it->it_ksi); 1423151993Sdavidxu if (__predict_false(ret != 0)) { 1424151993Sdavidxu it->it_overrun++; 1425151993Sdavidxu /* 1426151993Sdavidxu * Broken userland code, thread went 1427151993Sdavidxu * away, disarm the timer. 1428151869Sdavidxu */ 1429151993Sdavidxu if (ret == ESRCH) { 1430151869Sdavidxu ITIMER_LOCK(it); 1431151869Sdavidxu timespecclear(&it->it_time.it_value); 1432151869Sdavidxu timespecclear(&it->it_time.it_interval); 1433151869Sdavidxu callout_stop(&it->it_callout); 1434151869Sdavidxu ITIMER_UNLOCK(it); 1435151869Sdavidxu } 1436151869Sdavidxu } 1437151993Sdavidxu } else { 1438151993Sdavidxu it->it_overrun++; 1439151576Sdavidxu } 1440151576Sdavidxu PROC_UNLOCK(p); 1441151576Sdavidxu } 1442151576Sdavidxu} 1443151576Sdavidxu 1444151576Sdavidxustatic void 1445151576Sdavidxuitimers_alloc(struct proc *p) 1446151576Sdavidxu{ 1447151585Sdavidxu struct itimers *its; 1448151585Sdavidxu int i; 1449151576Sdavidxu 1450151585Sdavidxu its = malloc(sizeof (struct itimers), M_SUBPROC, M_WAITOK | M_ZERO); 1451151585Sdavidxu LIST_INIT(&its->its_virtual); 1452151585Sdavidxu LIST_INIT(&its->its_prof); 1453151585Sdavidxu TAILQ_INIT(&its->its_worklist); 1454151585Sdavidxu for (i = 0; i < TIMER_MAX; i++) 1455151585Sdavidxu its->its_timers[i] = NULL; 1456151576Sdavidxu PROC_LOCK(p); 1457151585Sdavidxu if (p->p_itimers == NULL) { 1458151585Sdavidxu p->p_itimers = its; 1459151576Sdavidxu PROC_UNLOCK(p); 1460151585Sdavidxu } 1461151585Sdavidxu else { 1462151576Sdavidxu PROC_UNLOCK(p); 1463151585Sdavidxu free(its, M_SUBPROC); 1464151576Sdavidxu } 1465151576Sdavidxu} 1466151576Sdavidxu 1467151576Sdavidxu/* Clean up timers when some process events are being triggered. */ 1468151576Sdavidxuvoid 1469151576Sdavidxuitimers_event_hook(struct proc *p, int event) 1470151576Sdavidxu{ 1471151576Sdavidxu struct itimers *its; 1472151576Sdavidxu struct itimer *it; 1473151576Sdavidxu int i; 1474151576Sdavidxu 1475151585Sdavidxu if (p->p_itimers != NULL) { 1476151585Sdavidxu its = p->p_itimers; 1477151576Sdavidxu for (i = 0; i < MAX_CLOCKS; ++i) { 1478151576Sdavidxu if (posix_clocks[i].event_hook != NULL) 1479151576Sdavidxu CLOCK_CALL(i, event_hook, (p, i, event)); 1480151576Sdavidxu } 1481151576Sdavidxu /* 1482151576Sdavidxu * According to susv3, XSI interval timers should be inherited 1483151576Sdavidxu * by new image. 1484151576Sdavidxu */ 1485151576Sdavidxu if (event == ITIMER_EV_EXEC) 1486151576Sdavidxu i = 3; 1487151576Sdavidxu else if (event == ITIMER_EV_EXIT) 1488151576Sdavidxu i = 0; 1489151576Sdavidxu else 1490151576Sdavidxu panic("unhandled event"); 1491151576Sdavidxu for (; i < TIMER_MAX; ++i) { 1492151576Sdavidxu if ((it = its->its_timers[i]) != NULL) { 1493151576Sdavidxu PROC_LOCK(p); 1494151576Sdavidxu if (KSI_ONQ(&it->it_ksi)) 1495151576Sdavidxu sigqueue_take(&it->it_ksi); 1496151576Sdavidxu PROC_UNLOCK(p); 1497151576Sdavidxu uma_zfree(itimer_zone, its->its_timers[i]); 1498151576Sdavidxu its->its_timers[i] = NULL; 1499151576Sdavidxu } 1500151576Sdavidxu } 1501151576Sdavidxu if (its->its_timers[0] == NULL && 1502151576Sdavidxu its->its_timers[1] == NULL && 1503151576Sdavidxu its->its_timers[2] == NULL) { 1504151585Sdavidxu free(its, M_SUBPROC); 1505151585Sdavidxu p->p_itimers = NULL; 1506151576Sdavidxu } 1507151576Sdavidxu } 1508151576Sdavidxu} 1509