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