1 /* $OpenBSD: kern_time.c,v 1.107 2019/01/18 05:03:42 cheloha 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/ktrace.h> 41 #include <sys/vnode.h> 42 #include <sys/signalvar.h> 43 #include <sys/pledge.h> 44 #include <sys/task.h> 45 #include <sys/timeout.h> 46 #include <sys/timetc.h> 47 48 #include <sys/mount.h> 49 #include <sys/syscallargs.h> 50 51 52 int64_t adjtimedelta; /* unapplied time correction (microseconds) */ 53 54 /* 55 * Time of day and interval timer support. 56 * 57 * These routines provide the kernel entry points to get and set 58 * the time-of-day and per-process interval timers. Subroutines 59 * here provide support for adding and subtracting timeval structures 60 * and decrementing interval timers, optionally reloading the interval 61 * timers when they expire. 62 */ 63 64 /* This function is used by clock_settime and settimeofday */ 65 int 66 settime(const struct timespec *ts) 67 { 68 struct timespec now; 69 70 /* 71 * Don't allow the time to be set forward so far it will wrap 72 * and become negative, thus allowing an attacker to bypass 73 * the next check below. The cutoff is 1 year before rollover 74 * occurs, so even if the attacker uses adjtime(2) to move 75 * the time past the cutoff, it will take a very long time 76 * to get to the wrap point. 77 * 78 * XXX: we check against UINT_MAX until we can figure out 79 * how to deal with the hardware RTCs. 80 */ 81 if (ts->tv_sec > UINT_MAX - 365*24*60*60) { 82 printf("denied attempt to set clock forward to %lld\n", 83 (long long)ts->tv_sec); 84 return (EPERM); 85 } 86 /* 87 * If the system is secure, we do not allow the time to be 88 * set to an earlier value (it may be slowed using adjtime, 89 * but not set back). This feature prevent interlopers from 90 * setting arbitrary time stamps on files. 91 */ 92 nanotime(&now); 93 if (securelevel > 1 && timespeccmp(ts, &now, <)) { 94 printf("denied attempt to set clock back %lld seconds\n", 95 (long long)now.tv_sec - ts->tv_sec); 96 return (EPERM); 97 } 98 99 /* 100 * Adjtime in progress is meaningless or harmful after 101 * setting the clock. Cancel adjtime and then set new time. 102 */ 103 adjtimedelta = 0; 104 tc_setrealtimeclock(ts); 105 resettodr(); 106 107 return (0); 108 } 109 110 int 111 clock_gettime(struct proc *p, clockid_t clock_id, struct timespec *tp) 112 { 113 struct bintime bt; 114 struct proc *q; 115 116 switch (clock_id) { 117 case CLOCK_REALTIME: 118 nanotime(tp); 119 break; 120 case CLOCK_UPTIME: 121 binuptime(&bt); 122 bintime_sub(&bt, &naptime); 123 bintime2timespec(&bt, tp); 124 break; 125 case CLOCK_MONOTONIC: 126 case CLOCK_BOOTTIME: 127 nanouptime(tp); 128 break; 129 case CLOCK_PROCESS_CPUTIME_ID: 130 nanouptime(tp); 131 timespecsub(tp, &curcpu()->ci_schedstate.spc_runtime, tp); 132 timespecadd(tp, &p->p_p->ps_tu.tu_runtime, tp); 133 timespecadd(tp, &p->p_rtime, tp); 134 break; 135 case CLOCK_THREAD_CPUTIME_ID: 136 nanouptime(tp); 137 timespecsub(tp, &curcpu()->ci_schedstate.spc_runtime, tp); 138 timespecadd(tp, &p->p_tu.tu_runtime, tp); 139 timespecadd(tp, &p->p_rtime, tp); 140 break; 141 default: 142 /* check for clock from pthread_getcpuclockid() */ 143 if (__CLOCK_TYPE(clock_id) == CLOCK_THREAD_CPUTIME_ID) { 144 q = tfind(__CLOCK_PTID(clock_id) - THREAD_PID_OFFSET); 145 if (q == NULL || q->p_p != p->p_p) 146 return (ESRCH); 147 *tp = q->p_tu.tu_runtime; 148 } else 149 return (EINVAL); 150 } 151 return (0); 152 } 153 154 int 155 sys_clock_gettime(struct proc *p, void *v, register_t *retval) 156 { 157 struct sys_clock_gettime_args /* { 158 syscallarg(clockid_t) clock_id; 159 syscallarg(struct timespec *) tp; 160 } */ *uap = v; 161 struct timespec ats; 162 int error; 163 164 memset(&ats, 0, sizeof(ats)); 165 if ((error = clock_gettime(p, SCARG(uap, clock_id), &ats)) != 0) 166 return (error); 167 168 error = copyout(&ats, SCARG(uap, tp), sizeof(ats)); 169 #ifdef KTRACE 170 if (error == 0 && KTRPOINT(p, KTR_STRUCT)) { 171 KERNEL_LOCK(); 172 ktrabstimespec(p, &ats); 173 KERNEL_UNLOCK(); 174 } 175 #endif 176 return (error); 177 } 178 179 int 180 sys_clock_settime(struct proc *p, void *v, register_t *retval) 181 { 182 struct sys_clock_settime_args /* { 183 syscallarg(clockid_t) clock_id; 184 syscallarg(const struct timespec *) tp; 185 } */ *uap = v; 186 struct timespec ats; 187 clockid_t clock_id; 188 int error; 189 190 if ((error = suser(p)) != 0) 191 return (error); 192 193 if ((error = copyin(SCARG(uap, tp), &ats, sizeof(ats))) != 0) 194 return (error); 195 196 clock_id = SCARG(uap, clock_id); 197 switch (clock_id) { 198 case CLOCK_REALTIME: 199 if (ats.tv_nsec < 0 || ats.tv_nsec >= 1000000000) 200 return (EINVAL); 201 if ((error = settime(&ats)) != 0) 202 return (error); 203 break; 204 default: /* Other clocks are read-only */ 205 return (EINVAL); 206 } 207 208 return (0); 209 } 210 211 int 212 sys_clock_getres(struct proc *p, void *v, register_t *retval) 213 { 214 struct sys_clock_getres_args /* { 215 syscallarg(clockid_t) clock_id; 216 syscallarg(struct timespec *) tp; 217 } */ *uap = v; 218 clockid_t clock_id; 219 struct timespec ts; 220 struct proc *q; 221 int error = 0; 222 223 memset(&ts, 0, sizeof(ts)); 224 clock_id = SCARG(uap, clock_id); 225 switch (clock_id) { 226 case CLOCK_REALTIME: 227 case CLOCK_MONOTONIC: 228 case CLOCK_BOOTTIME: 229 case CLOCK_UPTIME: 230 case CLOCK_PROCESS_CPUTIME_ID: 231 case CLOCK_THREAD_CPUTIME_ID: 232 ts.tv_sec = 0; 233 ts.tv_nsec = 1000000000 / hz; 234 break; 235 default: 236 /* check for clock from pthread_getcpuclockid() */ 237 if (__CLOCK_TYPE(clock_id) == CLOCK_THREAD_CPUTIME_ID) { 238 q = tfind(__CLOCK_PTID(clock_id) - THREAD_PID_OFFSET); 239 if (q == NULL || q->p_p != p->p_p) 240 return (ESRCH); 241 ts.tv_sec = 0; 242 ts.tv_nsec = 1000000000 / hz; 243 } else 244 return (EINVAL); 245 } 246 247 if (SCARG(uap, tp)) { 248 error = copyout(&ts, SCARG(uap, tp), sizeof (ts)); 249 #ifdef KTRACE 250 if (error == 0 && KTRPOINT(p, KTR_STRUCT)) { 251 KERNEL_LOCK(); 252 ktrreltimespec(p, &ts); 253 KERNEL_UNLOCK(); 254 } 255 #endif 256 } 257 258 return error; 259 } 260 261 int 262 sys_nanosleep(struct proc *p, void *v, register_t *retval) 263 { 264 static int nanowait; 265 struct sys_nanosleep_args/* { 266 syscallarg(const struct timespec *) rqtp; 267 syscallarg(struct timespec *) rmtp; 268 } */ *uap = v; 269 struct timespec elapsed, remainder, request, start, stop; 270 struct timespec *rmtp; 271 int copyout_error, error; 272 273 rmtp = SCARG(uap, rmtp); 274 error = copyin(SCARG(uap, rqtp), &request, sizeof(request)); 275 if (error) 276 return (error); 277 #ifdef KTRACE 278 if (KTRPOINT(p, KTR_STRUCT)) { 279 KERNEL_LOCK(); 280 ktrreltimespec(p, &request); 281 KERNEL_UNLOCK(); 282 } 283 #endif 284 285 if (request.tv_sec < 0 || request.tv_nsec < 0 || 286 request.tv_nsec >= 1000000000) 287 return (EINVAL); 288 289 do { 290 getnanouptime(&start); 291 error = tsleep(&nanowait, PWAIT | PCATCH, "nanosleep", 292 MAX(1, tstohz(&request))); 293 getnanouptime(&stop); 294 timespecsub(&stop, &start, &elapsed); 295 timespecsub(&request, &elapsed, &request); 296 if (error != EWOULDBLOCK) 297 break; 298 } while (request.tv_sec >= 0 && timespecisset(&request)); 299 300 if (error == ERESTART) 301 error = EINTR; 302 if (error == EWOULDBLOCK) 303 error = 0; 304 305 if (rmtp) { 306 memset(&remainder, 0, sizeof(remainder)); 307 remainder = request; 308 if (remainder.tv_sec < 0) 309 timespecclear(&remainder); 310 311 copyout_error = copyout(&remainder, rmtp, sizeof(remainder)); 312 if (copyout_error) 313 error = copyout_error; 314 #ifdef KTRACE 315 if (copyout_error == 0 && KTRPOINT(p, KTR_STRUCT)) { 316 KERNEL_LOCK(); 317 ktrreltimespec(p, &remainder); 318 KERNEL_UNLOCK(); 319 } 320 #endif 321 } 322 323 return error; 324 } 325 326 int 327 sys_gettimeofday(struct proc *p, void *v, register_t *retval) 328 { 329 struct sys_gettimeofday_args /* { 330 syscallarg(struct timeval *) tp; 331 syscallarg(struct timezone *) tzp; 332 } */ *uap = v; 333 struct timeval atv; 334 struct timeval *tp; 335 struct timezone *tzp; 336 int error = 0; 337 338 tp = SCARG(uap, tp); 339 tzp = SCARG(uap, tzp); 340 341 if (tp) { 342 memset(&atv, 0, sizeof(atv)); 343 microtime(&atv); 344 if ((error = copyout(&atv, tp, sizeof (atv)))) 345 return (error); 346 #ifdef KTRACE 347 if (KTRPOINT(p, KTR_STRUCT)) { 348 KERNEL_LOCK(); 349 ktrabstimeval(p, &atv); 350 KERNEL_UNLOCK(); 351 } 352 #endif 353 } 354 if (tzp) 355 error = copyout(&tz, tzp, sizeof (tz)); 356 return (error); 357 } 358 359 int 360 sys_settimeofday(struct proc *p, void *v, register_t *retval) 361 { 362 struct sys_settimeofday_args /* { 363 syscallarg(const struct timeval *) tv; 364 syscallarg(const struct timezone *) tzp; 365 } */ *uap = v; 366 struct timezone atz; 367 struct timeval atv; 368 const struct timeval *tv; 369 const struct timezone *tzp; 370 int error; 371 372 tv = SCARG(uap, tv); 373 tzp = SCARG(uap, tzp); 374 375 if ((error = suser(p))) 376 return (error); 377 /* Verify all parameters before changing time. */ 378 if (tv && (error = copyin(tv, &atv, sizeof(atv)))) 379 return (error); 380 if (tzp && (error = copyin(tzp, &atz, sizeof(atz)))) 381 return (error); 382 if (tv) { 383 struct timespec ts; 384 385 if (atv.tv_usec < 0 || atv.tv_usec >= 1000000) 386 return (EINVAL); 387 TIMEVAL_TO_TIMESPEC(&atv, &ts); 388 if ((error = settime(&ts)) != 0) 389 return (error); 390 } 391 if (tzp) 392 tz = atz; 393 return (0); 394 } 395 396 int 397 sys_adjfreq(struct proc *p, void *v, register_t *retval) 398 { 399 struct sys_adjfreq_args /* { 400 syscallarg(const int64_t *) freq; 401 syscallarg(int64_t *) oldfreq; 402 } */ *uap = v; 403 int error; 404 int64_t f; 405 const int64_t *freq = SCARG(uap, freq); 406 int64_t *oldfreq = SCARG(uap, oldfreq); 407 if (oldfreq) { 408 if ((error = tc_adjfreq(&f, NULL))) 409 return (error); 410 if ((error = copyout(&f, oldfreq, sizeof(f)))) 411 return (error); 412 } 413 if (freq) { 414 if ((error = suser(p))) 415 return (error); 416 if ((error = copyin(freq, &f, sizeof(f)))) 417 return (error); 418 if ((error = tc_adjfreq(NULL, &f))) 419 return (error); 420 } 421 return (0); 422 } 423 424 int 425 sys_adjtime(struct proc *p, void *v, register_t *retval) 426 { 427 struct sys_adjtime_args /* { 428 syscallarg(const struct timeval *) delta; 429 syscallarg(struct timeval *) olddelta; 430 } */ *uap = v; 431 const struct timeval *delta = SCARG(uap, delta); 432 struct timeval *olddelta = SCARG(uap, olddelta); 433 struct timeval atv; 434 int error; 435 436 error = pledge_adjtime(p, delta); 437 if (error) 438 return error; 439 440 if (olddelta) { 441 memset(&atv, 0, sizeof(atv)); 442 atv.tv_sec = adjtimedelta / 1000000; 443 atv.tv_usec = adjtimedelta % 1000000; 444 if (atv.tv_usec < 0) { 445 atv.tv_usec += 1000000; 446 atv.tv_sec--; 447 } 448 449 if ((error = copyout(&atv, olddelta, sizeof(struct timeval)))) 450 return (error); 451 } 452 453 if (delta) { 454 if ((error = suser(p))) 455 return (error); 456 457 if ((error = copyin(delta, &atv, sizeof(struct timeval)))) 458 return (error); 459 460 if (atv.tv_usec < 0 || atv.tv_usec >= 1000000) 461 return (EINVAL); 462 463 /* XXX Check for overflow? */ 464 adjtimedelta = (int64_t)atv.tv_sec * 1000000 + atv.tv_usec; 465 } 466 467 return (0); 468 } 469 470 471 struct mutex itimer_mtx = MUTEX_INITIALIZER(IPL_CLOCK); 472 473 /* 474 * Get value of an interval timer. The process virtual and 475 * profiling virtual time timers are kept internally in the 476 * way they are specified externally: in time until they expire. 477 * 478 * The real time interval timer's it_value, in contrast, is kept as an 479 * absolute time rather than as a delta, so that it is easy to keep 480 * periodic real-time signals from drifting. 481 * 482 * Virtual time timers are processed in the hardclock() routine of 483 * kern_clock.c. The real time timer is processed by a timeout 484 * routine, called from the softclock() routine. Since a callout 485 * may be delayed in real time due to interrupt processing in the system, 486 * it is possible for the real time timeout routine (realitexpire, given below), 487 * to be delayed in real time past when it is supposed to occur. It 488 * does not suffice, therefore, to reload the real timer .it_value from the 489 * real time timers .it_interval. Rather, we compute the next time in 490 * absolute time the timer should go off. 491 */ 492 int 493 sys_getitimer(struct proc *p, void *v, register_t *retval) 494 { 495 struct sys_getitimer_args /* { 496 syscallarg(int) which; 497 syscallarg(struct itimerval *) itv; 498 } */ *uap = v; 499 struct itimerval aitv; 500 int which; 501 502 which = SCARG(uap, which); 503 504 if (which < ITIMER_REAL || which > ITIMER_PROF) 505 return (EINVAL); 506 memset(&aitv, 0, sizeof(aitv)); 507 mtx_enter(&itimer_mtx); 508 aitv.it_interval.tv_sec = p->p_p->ps_timer[which].it_interval.tv_sec; 509 aitv.it_interval.tv_usec = p->p_p->ps_timer[which].it_interval.tv_usec; 510 aitv.it_value.tv_sec = p->p_p->ps_timer[which].it_value.tv_sec; 511 aitv.it_value.tv_usec = p->p_p->ps_timer[which].it_value.tv_usec; 512 mtx_leave(&itimer_mtx); 513 514 if (which == ITIMER_REAL) { 515 struct timeval now; 516 517 getmicrouptime(&now); 518 /* 519 * Convert from absolute to relative time in .it_value 520 * part of real time timer. If time for real time timer 521 * has passed return 0, else return difference between 522 * current time and time for the timer to go off. 523 */ 524 if (timerisset(&aitv.it_value)) { 525 if (timercmp(&aitv.it_value, &now, <)) 526 timerclear(&aitv.it_value); 527 else 528 timersub(&aitv.it_value, &now, 529 &aitv.it_value); 530 } 531 } 532 533 return (copyout(&aitv, SCARG(uap, itv), sizeof (struct itimerval))); 534 } 535 536 int 537 sys_setitimer(struct proc *p, void *v, register_t *retval) 538 { 539 struct sys_setitimer_args /* { 540 syscallarg(int) which; 541 syscallarg(const struct itimerval *) itv; 542 syscallarg(struct itimerval *) oitv; 543 } */ *uap = v; 544 struct sys_getitimer_args getargs; 545 struct itimerval aitv; 546 const struct itimerval *itvp; 547 struct itimerval *oitv; 548 struct process *pr = p->p_p; 549 int error; 550 int timo; 551 int which; 552 553 which = SCARG(uap, which); 554 oitv = SCARG(uap, oitv); 555 556 if (which < ITIMER_REAL || which > ITIMER_PROF) 557 return (EINVAL); 558 itvp = SCARG(uap, itv); 559 if (itvp && (error = copyin((void *)itvp, (void *)&aitv, 560 sizeof(struct itimerval)))) 561 return (error); 562 if (oitv != NULL) { 563 SCARG(&getargs, which) = which; 564 SCARG(&getargs, itv) = oitv; 565 if ((error = sys_getitimer(p, &getargs, retval))) 566 return (error); 567 } 568 if (itvp == 0) 569 return (0); 570 if (itimerfix(&aitv.it_value) || itimerfix(&aitv.it_interval)) 571 return (EINVAL); 572 if (which == ITIMER_REAL) { 573 struct timeval ctv; 574 575 timeout_del(&pr->ps_realit_to); 576 getmicrouptime(&ctv); 577 if (timerisset(&aitv.it_value)) { 578 timo = tvtohz(&aitv.it_value); 579 timeout_add(&pr->ps_realit_to, timo); 580 timeradd(&aitv.it_value, &ctv, &aitv.it_value); 581 } 582 pr->ps_timer[ITIMER_REAL] = aitv; 583 } else { 584 itimerround(&aitv.it_interval); 585 mtx_enter(&itimer_mtx); 586 pr->ps_timer[which] = aitv; 587 mtx_leave(&itimer_mtx); 588 } 589 590 return (0); 591 } 592 593 /* 594 * Real interval timer expired: 595 * send process whose timer expired an alarm signal. 596 * If time is not set up to reload, then just return. 597 * Else compute next time timer should go off which is > current time. 598 * This is where delay in processing this timeout causes multiple 599 * SIGALRM calls to be compressed into one. 600 */ 601 void 602 realitexpire(void *arg) 603 { 604 struct process *pr = arg; 605 struct itimerval *tp = &pr->ps_timer[ITIMER_REAL]; 606 607 prsignal(pr, SIGALRM); 608 if (!timerisset(&tp->it_interval)) { 609 timerclear(&tp->it_value); 610 return; 611 } 612 for (;;) { 613 struct timeval ctv, ntv; 614 int timo; 615 616 timeradd(&tp->it_value, &tp->it_interval, &tp->it_value); 617 getmicrouptime(&ctv); 618 if (timercmp(&tp->it_value, &ctv, >)) { 619 ntv = tp->it_value; 620 timersub(&ntv, &ctv, &ntv); 621 timo = tvtohz(&ntv) - 1; 622 if (timo <= 0) 623 timo = 1; 624 if ((pr->ps_flags & PS_EXITING) == 0) 625 timeout_add(&pr->ps_realit_to, timo); 626 return; 627 } 628 } 629 } 630 631 /* 632 * Check that a timespec value is legit 633 */ 634 int 635 timespecfix(struct timespec *ts) 636 { 637 if (ts->tv_sec < 0 || 638 ts->tv_nsec < 0 || ts->tv_nsec >= 1000000000) 639 return (EINVAL); 640 if (ts->tv_sec > 100000000) 641 ts->tv_sec = 100000000; 642 return (0); 643 } 644 645 /* 646 * Check that a proposed value to load into the .it_value or 647 * .it_interval part of an interval timer is acceptable. 648 */ 649 int 650 itimerfix(struct timeval *tv) 651 { 652 653 if (tv->tv_sec < 0 || tv->tv_sec > 100000000 || 654 tv->tv_usec < 0 || tv->tv_usec >= 1000000) 655 return (EINVAL); 656 657 if (tv->tv_sec == 0 && tv->tv_usec != 0 && tv->tv_usec < tick) 658 tv->tv_usec = tick; 659 660 return (0); 661 } 662 663 /* 664 * Nonzero timer interval smaller than the resolution of the 665 * system clock are rounded up. 666 */ 667 void 668 itimerround(struct timeval *tv) 669 { 670 if (tv->tv_sec == 0 && tv->tv_usec != 0 && tv->tv_usec < tick) 671 tv->tv_usec = tick; 672 } 673 674 /* 675 * Decrement an interval timer by a specified number 676 * of microseconds, which must be less than a second, 677 * i.e. < 1000000. If the timer expires, then reload 678 * it. In this case, carry over (usec - old value) to 679 * reduce the value reloaded into the timer so that 680 * the timer does not drift. This routine assumes 681 * that it is called in a context where the timers 682 * on which it is operating cannot change in value. 683 */ 684 int 685 itimerdecr(struct itimerval *itp, int usec) 686 { 687 mtx_enter(&itimer_mtx); 688 if (itp->it_value.tv_usec < usec) { 689 if (itp->it_value.tv_sec == 0) { 690 /* expired, and already in next interval */ 691 usec -= itp->it_value.tv_usec; 692 goto expire; 693 } 694 itp->it_value.tv_usec += 1000000; 695 itp->it_value.tv_sec--; 696 } 697 itp->it_value.tv_usec -= usec; 698 usec = 0; 699 if (timerisset(&itp->it_value)) { 700 mtx_leave(&itimer_mtx); 701 return (1); 702 } 703 /* expired, exactly at end of interval */ 704 expire: 705 if (timerisset(&itp->it_interval)) { 706 itp->it_value = itp->it_interval; 707 itp->it_value.tv_usec -= usec; 708 if (itp->it_value.tv_usec < 0) { 709 itp->it_value.tv_usec += 1000000; 710 itp->it_value.tv_sec--; 711 } 712 } else 713 itp->it_value.tv_usec = 0; /* sec is already 0 */ 714 mtx_leave(&itimer_mtx); 715 return (0); 716 } 717 718 /* 719 * ratecheck(): simple time-based rate-limit checking. see ratecheck(9) 720 * for usage and rationale. 721 */ 722 int 723 ratecheck(struct timeval *lasttime, const struct timeval *mininterval) 724 { 725 struct timeval tv, delta; 726 int rv = 0; 727 728 getmicrouptime(&tv); 729 730 timersub(&tv, lasttime, &delta); 731 732 /* 733 * check for 0,0 is so that the message will be seen at least once, 734 * even if interval is huge. 735 */ 736 if (timercmp(&delta, mininterval, >=) || 737 (lasttime->tv_sec == 0 && lasttime->tv_usec == 0)) { 738 *lasttime = tv; 739 rv = 1; 740 } 741 742 return (rv); 743 } 744 745 /* 746 * ppsratecheck(): packets (or events) per second limitation. 747 */ 748 int 749 ppsratecheck(struct timeval *lasttime, int *curpps, int maxpps) 750 { 751 struct timeval tv, delta; 752 int rv; 753 754 microuptime(&tv); 755 756 timersub(&tv, lasttime, &delta); 757 758 /* 759 * check for 0,0 is so that the message will be seen at least once. 760 * if more than one second have passed since the last update of 761 * lasttime, reset the counter. 762 * 763 * we do increment *curpps even in *curpps < maxpps case, as some may 764 * try to use *curpps for stat purposes as well. 765 */ 766 if (maxpps == 0) 767 rv = 0; 768 else if ((lasttime->tv_sec == 0 && lasttime->tv_usec == 0) || 769 delta.tv_sec >= 1) { 770 *lasttime = tv; 771 *curpps = 0; 772 rv = 1; 773 } else if (maxpps < 0) 774 rv = 1; 775 else if (*curpps < maxpps) 776 rv = 1; 777 else 778 rv = 0; 779 780 #if 1 /*DIAGNOSTIC?*/ 781 /* be careful about wrap-around */ 782 if (*curpps + 1 > *curpps) 783 *curpps = *curpps + 1; 784 #else 785 /* 786 * assume that there's not too many calls to this function. 787 * not sure if the assumption holds, as it depends on *caller's* 788 * behavior, not the behavior of this function. 789 * IMHO it is wrong to make assumption on the caller's behavior, 790 * so the above #if is #if 1, not #ifdef DIAGNOSTIC. 791 */ 792 *curpps = *curpps + 1; 793 #endif 794 795 return (rv); 796 } 797 798 799 #define RESETTODR_PERIOD 1800 800 801 void periodic_resettodr(void *); 802 void perform_resettodr(void *); 803 804 struct timeout resettodr_to = TIMEOUT_INITIALIZER(periodic_resettodr, NULL); 805 struct task resettodr_task = TASK_INITIALIZER(perform_resettodr, NULL); 806 807 void 808 periodic_resettodr(void *arg __unused) 809 { 810 task_add(systq, &resettodr_task); 811 } 812 813 void 814 perform_resettodr(void *arg __unused) 815 { 816 resettodr(); 817 timeout_add_sec(&resettodr_to, RESETTODR_PERIOD); 818 } 819 820 void 821 start_periodic_resettodr(void) 822 { 823 timeout_add_sec(&resettodr_to, RESETTODR_PERIOD); 824 } 825 826 void 827 stop_periodic_resettodr(void) 828 { 829 timeout_del(&resettodr_to); 830 task_del(systq, &resettodr_task); 831 } 832