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