Annotation of src/sys/kern/kern_time.c, Revision 1.146.2.2
1.146.2.2! wrstuden 1: /* $NetBSD: kern_time.c,v 1.146.2.1 2008/05/10 23:49:04 wrstuden Exp $ */
1.42 cgd 2:
3: /*-
1.142 ad 4: * Copyright (c) 2000, 2004, 2005, 2007, 2008 The NetBSD Foundation, Inc.
1.42 cgd 5: * All rights reserved.
6: *
7: * This code is derived from software contributed to The NetBSD Foundation
8: * by Christopher G. Demetriou.
9: *
10: * Redistribution and use in source and binary forms, with or without
11: * modification, are permitted provided that the following conditions
12: * are met:
13: * 1. Redistributions of source code must retain the above copyright
14: * notice, this list of conditions and the following disclaimer.
15: * 2. Redistributions in binary form must reproduce the above copyright
16: * notice, this list of conditions and the following disclaimer in the
17: * documentation and/or other materials provided with the distribution.
18: *
19: * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20: * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21: * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22: * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23: * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24: * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25: * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26: * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27: * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28: * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29: * POSSIBILITY OF SUCH DAMAGE.
30: */
1.9 cgd 31:
1.1 cgd 32: /*
1.8 cgd 33: * Copyright (c) 1982, 1986, 1989, 1993
34: * The Regents of the University of California. All rights reserved.
1.1 cgd 35: *
36: * Redistribution and use in source and binary forms, with or without
37: * modification, are permitted provided that the following conditions
38: * are met:
39: * 1. Redistributions of source code must retain the above copyright
40: * notice, this list of conditions and the following disclaimer.
41: * 2. Redistributions in binary form must reproduce the above copyright
42: * notice, this list of conditions and the following disclaimer in the
43: * documentation and/or other materials provided with the distribution.
1.72 agc 44: * 3. Neither the name of the University nor the names of its contributors
1.1 cgd 45: * may be used to endorse or promote products derived from this software
46: * without specific prior written permission.
47: *
48: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
49: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
50: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
51: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
52: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
53: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
54: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
55: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
56: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
57: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
58: * SUCH DAMAGE.
59: *
1.33 fvdl 60: * @(#)kern_time.c 8.4 (Berkeley) 5/26/95
1.1 cgd 61: */
1.58 lukem 62:
63: #include <sys/cdefs.h>
1.146.2.2! wrstuden 64: __KERNEL_RCSID(0, "$NetBSD: kern_time.c,v 1.146.2.1 2008/05/10 23:49:04 wrstuden Exp $");
1.1 cgd 65:
1.5 mycroft 66: #include <sys/param.h>
67: #include <sys/resourcevar.h>
68: #include <sys/kernel.h>
1.8 cgd 69: #include <sys/systm.h>
1.5 mycroft 70: #include <sys/proc.h>
1.8 cgd 71: #include <sys/vnode.h>
1.17 christos 72: #include <sys/signalvar.h>
1.25 perry 73: #include <sys/syslog.h>
1.101 kardel 74: #include <sys/timetc.h>
1.143 ad 75: #include <sys/timex.h>
1.99 elad 76: #include <sys/kauth.h>
1.11 cgd 77: #include <sys/mount.h>
78: #include <sys/syscallargs.h>
1.143 ad 79: #include <sys/cpu.h>
1.19 christos 80:
1.37 thorpej 81: #include <uvm/uvm_extern.h>
82:
1.142 ad 83: static void timer_intr(void *);
84: static void itimerfire(struct ptimer *);
85: static void itimerfree(struct ptimers *, int);
86:
1.131 ad 87: kmutex_t time_lock;
1.142 ad 88: kmutex_t timer_lock;
89:
90: static void *timer_sih;
91: static TAILQ_HEAD(, ptimer) timer_queue;
1.131 ad 92:
1.97 simonb 93: POOL_INIT(ptimer_pool, sizeof(struct ptimer), 0, 0, 0, "ptimerpl",
1.118 ad 94: &pool_allocator_nointr, IPL_NONE);
1.97 simonb 95: POOL_INIT(ptimers_pool, sizeof(struct ptimers), 0, 0, 0, "ptimerspl",
1.118 ad 96: &pool_allocator_nointr, IPL_NONE);
1.97 simonb 97:
1.131 ad 98: /*
99: * Initialize timekeeping.
100: */
101: void
102: time_init(void)
103: {
104:
105: mutex_init(&time_lock, MUTEX_DEFAULT, IPL_NONE);
106: }
107:
1.142 ad 108: void
109: time_init2(void)
110: {
111:
112: TAILQ_INIT(&timer_queue);
113: mutex_init(&timer_lock, MUTEX_DEFAULT, IPL_SCHED);
114: timer_sih = softint_establish(SOFTINT_CLOCK | SOFTINT_MPSAFE,
115: timer_intr, NULL);
116: }
117:
1.63 thorpej 118: /* Time of day and interval timer support.
1.1 cgd 119: *
120: * These routines provide the kernel entry points to get and set
121: * the time-of-day and per-process interval timers. Subroutines
122: * here provide support for adding and subtracting timeval structures
123: * and decrementing interval timers, optionally reloading the interval
124: * timers when they expire.
125: */
126:
1.22 jtc 127: /* This function is used by clock_settime and settimeofday */
1.132 elad 128: static int
129: settime1(struct proc *p, struct timespec *ts, bool check_kauth)
1.22 jtc 130: {
1.98 christos 131: struct timeval delta, tv;
1.101 kardel 132: struct timeval now;
133: struct timespec ts1;
1.137 yamt 134: struct bintime btdelta;
1.129 ad 135: lwp_t *l;
136: int s;
1.22 jtc 137:
1.98 christos 138: TIMESPEC_TO_TIMEVAL(&tv, ts);
139:
1.22 jtc 140: /* WHAT DO WE DO ABOUT PENDING REAL-TIME TIMEOUTS??? */
1.129 ad 141: s = splclock();
1.101 kardel 142: microtime(&now);
143: timersub(&tv, &now, &delta);
1.132 elad 144:
1.134 elad 145: if (check_kauth && kauth_authorize_system(kauth_cred_get(),
146: KAUTH_SYSTEM_TIME, KAUTH_REQ_SYSTEM_TIME_SYSTEM, ts, &delta,
1.132 elad 147: KAUTH_ARG(check_kauth ? false : true)) != 0) {
1.129 ad 148: splx(s);
1.29 tls 149: return (EPERM);
1.55 tron 150: }
1.132 elad 151:
1.29 tls 152: #ifdef notyet
1.109 elad 153: if ((delta.tv_sec < 86400) && securelevel > 0) { /* XXX elad - notyet */
1.129 ad 154: splx(s);
1.29 tls 155: return (EPERM);
1.55 tron 156: }
1.29 tls 157: #endif
1.103 kardel 158:
159: TIMEVAL_TO_TIMESPEC(&tv, &ts1);
1.101 kardel 160: tc_setclock(&ts1);
1.103 kardel 161:
1.22 jtc 162: timeradd(&boottime, &delta, &boottime);
1.103 kardel 163:
1.47 thorpej 164: /*
1.129 ad 165: * XXXSMP: There is a short race between setting the time above
166: * and adjusting LWP's run times. Fixing this properly means
167: * pausing all CPUs while we adjust the clock.
1.47 thorpej 168: */
1.137 yamt 169: timeval2bintime(&delta, &btdelta);
1.145 ad 170: mutex_enter(proc_lock);
1.129 ad 171: LIST_FOREACH(l, &alllwp, l_list) {
172: lwp_lock(l);
1.137 yamt 173: bintime_add(&l->l_stime, &btdelta);
1.129 ad 174: lwp_unlock(l);
175: }
1.145 ad 176: mutex_exit(proc_lock);
1.22 jtc 177: resettodr();
1.129 ad 178: splx(s);
179:
1.29 tls 180: return (0);
1.22 jtc 181: }
182:
1.132 elad 183: int
184: settime(struct proc *p, struct timespec *ts)
185: {
186: return (settime1(p, ts, true));
187: }
188:
1.22 jtc 189: /* ARGSUSED */
190: int
1.140 yamt 191: sys_clock_gettime(struct lwp *l, const struct sys_clock_gettime_args *uap,
192: register_t *retval)
1.22 jtc 193: {
1.135 dsl 194: /* {
1.22 jtc 195: syscallarg(clockid_t) clock_id;
1.23 cgd 196: syscallarg(struct timespec *) tp;
1.135 dsl 197: } */
1.22 jtc 198: clockid_t clock_id;
199: struct timespec ats;
200:
201: clock_id = SCARG(uap, clock_id);
1.61 simonb 202: switch (clock_id) {
203: case CLOCK_REALTIME:
1.96 simonb 204: nanotime(&ats);
1.61 simonb 205: break;
206: case CLOCK_MONOTONIC:
1.101 kardel 207: nanouptime(&ats);
1.61 simonb 208: break;
209: default:
1.22 jtc 210: return (EINVAL);
1.61 simonb 211: }
1.22 jtc 212:
1.24 cgd 213: return copyout(&ats, SCARG(uap, tp), sizeof(ats));
1.22 jtc 214: }
215:
216: /* ARGSUSED */
217: int
1.140 yamt 218: sys_clock_settime(struct lwp *l, const struct sys_clock_settime_args *uap,
219: register_t *retval)
1.22 jtc 220: {
1.135 dsl 221: /* {
1.22 jtc 222: syscallarg(clockid_t) clock_id;
1.23 cgd 223: syscallarg(const struct timespec *) tp;
1.135 dsl 224: } */
1.22 jtc 225:
1.132 elad 226: return clock_settime1(l->l_proc, SCARG(uap, clock_id), SCARG(uap, tp),
227: true);
1.56 manu 228: }
229:
230:
231: int
1.132 elad 232: clock_settime1(struct proc *p, clockid_t clock_id, const struct timespec *tp,
233: bool check_kauth)
1.56 manu 234: {
1.60 manu 235: struct timespec ats;
1.56 manu 236: int error;
237:
1.60 manu 238: if ((error = copyin(tp, &ats, sizeof(ats))) != 0)
239: return (error);
240:
1.61 simonb 241: switch (clock_id) {
242: case CLOCK_REALTIME:
1.132 elad 243: if ((error = settime1(p, &ats, check_kauth)) != 0)
1.61 simonb 244: return (error);
245: break;
246: case CLOCK_MONOTONIC:
247: return (EINVAL); /* read-only clock */
248: default:
1.56 manu 249: return (EINVAL);
1.61 simonb 250: }
1.22 jtc 251:
252: return 0;
253: }
254:
255: int
1.140 yamt 256: sys_clock_getres(struct lwp *l, const struct sys_clock_getres_args *uap,
257: register_t *retval)
1.22 jtc 258: {
1.135 dsl 259: /* {
1.22 jtc 260: syscallarg(clockid_t) clock_id;
1.23 cgd 261: syscallarg(struct timespec *) tp;
1.135 dsl 262: } */
1.22 jtc 263: clockid_t clock_id;
264: struct timespec ts;
265: int error = 0;
266:
267: clock_id = SCARG(uap, clock_id);
1.61 simonb 268: switch (clock_id) {
269: case CLOCK_REALTIME:
270: case CLOCK_MONOTONIC:
1.22 jtc 271: ts.tv_sec = 0;
1.102 kardel 272: if (tc_getfrequency() > 1000000000)
273: ts.tv_nsec = 1;
274: else
275: ts.tv_nsec = 1000000000 / tc_getfrequency();
1.61 simonb 276: break;
277: default:
278: return (EINVAL);
279: }
1.22 jtc 280:
1.61 simonb 281: if (SCARG(uap, tp))
1.35 perry 282: error = copyout(&ts, SCARG(uap, tp), sizeof(ts));
1.22 jtc 283:
284: return error;
285: }
286:
1.27 jtc 287: /* ARGSUSED */
288: int
1.140 yamt 289: sys_nanosleep(struct lwp *l, const struct sys_nanosleep_args *uap,
290: register_t *retval)
1.27 jtc 291: {
1.135 dsl 292: /* {
1.101 kardel 293: syscallarg(struct timespec *) rqtp;
294: syscallarg(struct timespec *) rmtp;
1.135 dsl 295: } */
1.101 kardel 296: struct timespec rmt, rqt;
1.120 dsl 297: int error, error1;
1.101 kardel 298:
299: error = copyin(SCARG(uap, rqtp), &rqt, sizeof(struct timespec));
300: if (error)
301: return (error);
302:
1.120 dsl 303: error = nanosleep1(l, &rqt, SCARG(uap, rmtp) ? &rmt : NULL);
304: if (SCARG(uap, rmtp) == NULL || (error != 0 && error != EINTR))
305: return error;
306:
307: error1 = copyout(&rmt, SCARG(uap, rmtp), sizeof(rmt));
308: return error1 ? error1 : error;
309: }
310:
311: int
312: nanosleep1(struct lwp *l, struct timespec *rqt, struct timespec *rmt)
313: {
1.141 yamt 314: struct timespec rmtstart;
1.120 dsl 315: int error, timo;
316:
317: if (itimespecfix(rqt))
1.101 kardel 318: return (EINVAL);
319:
1.120 dsl 320: timo = tstohz(rqt);
1.101 kardel 321: /*
322: * Avoid inadvertantly sleeping forever
323: */
324: if (timo == 0)
325: timo = 1;
1.141 yamt 326: getnanouptime(&rmtstart);
327: again:
328: error = kpause("nanoslp", true, timo, NULL);
329: if (rmt != NULL || error == 0) {
330: struct timespec rmtend;
331: struct timespec t0;
332: struct timespec *t;
1.101 kardel 333:
1.141 yamt 334: getnanouptime(&rmtend);
335: t = (rmt != NULL) ? rmt : &t0;
336: timespecsub(&rmtend, &rmtstart, t);
337: timespecsub(rqt, t, t);
338: if (t->tv_sec < 0)
339: timespecclear(t);
340: if (error == 0) {
341: timo = tstohz(t);
342: if (timo > 0)
343: goto again;
344: }
345: }
1.104 kardel 346:
1.101 kardel 347: if (error == ERESTART)
348: error = EINTR;
349: if (error == EWOULDBLOCK)
350: error = 0;
351:
352: return error;
1.27 jtc 353: }
1.22 jtc 354:
1.1 cgd 355: /* ARGSUSED */
1.3 andrew 356: int
1.140 yamt 357: sys_gettimeofday(struct lwp *l, const struct sys_gettimeofday_args *uap,
358: register_t *retval)
1.15 thorpej 359: {
1.135 dsl 360: /* {
1.11 cgd 361: syscallarg(struct timeval *) tp;
1.135 dsl 362: syscallarg(void *) tzp; really "struct timezone *";
363: } */
1.1 cgd 364: struct timeval atv;
365: int error = 0;
1.25 perry 366: struct timezone tzfake;
1.1 cgd 367:
1.11 cgd 368: if (SCARG(uap, tp)) {
1.1 cgd 369: microtime(&atv);
1.35 perry 370: error = copyout(&atv, SCARG(uap, tp), sizeof(atv));
1.17 christos 371: if (error)
1.1 cgd 372: return (error);
373: }
1.25 perry 374: if (SCARG(uap, tzp)) {
375: /*
1.32 mycroft 376: * NetBSD has no kernel notion of time zone, so we just
1.25 perry 377: * fake up a timezone struct and return it if demanded.
378: */
379: tzfake.tz_minuteswest = 0;
380: tzfake.tz_dsttime = 0;
1.35 perry 381: error = copyout(&tzfake, SCARG(uap, tzp), sizeof(tzfake));
1.25 perry 382: }
1.1 cgd 383: return (error);
384: }
385:
386: /* ARGSUSED */
1.3 andrew 387: int
1.140 yamt 388: sys_settimeofday(struct lwp *l, const struct sys_settimeofday_args *uap,
389: register_t *retval)
1.15 thorpej 390: {
1.135 dsl 391: /* {
1.24 cgd 392: syscallarg(const struct timeval *) tv;
1.140 yamt 393: syscallarg(const void *) tzp; really "const struct timezone *";
1.135 dsl 394: } */
1.60 manu 395:
1.119 dsl 396: return settimeofday1(SCARG(uap, tv), true, SCARG(uap, tzp), l, true);
1.60 manu 397: }
398:
399: int
1.119 dsl 400: settimeofday1(const struct timeval *utv, bool userspace,
401: const void *utzp, struct lwp *l, bool check_kauth)
1.60 manu 402: {
1.22 jtc 403: struct timeval atv;
1.98 christos 404: struct timespec ts;
1.22 jtc 405: int error;
1.1 cgd 406:
1.8 cgd 407: /* Verify all parameters before changing time. */
1.119 dsl 408:
1.25 perry 409: /*
1.32 mycroft 410: * NetBSD has no kernel notion of time zone, and only an
1.25 perry 411: * obsolete program would try to set it, so we log a warning.
412: */
1.98 christos 413: if (utzp)
1.25 perry 414: log(LOG_WARNING, "pid %d attempted to set the "
1.119 dsl 415: "(obsolete) kernel time zone\n", l->l_proc->p_pid);
1.98 christos 416:
417: if (utv == NULL)
418: return 0;
419:
1.119 dsl 420: if (userspace) {
421: if ((error = copyin(utv, &atv, sizeof(atv))) != 0)
422: return error;
423: utv = &atv;
424: }
425:
426: TIMEVAL_TO_TIMESPEC(utv, &ts);
1.133 elad 427: return settime1(l->l_proc, &ts, check_kauth);
1.1 cgd 428: }
429:
1.68 dsl 430: int time_adjusted; /* set if an adjustment is made */
1.1 cgd 431:
432: /* ARGSUSED */
1.3 andrew 433: int
1.140 yamt 434: sys_adjtime(struct lwp *l, const struct sys_adjtime_args *uap,
435: register_t *retval)
1.15 thorpej 436: {
1.135 dsl 437: /* {
1.24 cgd 438: syscallarg(const struct timeval *) delta;
1.11 cgd 439: syscallarg(struct timeval *) olddelta;
1.135 dsl 440: } */
1.56 manu 441: int error;
1.1 cgd 442:
1.106 elad 443: if ((error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_TIME,
444: KAUTH_REQ_SYSTEM_TIME_ADJTIME, NULL, NULL, NULL)) != 0)
1.1 cgd 445: return (error);
1.17 christos 446:
1.105 ad 447: return adjtime1(SCARG(uap, delta), SCARG(uap, olddelta), l->l_proc);
1.56 manu 448: }
449:
450: int
1.110 yamt 451: adjtime1(const struct timeval *delta, struct timeval *olddelta, struct proc *p)
1.56 manu 452: {
1.60 manu 453: struct timeval atv;
1.101 kardel 454: int error = 0;
455:
456: extern int64_t time_adjtime; /* in kern_ntptime.c */
457:
458: if (olddelta) {
1.143 ad 459: mutex_spin_enter(&timecounter_lock);
1.101 kardel 460: atv.tv_sec = time_adjtime / 1000000;
461: atv.tv_usec = time_adjtime % 1000000;
1.143 ad 462: mutex_spin_exit(&timecounter_lock);
1.101 kardel 463: if (atv.tv_usec < 0) {
464: atv.tv_usec += 1000000;
465: atv.tv_sec--;
466: }
467: error = copyout(&atv, olddelta, sizeof(struct timeval));
468: if (error)
469: return (error);
470: }
471:
472: if (delta) {
473: error = copyin(delta, &atv, sizeof(struct timeval));
474: if (error)
475: return (error);
476:
1.143 ad 477: mutex_spin_enter(&timecounter_lock);
1.101 kardel 478: time_adjtime = (int64_t)atv.tv_sec * 1000000 +
479: atv.tv_usec;
1.143 ad 480: if (time_adjtime) {
1.101 kardel 481: /* We need to save the system time during shutdown */
482: time_adjusted |= 1;
1.143 ad 483: }
484: mutex_spin_exit(&timecounter_lock);
1.101 kardel 485: }
486:
1.79 chs 487: return error;
1.1 cgd 488: }
489:
490: /*
1.63 thorpej 491: * Interval timer support. Both the BSD getitimer() family and the POSIX
492: * timer_*() family of routines are supported.
1.1 cgd 493: *
1.63 thorpej 494: * All timers are kept in an array pointed to by p_timers, which is
495: * allocated on demand - many processes don't use timers at all. The
496: * first three elements in this array are reserved for the BSD timers:
497: * element 0 is ITIMER_REAL, element 1 is ITIMER_VIRTUAL, and element
498: * 2 is ITIMER_PROF. The rest may be allocated by the timer_create()
499: * syscall.
1.1 cgd 500: *
1.63 thorpej 501: * Realtime timers are kept in the ptimer structure as an absolute
502: * time; virtual time timers are kept as a linked list of deltas.
1.1 cgd 503: * Virtual time timers are processed in the hardclock() routine of
1.63 thorpej 504: * kern_clock.c. The real time timer is processed by a callout
505: * routine, called from the softclock() routine. Since a callout may
506: * be delayed in real time due to interrupt processing in the system,
507: * it is possible for the real time timeout routine (realtimeexpire,
508: * given below), to be delayed in real time past when it is supposed
509: * to occur. It does not suffice, therefore, to reload the real timer
510: * .it_value from the real time timers .it_interval. Rather, we
511: * compute the next time in absolute time the timer should go off. */
512:
513: /* Allocate a POSIX realtime timer. */
514: int
1.140 yamt 515: sys_timer_create(struct lwp *l, const struct sys_timer_create_args *uap,
516: register_t *retval)
1.63 thorpej 517: {
1.135 dsl 518: /* {
1.63 thorpej 519: syscallarg(clockid_t) clock_id;
520: syscallarg(struct sigevent *) evp;
521: syscallarg(timer_t *) timerid;
1.135 dsl 522: } */
1.92 cube 523:
524: return timer_create1(SCARG(uap, timerid), SCARG(uap, clock_id),
1.105 ad 525: SCARG(uap, evp), copyin, l);
1.92 cube 526: }
527:
528: int
529: timer_create1(timer_t *tid, clockid_t id, struct sigevent *evp,
1.105 ad 530: copyin_t fetch_event, struct lwp *l)
1.92 cube 531: {
532: int error;
533: timer_t timerid;
1.142 ad 534: struct ptimers *pts;
1.63 thorpej 535: struct ptimer *pt;
1.105 ad 536: struct proc *p;
537:
538: p = l->l_proc;
1.63 thorpej 539:
1.142 ad 540: if (id < CLOCK_REALTIME || id > CLOCK_PROF)
1.63 thorpej 541: return (EINVAL);
542:
1.142 ad 543: if ((pts = p->p_timers) == NULL)
544: pts = timers_alloc(p);
1.63 thorpej 545:
546: pt = pool_get(&ptimer_pool, PR_WAITOK);
1.142 ad 547: if (evp != NULL) {
1.63 thorpej 548: if (((error =
1.92 cube 549: (*fetch_event)(evp, &pt->pt_ev, sizeof(pt->pt_ev))) != 0) ||
1.63 thorpej 550: ((pt->pt_ev.sigev_notify < SIGEV_NONE) ||
551: (pt->pt_ev.sigev_notify > SIGEV_SA))) {
552: pool_put(&ptimer_pool, pt);
553: return (error ? error : EINVAL);
554: }
1.142 ad 555: }
556:
557: /* Find a free timer slot, skipping those reserved for setitimer(). */
558: mutex_spin_enter(&timer_lock);
559: for (timerid = 3; timerid < TIMER_MAX; timerid++)
560: if (pts->pts_timers[timerid] == NULL)
561: break;
562: if (timerid == TIMER_MAX) {
563: mutex_spin_exit(&timer_lock);
564: pool_put(&ptimer_pool, pt);
565: return EAGAIN;
566: }
567: if (evp == NULL) {
1.63 thorpej 568: pt->pt_ev.sigev_notify = SIGEV_SIGNAL;
569: switch (id) {
570: case CLOCK_REALTIME:
571: pt->pt_ev.sigev_signo = SIGALRM;
572: break;
573: case CLOCK_VIRTUAL:
574: pt->pt_ev.sigev_signo = SIGVTALRM;
575: break;
576: case CLOCK_PROF:
577: pt->pt_ev.sigev_signo = SIGPROF;
578: break;
579: }
580: pt->pt_ev.sigev_value.sival_int = timerid;
581: }
1.73 christos 582: pt->pt_info.ksi_signo = pt->pt_ev.sigev_signo;
583: pt->pt_info.ksi_errno = 0;
584: pt->pt_info.ksi_code = 0;
585: pt->pt_info.ksi_pid = p->p_pid;
1.105 ad 586: pt->pt_info.ksi_uid = kauth_cred_getuid(l->l_cred);
1.124 christos 587: pt->pt_info.ksi_value = pt->pt_ev.sigev_value;
1.63 thorpej 588: pt->pt_type = id;
589: pt->pt_proc = p;
590: pt->pt_overruns = 0;
591: pt->pt_poverruns = 0;
1.64 nathanw 592: pt->pt_entry = timerid;
1.142 ad 593: pt->pt_queued = false;
594: pt->pt_active = 0;
1.63 thorpej 595: timerclear(&pt->pt_time.it_value);
1.142 ad 596: callout_init(&pt->pt_ch, 0);
597: pts->pts_timers[timerid] = pt;
598: mutex_spin_exit(&timer_lock);
1.63 thorpej 599:
1.92 cube 600: return copyout(&timerid, tid, sizeof(timerid));
1.63 thorpej 601: }
602:
603: /* Delete a POSIX realtime timer */
1.3 andrew 604: int
1.140 yamt 605: sys_timer_delete(struct lwp *l, const struct sys_timer_delete_args *uap,
606: register_t *retval)
1.15 thorpej 607: {
1.135 dsl 608: /* {
1.63 thorpej 609: syscallarg(timer_t) timerid;
1.135 dsl 610: } */
1.63 thorpej 611: struct proc *p = l->l_proc;
1.65 jdolecek 612: timer_t timerid;
1.142 ad 613: struct ptimers *pts;
1.63 thorpej 614: struct ptimer *pt, *ptn;
1.1 cgd 615:
1.63 thorpej 616: timerid = SCARG(uap, timerid);
1.142 ad 617: pts = p->p_timers;
618:
619: if (pts == NULL || timerid < 2 || timerid >= TIMER_MAX)
620: return (EINVAL);
1.63 thorpej 621:
1.142 ad 622: mutex_spin_enter(&timer_lock);
623: if ((pt = pts->pts_timers[timerid]) == NULL) {
624: mutex_spin_exit(&timer_lock);
1.1 cgd 625: return (EINVAL);
1.142 ad 626: }
627: if (pt->pt_active) {
1.63 thorpej 628: ptn = LIST_NEXT(pt, pt_list);
629: LIST_REMOVE(pt, pt_list);
630: for ( ; ptn; ptn = LIST_NEXT(ptn, pt_list))
631: timeradd(&pt->pt_time.it_value, &ptn->pt_time.it_value,
632: &ptn->pt_time.it_value);
1.142 ad 633: pt->pt_active = 0;
1.63 thorpej 634: }
1.142 ad 635: itimerfree(pts, timerid);
1.63 thorpej 636:
637: return (0);
638: }
639:
640: /*
1.67 nathanw 641: * Set up the given timer. The value in pt->pt_time.it_value is taken
642: * to be an absolute time for CLOCK_REALTIME timers and a relative
643: * time for virtual timers.
1.63 thorpej 644: * Must be called at splclock().
645: */
646: void
647: timer_settime(struct ptimer *pt)
648: {
649: struct ptimer *ptn, *pptn;
650: struct ptlist *ptl;
651:
1.142 ad 652: KASSERT(mutex_owned(&timer_lock));
653:
1.63 thorpej 654: if (pt->pt_type == CLOCK_REALTIME) {
655: callout_stop(&pt->pt_ch);
656: if (timerisset(&pt->pt_time.it_value)) {
657: /*
658: * Don't need to check hzto() return value, here.
659: * callout_reset() does it for us.
660: */
661: callout_reset(&pt->pt_ch, hzto(&pt->pt_time.it_value),
662: realtimerexpire, pt);
663: }
664: } else {
665: if (pt->pt_active) {
666: ptn = LIST_NEXT(pt, pt_list);
667: LIST_REMOVE(pt, pt_list);
668: for ( ; ptn; ptn = LIST_NEXT(ptn, pt_list))
669: timeradd(&pt->pt_time.it_value,
670: &ptn->pt_time.it_value,
671: &ptn->pt_time.it_value);
672: }
673: if (timerisset(&pt->pt_time.it_value)) {
674: if (pt->pt_type == CLOCK_VIRTUAL)
675: ptl = &pt->pt_proc->p_timers->pts_virtual;
676: else
677: ptl = &pt->pt_proc->p_timers->pts_prof;
678:
679: for (ptn = LIST_FIRST(ptl), pptn = NULL;
680: ptn && timercmp(&pt->pt_time.it_value,
681: &ptn->pt_time.it_value, >);
682: pptn = ptn, ptn = LIST_NEXT(ptn, pt_list))
683: timersub(&pt->pt_time.it_value,
684: &ptn->pt_time.it_value,
685: &pt->pt_time.it_value);
686:
687: if (pptn)
688: LIST_INSERT_AFTER(pptn, pt, pt_list);
689: else
690: LIST_INSERT_HEAD(ptl, pt, pt_list);
691:
692: for ( ; ptn ; ptn = LIST_NEXT(ptn, pt_list))
693: timersub(&ptn->pt_time.it_value,
694: &pt->pt_time.it_value,
695: &ptn->pt_time.it_value);
696:
697: pt->pt_active = 1;
698: } else
699: pt->pt_active = 0;
700: }
701: }
702:
703: void
704: timer_gettime(struct ptimer *pt, struct itimerval *aitv)
705: {
1.101 kardel 706: struct timeval now;
1.63 thorpej 707: struct ptimer *ptn;
708:
1.142 ad 709: KASSERT(mutex_owned(&timer_lock));
710:
1.63 thorpej 711: *aitv = pt->pt_time;
712: if (pt->pt_type == CLOCK_REALTIME) {
1.1 cgd 713: /*
1.12 mycroft 714: * Convert from absolute to relative time in .it_value
1.63 thorpej 715: * part of real time timer. If time for real time
716: * timer has passed return 0, else return difference
717: * between current time and time for the timer to go
718: * off.
1.1 cgd 719: */
1.63 thorpej 720: if (timerisset(&aitv->it_value)) {
1.101 kardel 721: getmicrotime(&now);
722: if (timercmp(&aitv->it_value, &now, <))
723: timerclear(&aitv->it_value);
724: else
725: timersub(&aitv->it_value, &now,
726: &aitv->it_value);
1.36 thorpej 727: }
1.63 thorpej 728: } else if (pt->pt_active) {
729: if (pt->pt_type == CLOCK_VIRTUAL)
730: ptn = LIST_FIRST(&pt->pt_proc->p_timers->pts_virtual);
731: else
732: ptn = LIST_FIRST(&pt->pt_proc->p_timers->pts_prof);
733: for ( ; ptn && ptn != pt; ptn = LIST_NEXT(ptn, pt_list))
734: timeradd(&aitv->it_value,
735: &ptn->pt_time.it_value, &aitv->it_value);
736: KASSERT(ptn != NULL); /* pt should be findable on the list */
1.1 cgd 737: } else
1.63 thorpej 738: timerclear(&aitv->it_value);
739: }
740:
741:
742:
743: /* Set and arm a POSIX realtime timer */
744: int
1.140 yamt 745: sys_timer_settime(struct lwp *l, const struct sys_timer_settime_args *uap,
746: register_t *retval)
1.63 thorpej 747: {
1.135 dsl 748: /* {
1.63 thorpej 749: syscallarg(timer_t) timerid;
750: syscallarg(int) flags;
751: syscallarg(const struct itimerspec *) value;
752: syscallarg(struct itimerspec *) ovalue;
1.135 dsl 753: } */
1.92 cube 754: int error;
755: struct itimerspec value, ovalue, *ovp = NULL;
756:
757: if ((error = copyin(SCARG(uap, value), &value,
758: sizeof(struct itimerspec))) != 0)
759: return (error);
760:
761: if (SCARG(uap, ovalue))
762: ovp = &ovalue;
763:
764: if ((error = dotimer_settime(SCARG(uap, timerid), &value, ovp,
765: SCARG(uap, flags), l->l_proc)) != 0)
766: return error;
767:
768: if (ovp)
769: return copyout(&ovalue, SCARG(uap, ovalue),
770: sizeof(struct itimerspec));
771: return 0;
772: }
773:
774: int
775: dotimer_settime(int timerid, struct itimerspec *value,
776: struct itimerspec *ovalue, int flags, struct proc *p)
777: {
1.101 kardel 778: struct timeval now;
1.63 thorpej 779: struct itimerval val, oval;
1.142 ad 780: struct ptimers *pts;
1.63 thorpej 781: struct ptimer *pt;
782:
1.142 ad 783: pts = p->p_timers;
1.63 thorpej 784:
1.142 ad 785: if (pts == NULL || timerid < 2 || timerid >= TIMER_MAX)
786: return EINVAL;
1.92 cube 787: TIMESPEC_TO_TIMEVAL(&val.it_value, &value->it_value);
788: TIMESPEC_TO_TIMEVAL(&val.it_interval, &value->it_interval);
1.63 thorpej 789: if (itimerfix(&val.it_value) || itimerfix(&val.it_interval))
790: return (EINVAL);
791:
1.142 ad 792: mutex_spin_enter(&timer_lock);
793: if ((pt = pts->pts_timers[timerid]) == NULL) {
794: mutex_spin_exit(&timer_lock);
795: return (EINVAL);
796: }
797:
1.63 thorpej 798: oval = pt->pt_time;
799: pt->pt_time = val;
800:
1.67 nathanw 801: /*
802: * If we've been passed a relative time for a realtime timer,
803: * convert it to absolute; if an absolute time for a virtual
804: * timer, convert it to relative and make sure we don't set it
805: * to zero, which would cancel the timer, or let it go
806: * negative, which would confuse the comparison tests.
807: */
808: if (timerisset(&pt->pt_time.it_value)) {
809: if (pt->pt_type == CLOCK_REALTIME) {
1.101 kardel 810: if ((flags & TIMER_ABSTIME) == 0) {
811: getmicrotime(&now);
812: timeradd(&pt->pt_time.it_value, &now,
813: &pt->pt_time.it_value);
814: }
1.67 nathanw 815: } else {
1.92 cube 816: if ((flags & TIMER_ABSTIME) != 0) {
1.101 kardel 817: getmicrotime(&now);
818: timersub(&pt->pt_time.it_value, &now,
819: &pt->pt_time.it_value);
1.67 nathanw 820: if (!timerisset(&pt->pt_time.it_value) ||
821: pt->pt_time.it_value.tv_sec < 0) {
822: pt->pt_time.it_value.tv_sec = 0;
823: pt->pt_time.it_value.tv_usec = 1;
824: }
825: }
826: }
827: }
828:
1.63 thorpej 829: timer_settime(pt);
1.142 ad 830: mutex_spin_exit(&timer_lock);
1.63 thorpej 831:
1.92 cube 832: if (ovalue) {
833: TIMEVAL_TO_TIMESPEC(&oval.it_value, &ovalue->it_value);
834: TIMEVAL_TO_TIMESPEC(&oval.it_interval, &ovalue->it_interval);
1.63 thorpej 835: }
836:
837: return (0);
838: }
839:
840: /* Return the time remaining until a POSIX timer fires. */
841: int
1.140 yamt 842: sys_timer_gettime(struct lwp *l, const struct sys_timer_gettime_args *uap,
843: register_t *retval)
1.63 thorpej 844: {
1.135 dsl 845: /* {
1.63 thorpej 846: syscallarg(timer_t) timerid;
847: syscallarg(struct itimerspec *) value;
1.135 dsl 848: } */
1.63 thorpej 849: struct itimerspec its;
1.92 cube 850: int error;
851:
852: if ((error = dotimer_gettime(SCARG(uap, timerid), l->l_proc,
853: &its)) != 0)
854: return error;
855:
856: return copyout(&its, SCARG(uap, value), sizeof(its));
857: }
858:
859: int
860: dotimer_gettime(int timerid, struct proc *p, struct itimerspec *its)
861: {
1.63 thorpej 862: struct ptimer *pt;
1.142 ad 863: struct ptimers *pts;
1.92 cube 864: struct itimerval aitv;
1.63 thorpej 865:
1.142 ad 866: pts = p->p_timers;
867: if (pts == NULL || timerid < 2 || timerid >= TIMER_MAX)
1.63 thorpej 868: return (EINVAL);
1.142 ad 869: mutex_spin_enter(&timer_lock);
870: if ((pt = pts->pts_timers[timerid]) == NULL) {
871: mutex_spin_exit(&timer_lock);
872: return (EINVAL);
873: }
1.63 thorpej 874: timer_gettime(pt, &aitv);
1.142 ad 875: mutex_spin_exit(&timer_lock);
1.63 thorpej 876:
1.92 cube 877: TIMEVAL_TO_TIMESPEC(&aitv.it_interval, &its->it_interval);
878: TIMEVAL_TO_TIMESPEC(&aitv.it_value, &its->it_value);
1.63 thorpej 879:
1.92 cube 880: return 0;
1.63 thorpej 881: }
882:
883: /*
884: * Return the count of the number of times a periodic timer expired
885: * while a notification was already pending. The counter is reset when
886: * a timer expires and a notification can be posted.
887: */
888: int
1.140 yamt 889: sys_timer_getoverrun(struct lwp *l, const struct sys_timer_getoverrun_args *uap,
890: register_t *retval)
1.63 thorpej 891: {
1.135 dsl 892: /* {
1.63 thorpej 893: syscallarg(timer_t) timerid;
1.135 dsl 894: } */
1.63 thorpej 895: struct proc *p = l->l_proc;
1.142 ad 896: struct ptimers *pts;
1.63 thorpej 897: int timerid;
898: struct ptimer *pt;
899:
900: timerid = SCARG(uap, timerid);
901:
1.142 ad 902: pts = p->p_timers;
903: if (pts == NULL || timerid < 2 || timerid >= TIMER_MAX)
904: return (EINVAL);
905: mutex_spin_enter(&timer_lock);
906: if ((pt = pts->pts_timers[timerid]) == NULL) {
907: mutex_spin_exit(&timer_lock);
1.63 thorpej 908: return (EINVAL);
1.142 ad 909: }
1.63 thorpej 910: *retval = pt->pt_poverruns;
1.142 ad 911: mutex_spin_exit(&timer_lock);
1.63 thorpej 912:
913: return (0);
914: }
915:
916: /*
917: * Real interval timer expired:
918: * send process whose timer expired an alarm signal.
919: * If time is not set up to reload, then just return.
920: * Else compute next time timer should go off which is > current time.
921: * This is where delay in processing this timeout causes multiple
922: * SIGALRM calls to be compressed into one.
923: */
924: void
925: realtimerexpire(void *arg)
926: {
1.101 kardel 927: struct timeval now;
1.63 thorpej 928: struct ptimer *pt;
929:
1.142 ad 930: pt = arg;
1.63 thorpej 931:
1.142 ad 932: mutex_spin_enter(&timer_lock);
1.63 thorpej 933: itimerfire(pt);
934:
935: if (!timerisset(&pt->pt_time.it_interval)) {
936: timerclear(&pt->pt_time.it_value);
1.142 ad 937: mutex_spin_exit(&timer_lock);
1.63 thorpej 938: return;
939: }
1.101 kardel 940: for (;;) {
941: timeradd(&pt->pt_time.it_value,
942: &pt->pt_time.it_interval, &pt->pt_time.it_value);
943: getmicrotime(&now);
944: if (timercmp(&pt->pt_time.it_value, &now, >)) {
945: /*
946: * Don't need to check hzto() return value, here.
947: * callout_reset() does it for us.
948: */
949: callout_reset(&pt->pt_ch, hzto(&pt->pt_time.it_value),
950: realtimerexpire, pt);
1.142 ad 951: mutex_spin_exit(&timer_lock);
1.101 kardel 952: return;
953: }
1.142 ad 954: mutex_spin_exit(&timer_lock);
1.101 kardel 955: pt->pt_overruns++;
1.142 ad 956: mutex_spin_enter(&timer_lock);
1.101 kardel 957: }
1.63 thorpej 958: }
959:
960: /* BSD routine to get the value of an interval timer. */
961: /* ARGSUSED */
962: int
1.140 yamt 963: sys_getitimer(struct lwp *l, const struct sys_getitimer_args *uap,
964: register_t *retval)
1.63 thorpej 965: {
1.135 dsl 966: /* {
1.63 thorpej 967: syscallarg(int) which;
968: syscallarg(struct itimerval *) itv;
1.135 dsl 969: } */
1.63 thorpej 970: struct proc *p = l->l_proc;
971: struct itimerval aitv;
1.91 cube 972: int error;
973:
974: error = dogetitimer(p, SCARG(uap, which), &aitv);
975: if (error)
976: return error;
977: return (copyout(&aitv, SCARG(uap, itv), sizeof(struct itimerval)));
978: }
1.63 thorpej 979:
1.91 cube 980: int
981: dogetitimer(struct proc *p, int which, struct itimerval *itvp)
982: {
1.142 ad 983: struct ptimers *pts;
984: struct ptimer *pt;
1.63 thorpej 985:
986: if ((u_int)which > ITIMER_PROF)
987: return (EINVAL);
988:
1.142 ad 989: mutex_spin_enter(&timer_lock);
990: pts = p->p_timers;
991: if (pts == NULL || (pt = pts->pts_timers[which]) == NULL) {
1.91 cube 992: timerclear(&itvp->it_value);
993: timerclear(&itvp->it_interval);
1.142 ad 994: } else
995: timer_gettime(pt, itvp);
996: mutex_spin_exit(&timer_lock);
1.63 thorpej 997:
1.91 cube 998: return 0;
1.1 cgd 999: }
1000:
1.63 thorpej 1001: /* BSD routine to set/arm an interval timer. */
1.1 cgd 1002: /* ARGSUSED */
1.3 andrew 1003: int
1.140 yamt 1004: sys_setitimer(struct lwp *l, const struct sys_setitimer_args *uap,
1005: register_t *retval)
1.15 thorpej 1006: {
1.135 dsl 1007: /* {
1.30 mycroft 1008: syscallarg(int) which;
1.24 cgd 1009: syscallarg(const struct itimerval *) itv;
1.11 cgd 1010: syscallarg(struct itimerval *) oitv;
1.135 dsl 1011: } */
1.63 thorpej 1012: struct proc *p = l->l_proc;
1.30 mycroft 1013: int which = SCARG(uap, which);
1.21 cgd 1014: struct sys_getitimer_args getargs;
1.91 cube 1015: const struct itimerval *itvp;
1.1 cgd 1016: struct itimerval aitv;
1.91 cube 1017: int error;
1.1 cgd 1018:
1.30 mycroft 1019: if ((u_int)which > ITIMER_PROF)
1.1 cgd 1020: return (EINVAL);
1.11 cgd 1021: itvp = SCARG(uap, itv);
1.63 thorpej 1022: if (itvp &&
1.56 manu 1023: (error = copyin(itvp, &aitv, sizeof(struct itimerval)) != 0))
1.1 cgd 1024: return (error);
1.21 cgd 1025: if (SCARG(uap, oitv) != NULL) {
1.30 mycroft 1026: SCARG(&getargs, which) = which;
1.21 cgd 1027: SCARG(&getargs, itv) = SCARG(uap, oitv);
1.63 thorpej 1028: if ((error = sys_getitimer(l, &getargs, retval)) != 0)
1.21 cgd 1029: return (error);
1030: }
1.1 cgd 1031: if (itvp == 0)
1032: return (0);
1.91 cube 1033:
1034: return dosetitimer(p, which, &aitv);
1035: }
1036:
1037: int
1038: dosetitimer(struct proc *p, int which, struct itimerval *itvp)
1039: {
1.101 kardel 1040: struct timeval now;
1.142 ad 1041: struct ptimers *pts;
1042: struct ptimer *pt, *spare;
1.91 cube 1043:
1044: if (itimerfix(&itvp->it_value) || itimerfix(&itvp->it_interval))
1.1 cgd 1045: return (EINVAL);
1.63 thorpej 1046:
1047: /*
1048: * Don't bother allocating data structures if the process just
1049: * wants to clear the timer.
1050: */
1.142 ad 1051: spare = NULL;
1052: pts = p->p_timers;
1053: retry:
1054: if (!timerisset(&itvp->it_value) && (pts == NULL ||
1055: pts->pts_timers[which] == NULL))
1.63 thorpej 1056: return (0);
1.142 ad 1057: if (pts == NULL)
1058: pts = timers_alloc(p);
1059: mutex_spin_enter(&timer_lock);
1060: pt = pts->pts_timers[which];
1061: if (pt == NULL) {
1062: if (spare == NULL) {
1063: mutex_spin_exit(&timer_lock);
1064: spare = pool_get(&ptimer_pool, PR_WAITOK);
1065: goto retry;
1066: }
1067: pt = spare;
1068: spare = NULL;
1.63 thorpej 1069: pt->pt_ev.sigev_notify = SIGEV_SIGNAL;
1.76 christos 1070: pt->pt_ev.sigev_value.sival_int = which;
1.63 thorpej 1071: pt->pt_overruns = 0;
1072: pt->pt_proc = p;
1073: pt->pt_type = which;
1.64 nathanw 1074: pt->pt_entry = which;
1.142 ad 1075: pt->pt_active = 0;
1076: pt->pt_queued = false;
1077: callout_init(&pt->pt_ch, CALLOUT_MPSAFE);
1.63 thorpej 1078: switch (which) {
1079: case ITIMER_REAL:
1080: pt->pt_ev.sigev_signo = SIGALRM;
1081: break;
1082: case ITIMER_VIRTUAL:
1083: pt->pt_ev.sigev_signo = SIGVTALRM;
1084: break;
1085: case ITIMER_PROF:
1086: pt->pt_ev.sigev_signo = SIGPROF;
1087: break;
1.1 cgd 1088: }
1.142 ad 1089: pts->pts_timers[which] = pt;
1090: }
1.91 cube 1091: pt->pt_time = *itvp;
1.63 thorpej 1092:
1.67 nathanw 1093: if ((which == ITIMER_REAL) && timerisset(&pt->pt_time.it_value)) {
1094: /* Convert to absolute time */
1.101 kardel 1095: /* XXX need to wrap in splclock for timecounters case? */
1096: getmicrotime(&now);
1097: timeradd(&pt->pt_time.it_value, &now, &pt->pt_time.it_value);
1.67 nathanw 1098: }
1.63 thorpej 1099: timer_settime(pt);
1.142 ad 1100: mutex_spin_exit(&timer_lock);
1101: if (spare != NULL)
1102: pool_put(&ptimer_pool, spare);
1.63 thorpej 1103:
1.1 cgd 1104: return (0);
1105: }
1106:
1.63 thorpej 1107: /* Utility routines to manage the array of pointers to timers. */
1.142 ad 1108: struct ptimers *
1.63 thorpej 1109: timers_alloc(struct proc *p)
1110: {
1.142 ad 1111: struct ptimers *pts;
1.63 thorpej 1112: int i;
1113:
1.100 yamt 1114: pts = pool_get(&ptimers_pool, PR_WAITOK);
1.63 thorpej 1115: LIST_INIT(&pts->pts_virtual);
1116: LIST_INIT(&pts->pts_prof);
1117: for (i = 0; i < TIMER_MAX; i++)
1118: pts->pts_timers[i] = NULL;
1.64 nathanw 1119: pts->pts_fired = 0;
1.142 ad 1120: mutex_spin_enter(&timer_lock);
1121: if (p->p_timers == NULL) {
1122: p->p_timers = pts;
1123: mutex_spin_exit(&timer_lock);
1124: return pts;
1125: }
1126: mutex_spin_exit(&timer_lock);
1127: pool_put(&ptimers_pool, pts);
1128: return p->p_timers;
1.63 thorpej 1129: }
1130:
1.1 cgd 1131: /*
1.63 thorpej 1132: * Clean up the per-process timers. If "which" is set to TIMERS_ALL,
1133: * then clean up all timers and free all the data structures. If
1134: * "which" is set to TIMERS_POSIX, only clean up the timers allocated
1135: * by timer_create(), not the BSD setitimer() timers, and only free the
1136: * structure if none of those remain.
1.1 cgd 1137: */
1.3 andrew 1138: void
1.63 thorpej 1139: timers_free(struct proc *p, int which)
1.6 cgd 1140: {
1.63 thorpej 1141: struct ptimers *pts;
1.142 ad 1142: struct ptimer *ptn;
1.63 thorpej 1143: struct timeval tv;
1.142 ad 1144: int i;
1.63 thorpej 1145:
1.142 ad 1146: if (p->p_timers == NULL)
1147: return;
1.63 thorpej 1148:
1.142 ad 1149: pts = p->p_timers;
1150: mutex_spin_enter(&timer_lock);
1151: if (which == TIMERS_ALL) {
1152: p->p_timers = NULL;
1153: i = 0;
1154: } else {
1155: timerclear(&tv);
1156: for (ptn = LIST_FIRST(&pts->pts_virtual);
1157: ptn && ptn != pts->pts_timers[ITIMER_VIRTUAL];
1158: ptn = LIST_NEXT(ptn, pt_list))
1159: timeradd(&tv, &ptn->pt_time.it_value, &tv);
1160: LIST_FIRST(&pts->pts_virtual) = NULL;
1161: if (ptn) {
1162: timeradd(&tv, &ptn->pt_time.it_value,
1163: &ptn->pt_time.it_value);
1164: LIST_INSERT_HEAD(&pts->pts_virtual, ptn, pt_list);
1165: }
1166: timerclear(&tv);
1167: for (ptn = LIST_FIRST(&pts->pts_prof);
1168: ptn && ptn != pts->pts_timers[ITIMER_PROF];
1169: ptn = LIST_NEXT(ptn, pt_list))
1170: timeradd(&tv, &ptn->pt_time.it_value, &tv);
1171: LIST_FIRST(&pts->pts_prof) = NULL;
1172: if (ptn) {
1173: timeradd(&tv, &ptn->pt_time.it_value,
1174: &ptn->pt_time.it_value);
1175: LIST_INSERT_HEAD(&pts->pts_prof, ptn, pt_list);
1.63 thorpej 1176: }
1.142 ad 1177: i = 3;
1178: }
1179: for ( ; i < TIMER_MAX; i++) {
1180: if (pts->pts_timers[i] != NULL) {
1181: itimerfree(pts, i);
1182: mutex_spin_enter(&timer_lock);
1.1 cgd 1183: }
1184: }
1.142 ad 1185: if (pts->pts_timers[0] == NULL && pts->pts_timers[1] == NULL &&
1186: pts->pts_timers[2] == NULL) {
1187: p->p_timers = NULL;
1188: mutex_spin_exit(&timer_lock);
1189: pool_put(&ptimers_pool, pts);
1190: } else
1191: mutex_spin_exit(&timer_lock);
1192: }
1193:
1194: static void
1195: itimerfree(struct ptimers *pts, int index)
1196: {
1197: struct ptimer *pt;
1198:
1199: KASSERT(mutex_owned(&timer_lock));
1200:
1201: pt = pts->pts_timers[index];
1202: pts->pts_timers[index] = NULL;
1.144 ad 1203: if (pt->pt_type == CLOCK_REALTIME)
1204: callout_halt(&pt->pt_ch, &timer_lock);
1205: else if (pt->pt_queued)
1.142 ad 1206: TAILQ_REMOVE(&timer_queue, pt, pt_chain);
1.144 ad 1207: mutex_spin_exit(&timer_lock);
1.142 ad 1208: callout_destroy(&pt->pt_ch);
1209: pool_put(&ptimer_pool, pt);
1.1 cgd 1210: }
1211:
1212: /*
1213: * Decrement an interval timer by a specified number
1214: * of microseconds, which must be less than a second,
1215: * i.e. < 1000000. If the timer expires, then reload
1216: * it. In this case, carry over (usec - old value) to
1.8 cgd 1217: * reduce the value reloaded into the timer so that
1.1 cgd 1218: * the timer does not drift. This routine assumes
1219: * that it is called in a context where the timers
1220: * on which it is operating cannot change in value.
1221: */
1.142 ad 1222: static int
1.63 thorpej 1223: itimerdecr(struct ptimer *pt, int usec)
1224: {
1.45 augustss 1225: struct itimerval *itp;
1.1 cgd 1226:
1.142 ad 1227: KASSERT(mutex_owned(&timer_lock));
1228:
1.63 thorpej 1229: itp = &pt->pt_time;
1.1 cgd 1230: if (itp->it_value.tv_usec < usec) {
1231: if (itp->it_value.tv_sec == 0) {
1232: /* expired, and already in next interval */
1233: usec -= itp->it_value.tv_usec;
1234: goto expire;
1235: }
1236: itp->it_value.tv_usec += 1000000;
1237: itp->it_value.tv_sec--;
1238: }
1239: itp->it_value.tv_usec -= usec;
1240: usec = 0;
1241: if (timerisset(&itp->it_value))
1242: return (1);
1243: /* expired, exactly at end of interval */
1244: expire:
1245: if (timerisset(&itp->it_interval)) {
1246: itp->it_value = itp->it_interval;
1247: itp->it_value.tv_usec -= usec;
1248: if (itp->it_value.tv_usec < 0) {
1249: itp->it_value.tv_usec += 1000000;
1250: itp->it_value.tv_sec--;
1251: }
1.63 thorpej 1252: timer_settime(pt);
1.1 cgd 1253: } else
1254: itp->it_value.tv_usec = 0; /* sec is already 0 */
1255: return (0);
1.42 cgd 1256: }
1257:
1.142 ad 1258: static void
1.63 thorpej 1259: itimerfire(struct ptimer *pt)
1260: {
1.78 cl 1261:
1.142 ad 1262: KASSERT(mutex_owned(&timer_lock));
1263:
1264: /*
1265: * XXX Can overrun, but we don't do signal queueing yet, anyway.
1266: * XXX Relying on the clock interrupt is stupid.
1267: */
1268: if (pt->pt_ev.sigev_notify != SIGEV_SIGNAL || pt->pt_queued)
1269: return;
1270: TAILQ_INSERT_TAIL(&timer_queue, pt, pt_chain);
1271: pt->pt_queued = true;
1272: softint_schedule(timer_sih);
1273: }
1274:
1275: void
1276: timer_tick(lwp_t *l, bool user)
1277: {
1278: struct ptimers *pts;
1279: struct ptimer *pt;
1280: proc_t *p;
1281:
1282: p = l->l_proc;
1283: if (p->p_timers == NULL)
1284: return;
1285:
1286: mutex_spin_enter(&timer_lock);
1287: if ((pts = l->l_proc->p_timers) != NULL) {
1.63 thorpej 1288: /*
1.142 ad 1289: * Run current process's virtual and profile time, as needed.
1.63 thorpej 1290: */
1.142 ad 1291: if (user && (pt = LIST_FIRST(&pts->pts_virtual)) != NULL)
1292: if (itimerdecr(pt, tick) == 0)
1293: itimerfire(pt);
1294: if ((pt = LIST_FIRST(&pts->pts_prof)) != NULL)
1295: if (itimerdecr(pt, tick) == 0)
1296: itimerfire(pt);
1297: }
1298: mutex_spin_exit(&timer_lock);
1299: }
1300:
1301: static void
1302: timer_intr(void *cookie)
1303: {
1304: ksiginfo_t ksi;
1305: struct ptimer *pt;
1306: proc_t *p;
1307:
1308: mutex_spin_enter(&timer_lock);
1309: while ((pt = TAILQ_FIRST(&timer_queue)) != NULL) {
1310: TAILQ_REMOVE(&timer_queue, pt, pt_chain);
1311: KASSERT(pt->pt_queued);
1312: pt->pt_queued = false;
1313:
1314: if (pt->pt_ev.sigev_notify != SIGEV_SIGNAL)
1315: continue;
1316: p = pt->pt_proc;
1317: if (pt->pt_proc->p_timers == NULL) {
1318: /* Process is dying. */
1319: continue;
1320: }
1321: if (sigismember(&p->p_sigpend.sp_set, pt->pt_ev.sigev_signo)) {
1.63 thorpej 1322: pt->pt_overruns++;
1.142 ad 1323: continue;
1.64 nathanw 1324: }
1.142 ad 1325:
1326: KSI_INIT(&ksi);
1327: ksi.ksi_signo = pt->pt_ev.sigev_signo;
1328: ksi.ksi_code = SI_TIMER;
1329: ksi.ksi_value = pt->pt_ev.sigev_value;
1330: pt->pt_poverruns = pt->pt_overruns;
1331: pt->pt_overruns = 0;
1332: mutex_spin_exit(&timer_lock);
1333:
1.145 ad 1334: mutex_enter(proc_lock);
1.142 ad 1335: kpsignal(p, &ksi, NULL);
1.145 ad 1336: mutex_exit(proc_lock);
1.142 ad 1337:
1338: mutex_spin_enter(&timer_lock);
1.63 thorpej 1339: }
1.142 ad 1340: mutex_spin_exit(&timer_lock);
1.63 thorpej 1341: }
1342:
1.42 cgd 1343: /*
1344: * ratecheck(): simple time-based rate-limit checking. see ratecheck(9)
1345: * for usage and rationale.
1346: */
1347: int
1.63 thorpej 1348: ratecheck(struct timeval *lasttime, const struct timeval *mininterval)
1.42 cgd 1349: {
1.49 itojun 1350: struct timeval tv, delta;
1.101 kardel 1351: int rv = 0;
1.42 cgd 1352:
1.101 kardel 1353: getmicrouptime(&tv);
1.49 itojun 1354: timersub(&tv, lasttime, &delta);
1.42 cgd 1355:
1356: /*
1357: * check for 0,0 is so that the message will be seen at least once,
1358: * even if interval is huge.
1359: */
1360: if (timercmp(&delta, mininterval, >=) ||
1361: (lasttime->tv_sec == 0 && lasttime->tv_usec == 0)) {
1.49 itojun 1362: *lasttime = tv;
1.42 cgd 1363: rv = 1;
1364: }
1.50 itojun 1365:
1366: return (rv);
1367: }
1368:
1369: /*
1370: * ppsratecheck(): packets (or events) per second limitation.
1371: */
1372: int
1.63 thorpej 1373: ppsratecheck(struct timeval *lasttime, int *curpps, int maxpps)
1.50 itojun 1374: {
1375: struct timeval tv, delta;
1.101 kardel 1376: int rv;
1.50 itojun 1377:
1.101 kardel 1378: getmicrouptime(&tv);
1.50 itojun 1379: timersub(&tv, lasttime, &delta);
1380:
1381: /*
1382: * check for 0,0 is so that the message will be seen at least once.
1383: * if more than one second have passed since the last update of
1384: * lasttime, reset the counter.
1385: *
1386: * we do increment *curpps even in *curpps < maxpps case, as some may
1387: * try to use *curpps for stat purposes as well.
1388: */
1389: if ((lasttime->tv_sec == 0 && lasttime->tv_usec == 0) ||
1390: delta.tv_sec >= 1) {
1391: *lasttime = tv;
1392: *curpps = 0;
1.69 dyoung 1393: }
1394: if (maxpps < 0)
1.53 itojun 1395: rv = 1;
1396: else if (*curpps < maxpps)
1.50 itojun 1397: rv = 1;
1398: else
1399: rv = 0;
1400:
1.51 jhawk 1401: #if 1 /*DIAGNOSTIC?*/
1.50 itojun 1402: /* be careful about wrap-around */
1403: if (*curpps + 1 > *curpps)
1404: *curpps = *curpps + 1;
1405: #else
1406: /*
1407: * assume that there's not too many calls to this function.
1408: * not sure if the assumption holds, as it depends on *caller's*
1409: * behavior, not the behavior of this function.
1410: * IMHO it is wrong to make assumption on the caller's behavior,
1.51 jhawk 1411: * so the above #if is #if 1, not #ifdef DIAGNOSTIC.
1.50 itojun 1412: */
1413: *curpps = *curpps + 1;
1414: #endif
1.42 cgd 1415:
1416: return (rv);
1.1 cgd 1417: }
CVSweb <webmaster@jp.NetBSD.org>