kern_time.c revision 152844
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 152844 2005-11-27 00:55:18Z rwatson $"); 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) { 210152844Srwatson case CLOCK_REALTIME: /* Default to precise. */ 211152844Srwatson case CLOCK_REALTIME_PRECISE: 212151357Sps nanotime(ats); 213130654Skbyanc break; 214152844Srwatson case CLOCK_REALTIME_FAST: 215152844Srwatson getnanotime(ats); 216152844Srwatson break; 217130654Skbyanc case CLOCK_VIRTUAL: 218136152Sjhb PROC_LOCK(p); 219136152Sjhb calcru(p, &user, &sys); 220136152Sjhb PROC_UNLOCK(p); 221151357Sps TIMEVAL_TO_TIMESPEC(&user, ats); 222130654Skbyanc break; 223130654Skbyanc case CLOCK_PROF: 224136152Sjhb PROC_LOCK(p); 225136152Sjhb calcru(p, &user, &sys); 226136152Sjhb PROC_UNLOCK(p); 227130884Skbyanc timevaladd(&user, &sys); 228151357Sps TIMEVAL_TO_TIMESPEC(&user, ats); 229130654Skbyanc break; 230152844Srwatson case CLOCK_MONOTONIC: /* Default to precise. */ 231152844Srwatson case CLOCK_MONOTONIC_PRECISE: 232152585Sandre case CLOCK_UPTIME: 233152844Srwatson case CLOCK_UPTIME_PRECISE: 234151357Sps nanouptime(ats); 235130884Skbyanc break; 236152844Srwatson case CLOCK_UPTIME_FAST: 237152844Srwatson case CLOCK_MONOTONIC_FAST: 238152844Srwatson getnanouptime(ats); 239152844Srwatson break; 240152844Srwatson case CLOCK_SECOND: 241152844Srwatson ats->tv_sec = time_second; 242152844Srwatson ats->tv_nsec = 0; 243152844Srwatson break; 244130654Skbyanc default: 245111315Sphk return (EINVAL); 246130654Skbyanc } 247151357Sps return (0); 24825583Speter} 24925583Speter 25025583Speter#ifndef _SYS_SYSPROTO_H_ 25125583Speterstruct clock_settime_args { 25225583Speter clockid_t clock_id; 25325583Speter const struct timespec *tp; 25425583Speter}; 25525583Speter#endif 25625656Speter 25782746Sdillon/* 25882746Sdillon * MPSAFE 25982746Sdillon */ 26025583Speter/* ARGSUSED */ 26125583Speterint 262102074Sphkclock_settime(struct thread *td, struct clock_settime_args *uap) 26325583Speter{ 26425583Speter struct timespec ats; 26525583Speter int error; 26625583Speter 267151357Sps if ((error = copyin(uap->tp, &ats, sizeof(ats))) != 0) 268151357Sps return (error); 269151357Sps return (kern_clock_settime(td, uap->clock_id, &ats)); 270151357Sps} 271151357Sps 272151357Spsint 273151357Spskern_clock_settime(struct thread *td, clockid_t clock_id, struct timespec *ats) 274151357Sps{ 275151357Sps struct timeval atv; 276151357Sps int error; 277151357Sps 278106369Srwatson#ifdef MAC 279106369Srwatson error = mac_check_system_settime(td->td_ucred); 280106369Srwatson if (error) 281106369Srwatson return (error); 282106369Srwatson#endif 28393593Sjhb if ((error = suser(td)) != 0) 28494343Sjhb return (error); 285151357Sps if (clock_id != CLOCK_REALTIME) 28694343Sjhb return (EINVAL); 287151357Sps if (ats->tv_nsec < 0 || ats->tv_nsec >= 1000000000) 28894343Sjhb return (EINVAL); 28934901Sphk /* XXX Don't convert nsec->usec and back */ 290151357Sps TIMESPEC_TO_TIMEVAL(&atv, ats); 29194343Sjhb error = settime(td, &atv); 29282746Sdillon return (error); 29325583Speter} 29425583Speter 29525583Speter#ifndef _SYS_SYSPROTO_H_ 29625583Speterstruct clock_getres_args { 29725583Speter clockid_t clock_id; 29825583Speter struct timespec *tp; 29925583Speter}; 30025583Speter#endif 30125656Speter 30225583Speterint 303102074Sphkclock_getres(struct thread *td, struct clock_getres_args *uap) 30425583Speter{ 30525583Speter struct timespec ts; 306151357Sps int error; 30725583Speter 308151357Sps if (uap->tp == NULL) 309151357Sps return (0); 310151357Sps 311151357Sps error = kern_clock_getres(td, uap->clock_id, &ts); 312151357Sps if (error == 0) 313151357Sps error = copyout(&ts, uap->tp, sizeof(ts)); 314151357Sps return (error); 315151357Sps} 316151357Sps 317151357Spsint 318151357Spskern_clock_getres(struct thread *td, clockid_t clock_id, struct timespec *ts) 319151357Sps{ 320151357Sps 321151357Sps ts->tv_sec = 0; 322151357Sps switch (clock_id) { 323130654Skbyanc case CLOCK_REALTIME: 324152844Srwatson case CLOCK_REALTIME_FAST: 325152844Srwatson case CLOCK_REALTIME_PRECISE: 326130654Skbyanc case CLOCK_MONOTONIC: 327152844Srwatson case CLOCK_MONOTONIC_FAST: 328152844Srwatson case CLOCK_MONOTONIC_PRECISE: 329152585Sandre case CLOCK_UPTIME: 330152844Srwatson case CLOCK_UPTIME_FAST: 331152844Srwatson case CLOCK_UPTIME_PRECISE: 332103964Sbde /* 333103964Sbde * Round up the result of the division cheaply by adding 1. 334103964Sbde * Rounding up is especially important if rounding down 335103964Sbde * would give 0. Perfect rounding is unimportant. 336103964Sbde */ 337151357Sps ts->tv_nsec = 1000000000 / tc_getfrequency() + 1; 338130654Skbyanc break; 339130654Skbyanc case CLOCK_VIRTUAL: 340130654Skbyanc case CLOCK_PROF: 341130654Skbyanc /* Accurately round up here because we can do so cheaply. */ 342151357Sps ts->tv_nsec = (1000000000 + hz - 1) / hz; 343130654Skbyanc break; 344152844Srwatson case CLOCK_SECOND: 345152844Srwatson ts->tv_sec = 1; 346152844Srwatson ts->tv_nsec = 0; 347152844Srwatson break; 348130654Skbyanc default: 349130654Skbyanc return (EINVAL); 350130654Skbyanc } 351151357Sps return (0); 35225583Speter} 35325583Speter 35426335Speterstatic int nanowait; 35525656Speter 356140481Spsint 357140481Spskern_nanosleep(struct thread *td, struct timespec *rqt, struct timespec *rmt) 35825583Speter{ 35935045Sphk struct timespec ts, ts2, ts3; 36035042Sphk struct timeval tv; 36135042Sphk int error; 36225583Speter 36328773Sbde if (rqt->tv_nsec < 0 || rqt->tv_nsec >= 1000000000) 36425656Speter return (EINVAL); 36543301Sdillon if (rqt->tv_sec < 0 || (rqt->tv_sec == 0 && rqt->tv_nsec == 0)) 36628773Sbde return (0); 36736119Sphk getnanouptime(&ts); 36835029Sphk timespecadd(&ts, rqt); 36935042Sphk TIMESPEC_TO_TIMEVAL(&tv, rqt); 37035042Sphk for (;;) { 37135042Sphk error = tsleep(&nanowait, PWAIT | PCATCH, "nanslp", 37235042Sphk tvtohz(&tv)); 37336119Sphk getnanouptime(&ts2); 37435042Sphk if (error != EWOULDBLOCK) { 37535042Sphk if (error == ERESTART) 37635042Sphk error = EINTR; 37735042Sphk if (rmt != NULL) { 37835042Sphk timespecsub(&ts, &ts2); 37935042Sphk if (ts.tv_sec < 0) 38035042Sphk timespecclear(&ts); 38135042Sphk *rmt = ts; 38235042Sphk } 38335042Sphk return (error); 38435042Sphk } 38535029Sphk if (timespeccmp(&ts2, &ts, >=)) 38635042Sphk return (0); 38735045Sphk ts3 = ts; 38835045Sphk timespecsub(&ts3, &ts2); 38935045Sphk TIMESPEC_TO_TIMEVAL(&tv, &ts3); 39026335Speter } 39126335Speter} 39225583Speter 39326335Speter#ifndef _SYS_SYSPROTO_H_ 39426335Speterstruct nanosleep_args { 39526335Speter struct timespec *rqtp; 39626335Speter struct timespec *rmtp; 39726335Speter}; 39826335Speter#endif 39926335Speter 40082746Sdillon/* 40182746Sdillon * MPSAFE 40282746Sdillon */ 40326335Speter/* ARGSUSED */ 40426335Speterint 405102074Sphknanosleep(struct thread *td, struct nanosleep_args *uap) 40626335Speter{ 40726335Speter struct timespec rmt, rqt; 40882746Sdillon int error; 40926335Speter 410107849Salfred error = copyin(uap->rqtp, &rqt, sizeof(rqt)); 41126335Speter if (error) 41226335Speter return (error); 41382746Sdillon 414109521Salfred if (uap->rmtp && 415109521Salfred !useracc((caddr_t)uap->rmtp, sizeof(rmt), VM_PROT_WRITE)) 416109521Salfred return (EFAULT); 417140481Sps error = kern_nanosleep(td, &rqt, &rmt); 418107849Salfred if (error && uap->rmtp) { 41982746Sdillon int error2; 42082746Sdillon 421107849Salfred error2 = copyout(&rmt, uap->rmtp, sizeof(rmt)); 422109521Salfred if (error2) 42382746Sdillon error = error2; 42425583Speter } 42525656Speter return (error); 42625583Speter} 42725583Speter 42826335Speter#ifndef _SYS_SYSPROTO_H_ 4291541Srgrimesstruct gettimeofday_args { 4301541Srgrimes struct timeval *tp; 4311541Srgrimes struct timezone *tzp; 4321541Srgrimes}; 43312221Sbde#endif 43482746Sdillon/* 43582746Sdillon * MPSAFE 43682746Sdillon */ 4371541Srgrimes/* ARGSUSED */ 4381549Srgrimesint 439102074Sphkgettimeofday(struct thread *td, struct gettimeofday_args *uap) 4401541Srgrimes{ 4411541Srgrimes struct timeval atv; 442110286Stjr struct timezone rtz; 4431541Srgrimes int error = 0; 4441541Srgrimes 4451541Srgrimes if (uap->tp) { 4461541Srgrimes microtime(&atv); 44799012Salfred error = copyout(&atv, uap->tp, sizeof (atv)); 4481541Srgrimes } 44990836Sphk if (error == 0 && uap->tzp != NULL) { 450110299Sphk rtz.tz_minuteswest = tz_minuteswest; 451110299Sphk rtz.tz_dsttime = tz_dsttime; 452110286Stjr error = copyout(&rtz, uap->tzp, sizeof (rtz)); 45382746Sdillon } 4541541Srgrimes return (error); 4551541Srgrimes} 4561541Srgrimes 45712221Sbde#ifndef _SYS_SYSPROTO_H_ 4581541Srgrimesstruct settimeofday_args { 4591541Srgrimes struct timeval *tv; 4601541Srgrimes struct timezone *tzp; 4611541Srgrimes}; 46212221Sbde#endif 46382746Sdillon/* 46482746Sdillon * MPSAFE 46582746Sdillon */ 4661541Srgrimes/* ARGSUSED */ 4671549Srgrimesint 468102074Sphksettimeofday(struct thread *td, struct settimeofday_args *uap) 4691541Srgrimes{ 470144445Sjhb struct timeval atv, *tvp; 471144445Sjhb struct timezone atz, *tzp; 472144445Sjhb int error; 4731541Srgrimes 474144445Sjhb if (uap->tv) { 475144445Sjhb error = copyin(uap->tv, &atv, sizeof(atv)); 476144445Sjhb if (error) 477144445Sjhb return (error); 478144445Sjhb tvp = &atv; 479144445Sjhb } else 480144445Sjhb tvp = NULL; 481144445Sjhb if (uap->tzp) { 482144445Sjhb error = copyin(uap->tzp, &atz, sizeof(atz)); 483144445Sjhb if (error) 484144445Sjhb return (error); 485144445Sjhb tzp = &atz; 486144445Sjhb } else 487144445Sjhb tzp = NULL; 488144445Sjhb return (kern_settimeofday(td, tvp, tzp)); 489144445Sjhb} 490144445Sjhb 491144445Sjhbint 492144445Sjhbkern_settimeofday(struct thread *td, struct timeval *tv, struct timezone *tzp) 493144445Sjhb{ 494144445Sjhb int error; 495144445Sjhb 496106369Srwatson#ifdef MAC 497106369Srwatson error = mac_check_system_settime(td->td_ucred); 498106369Srwatson if (error) 499106369Srwatson return (error); 500106369Srwatson#endif 501144445Sjhb error = suser(td); 502144445Sjhb if (error) 50394343Sjhb return (error); 5041541Srgrimes /* Verify all parameters before changing time. */ 505144445Sjhb if (tv) { 506144445Sjhb if (tv->tv_usec < 0 || tv->tv_usec >= 1000000) 50794343Sjhb return (EINVAL); 508144445Sjhb error = settime(td, tv); 50925656Speter } 510144445Sjhb if (tzp && error == 0) { 511144445Sjhb tz_minuteswest = tzp->tz_minuteswest; 512144445Sjhb tz_dsttime = tzp->tz_dsttime; 51382746Sdillon } 51482746Sdillon return (error); 5151541Srgrimes} 516144445Sjhb 51782746Sdillon/* 5181541Srgrimes * Get value of an interval timer. The process virtual and 5191541Srgrimes * profiling virtual time timers are kept in the p_stats area, since 5201541Srgrimes * they can be swapped out. These are kept internally in the 5211541Srgrimes * way they are specified externally: in time until they expire. 5221541Srgrimes * 5231541Srgrimes * The real time interval timer is kept in the process table slot 5241541Srgrimes * for the process, and its value (it_value) is kept as an 5251541Srgrimes * absolute time rather than as a delta, so that it is easy to keep 5261541Srgrimes * periodic real-time signals from drifting. 5271541Srgrimes * 5281541Srgrimes * Virtual time timers are processed in the hardclock() routine of 5291541Srgrimes * kern_clock.c. The real time timer is processed by a timeout 5301541Srgrimes * routine, called from the softclock() routine. Since a callout 5311541Srgrimes * may be delayed in real time due to interrupt processing in the system, 5321541Srgrimes * it is possible for the real time timeout routine (realitexpire, given below), 5331541Srgrimes * to be delayed in real time past when it is supposed to occur. It 5341541Srgrimes * does not suffice, therefore, to reload the real timer .it_value from the 5351541Srgrimes * real time timers .it_interval. Rather, we compute the next time in 5361541Srgrimes * absolute time the timer should go off. 5371541Srgrimes */ 53812221Sbde#ifndef _SYS_SYSPROTO_H_ 5391541Srgrimesstruct getitimer_args { 5401541Srgrimes u_int which; 5411541Srgrimes struct itimerval *itv; 5421541Srgrimes}; 54312221Sbde#endif 54482746Sdillon/* 54582746Sdillon * MPSAFE 54682746Sdillon */ 5471549Srgrimesint 548102074Sphkgetitimer(struct thread *td, struct getitimer_args *uap) 5491541Srgrimes{ 550141470Sjhb struct itimerval aitv; 551140832Ssobomax int error; 552140832Ssobomax 553140832Ssobomax error = kern_getitimer(td, uap->which, &aitv); 554140832Ssobomax if (error != 0) 555140832Ssobomax return (error); 556140832Ssobomax return (copyout(&aitv, uap->itv, sizeof (struct itimerval))); 557140832Ssobomax} 558140832Ssobomax 559140832Ssobomaxint 560140832Ssobomaxkern_getitimer(struct thread *td, u_int which, struct itimerval *aitv) 561140832Ssobomax{ 56283366Sjulian struct proc *p = td->td_proc; 56334961Sphk struct timeval ctv; 5641541Srgrimes 565140832Ssobomax if (which > ITIMER_PROF) 5661541Srgrimes return (EINVAL); 56782746Sdillon 568140832Ssobomax if (which == ITIMER_REAL) { 5691541Srgrimes /* 57036128Sbde * Convert from absolute to relative time in .it_value 5711541Srgrimes * part of real time timer. If time for real time timer 5721541Srgrimes * has passed return 0, else return difference between 5731541Srgrimes * current time and time for the timer to go off. 5741541Srgrimes */ 575111034Stjr PROC_LOCK(p); 576140832Ssobomax *aitv = p->p_realtimer; 577111034Stjr PROC_UNLOCK(p); 578140832Ssobomax if (timevalisset(&aitv->it_value)) { 57936119Sphk getmicrouptime(&ctv); 580140832Ssobomax if (timevalcmp(&aitv->it_value, &ctv, <)) 581140832Ssobomax timevalclear(&aitv->it_value); 5821541Srgrimes else 583140832Ssobomax timevalsub(&aitv->it_value, &ctv); 58434961Sphk } 58582746Sdillon } else { 586111034Stjr mtx_lock_spin(&sched_lock); 587140832Ssobomax *aitv = p->p_stats->p_timer[which]; 588111034Stjr mtx_unlock_spin(&sched_lock); 58982746Sdillon } 590140832Ssobomax return (0); 5911541Srgrimes} 5921541Srgrimes 59312221Sbde#ifndef _SYS_SYSPROTO_H_ 5941541Srgrimesstruct setitimer_args { 5951541Srgrimes u_int which; 5961541Srgrimes struct itimerval *itv, *oitv; 5971541Srgrimes}; 59812221Sbde#endif 599140832Ssobomax 60082746Sdillon/* 60182746Sdillon * MPSAFE 60282746Sdillon */ 6031549Srgrimesint 604102074Sphksetitimer(struct thread *td, struct setitimer_args *uap) 6051541Srgrimes{ 606141470Sjhb struct itimerval aitv, oitv; 607140832Ssobomax int error; 6081541Srgrimes 609111034Stjr if (uap->itv == NULL) { 610111034Stjr uap->itv = uap->oitv; 611111034Stjr return (getitimer(td, (struct getitimer_args *)uap)); 612111034Stjr } 613111034Stjr 614111034Stjr if ((error = copyin(uap->itv, &aitv, sizeof(struct itimerval)))) 6151541Srgrimes return (error); 616140832Ssobomax error = kern_setitimer(td, uap->which, &aitv, &oitv); 617140832Ssobomax if (error != 0 || uap->oitv == NULL) 618140832Ssobomax return (error); 619140832Ssobomax return (copyout(&oitv, uap->oitv, sizeof(struct itimerval))); 620140832Ssobomax} 621140832Ssobomax 622140832Ssobomaxint 623141470Sjhbkern_setitimer(struct thread *td, u_int which, struct itimerval *aitv, 624141470Sjhb struct itimerval *oitv) 625140832Ssobomax{ 626140832Ssobomax struct proc *p = td->td_proc; 627140832Ssobomax struct timeval ctv; 628140832Ssobomax 629141483Sjhb if (aitv == NULL) 630141483Sjhb return (kern_getitimer(td, which, oitv)); 631141483Sjhb 632140832Ssobomax if (which > ITIMER_PROF) 633111034Stjr return (EINVAL); 634140832Ssobomax if (itimerfix(&aitv->it_value)) 635111034Stjr return (EINVAL); 636140832Ssobomax if (!timevalisset(&aitv->it_value)) 637140832Ssobomax timevalclear(&aitv->it_interval); 638140832Ssobomax else if (itimerfix(&aitv->it_interval)) 639140832Ssobomax return (EINVAL); 64082746Sdillon 641140832Ssobomax if (which == ITIMER_REAL) { 642111034Stjr PROC_LOCK(p); 64335058Sphk if (timevalisset(&p->p_realtimer.it_value)) 64469286Sjake callout_stop(&p->p_itcallout); 645114980Sjhb getmicrouptime(&ctv); 646140832Ssobomax if (timevalisset(&aitv->it_value)) { 647140832Ssobomax callout_reset(&p->p_itcallout, tvtohz(&aitv->it_value), 64869286Sjake realitexpire, p); 649140832Ssobomax timevaladd(&aitv->it_value, &ctv); 650114980Sjhb } 651140832Ssobomax *oitv = p->p_realtimer; 652140832Ssobomax p->p_realtimer = *aitv; 653111034Stjr PROC_UNLOCK(p); 654140832Ssobomax if (timevalisset(&oitv->it_value)) { 655140832Ssobomax if (timevalcmp(&oitv->it_value, &ctv, <)) 656140832Ssobomax timevalclear(&oitv->it_value); 657111034Stjr else 658140832Ssobomax timevalsub(&oitv->it_value, &ctv); 659111034Stjr } 66082746Sdillon } else { 661111034Stjr mtx_lock_spin(&sched_lock); 662140832Ssobomax *oitv = p->p_stats->p_timer[which]; 663140832Ssobomax p->p_stats->p_timer[which] = *aitv; 664111034Stjr mtx_unlock_spin(&sched_lock); 66582746Sdillon } 666140832Ssobomax return (0); 6671541Srgrimes} 6681541Srgrimes 6691541Srgrimes/* 6701541Srgrimes * Real interval timer expired: 6711541Srgrimes * send process whose timer expired an alarm signal. 6721541Srgrimes * If time is not set up to reload, then just return. 6731541Srgrimes * Else compute next time timer should go off which is > current time. 6741541Srgrimes * This is where delay in processing this timeout causes multiple 6751541Srgrimes * SIGALRM calls to be compressed into one. 67636127Sbde * tvtohz() always adds 1 to allow for the time until the next clock 6779327Sbde * interrupt being strictly less than 1 clock tick, but we don't want 6789327Sbde * that here since we want to appear to be in sync with the clock 6799327Sbde * interrupt even when we're delayed. 6801541Srgrimes */ 6811541Srgrimesvoid 682102074Sphkrealitexpire(void *arg) 6831541Srgrimes{ 684102074Sphk struct proc *p; 68535044Sphk struct timeval ctv, ntv; 6861541Srgrimes 6871541Srgrimes p = (struct proc *)arg; 68873916Sjhb PROC_LOCK(p); 6891541Srgrimes psignal(p, SIGALRM); 69035058Sphk if (!timevalisset(&p->p_realtimer.it_interval)) { 69135058Sphk timevalclear(&p->p_realtimer.it_value); 692116123Sjhb if (p->p_flag & P_WEXIT) 693116123Sjhb wakeup(&p->p_itcallout); 69473916Sjhb PROC_UNLOCK(p); 6951541Srgrimes return; 6961541Srgrimes } 6971541Srgrimes for (;;) { 6981541Srgrimes timevaladd(&p->p_realtimer.it_value, 6991541Srgrimes &p->p_realtimer.it_interval); 70036119Sphk getmicrouptime(&ctv); 70135058Sphk if (timevalcmp(&p->p_realtimer.it_value, &ctv, >)) { 70235044Sphk ntv = p->p_realtimer.it_value; 70335044Sphk timevalsub(&ntv, &ctv); 70469286Sjake callout_reset(&p->p_itcallout, tvtohz(&ntv) - 1, 70569286Sjake realitexpire, p); 70673916Sjhb PROC_UNLOCK(p); 7071541Srgrimes return; 7081541Srgrimes } 7091541Srgrimes } 71073916Sjhb /*NOTREACHED*/ 7111541Srgrimes} 7121541Srgrimes 7131541Srgrimes/* 7141541Srgrimes * Check that a proposed value to load into the .it_value or 7151541Srgrimes * .it_interval part of an interval timer is acceptable, and 7161541Srgrimes * fix it to have at least minimal value (i.e. if it is less 7171541Srgrimes * than the resolution of the clock, round it up.) 7181541Srgrimes */ 7191549Srgrimesint 720102074Sphkitimerfix(struct timeval *tv) 7211541Srgrimes{ 7221541Srgrimes 723151576Sdavidxu if (tv->tv_sec < 0 || tv->tv_usec < 0 || tv->tv_usec >= 1000000) 7241541Srgrimes return (EINVAL); 7251541Srgrimes if (tv->tv_sec == 0 && tv->tv_usec != 0 && tv->tv_usec < tick) 7261541Srgrimes tv->tv_usec = tick; 7271541Srgrimes return (0); 7281541Srgrimes} 7291541Srgrimes 7301541Srgrimes/* 7311541Srgrimes * Decrement an interval timer by a specified number 7321541Srgrimes * of microseconds, which must be less than a second, 7331541Srgrimes * i.e. < 1000000. If the timer expires, then reload 7341541Srgrimes * it. In this case, carry over (usec - old value) to 7351541Srgrimes * reduce the value reloaded into the timer so that 7361541Srgrimes * the timer does not drift. This routine assumes 7371541Srgrimes * that it is called in a context where the timers 7381541Srgrimes * on which it is operating cannot change in value. 7391541Srgrimes */ 7401549Srgrimesint 741102074Sphkitimerdecr(struct itimerval *itp, int usec) 7421541Srgrimes{ 7431541Srgrimes 7441541Srgrimes if (itp->it_value.tv_usec < usec) { 7451541Srgrimes if (itp->it_value.tv_sec == 0) { 7461541Srgrimes /* expired, and already in next interval */ 7471541Srgrimes usec -= itp->it_value.tv_usec; 7481541Srgrimes goto expire; 7491541Srgrimes } 7501541Srgrimes itp->it_value.tv_usec += 1000000; 7511541Srgrimes itp->it_value.tv_sec--; 7521541Srgrimes } 7531541Srgrimes itp->it_value.tv_usec -= usec; 7541541Srgrimes usec = 0; 75535058Sphk if (timevalisset(&itp->it_value)) 7561541Srgrimes return (1); 7571541Srgrimes /* expired, exactly at end of interval */ 7581541Srgrimesexpire: 75935058Sphk if (timevalisset(&itp->it_interval)) { 7601541Srgrimes itp->it_value = itp->it_interval; 7611541Srgrimes itp->it_value.tv_usec -= usec; 7621541Srgrimes if (itp->it_value.tv_usec < 0) { 7631541Srgrimes itp->it_value.tv_usec += 1000000; 7641541Srgrimes itp->it_value.tv_sec--; 7651541Srgrimes } 7661541Srgrimes } else 7671541Srgrimes itp->it_value.tv_usec = 0; /* sec is already 0 */ 7681541Srgrimes return (0); 7691541Srgrimes} 7701541Srgrimes 7711541Srgrimes/* 7721541Srgrimes * Add and subtract routines for timevals. 7731541Srgrimes * N.B.: subtract routine doesn't deal with 7741541Srgrimes * results which are before the beginning, 7751541Srgrimes * it just gets very confused in this case. 7761541Srgrimes * Caveat emptor. 7771541Srgrimes */ 7781549Srgrimesvoid 779121523Salfredtimevaladd(struct timeval *t1, const struct timeval *t2) 7801541Srgrimes{ 7811541Srgrimes 7821541Srgrimes t1->tv_sec += t2->tv_sec; 7831541Srgrimes t1->tv_usec += t2->tv_usec; 7841541Srgrimes timevalfix(t1); 7851541Srgrimes} 7861541Srgrimes 7871549Srgrimesvoid 788121523Salfredtimevalsub(struct timeval *t1, const struct timeval *t2) 7891541Srgrimes{ 7901541Srgrimes 7911541Srgrimes t1->tv_sec -= t2->tv_sec; 7921541Srgrimes t1->tv_usec -= t2->tv_usec; 7931541Srgrimes timevalfix(t1); 7941541Srgrimes} 7951541Srgrimes 79612819Sphkstatic void 797102074Sphktimevalfix(struct timeval *t1) 7981541Srgrimes{ 7991541Srgrimes 8001541Srgrimes if (t1->tv_usec < 0) { 8011541Srgrimes t1->tv_sec--; 8021541Srgrimes t1->tv_usec += 1000000; 8031541Srgrimes } 8041541Srgrimes if (t1->tv_usec >= 1000000) { 8051541Srgrimes t1->tv_sec++; 8061541Srgrimes t1->tv_usec -= 1000000; 8071541Srgrimes } 8081541Srgrimes} 809108142Ssam 810108142Ssam/* 811108511Ssam * ratecheck(): simple time-based rate-limit checking. 812108142Ssam */ 813108142Ssamint 814108142Ssamratecheck(struct timeval *lasttime, const struct timeval *mininterval) 815108142Ssam{ 816108142Ssam struct timeval tv, delta; 817108142Ssam int rv = 0; 818108142Ssam 819108511Ssam getmicrouptime(&tv); /* NB: 10ms precision */ 820108511Ssam delta = tv; 821108511Ssam timevalsub(&delta, lasttime); 822108142Ssam 823108142Ssam /* 824108142Ssam * check for 0,0 is so that the message will be seen at least once, 825108142Ssam * even if interval is huge. 826108142Ssam */ 827108142Ssam if (timevalcmp(&delta, mininterval, >=) || 828108142Ssam (lasttime->tv_sec == 0 && lasttime->tv_usec == 0)) { 829108142Ssam *lasttime = tv; 830108142Ssam rv = 1; 831108142Ssam } 832108142Ssam 833108142Ssam return (rv); 834108142Ssam} 835108142Ssam 836108142Ssam/* 837108142Ssam * ppsratecheck(): packets (or events) per second limitation. 838108511Ssam * 839108511Ssam * Return 0 if the limit is to be enforced (e.g. the caller 840108511Ssam * should drop a packet because of the rate limitation). 841108511Ssam * 842111558Ssam * maxpps of 0 always causes zero to be returned. maxpps of -1 843111558Ssam * always causes 1 to be returned; this effectively defeats rate 844111558Ssam * limiting. 845111558Ssam * 846108511Ssam * Note that we maintain the struct timeval for compatibility 847108511Ssam * with other bsd systems. We reuse the storage and just monitor 848108511Ssam * clock ticks for minimal overhead. 849108142Ssam */ 850108142Ssamint 851108142Ssamppsratecheck(struct timeval *lasttime, int *curpps, int maxpps) 852108142Ssam{ 853108511Ssam int now; 854108142Ssam 855108142Ssam /* 856108511Ssam * Reset the last time and counter if this is the first call 857108511Ssam * or more than a second has passed since the last update of 858108511Ssam * lasttime. 859108142Ssam */ 860108511Ssam now = ticks; 861108511Ssam if (lasttime->tv_sec == 0 || (u_int)(now - lasttime->tv_sec) >= hz) { 862108511Ssam lasttime->tv_sec = now; 863108511Ssam *curpps = 1; 864111558Ssam return (maxpps != 0); 865108511Ssam } else { 866108511Ssam (*curpps)++; /* NB: ignore potential overflow */ 867108511Ssam return (maxpps < 0 || *curpps < maxpps); 868108511Ssam } 869108142Ssam} 870151576Sdavidxu 871151576Sdavidxustatic void 872151576Sdavidxuitimer_start(void) 873151576Sdavidxu{ 874151576Sdavidxu struct kclock rt_clock = { 875151576Sdavidxu .timer_create = realtimer_create, 876151576Sdavidxu .timer_delete = realtimer_delete, 877151576Sdavidxu .timer_settime = realtimer_settime, 878151576Sdavidxu .timer_gettime = realtimer_gettime, 879151576Sdavidxu .event_hook = realtimer_event_hook 880151576Sdavidxu }; 881151576Sdavidxu 882151576Sdavidxu itimer_zone = uma_zcreate("itimer", sizeof(struct itimer), 883151576Sdavidxu NULL, NULL, itimer_init, itimer_fini, UMA_ALIGN_PTR, 0); 884151576Sdavidxu register_posix_clock(CLOCK_REALTIME, &rt_clock); 885151576Sdavidxu register_posix_clock(CLOCK_MONOTONIC, &rt_clock); 886151576Sdavidxu} 887151576Sdavidxu 888151576Sdavidxuint 889151576Sdavidxuregister_posix_clock(int clockid, struct kclock *clk) 890151576Sdavidxu{ 891151576Sdavidxu if ((unsigned)clockid >= MAX_CLOCKS) { 892151576Sdavidxu printf("%s: invalid clockid\n", __func__); 893151576Sdavidxu return (0); 894151576Sdavidxu } 895151576Sdavidxu posix_clocks[clockid] = *clk; 896151576Sdavidxu return (1); 897151576Sdavidxu} 898151576Sdavidxu 899151576Sdavidxustatic int 900151576Sdavidxuitimer_init(void *mem, int size, int flags) 901151576Sdavidxu{ 902151576Sdavidxu struct itimer *it; 903151576Sdavidxu 904151576Sdavidxu it = (struct itimer *)mem; 905151576Sdavidxu mtx_init(&it->it_mtx, "itimer lock", NULL, MTX_DEF); 906151576Sdavidxu return (0); 907151576Sdavidxu} 908151576Sdavidxu 909151576Sdavidxustatic void 910151576Sdavidxuitimer_fini(void *mem, int size) 911151576Sdavidxu{ 912151576Sdavidxu struct itimer *it; 913151576Sdavidxu 914151576Sdavidxu it = (struct itimer *)mem; 915151576Sdavidxu mtx_destroy(&it->it_mtx); 916151576Sdavidxu} 917151576Sdavidxu 918151576Sdavidxustatic void 919151576Sdavidxuitimer_enter(struct itimer *it) 920151576Sdavidxu{ 921151576Sdavidxu 922151576Sdavidxu mtx_assert(&it->it_mtx, MA_OWNED); 923151576Sdavidxu it->it_usecount++; 924151576Sdavidxu} 925151576Sdavidxu 926151576Sdavidxustatic void 927151576Sdavidxuitimer_leave(struct itimer *it) 928151576Sdavidxu{ 929151576Sdavidxu 930151576Sdavidxu mtx_assert(&it->it_mtx, MA_OWNED); 931151576Sdavidxu KASSERT(it->it_usecount > 0, ("invalid it_usecount")); 932151576Sdavidxu 933151576Sdavidxu if (--it->it_usecount == 0 && (it->it_flags & ITF_WANTED) != 0) 934151576Sdavidxu wakeup(it); 935151576Sdavidxu} 936151576Sdavidxu 937151576Sdavidxu#ifndef _SYS_SYSPROTO_H_ 938151576Sdavidxustruct timer_create_args { 939151576Sdavidxu clockid_t clock_id; 940151576Sdavidxu struct sigevent * evp; 941151576Sdavidxu timer_t * timerid; 942151576Sdavidxu}; 943151576Sdavidxu#endif 944151576Sdavidxu 945151576Sdavidxuint 946151576Sdavidxutimer_create(struct thread *td, struct timer_create_args *uap) 947151576Sdavidxu{ 948151576Sdavidxu struct sigevent *evp1, ev; 949151576Sdavidxu timer_t id; 950151576Sdavidxu int error; 951151576Sdavidxu 952151576Sdavidxu if (uap->evp != NULL) { 953151576Sdavidxu error = copyin(uap->evp, &ev, sizeof(ev)); 954151576Sdavidxu if (error != 0) 955151576Sdavidxu return (error); 956151576Sdavidxu evp1 = &ev; 957151576Sdavidxu } else 958151576Sdavidxu evp1 = NULL; 959151576Sdavidxu 960151576Sdavidxu error = kern_timer_create(td, uap->clock_id, evp1, &id, -1); 961151576Sdavidxu 962151576Sdavidxu if (error == 0) { 963151576Sdavidxu error = copyout(&id, uap->timerid, sizeof(timer_t)); 964151576Sdavidxu if (error != 0) 965151576Sdavidxu kern_timer_delete(td, id); 966151576Sdavidxu } 967151576Sdavidxu return (error); 968151576Sdavidxu} 969151576Sdavidxu 970151576Sdavidxustatic int 971151576Sdavidxukern_timer_create(struct thread *td, clockid_t clock_id, 972151576Sdavidxu struct sigevent *evp, timer_t *timerid, timer_t preset_id) 973151576Sdavidxu{ 974151576Sdavidxu struct proc *p = td->td_proc; 975151576Sdavidxu struct itimer *it; 976151576Sdavidxu int id; 977151576Sdavidxu int error; 978151576Sdavidxu 979151576Sdavidxu if (clock_id < 0 || clock_id >= MAX_CLOCKS) 980151576Sdavidxu return (EINVAL); 981151576Sdavidxu 982151576Sdavidxu if (posix_clocks[clock_id].timer_create == NULL) 983151576Sdavidxu return (EINVAL); 984151576Sdavidxu 985151576Sdavidxu if (evp != NULL) { 986151576Sdavidxu if (evp->sigev_notify != SIGEV_NONE && 987151869Sdavidxu evp->sigev_notify != SIGEV_SIGNAL && 988151869Sdavidxu evp->sigev_notify != SIGEV_THREAD_ID) 989151576Sdavidxu return (EINVAL); 990151869Sdavidxu if ((evp->sigev_notify == SIGEV_SIGNAL || 991151869Sdavidxu evp->sigev_notify == SIGEV_THREAD_ID) && 992151576Sdavidxu !_SIG_VALID(evp->sigev_signo)) 993151576Sdavidxu return (EINVAL); 994151576Sdavidxu } 995151576Sdavidxu 996151585Sdavidxu if (p->p_itimers == NULL) 997151576Sdavidxu itimers_alloc(p); 998151576Sdavidxu 999151576Sdavidxu it = uma_zalloc(itimer_zone, M_WAITOK); 1000151576Sdavidxu it->it_flags = 0; 1001151576Sdavidxu it->it_usecount = 0; 1002151576Sdavidxu it->it_active = 0; 1003151869Sdavidxu timespecclear(&it->it_time.it_value); 1004151869Sdavidxu timespecclear(&it->it_time.it_interval); 1005151576Sdavidxu it->it_overrun = 0; 1006151576Sdavidxu it->it_overrun_last = 0; 1007151576Sdavidxu it->it_clockid = clock_id; 1008151576Sdavidxu it->it_timerid = -1; 1009151576Sdavidxu it->it_proc = p; 1010151576Sdavidxu ksiginfo_init(&it->it_ksi); 1011151576Sdavidxu it->it_ksi.ksi_flags |= KSI_INS | KSI_EXT; 1012151576Sdavidxu error = CLOCK_CALL(clock_id, timer_create, (it)); 1013151576Sdavidxu if (error != 0) 1014151576Sdavidxu goto out; 1015151576Sdavidxu 1016151576Sdavidxu PROC_LOCK(p); 1017151576Sdavidxu if (preset_id != -1) { 1018151576Sdavidxu KASSERT(preset_id >= 0 && preset_id < 3, ("invalid preset_id")); 1019151576Sdavidxu id = preset_id; 1020151585Sdavidxu if (p->p_itimers->its_timers[id] != NULL) { 1021151576Sdavidxu PROC_UNLOCK(p); 1022151576Sdavidxu error = 0; 1023151576Sdavidxu goto out; 1024151576Sdavidxu } 1025151576Sdavidxu } else { 1026151576Sdavidxu /* 1027151576Sdavidxu * Find a free timer slot, skipping those reserved 1028151576Sdavidxu * for setitimer(). 1029151576Sdavidxu */ 1030151576Sdavidxu for (id = 3; id < TIMER_MAX; id++) 1031151585Sdavidxu if (p->p_itimers->its_timers[id] == NULL) 1032151576Sdavidxu break; 1033151576Sdavidxu if (id == TIMER_MAX) { 1034151576Sdavidxu PROC_UNLOCK(p); 1035151576Sdavidxu error = EAGAIN; 1036151576Sdavidxu goto out; 1037151576Sdavidxu } 1038151576Sdavidxu } 1039151576Sdavidxu it->it_timerid = id; 1040151585Sdavidxu p->p_itimers->its_timers[id] = it; 1041151576Sdavidxu if (evp != NULL) 1042151576Sdavidxu it->it_sigev = *evp; 1043151576Sdavidxu else { 1044151576Sdavidxu it->it_sigev.sigev_notify = SIGEV_SIGNAL; 1045151576Sdavidxu switch (clock_id) { 1046151576Sdavidxu default: 1047151576Sdavidxu case CLOCK_REALTIME: 1048151576Sdavidxu it->it_sigev.sigev_signo = SIGALRM; 1049151576Sdavidxu break; 1050151576Sdavidxu case CLOCK_VIRTUAL: 1051151576Sdavidxu it->it_sigev.sigev_signo = SIGVTALRM; 1052151576Sdavidxu break; 1053151576Sdavidxu case CLOCK_PROF: 1054151576Sdavidxu it->it_sigev.sigev_signo = SIGPROF; 1055151576Sdavidxu break; 1056151576Sdavidxu } 1057152029Sdavidxu it->it_sigev.sigev_value.sival_int = id; 1058151576Sdavidxu } 1059151576Sdavidxu 1060151869Sdavidxu if (it->it_sigev.sigev_notify == SIGEV_SIGNAL || 1061151869Sdavidxu it->it_sigev.sigev_notify == SIGEV_THREAD_ID) { 1062151576Sdavidxu it->it_ksi.ksi_signo = it->it_sigev.sigev_signo; 1063151576Sdavidxu it->it_ksi.ksi_code = SI_TIMER; 1064151576Sdavidxu it->it_ksi.ksi_value = it->it_sigev.sigev_value; 1065151576Sdavidxu it->it_ksi.ksi_timerid = id; 1066151576Sdavidxu } 1067151576Sdavidxu PROC_UNLOCK(p); 1068151576Sdavidxu *timerid = id; 1069151576Sdavidxu return (0); 1070151576Sdavidxu 1071151576Sdavidxuout: 1072151576Sdavidxu ITIMER_LOCK(it); 1073151576Sdavidxu CLOCK_CALL(it->it_clockid, timer_delete, (it)); 1074151576Sdavidxu ITIMER_UNLOCK(it); 1075151576Sdavidxu uma_zfree(itimer_zone, it); 1076151576Sdavidxu return (error); 1077151576Sdavidxu} 1078151576Sdavidxu 1079151576Sdavidxu#ifndef _SYS_SYSPROTO_H_ 1080151576Sdavidxustruct timer_delete_args { 1081151576Sdavidxu timer_t timerid; 1082151576Sdavidxu}; 1083151576Sdavidxu#endif 1084151576Sdavidxu 1085151576Sdavidxuint 1086151576Sdavidxutimer_delete(struct thread *td, struct timer_delete_args *uap) 1087151576Sdavidxu{ 1088151576Sdavidxu return (kern_timer_delete(td, uap->timerid)); 1089151576Sdavidxu} 1090151576Sdavidxu 1091151576Sdavidxustatic struct itimer * 1092151576Sdavidxuitimer_find(struct proc *p, timer_t timerid, int include_deleting) 1093151576Sdavidxu{ 1094151576Sdavidxu struct itimer *it; 1095151576Sdavidxu 1096151576Sdavidxu PROC_LOCK_ASSERT(p, MA_OWNED); 1097151585Sdavidxu if ((p->p_itimers == NULL) || (timerid >= TIMER_MAX) || 1098151585Sdavidxu (it = p->p_itimers->its_timers[timerid]) == NULL) { 1099151576Sdavidxu return (NULL); 1100151576Sdavidxu } 1101151576Sdavidxu ITIMER_LOCK(it); 1102151576Sdavidxu if (!include_deleting && (it->it_flags & ITF_DELETING) != 0) { 1103151576Sdavidxu ITIMER_UNLOCK(it); 1104151576Sdavidxu it = NULL; 1105151576Sdavidxu } 1106151576Sdavidxu return (it); 1107151576Sdavidxu} 1108151576Sdavidxu 1109151576Sdavidxustatic int 1110151576Sdavidxukern_timer_delete(struct thread *td, timer_t timerid) 1111151576Sdavidxu{ 1112151576Sdavidxu struct proc *p = td->td_proc; 1113151576Sdavidxu struct itimer *it; 1114151576Sdavidxu 1115151576Sdavidxu PROC_LOCK(p); 1116151576Sdavidxu it = itimer_find(p, timerid, 0); 1117151576Sdavidxu if (it == NULL) { 1118151576Sdavidxu PROC_UNLOCK(p); 1119151576Sdavidxu return (EINVAL); 1120151576Sdavidxu } 1121151576Sdavidxu PROC_UNLOCK(p); 1122151576Sdavidxu 1123151576Sdavidxu it->it_flags |= ITF_DELETING; 1124151576Sdavidxu while (it->it_usecount > 0) { 1125151576Sdavidxu it->it_flags |= ITF_WANTED; 1126151576Sdavidxu msleep(it, &it->it_mtx, PPAUSE, "itimer", 0); 1127151576Sdavidxu } 1128151576Sdavidxu it->it_flags &= ~ITF_WANTED; 1129151576Sdavidxu CLOCK_CALL(it->it_clockid, timer_delete, (it)); 1130151576Sdavidxu ITIMER_UNLOCK(it); 1131151576Sdavidxu 1132151576Sdavidxu PROC_LOCK(p); 1133151576Sdavidxu if (KSI_ONQ(&it->it_ksi)) 1134151576Sdavidxu sigqueue_take(&it->it_ksi); 1135151585Sdavidxu p->p_itimers->its_timers[timerid] = NULL; 1136151576Sdavidxu PROC_UNLOCK(p); 1137151576Sdavidxu uma_zfree(itimer_zone, it); 1138151576Sdavidxu return (0); 1139151576Sdavidxu} 1140151576Sdavidxu 1141151576Sdavidxu#ifndef _SYS_SYSPROTO_H_ 1142151576Sdavidxustruct timer_settime_args { 1143151576Sdavidxu timer_t timerid; 1144151576Sdavidxu int flags; 1145151576Sdavidxu const struct itimerspec * value; 1146151576Sdavidxu struct itimerspec * ovalue; 1147151576Sdavidxu}; 1148151576Sdavidxu#endif 1149151576Sdavidxu 1150151576Sdavidxuint 1151151576Sdavidxutimer_settime(struct thread *td, struct timer_settime_args *uap) 1152151576Sdavidxu{ 1153151576Sdavidxu struct proc *p = td->td_proc; 1154151576Sdavidxu struct itimer *it; 1155151576Sdavidxu struct itimerspec val, oval, *ovalp; 1156151576Sdavidxu int error; 1157151576Sdavidxu 1158151576Sdavidxu error = copyin(uap->value, &val, sizeof(val)); 1159151576Sdavidxu if (error != 0) 1160151576Sdavidxu return (error); 1161151576Sdavidxu 1162151576Sdavidxu if (uap->ovalue != NULL) 1163151576Sdavidxu ovalp = &oval; 1164151576Sdavidxu else 1165151576Sdavidxu ovalp = NULL; 1166151576Sdavidxu 1167151576Sdavidxu PROC_LOCK(p); 1168151576Sdavidxu if (uap->timerid < 3 || 1169151576Sdavidxu (it = itimer_find(p, uap->timerid, 0)) == NULL) { 1170151576Sdavidxu PROC_UNLOCK(p); 1171151576Sdavidxu error = EINVAL; 1172151576Sdavidxu } else { 1173151576Sdavidxu PROC_UNLOCK(p); 1174151576Sdavidxu itimer_enter(it); 1175151576Sdavidxu error = CLOCK_CALL(it->it_clockid, timer_settime, 1176151576Sdavidxu (it, uap->flags, &val, ovalp)); 1177151576Sdavidxu itimer_leave(it); 1178151576Sdavidxu ITIMER_UNLOCK(it); 1179151576Sdavidxu } 1180151576Sdavidxu if (error == 0 && uap->ovalue != NULL) 1181151576Sdavidxu error = copyout(ovalp, uap->ovalue, sizeof(*ovalp)); 1182151576Sdavidxu return (error); 1183151576Sdavidxu} 1184151576Sdavidxu 1185151576Sdavidxu#ifndef _SYS_SYSPROTO_H_ 1186151576Sdavidxustruct timer_gettime_args { 1187151576Sdavidxu timer_t timerid; 1188151576Sdavidxu struct itimerspec * value; 1189151576Sdavidxu}; 1190151576Sdavidxu#endif 1191151576Sdavidxu 1192151576Sdavidxuint 1193151576Sdavidxutimer_gettime(struct thread *td, struct timer_gettime_args *uap) 1194151576Sdavidxu{ 1195151576Sdavidxu struct proc *p = td->td_proc; 1196151576Sdavidxu struct itimer *it; 1197151576Sdavidxu struct itimerspec val; 1198151576Sdavidxu int error; 1199151576Sdavidxu 1200151576Sdavidxu PROC_LOCK(p); 1201151576Sdavidxu if (uap->timerid < 3 || 1202151576Sdavidxu (it = itimer_find(p, uap->timerid, 0)) == NULL) { 1203151576Sdavidxu PROC_UNLOCK(p); 1204151576Sdavidxu error = EINVAL; 1205151576Sdavidxu } else { 1206151576Sdavidxu PROC_UNLOCK(p); 1207151576Sdavidxu itimer_enter(it); 1208151576Sdavidxu error = CLOCK_CALL(it->it_clockid, timer_gettime, 1209151576Sdavidxu (it, &val)); 1210151576Sdavidxu itimer_leave(it); 1211151576Sdavidxu ITIMER_UNLOCK(it); 1212151576Sdavidxu } 1213151576Sdavidxu if (error == 0) 1214151576Sdavidxu error = copyout(&val, uap->value, sizeof(val)); 1215151576Sdavidxu return (error); 1216151576Sdavidxu} 1217151576Sdavidxu 1218151576Sdavidxu#ifndef _SYS_SYSPROTO_H_ 1219151576Sdavidxustruct timer_getoverrun_args { 1220151576Sdavidxu timer_t timerid; 1221151576Sdavidxu}; 1222151576Sdavidxu#endif 1223151576Sdavidxu 1224151576Sdavidxuint 1225151576Sdavidxutimer_getoverrun(struct thread *td, struct timer_getoverrun_args *uap) 1226151576Sdavidxu{ 1227151576Sdavidxu struct proc *p = td->td_proc; 1228151576Sdavidxu struct itimer *it; 1229151576Sdavidxu int error ; 1230151576Sdavidxu 1231151576Sdavidxu PROC_LOCK(p); 1232151576Sdavidxu if (uap->timerid < 3 || 1233151576Sdavidxu (it = itimer_find(p, uap->timerid, 0)) == NULL) { 1234151576Sdavidxu PROC_UNLOCK(p); 1235151576Sdavidxu error = EINVAL; 1236151576Sdavidxu } else { 1237151576Sdavidxu td->td_retval[0] = it->it_overrun_last; 1238151576Sdavidxu ITIMER_UNLOCK(it); 1239151869Sdavidxu PROC_UNLOCK(p); 1240151576Sdavidxu error = 0; 1241151576Sdavidxu } 1242151576Sdavidxu return (error); 1243151576Sdavidxu} 1244151576Sdavidxu 1245151576Sdavidxustatic int 1246151576Sdavidxurealtimer_create(struct itimer *it) 1247151576Sdavidxu{ 1248151576Sdavidxu callout_init_mtx(&it->it_callout, &it->it_mtx, 0); 1249151576Sdavidxu return (0); 1250151576Sdavidxu} 1251151576Sdavidxu 1252151576Sdavidxustatic int 1253151576Sdavidxurealtimer_delete(struct itimer *it) 1254151576Sdavidxu{ 1255151576Sdavidxu mtx_assert(&it->it_mtx, MA_OWNED); 1256151576Sdavidxu callout_stop(&it->it_callout); 1257151576Sdavidxu return (0); 1258151576Sdavidxu} 1259151576Sdavidxu 1260151576Sdavidxustatic int 1261151576Sdavidxurealtimer_gettime(struct itimer *it, struct itimerspec *ovalue) 1262151576Sdavidxu{ 1263151869Sdavidxu struct timespec cts; 1264151576Sdavidxu 1265151576Sdavidxu mtx_assert(&it->it_mtx, MA_OWNED); 1266151576Sdavidxu 1267151869Sdavidxu realtimer_clocktime(it->it_clockid, &cts); 1268151869Sdavidxu *ovalue = it->it_time; 1269151576Sdavidxu if (ovalue->it_value.tv_sec != 0 || ovalue->it_value.tv_nsec != 0) { 1270151869Sdavidxu timespecsub(&ovalue->it_value, &cts); 1271151576Sdavidxu if (ovalue->it_value.tv_sec < 0 || 1272151576Sdavidxu (ovalue->it_value.tv_sec == 0 && 1273151576Sdavidxu ovalue->it_value.tv_nsec == 0)) { 1274151576Sdavidxu ovalue->it_value.tv_sec = 0; 1275151576Sdavidxu ovalue->it_value.tv_nsec = 1; 1276151576Sdavidxu } 1277151576Sdavidxu } 1278151576Sdavidxu return (0); 1279151576Sdavidxu} 1280151576Sdavidxu 1281151576Sdavidxustatic int 1282151576Sdavidxurealtimer_settime(struct itimer *it, int flags, 1283151576Sdavidxu struct itimerspec *value, struct itimerspec *ovalue) 1284151576Sdavidxu{ 1285151869Sdavidxu struct timespec cts, ts; 1286151869Sdavidxu struct timeval tv; 1287151869Sdavidxu struct itimerspec val; 1288151576Sdavidxu 1289151576Sdavidxu mtx_assert(&it->it_mtx, MA_OWNED); 1290151576Sdavidxu 1291151869Sdavidxu val = *value; 1292151869Sdavidxu if (itimespecfix(&val.it_value)) 1293151576Sdavidxu return (EINVAL); 1294151576Sdavidxu 1295151869Sdavidxu if (timespecisset(&val.it_value)) { 1296151869Sdavidxu if (itimespecfix(&val.it_interval)) 1297151576Sdavidxu return (EINVAL); 1298151576Sdavidxu } else { 1299151869Sdavidxu timespecclear(&val.it_interval); 1300151576Sdavidxu } 1301151576Sdavidxu 1302151576Sdavidxu if (ovalue != NULL) 1303151576Sdavidxu realtimer_gettime(it, ovalue); 1304151576Sdavidxu 1305151576Sdavidxu it->it_time = val; 1306151869Sdavidxu if (timespecisset(&val.it_value)) { 1307151869Sdavidxu realtimer_clocktime(it->it_clockid, &cts); 1308151869Sdavidxu ts = val.it_value; 1309151576Sdavidxu if ((flags & TIMER_ABSTIME) == 0) { 1310151576Sdavidxu /* Convert to absolute time. */ 1311151869Sdavidxu timespecadd(&it->it_time.it_value, &cts); 1312151576Sdavidxu } else { 1313151869Sdavidxu timespecsub(&ts, &cts); 1314151576Sdavidxu /* 1315151869Sdavidxu * We don't care if ts is negative, tztohz will 1316151576Sdavidxu * fix it. 1317151576Sdavidxu */ 1318151576Sdavidxu } 1319151869Sdavidxu TIMESPEC_TO_TIMEVAL(&tv, &ts); 1320151869Sdavidxu callout_reset(&it->it_callout, tvtohz(&tv), 1321151576Sdavidxu realtimer_expire, it); 1322151576Sdavidxu } else { 1323151576Sdavidxu callout_stop(&it->it_callout); 1324151576Sdavidxu } 1325151576Sdavidxu 1326151576Sdavidxu return (0); 1327151576Sdavidxu} 1328151576Sdavidxu 1329151576Sdavidxustatic void 1330151869Sdavidxurealtimer_clocktime(clockid_t id, struct timespec *ts) 1331151576Sdavidxu{ 1332151576Sdavidxu if (id == CLOCK_REALTIME) 1333151869Sdavidxu getnanotime(ts); 1334151576Sdavidxu else /* CLOCK_MONOTONIC */ 1335151869Sdavidxu getnanouptime(ts); 1336151576Sdavidxu} 1337151576Sdavidxu 1338151869Sdavidxuint 1339151869Sdavidxuitimer_accept(struct proc *p, timer_t timerid, ksiginfo_t *ksi) 1340151869Sdavidxu{ 1341151869Sdavidxu struct itimer *it; 1342151869Sdavidxu 1343151869Sdavidxu PROC_LOCK_ASSERT(p, MA_OWNED); 1344151869Sdavidxu it = itimer_find(p, timerid, 0); 1345151869Sdavidxu if (it != NULL) { 1346151869Sdavidxu ksi->ksi_overrun = it->it_overrun; 1347151869Sdavidxu it->it_overrun_last = it->it_overrun; 1348151869Sdavidxu it->it_overrun = 0; 1349151869Sdavidxu ITIMER_UNLOCK(it); 1350151869Sdavidxu return (0); 1351151869Sdavidxu } 1352151869Sdavidxu return (EINVAL); 1353151869Sdavidxu} 1354151869Sdavidxu 1355151869Sdavidxuint 1356151869Sdavidxuitimespecfix(struct timespec *ts) 1357151869Sdavidxu{ 1358151869Sdavidxu 1359151869Sdavidxu if (ts->tv_sec < 0 || ts->tv_nsec < 0 || ts->tv_nsec >= 1000000000) 1360151869Sdavidxu return (EINVAL); 1361151869Sdavidxu if (ts->tv_sec == 0 && ts->tv_nsec != 0 && ts->tv_nsec < tick * 1000) 1362151869Sdavidxu ts->tv_nsec = tick * 1000; 1363151869Sdavidxu return (0); 1364151869Sdavidxu} 1365151869Sdavidxu 1366151576Sdavidxustatic void 1367151576Sdavidxurealtimer_event_hook(struct proc *p, clockid_t clock_id, int event) 1368151576Sdavidxu{ 1369151576Sdavidxu struct itimers *its; 1370151576Sdavidxu struct itimer *it; 1371151576Sdavidxu int i; 1372151576Sdavidxu 1373151576Sdavidxu /* 1374151576Sdavidxu * Timer 0 (ITIMER_REAL) is XSI interval timer, according to POSIX 1375151576Sdavidxu * specification, it should be inherited by new process image. 1376151576Sdavidxu */ 1377151576Sdavidxu if (event == ITIMER_EV_EXEC) 1378151576Sdavidxu i = 1; 1379151576Sdavidxu else 1380151576Sdavidxu i = 0; 1381151585Sdavidxu its = p->p_itimers; 1382151576Sdavidxu for (; i < TIMER_MAX; i++) { 1383151576Sdavidxu if ((it = its->its_timers[i]) != NULL && 1384151576Sdavidxu it->it_clockid == clock_id) { 1385151576Sdavidxu ITIMER_LOCK(it); 1386151576Sdavidxu callout_stop(&it->it_callout); 1387151576Sdavidxu ITIMER_UNLOCK(it); 1388151576Sdavidxu } 1389151576Sdavidxu } 1390151576Sdavidxu} 1391151576Sdavidxu 1392151576Sdavidxu/* Timeout callback for realtime timer */ 1393151576Sdavidxustatic void 1394151576Sdavidxurealtimer_expire(void *arg) 1395151576Sdavidxu{ 1396151869Sdavidxu struct timespec cts, ts; 1397151869Sdavidxu struct timeval tv; 1398151576Sdavidxu struct itimer *it; 1399151576Sdavidxu struct proc *p; 1400151576Sdavidxu 1401151576Sdavidxu it = (struct itimer *)arg; 1402151576Sdavidxu p = it->it_proc; 1403151576Sdavidxu 1404151869Sdavidxu realtimer_clocktime(it->it_clockid, &cts); 1405151576Sdavidxu /* Only fire if time is reached. */ 1406151869Sdavidxu if (timespeccmp(&cts, &it->it_time.it_value, >=)) { 1407151869Sdavidxu if (timespecisset(&it->it_time.it_interval)) { 1408151869Sdavidxu timespecadd(&it->it_time.it_value, 1409151869Sdavidxu &it->it_time.it_interval); 1410151869Sdavidxu while (timespeccmp(&cts, &it->it_time.it_value, >=)) { 1411151576Sdavidxu it->it_overrun++; 1412151869Sdavidxu timespecadd(&it->it_time.it_value, 1413151869Sdavidxu &it->it_time.it_interval); 1414151576Sdavidxu } 1415151576Sdavidxu } else { 1416151576Sdavidxu /* single shot timer ? */ 1417151869Sdavidxu timespecclear(&it->it_time.it_value); 1418151576Sdavidxu } 1419151869Sdavidxu if (timespecisset(&it->it_time.it_value)) { 1420151869Sdavidxu ts = it->it_time.it_value; 1421151869Sdavidxu timespecsub(&ts, &cts); 1422151869Sdavidxu TIMESPEC_TO_TIMEVAL(&tv, &ts); 1423151869Sdavidxu callout_reset(&it->it_callout, tvtohz(&tv), 1424151576Sdavidxu realtimer_expire, it); 1425151576Sdavidxu } 1426151576Sdavidxu ITIMER_UNLOCK(it); 1427151576Sdavidxu itimer_fire(it); 1428151576Sdavidxu ITIMER_LOCK(it); 1429151869Sdavidxu } else if (timespecisset(&it->it_time.it_value)) { 1430151869Sdavidxu ts = it->it_time.it_value; 1431151869Sdavidxu timespecsub(&ts, &cts); 1432151869Sdavidxu TIMESPEC_TO_TIMEVAL(&tv, &ts); 1433151869Sdavidxu callout_reset(&it->it_callout, tvtohz(&tv), realtimer_expire, 1434151576Sdavidxu it); 1435151576Sdavidxu } 1436151576Sdavidxu} 1437151576Sdavidxu 1438151576Sdavidxuvoid 1439151576Sdavidxuitimer_fire(struct itimer *it) 1440151576Sdavidxu{ 1441151576Sdavidxu struct proc *p = it->it_proc; 1442151993Sdavidxu int ret; 1443151576Sdavidxu 1444151869Sdavidxu if (it->it_sigev.sigev_notify == SIGEV_SIGNAL || 1445151869Sdavidxu it->it_sigev.sigev_notify == SIGEV_THREAD_ID) { 1446151576Sdavidxu PROC_LOCK(p); 1447151993Sdavidxu if (!KSI_ONQ(&it->it_ksi)) { 1448151993Sdavidxu ret = psignal_event(p, &it->it_sigev, &it->it_ksi); 1449151993Sdavidxu if (__predict_false(ret != 0)) { 1450151993Sdavidxu it->it_overrun++; 1451151993Sdavidxu /* 1452151993Sdavidxu * Broken userland code, thread went 1453151993Sdavidxu * away, disarm the timer. 1454151869Sdavidxu */ 1455151993Sdavidxu if (ret == ESRCH) { 1456151869Sdavidxu ITIMER_LOCK(it); 1457151869Sdavidxu timespecclear(&it->it_time.it_value); 1458151869Sdavidxu timespecclear(&it->it_time.it_interval); 1459151869Sdavidxu callout_stop(&it->it_callout); 1460151869Sdavidxu ITIMER_UNLOCK(it); 1461151869Sdavidxu } 1462151869Sdavidxu } 1463151993Sdavidxu } else { 1464151993Sdavidxu it->it_overrun++; 1465151576Sdavidxu } 1466151576Sdavidxu PROC_UNLOCK(p); 1467151576Sdavidxu } 1468151576Sdavidxu} 1469151576Sdavidxu 1470151576Sdavidxustatic void 1471151576Sdavidxuitimers_alloc(struct proc *p) 1472151576Sdavidxu{ 1473151585Sdavidxu struct itimers *its; 1474151585Sdavidxu int i; 1475151576Sdavidxu 1476151585Sdavidxu its = malloc(sizeof (struct itimers), M_SUBPROC, M_WAITOK | M_ZERO); 1477151585Sdavidxu LIST_INIT(&its->its_virtual); 1478151585Sdavidxu LIST_INIT(&its->its_prof); 1479151585Sdavidxu TAILQ_INIT(&its->its_worklist); 1480151585Sdavidxu for (i = 0; i < TIMER_MAX; i++) 1481151585Sdavidxu its->its_timers[i] = NULL; 1482151576Sdavidxu PROC_LOCK(p); 1483151585Sdavidxu if (p->p_itimers == NULL) { 1484151585Sdavidxu p->p_itimers = its; 1485151576Sdavidxu PROC_UNLOCK(p); 1486151585Sdavidxu } 1487151585Sdavidxu else { 1488151576Sdavidxu PROC_UNLOCK(p); 1489151585Sdavidxu free(its, M_SUBPROC); 1490151576Sdavidxu } 1491151576Sdavidxu} 1492151576Sdavidxu 1493151576Sdavidxu/* Clean up timers when some process events are being triggered. */ 1494151576Sdavidxuvoid 1495151576Sdavidxuitimers_event_hook(struct proc *p, int event) 1496151576Sdavidxu{ 1497151576Sdavidxu struct itimers *its; 1498151576Sdavidxu struct itimer *it; 1499151576Sdavidxu int i; 1500151576Sdavidxu 1501151585Sdavidxu if (p->p_itimers != NULL) { 1502151585Sdavidxu its = p->p_itimers; 1503151576Sdavidxu for (i = 0; i < MAX_CLOCKS; ++i) { 1504151576Sdavidxu if (posix_clocks[i].event_hook != NULL) 1505151576Sdavidxu CLOCK_CALL(i, event_hook, (p, i, event)); 1506151576Sdavidxu } 1507151576Sdavidxu /* 1508151576Sdavidxu * According to susv3, XSI interval timers should be inherited 1509151576Sdavidxu * by new image. 1510151576Sdavidxu */ 1511151576Sdavidxu if (event == ITIMER_EV_EXEC) 1512151576Sdavidxu i = 3; 1513151576Sdavidxu else if (event == ITIMER_EV_EXIT) 1514151576Sdavidxu i = 0; 1515151576Sdavidxu else 1516151576Sdavidxu panic("unhandled event"); 1517151576Sdavidxu for (; i < TIMER_MAX; ++i) { 1518151576Sdavidxu if ((it = its->its_timers[i]) != NULL) { 1519151576Sdavidxu PROC_LOCK(p); 1520151576Sdavidxu if (KSI_ONQ(&it->it_ksi)) 1521151576Sdavidxu sigqueue_take(&it->it_ksi); 1522151576Sdavidxu PROC_UNLOCK(p); 1523151576Sdavidxu uma_zfree(itimer_zone, its->its_timers[i]); 1524151576Sdavidxu its->its_timers[i] = NULL; 1525151576Sdavidxu } 1526151576Sdavidxu } 1527151576Sdavidxu if (its->its_timers[0] == NULL && 1528151576Sdavidxu its->its_timers[1] == NULL && 1529151576Sdavidxu its->its_timers[2] == NULL) { 1530151585Sdavidxu free(its, M_SUBPROC); 1531151585Sdavidxu p->p_itimers = NULL; 1532151576Sdavidxu } 1533151576Sdavidxu } 1534151576Sdavidxu} 1535