Annotation of sys/kern/kern_time.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: kern_time.c,v 1.62 2007/04/04 17:32:20 art Exp $ */
! 2: /* $NetBSD: kern_time.c,v 1.20 1996/02/18 11:57:06 fvdl Exp $ */
! 3:
! 4: /*
! 5: * Copyright (c) 1982, 1986, 1989, 1993
! 6: * The Regents of the University of California. All rights reserved.
! 7: *
! 8: * Redistribution and use in source and binary forms, with or without
! 9: * modification, are permitted provided that the following conditions
! 10: * are met:
! 11: * 1. Redistributions of source code must retain the above copyright
! 12: * notice, this list of conditions and the following disclaimer.
! 13: * 2. Redistributions in binary form must reproduce the above copyright
! 14: * notice, this list of conditions and the following disclaimer in the
! 15: * documentation and/or other materials provided with the distribution.
! 16: * 3. Neither the name of the University nor the names of its contributors
! 17: * may be used to endorse or promote products derived from this software
! 18: * without specific prior written permission.
! 19: *
! 20: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
! 21: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
! 22: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
! 23: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
! 24: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
! 25: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
! 26: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
! 27: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
! 28: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
! 29: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
! 30: * SUCH DAMAGE.
! 31: *
! 32: * @(#)kern_time.c 8.4 (Berkeley) 5/26/95
! 33: */
! 34:
! 35: #include <sys/param.h>
! 36: #include <sys/resourcevar.h>
! 37: #include <sys/kernel.h>
! 38: #include <sys/systm.h>
! 39: #include <sys/proc.h>
! 40: #include <sys/vnode.h>
! 41: #include <sys/signalvar.h>
! 42: #ifdef __HAVE_TIMECOUNTER
! 43: #include <sys/timetc.h>
! 44: #endif
! 45:
! 46: #include <sys/mount.h>
! 47: #include <sys/syscallargs.h>
! 48:
! 49: #include <machine/cpu.h>
! 50:
! 51: void itimerround(struct timeval *);
! 52:
! 53: /*
! 54: * Time of day and interval timer support.
! 55: *
! 56: * These routines provide the kernel entry points to get and set
! 57: * the time-of-day and per-process interval timers. Subroutines
! 58: * here provide support for adding and subtracting timeval structures
! 59: * and decrementing interval timers, optionally reloading the interval
! 60: * timers when they expire.
! 61: */
! 62:
! 63: /* This function is used by clock_settime and settimeofday */
! 64: #ifdef __HAVE_TIMECOUNTER
! 65: int
! 66: settime(struct timespec *ts)
! 67: {
! 68: struct timespec now;
! 69:
! 70:
! 71: /*
! 72: * Don't allow the time to be set forward so far it will wrap
! 73: * and become negative, thus allowing an attacker to bypass
! 74: * the next check below. The cutoff is 1 year before rollover
! 75: * occurs, so even if the attacker uses adjtime(2) to move
! 76: * the time past the cutoff, it will take a very long time
! 77: * to get to the wrap point.
! 78: *
! 79: * XXX: we check against INT_MAX since on 64-bit
! 80: * platforms, sizeof(int) != sizeof(long) and
! 81: * time_t is 32 bits even when atv.tv_sec is 64 bits.
! 82: */
! 83: if (ts->tv_sec > INT_MAX - 365*24*60*60) {
! 84: printf("denied attempt to set clock forward to %ld\n",
! 85: ts->tv_sec);
! 86: return (EPERM);
! 87: }
! 88: /*
! 89: * If the system is secure, we do not allow the time to be
! 90: * set to an earlier value (it may be slowed using adjtime,
! 91: * but not set back). This feature prevent interlopers from
! 92: * setting arbitrary time stamps on files.
! 93: */
! 94: nanotime(&now);
! 95: if (securelevel > 1 && timespeccmp(ts, &now, <)) {
! 96: printf("denied attempt to set clock back %ld seconds\n",
! 97: now.tv_sec - ts->tv_sec);
! 98: return (EPERM);
! 99: }
! 100:
! 101: tc_setclock(ts);
! 102: resettodr();
! 103:
! 104: return (0);
! 105: }
! 106: #else
! 107: int
! 108: settime(struct timespec *ts)
! 109: {
! 110: struct timeval delta, tvv, *tv;
! 111: int s;
! 112:
! 113: /* XXX - Ugh. */
! 114: tv = &tvv;
! 115: tvv.tv_sec = ts->tv_sec;
! 116: tvv.tv_usec = ts->tv_nsec / 1000;
! 117:
! 118: /*
! 119: * Don't allow the time to be set forward so far it will wrap
! 120: * and become negative, thus allowing an attacker to bypass
! 121: * the next check below. The cutoff is 1 year before rollover
! 122: * occurs, so even if the attacker uses adjtime(2) to move
! 123: * the time past the cutoff, it will take a very long time
! 124: * to get to the wrap point.
! 125: *
! 126: * XXX: we check against INT_MAX since on 64-bit
! 127: * platforms, sizeof(int) != sizeof(long) and
! 128: * time_t is 32 bits even when atv.tv_sec is 64 bits.
! 129: */
! 130: if (tv->tv_sec > INT_MAX - 365*24*60*60) {
! 131: printf("denied attempt to set clock forward to %ld\n",
! 132: tv->tv_sec);
! 133: return (EPERM);
! 134: }
! 135: /*
! 136: * If the system is secure, we do not allow the time to be
! 137: * set to an earlier value (it may be slowed using adjtime,
! 138: * but not set back). This feature prevent interlopers from
! 139: * setting arbitrary time stamps on files.
! 140: */
! 141: if (securelevel > 1 && timercmp(tv, &time, <)) {
! 142: printf("denied attempt to set clock back %ld seconds\n",
! 143: time_second - tv->tv_sec);
! 144: return (EPERM);
! 145: }
! 146:
! 147: /* WHAT DO WE DO ABOUT PENDING REAL-TIME TIMEOUTS??? */
! 148: s = splclock();
! 149: timersub(tv, &time, &delta);
! 150: time = *tv;
! 151: timeradd(&boottime, &delta, &boottime);
! 152: splx(s);
! 153: resettodr();
! 154:
! 155: return (0);
! 156: }
! 157: #endif
! 158:
! 159: /* ARGSUSED */
! 160: int
! 161: sys_clock_gettime(struct proc *p, void *v, register_t *retval)
! 162: {
! 163: struct sys_clock_gettime_args /* {
! 164: syscallarg(clockid_t) clock_id;
! 165: syscallarg(struct timespec *) tp;
! 166: } */ *uap = v;
! 167: clockid_t clock_id;
! 168: struct timespec ats;
! 169:
! 170: clock_id = SCARG(uap, clock_id);
! 171: switch (clock_id) {
! 172: case CLOCK_REALTIME:
! 173: nanotime(&ats);
! 174: break;
! 175: case CLOCK_MONOTONIC:
! 176: nanouptime(&ats);
! 177: break;
! 178: case CLOCK_PROF:
! 179: ats.tv_sec = p->p_rtime.tv_sec;
! 180: ats.tv_nsec = p->p_rtime.tv_usec * 1000;
! 181: break;
! 182: default:
! 183: return (EINVAL);
! 184: }
! 185:
! 186: return copyout(&ats, SCARG(uap, tp), sizeof(ats));
! 187: }
! 188:
! 189: /* ARGSUSED */
! 190: int
! 191: sys_clock_settime(struct proc *p, void *v, register_t *retval)
! 192: {
! 193: struct sys_clock_settime_args /* {
! 194: syscallarg(clockid_t) clock_id;
! 195: syscallarg(const struct timespec *) tp;
! 196: } */ *uap = v;
! 197: struct timespec ats;
! 198: clockid_t clock_id;
! 199: int error;
! 200:
! 201: if ((error = suser(p, 0)) != 0)
! 202: return (error);
! 203:
! 204: if ((error = copyin(SCARG(uap, tp), &ats, sizeof(ats))) != 0)
! 205: return (error);
! 206:
! 207: clock_id = SCARG(uap, clock_id);
! 208: switch (clock_id) {
! 209: case CLOCK_REALTIME:
! 210: if ((error = settime(&ats)) != 0)
! 211: return (error);
! 212: break;
! 213: default: /* Other clocks are read-only */
! 214: return (EINVAL);
! 215: }
! 216:
! 217: return (0);
! 218: }
! 219:
! 220: int
! 221: sys_clock_getres(struct proc *p, void *v, register_t *retval)
! 222: {
! 223: struct sys_clock_getres_args /* {
! 224: syscallarg(clockid_t) clock_id;
! 225: syscallarg(struct timespec *) tp;
! 226: } */ *uap = v;
! 227: clockid_t clock_id;
! 228: struct timespec ts;
! 229: int error = 0;
! 230:
! 231: clock_id = SCARG(uap, clock_id);
! 232: switch (clock_id) {
! 233: case CLOCK_REALTIME:
! 234: case CLOCK_MONOTONIC:
! 235: ts.tv_sec = 0;
! 236: ts.tv_nsec = 1000000000 / hz;
! 237: break;
! 238: default:
! 239: return (EINVAL);
! 240: }
! 241:
! 242: if (SCARG(uap, tp))
! 243: error = copyout(&ts, SCARG(uap, tp), sizeof (ts));
! 244:
! 245: return error;
! 246: }
! 247:
! 248: /* ARGSUSED */
! 249: int
! 250: sys_nanosleep(struct proc *p, void *v, register_t *retval)
! 251: {
! 252: static int nanowait;
! 253: struct sys_nanosleep_args/* {
! 254: syscallarg(const struct timespec *) rqtp;
! 255: syscallarg(struct timespec *) rmtp;
! 256: } */ *uap = v;
! 257: struct timespec rqt, rmt;
! 258: struct timespec sts, ets;
! 259: struct timeval tv;
! 260: int error;
! 261:
! 262: error = copyin((const void *)SCARG(uap, rqtp), (void *)&rqt,
! 263: sizeof(struct timespec));
! 264: if (error)
! 265: return (error);
! 266:
! 267: TIMESPEC_TO_TIMEVAL(&tv, &rqt);
! 268: if (itimerfix(&tv))
! 269: return (EINVAL);
! 270:
! 271: if (SCARG(uap, rmtp))
! 272: getnanouptime(&sts);
! 273:
! 274: error = tsleep(&nanowait, PWAIT | PCATCH, "nanosleep",
! 275: MAX(1, tvtohz(&tv)));
! 276: if (error == ERESTART)
! 277: error = EINTR;
! 278: if (error == EWOULDBLOCK)
! 279: error = 0;
! 280:
! 281: if (SCARG(uap, rmtp)) {
! 282: getnanouptime(&ets);
! 283:
! 284: timespecsub(&ets, &sts, &sts);
! 285: timespecsub(&rqt, &sts, &rmt);
! 286:
! 287: if (rmt.tv_sec < 0)
! 288: timespecclear(&rmt);
! 289:
! 290: error = copyout((void *)&rmt, (void *)SCARG(uap,rmtp),
! 291: sizeof(rmt));
! 292: }
! 293:
! 294: return error;
! 295: }
! 296:
! 297: /* ARGSUSED */
! 298: int
! 299: sys_gettimeofday(struct proc *p, void *v, register_t *retval)
! 300: {
! 301: struct sys_gettimeofday_args /* {
! 302: syscallarg(struct timeval *) tp;
! 303: syscallarg(struct timezone *) tzp;
! 304: } */ *uap = v;
! 305: struct timeval atv;
! 306: int error = 0;
! 307:
! 308: if (SCARG(uap, tp)) {
! 309: microtime(&atv);
! 310: if ((error = copyout((void *)&atv, (void *)SCARG(uap, tp),
! 311: sizeof (atv))))
! 312: return (error);
! 313: }
! 314: if (SCARG(uap, tzp))
! 315: error = copyout((void *)&tz, (void *)SCARG(uap, tzp),
! 316: sizeof (tz));
! 317: return (error);
! 318: }
! 319:
! 320: /* ARGSUSED */
! 321: int
! 322: sys_settimeofday(struct proc *p, void *v, register_t *retval)
! 323: {
! 324: struct sys_settimeofday_args /* {
! 325: syscallarg(const struct timeval *) tv;
! 326: syscallarg(const struct timezone *) tzp;
! 327: } */ *uap = v;
! 328: struct timezone atz;
! 329: struct timeval atv;
! 330: int error;
! 331:
! 332: if ((error = suser(p, 0)))
! 333: return (error);
! 334: /* Verify all parameters before changing time. */
! 335: if (SCARG(uap, tv) && (error = copyin((void *)SCARG(uap, tv),
! 336: (void *)&atv, sizeof(atv))))
! 337: return (error);
! 338: if (SCARG(uap, tzp) && (error = copyin((void *)SCARG(uap, tzp),
! 339: (void *)&atz, sizeof(atz))))
! 340: return (error);
! 341: if (SCARG(uap, tv)) {
! 342: struct timespec ts;
! 343:
! 344: TIMEVAL_TO_TIMESPEC(&atv, &ts);
! 345: if ((error = settime(&ts)) != 0)
! 346: return (error);
! 347: }
! 348: if (SCARG(uap, tzp))
! 349: tz = atz;
! 350: return (0);
! 351: }
! 352:
! 353: #ifdef __HAVE_TIMECOUNTER
! 354: struct timeval adjtimedelta; /* unapplied time correction */
! 355: #else
! 356: int tickdelta; /* current clock skew, us. per tick */
! 357: long timedelta; /* unapplied time correction, us. */
! 358: long bigadj = 1000000; /* use 10x skew above bigadj us. */
! 359: int64_t ntp_tick_permanent;
! 360: int64_t ntp_tick_acc;
! 361: #endif
! 362:
! 363: /* ARGSUSED */
! 364: int
! 365: sys_adjfreq(struct proc *p, void *v, register_t *retval)
! 366: {
! 367: struct sys_adjfreq_args /* {
! 368: syscallarg(const int64_t *) freq;
! 369: syscallarg(int64_t *) oldfreq;
! 370: } */ *uap = v;
! 371: int error;
! 372: int64_t f;
! 373: #ifndef __HAVE_TIMECOUNTER
! 374: int s;
! 375:
! 376: if (SCARG(uap, oldfreq)) {
! 377: f = ntp_tick_permanent * hz;
! 378: if ((error = copyout((void *)&f, (void *)SCARG(uap, oldfreq),
! 379: sizeof(int64_t))))
! 380: return (error);
! 381: }
! 382: if (SCARG(uap, freq)) {
! 383: if ((error = suser(p, 0)))
! 384: return (error);
! 385: if ((error = copyin((void *)SCARG(uap, freq), (void *)&f,
! 386: sizeof(int64_t))))
! 387: return (error);
! 388: s = splclock();
! 389: ntp_tick_permanent = f / hz;
! 390: splx(s);
! 391: }
! 392: #else
! 393: if (SCARG(uap, oldfreq)) {
! 394: if ((error = tc_adjfreq(&f, NULL)) != 0)
! 395: return (error);
! 396: if ((error = copyout(&f, SCARG(uap, oldfreq), sizeof(f))) != 0)
! 397: return (error);
! 398: }
! 399: if (SCARG(uap, freq)) {
! 400: if ((error = suser(p, 0)))
! 401: return (error);
! 402: if ((error = copyin(SCARG(uap, freq), &f, sizeof(f))) != 0)
! 403: return (error);
! 404: if ((error = tc_adjfreq(NULL, &f)) != 0)
! 405: return (error);
! 406: }
! 407: #endif
! 408: return (0);
! 409: }
! 410:
! 411: /* ARGSUSED */
! 412: int
! 413: sys_adjtime(struct proc *p, void *v, register_t *retval)
! 414: {
! 415: struct sys_adjtime_args /* {
! 416: syscallarg(const struct timeval *) delta;
! 417: syscallarg(struct timeval *) olddelta;
! 418: } */ *uap = v;
! 419: #ifdef __HAVE_TIMECOUNTER
! 420: int error;
! 421:
! 422: if (SCARG(uap, olddelta))
! 423: if ((error = copyout((void *)&adjtimedelta,
! 424: (void *)SCARG(uap, olddelta), sizeof(struct timeval))))
! 425: return (error);
! 426:
! 427: if (SCARG(uap, delta)) {
! 428: if ((error = suser(p, 0)))
! 429: return (error);
! 430:
! 431: if ((error = copyin((void *)SCARG(uap, delta),
! 432: (void *)&adjtimedelta, sizeof(struct timeval))))
! 433: return (error);
! 434: }
! 435:
! 436: /* Normalize the correction. */
! 437: while (adjtimedelta.tv_usec >= 1000000) {
! 438: adjtimedelta.tv_usec -= 1000000;
! 439: adjtimedelta.tv_sec += 1;
! 440: }
! 441: while (adjtimedelta.tv_usec < 0) {
! 442: adjtimedelta.tv_usec += 1000000;
! 443: adjtimedelta.tv_sec -= 1;
! 444: }
! 445: return (0);
! 446: #else
! 447: struct timeval atv;
! 448: long ndelta, ntickdelta, odelta;
! 449: int s, error;
! 450:
! 451: if (!SCARG(uap, delta)) {
! 452: s = splclock();
! 453: odelta = timedelta;
! 454: splx(s);
! 455: goto out;
! 456: }
! 457: if ((error = suser(p, 0)))
! 458: return (error);
! 459: if ((error = copyin((void *)SCARG(uap, delta), (void *)&atv,
! 460: sizeof(struct timeval))))
! 461: return (error);
! 462:
! 463: /*
! 464: * Compute the total correction and the rate at which to apply it.
! 465: * Round the adjustment down to a whole multiple of the per-tick
! 466: * delta, so that after some number of incremental changes in
! 467: * hardclock(), tickdelta will become zero, lest the correction
! 468: * overshoot and start taking us away from the desired final time.
! 469: */
! 470: if (atv.tv_sec > LONG_MAX / 1000000L)
! 471: ndelta = LONG_MAX;
! 472: else if (atv.tv_sec < LONG_MIN / 1000000L)
! 473: ndelta = LONG_MIN;
! 474: else {
! 475: ndelta = atv.tv_sec * 1000000L;
! 476: odelta = ndelta;
! 477: ndelta += atv.tv_usec;
! 478: if (atv.tv_usec > 0 && ndelta <= odelta)
! 479: ndelta = LONG_MAX;
! 480: else if (atv.tv_usec < 0 && ndelta >= odelta)
! 481: ndelta = LONG_MIN;
! 482: }
! 483:
! 484: if (ndelta > bigadj || ndelta < -bigadj)
! 485: ntickdelta = 10 * tickadj;
! 486: else
! 487: ntickdelta = tickadj;
! 488: if (ndelta % ntickdelta)
! 489: ndelta = ndelta / ntickdelta * ntickdelta;
! 490:
! 491: /*
! 492: * To make hardclock()'s job easier, make the per-tick delta negative
! 493: * if we want time to run slower; then hardclock can simply compute
! 494: * tick + tickdelta, and subtract tickdelta from timedelta.
! 495: */
! 496: if (ndelta < 0)
! 497: ntickdelta = -ntickdelta;
! 498: s = splclock();
! 499: odelta = timedelta;
! 500: timedelta = ndelta;
! 501: tickdelta = ntickdelta;
! 502: splx(s);
! 503:
! 504: out:
! 505: if (SCARG(uap, olddelta)) {
! 506: atv.tv_sec = odelta / 1000000;
! 507: atv.tv_usec = odelta % 1000000;
! 508: if ((error = copyout((void *)&atv, (void *)SCARG(uap, olddelta),
! 509: sizeof(struct timeval))))
! 510: return (error);
! 511: }
! 512: return (0);
! 513: #endif
! 514: }
! 515:
! 516:
! 517: /*
! 518: * Get value of an interval timer. The process virtual and
! 519: * profiling virtual time timers are kept in the p_stats area, since
! 520: * they can be swapped out. These are kept internally in the
! 521: * way they are specified externally: in time until they expire.
! 522: *
! 523: * The real time interval timer is kept in the process table slot
! 524: * for the process, and its value (it_value) is kept as an
! 525: * absolute time rather than as a delta, so that it is easy to keep
! 526: * periodic real-time signals from drifting.
! 527: *
! 528: * Virtual time timers are processed in the hardclock() routine of
! 529: * kern_clock.c. The real time timer is processed by a timeout
! 530: * routine, called from the softclock() routine. Since a callout
! 531: * may be delayed in real time due to interrupt processing in the system,
! 532: * it is possible for the real time timeout routine (realitexpire, given below),
! 533: * to be delayed in real time past when it is supposed to occur. It
! 534: * does not suffice, therefore, to reload the real timer .it_value from the
! 535: * real time timers .it_interval. Rather, we compute the next time in
! 536: * absolute time the timer should go off.
! 537: */
! 538: /* ARGSUSED */
! 539: int
! 540: sys_getitimer(struct proc *p, void *v, register_t *retval)
! 541: {
! 542: struct sys_getitimer_args /* {
! 543: syscallarg(int) which;
! 544: syscallarg(struct itimerval *) itv;
! 545: } */ *uap = v;
! 546: struct itimerval aitv;
! 547: int s;
! 548:
! 549: if (SCARG(uap, which) < ITIMER_REAL || SCARG(uap, which) > ITIMER_PROF)
! 550: return (EINVAL);
! 551: s = splclock();
! 552: if (SCARG(uap, which) == ITIMER_REAL) {
! 553: struct timeval now;
! 554:
! 555: getmicrouptime(&now);
! 556: /*
! 557: * Convert from absolute to relative time in .it_value
! 558: * part of real time timer. If time for real time timer
! 559: * has passed return 0, else return difference between
! 560: * current time and time for the timer to go off.
! 561: */
! 562: aitv = p->p_realtimer;
! 563: if (timerisset(&aitv.it_value)) {
! 564: if (timercmp(&aitv.it_value, &now, <))
! 565: timerclear(&aitv.it_value);
! 566: else
! 567: timersub(&aitv.it_value, &now,
! 568: &aitv.it_value);
! 569: }
! 570: } else
! 571: aitv = p->p_stats->p_timer[SCARG(uap, which)];
! 572: splx(s);
! 573: return (copyout((void *)&aitv, (void *)SCARG(uap, itv),
! 574: sizeof (struct itimerval)));
! 575: }
! 576:
! 577: /* ARGSUSED */
! 578: int
! 579: sys_setitimer(struct proc *p, void *v, register_t *retval)
! 580: {
! 581: struct sys_setitimer_args /* {
! 582: syscallarg(int) which;
! 583: syscallarg(const struct itimerval *) itv;
! 584: syscallarg(struct itimerval *) oitv;
! 585: } */ *uap = v;
! 586: struct sys_getitimer_args getargs;
! 587: struct itimerval aitv;
! 588: const struct itimerval *itvp;
! 589: int error;
! 590: int timo;
! 591:
! 592: if (SCARG(uap, which) < ITIMER_REAL || SCARG(uap, which) > ITIMER_PROF)
! 593: return (EINVAL);
! 594: itvp = SCARG(uap, itv);
! 595: if (itvp && (error = copyin((void *)itvp, (void *)&aitv,
! 596: sizeof(struct itimerval))))
! 597: return (error);
! 598: if (SCARG(uap, oitv) != NULL) {
! 599: SCARG(&getargs, which) = SCARG(uap, which);
! 600: SCARG(&getargs, itv) = SCARG(uap, oitv);
! 601: if ((error = sys_getitimer(p, &getargs, retval)))
! 602: return (error);
! 603: }
! 604: if (itvp == 0)
! 605: return (0);
! 606: if (itimerfix(&aitv.it_value) || itimerfix(&aitv.it_interval))
! 607: return (EINVAL);
! 608: if (SCARG(uap, which) == ITIMER_REAL) {
! 609: struct timeval ctv;
! 610:
! 611: timeout_del(&p->p_realit_to);
! 612: getmicrouptime(&ctv);
! 613: if (timerisset(&aitv.it_value)) {
! 614: timo = tvtohz(&aitv.it_value);
! 615: timeout_add(&p->p_realit_to, timo);
! 616: timeradd(&aitv.it_value, &ctv, &aitv.it_value);
! 617: }
! 618: p->p_realtimer = aitv;
! 619: } else {
! 620: int s;
! 621:
! 622: itimerround(&aitv.it_interval);
! 623: s = splclock();
! 624: p->p_stats->p_timer[SCARG(uap, which)] = aitv;
! 625: splx(s);
! 626: }
! 627:
! 628: return (0);
! 629: }
! 630:
! 631: /*
! 632: * Real interval timer expired:
! 633: * send process whose timer expired an alarm signal.
! 634: * If time is not set up to reload, then just return.
! 635: * Else compute next time timer should go off which is > current time.
! 636: * This is where delay in processing this timeout causes multiple
! 637: * SIGALRM calls to be compressed into one.
! 638: */
! 639: void
! 640: realitexpire(void *arg)
! 641: {
! 642: struct proc *p;
! 643:
! 644: p = (struct proc *)arg;
! 645: psignal(p, SIGALRM);
! 646: if (!timerisset(&p->p_realtimer.it_interval)) {
! 647: timerclear(&p->p_realtimer.it_value);
! 648: return;
! 649: }
! 650: for (;;) {
! 651: struct timeval ctv, ntv;
! 652: int timo;
! 653:
! 654: timeradd(&p->p_realtimer.it_value,
! 655: &p->p_realtimer.it_interval, &p->p_realtimer.it_value);
! 656: getmicrouptime(&ctv);
! 657: if (timercmp(&p->p_realtimer.it_value, &ctv, >)) {
! 658: ntv = p->p_realtimer.it_value;
! 659: timersub(&ntv, &ctv, &ntv);
! 660: timo = tvtohz(&ntv) - 1;
! 661: if (timo <= 0)
! 662: timo = 1;
! 663: if ((p->p_flag & P_WEXIT) == 0)
! 664: timeout_add(&p->p_realit_to, timo);
! 665: return;
! 666: }
! 667: }
! 668: }
! 669:
! 670: /*
! 671: * Check that a proposed value to load into the .it_value or
! 672: * .it_interval part of an interval timer is acceptable.
! 673: */
! 674: int
! 675: itimerfix(struct timeval *tv)
! 676: {
! 677:
! 678: if (tv->tv_sec < 0 || tv->tv_sec > 100000000 ||
! 679: tv->tv_usec < 0 || tv->tv_usec >= 1000000)
! 680: return (EINVAL);
! 681:
! 682: if (tv->tv_sec == 0 && tv->tv_usec != 0 && tv->tv_usec < tick)
! 683: tv->tv_usec = tick;
! 684:
! 685: return (0);
! 686: }
! 687:
! 688: /*
! 689: * Timer interval smaller than the resolution of the system clock are
! 690: * rounded up.
! 691: */
! 692: void
! 693: itimerround(struct timeval *tv)
! 694: {
! 695: if (tv->tv_sec == 0 && tv->tv_usec < tick)
! 696: tv->tv_usec = tick;
! 697: }
! 698:
! 699: /*
! 700: * Decrement an interval timer by a specified number
! 701: * of microseconds, which must be less than a second,
! 702: * i.e. < 1000000. If the timer expires, then reload
! 703: * it. In this case, carry over (usec - old value) to
! 704: * reduce the value reloaded into the timer so that
! 705: * the timer does not drift. This routine assumes
! 706: * that it is called in a context where the timers
! 707: * on which it is operating cannot change in value.
! 708: */
! 709: int
! 710: itimerdecr(struct itimerval *itp, int usec)
! 711: {
! 712:
! 713: if (itp->it_value.tv_usec < usec) {
! 714: if (itp->it_value.tv_sec == 0) {
! 715: /* expired, and already in next interval */
! 716: usec -= itp->it_value.tv_usec;
! 717: goto expire;
! 718: }
! 719: itp->it_value.tv_usec += 1000000;
! 720: itp->it_value.tv_sec--;
! 721: }
! 722: itp->it_value.tv_usec -= usec;
! 723: usec = 0;
! 724: if (timerisset(&itp->it_value))
! 725: return (1);
! 726: /* expired, exactly at end of interval */
! 727: expire:
! 728: if (timerisset(&itp->it_interval)) {
! 729: itp->it_value = itp->it_interval;
! 730: itp->it_value.tv_usec -= usec;
! 731: if (itp->it_value.tv_usec < 0) {
! 732: itp->it_value.tv_usec += 1000000;
! 733: itp->it_value.tv_sec--;
! 734: }
! 735: } else
! 736: itp->it_value.tv_usec = 0; /* sec is already 0 */
! 737: return (0);
! 738: }
! 739:
! 740: /*
! 741: * ratecheck(): simple time-based rate-limit checking. see ratecheck(9)
! 742: * for usage and rationale.
! 743: */
! 744: int
! 745: ratecheck(struct timeval *lasttime, const struct timeval *mininterval)
! 746: {
! 747: struct timeval tv, delta;
! 748: int rv = 0;
! 749:
! 750: microuptime(&tv);
! 751:
! 752: timersub(&tv, lasttime, &delta);
! 753:
! 754: /*
! 755: * check for 0,0 is so that the message will be seen at least once,
! 756: * even if interval is huge.
! 757: */
! 758: if (timercmp(&delta, mininterval, >=) ||
! 759: (lasttime->tv_sec == 0 && lasttime->tv_usec == 0)) {
! 760: *lasttime = tv;
! 761: rv = 1;
! 762: }
! 763:
! 764: return (rv);
! 765: }
! 766:
! 767: /*
! 768: * ppsratecheck(): packets (or events) per second limitation.
! 769: */
! 770: int
! 771: ppsratecheck(struct timeval *lasttime, int *curpps, int maxpps)
! 772: {
! 773: struct timeval tv, delta;
! 774: int rv;
! 775:
! 776: microuptime(&tv);
! 777:
! 778: timersub(&tv, lasttime, &delta);
! 779:
! 780: /*
! 781: * check for 0,0 is so that the message will be seen at least once.
! 782: * if more than one second have passed since the last update of
! 783: * lasttime, reset the counter.
! 784: *
! 785: * we do increment *curpps even in *curpps < maxpps case, as some may
! 786: * try to use *curpps for stat purposes as well.
! 787: */
! 788: if (maxpps == 0)
! 789: rv = 0;
! 790: else if ((lasttime->tv_sec == 0 && lasttime->tv_usec == 0) ||
! 791: delta.tv_sec >= 1) {
! 792: *lasttime = tv;
! 793: *curpps = 0;
! 794: rv = 1;
! 795: } else if (maxpps < 0)
! 796: rv = 1;
! 797: else if (*curpps < maxpps)
! 798: rv = 1;
! 799: else
! 800: rv = 0;
! 801:
! 802: #if 1 /*DIAGNOSTIC?*/
! 803: /* be careful about wrap-around */
! 804: if (*curpps + 1 > *curpps)
! 805: *curpps = *curpps + 1;
! 806: #else
! 807: /*
! 808: * assume that there's not too many calls to this function.
! 809: * not sure if the assumption holds, as it depends on *caller's*
! 810: * behavior, not the behavior of this function.
! 811: * IMHO it is wrong to make assumption on the caller's behavior,
! 812: * so the above #if is #if 1, not #ifdef DIAGNOSTIC.
! 813: */
! 814: *curpps = *curpps + 1;
! 815: #endif
! 816:
! 817: return (rv);
! 818: }
CVSweb