The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/kern/kern_time.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*
    2  * Copyright (c) 1982, 1986, 1989, 1993
    3  *      The Regents of the University of California.  All rights reserved.
    4  *
    5  * Redistribution and use in source and binary forms, with or without
    6  * modification, are permitted provided that the following conditions
    7  * are met:
    8  * 1. Redistributions of source code must retain the above copyright
    9  *    notice, this list of conditions and the following disclaimer.
   10  * 2. Redistributions in binary form must reproduce the above copyright
   11  *    notice, this list of conditions and the following disclaimer in the
   12  *    documentation and/or other materials provided with the distribution.
   13  * 3. All advertising materials mentioning features or use of this software
   14  *    must display the following acknowledgement:
   15  *      This product includes software developed by the University of
   16  *      California, Berkeley and its contributors.
   17  * 4. Neither the name of the University nor the names of its contributors
   18  *    may be used to endorse or promote products derived from this software
   19  *    without specific prior written permission.
   20  *
   21  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
   22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   24  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
   25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   31  * SUCH DAMAGE.
   32  *
   33  *      @(#)kern_time.c 8.1 (Berkeley) 6/10/93
   34  * $FreeBSD$
   35  */
   36 
   37 #include <sys/param.h>
   38 #include <sys/systm.h>
   39 #include <sys/buf.h>
   40 #include <sys/sysproto.h>
   41 #include <sys/resourcevar.h>
   42 #include <sys/signalvar.h>
   43 #include <sys/kernel.h>
   44 #include <sys/systm.h>
   45 #include <sys/sysent.h>
   46 #include <sys/proc.h>
   47 #include <sys/time.h>
   48 #include <sys/vnode.h>
   49 #include <vm/vm.h>
   50 #include <vm/vm_extern.h>
   51 
   52 struct timezone tz;
   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 static int      nanosleep1 __P((struct proc *p, struct timespec *rqt,
   65                     struct timespec *rmt));
   66 static int      settime __P((struct timeval *));
   67 static void     timevalfix __P((struct timeval *));
   68 static void     no_lease_updatetime __P((int));
   69 
   70 static void 
   71 no_lease_updatetime(deltat)
   72         int deltat;
   73 {
   74 }
   75 
   76 void (*lease_updatetime) __P((int))  = no_lease_updatetime;
   77 
   78 static int
   79 settime(tv)
   80         struct timeval *tv;
   81 {
   82         struct timeval delta, tv1, tv2;
   83         static struct timeval maxtime, laststep;
   84         struct timespec ts;
   85         int s;
   86 
   87         s = splclock();
   88         microtime(&tv1);
   89         delta = *tv;
   90         timevalsub(&delta, &tv1);
   91 
   92         /*
   93          * If the system is secure, we do not allow the time to be 
   94          * set to a value earlier than 1 second less than the highest
   95          * time we have yet seen. The worst a miscreant can do in
   96          * this circumstance is "freeze" time. He couldn't go
   97          * back to the past.
   98          *
   99          * We similarly do not allow the clock to be stepped more
  100          * than one second, nor more than once per second. This allows
  101          * a miscreant to make the clock march double-time, but no worse.
  102          */
  103         if (securelevel > 1) {
  104                 if (delta.tv_sec < 0 || delta.tv_usec < 0) {
  105                         /*
  106                          * Update maxtime to latest time we've seen.
  107                          */
  108                         if (tv1.tv_sec > maxtime.tv_sec)
  109                                 maxtime = tv1;
  110                         tv2 = *tv;
  111                         timevalsub(&tv2, &maxtime);
  112                         if (tv2.tv_sec < -1) {
  113                                 tv->tv_sec = maxtime.tv_sec - 1;
  114                                 printf("Time adjustment clamped to -1 second\n");
  115                         }
  116                 } else {
  117                         if (tv1.tv_sec == laststep.tv_sec) {
  118                                 splx(s);
  119                                 return (EPERM);
  120                         }
  121                         if (delta.tv_sec > 1) {
  122                                 tv->tv_sec = tv1.tv_sec + 1;
  123                                 printf("Time adjustment clamped to +1 second\n");
  124                         }
  125                         laststep = *tv;
  126                 }
  127         }
  128 
  129         ts.tv_sec = tv->tv_sec;
  130         ts.tv_nsec = tv->tv_usec * 1000;
  131         set_timecounter(&ts);
  132         (void) splsoftclock();
  133         lease_updatetime(delta.tv_sec);
  134         splx(s);
  135         resettodr();
  136         return (0);
  137 }
  138 
  139 #ifndef _SYS_SYSPROTO_H_
  140 struct clock_gettime_args {
  141         clockid_t clock_id;
  142         struct  timespec *tp;
  143 };
  144 #endif
  145 
  146 /* ARGSUSED */
  147 int
  148 clock_gettime(p, uap)
  149         struct proc *p;
  150         struct clock_gettime_args *uap;
  151 {
  152         struct timespec ats;
  153 
  154         if (SCARG(uap, clock_id) != CLOCK_REALTIME)
  155                 return (EINVAL);
  156         nanotime(&ats);
  157         return (copyout(&ats, SCARG(uap, tp), sizeof(ats)));
  158 }
  159 
  160 #ifndef _SYS_SYSPROTO_H_
  161 struct clock_settime_args {
  162         clockid_t clock_id;
  163         const struct    timespec *tp;
  164 };
  165 #endif
  166 
  167 /* ARGSUSED */
  168 int
  169 clock_settime(p, uap)
  170         struct proc *p;
  171         struct clock_settime_args *uap;
  172 {
  173         struct timeval atv;
  174         struct timespec ats;
  175         int error;
  176 
  177         if ((error = suser(p)) != 0)
  178                 return (error);
  179         if (SCARG(uap, clock_id) != CLOCK_REALTIME)
  180                 return (EINVAL);
  181         if ((error = copyin(SCARG(uap, tp), &ats, sizeof(ats))) != 0)
  182                 return (error);
  183         if (ats.tv_nsec < 0 || ats.tv_nsec >= 1000000000)
  184                 return (EINVAL);
  185         /* XXX Don't convert nsec->usec and back */
  186         TIMESPEC_TO_TIMEVAL(&atv, &ats);
  187         if ((error = settime(&atv)))
  188                 return (error);
  189         return (0);
  190 }
  191 
  192 #ifndef _SYS_SYSPROTO_H_
  193 struct clock_getres_args {
  194         clockid_t clock_id;
  195         struct  timespec *tp;
  196 };
  197 #endif
  198 
  199 int
  200 clock_getres(p, uap)
  201         struct proc *p;
  202         struct clock_getres_args *uap;
  203 {
  204         struct timespec ts;
  205         int error;
  206 
  207         if (SCARG(uap, clock_id) != CLOCK_REALTIME)
  208                 return (EINVAL);
  209         error = 0;
  210         if (SCARG(uap, tp)) {
  211                 ts.tv_sec = 0;
  212                 /*
  213                  * Round up the result of the division cheaply by adding 1.
  214                  * Rounding up is especially important if rounding down
  215                  * would give 0.  Perfect rounding is unimportant.
  216                  */
  217                 ts.tv_nsec = 1000000000 / timecounter->tc_frequency + 1;
  218                 error = copyout(&ts, SCARG(uap, tp), sizeof(ts));
  219         }
  220         return (error);
  221 }
  222 
  223 static int nanowait;
  224 
  225 static int
  226 nanosleep1(p, rqt, rmt)
  227         struct proc *p;
  228         struct timespec *rqt, *rmt;
  229 {
  230         struct timespec ts, ts2, ts3;
  231         struct timeval tv;
  232         int error;
  233 
  234         if (rqt->tv_nsec < 0 || rqt->tv_nsec >= 1000000000)
  235                 return (EINVAL);
  236         if (rqt->tv_sec < 0 || (rqt->tv_sec == 0 && rqt->tv_nsec == 0))
  237                 return (0);
  238         getnanouptime(&ts);
  239         timespecadd(&ts, rqt);
  240         TIMESPEC_TO_TIMEVAL(&tv, rqt);
  241         for (;;) {
  242                 error = tsleep(&nanowait, PWAIT | PCATCH, "nanslp",
  243                     tvtohz(&tv));
  244                 getnanouptime(&ts2);
  245                 if (error != EWOULDBLOCK) {
  246                         if (error == ERESTART)
  247                                 error = EINTR;
  248                         if (rmt != NULL) {
  249                                 timespecsub(&ts, &ts2);
  250                                 if (ts.tv_sec < 0)
  251                                         timespecclear(&ts);
  252                                 *rmt = ts;
  253                         }
  254                         return (error);
  255                 }
  256                 if (timespeccmp(&ts2, &ts, >=))
  257                         return (0);
  258                 ts3 = ts;
  259                 timespecsub(&ts3, &ts2);
  260                 TIMESPEC_TO_TIMEVAL(&tv, &ts3);
  261         }
  262 }
  263 
  264 #ifndef _SYS_SYSPROTO_H_
  265 struct nanosleep_args {
  266         struct  timespec *rqtp;
  267         struct  timespec *rmtp;
  268 };
  269 #endif
  270 
  271 /* ARGSUSED */
  272 int
  273 nanosleep(p, uap)
  274         struct proc *p;
  275         struct nanosleep_args *uap;
  276 {
  277         struct timespec rmt, rqt;
  278         int error, error2;
  279 
  280         error = copyin(SCARG(uap, rqtp), &rqt, sizeof(rqt));
  281         if (error)
  282                 return (error);
  283         if (SCARG(uap, rmtp))
  284                 if (!useracc((caddr_t)SCARG(uap, rmtp), sizeof(rmt), 
  285                     VM_PROT_WRITE))
  286                         return (EFAULT);
  287         error = nanosleep1(p, &rqt, &rmt);
  288         if (error && SCARG(uap, rmtp)) {
  289                 error2 = copyout(&rmt, SCARG(uap, rmtp), sizeof(rmt));
  290                 if (error2)     /* XXX shouldn't happen, did useracc() above */
  291                         return (error2);
  292         }
  293         return (error);
  294 }
  295 
  296 #ifndef _SYS_SYSPROTO_H_
  297 struct gettimeofday_args {
  298         struct  timeval *tp;
  299         struct  timezone *tzp;
  300 };
  301 #endif
  302 /* ARGSUSED */
  303 int
  304 gettimeofday(p, uap)
  305         struct proc *p;
  306         register struct gettimeofday_args *uap;
  307 {
  308         struct timeval atv;
  309         int error = 0;
  310 
  311         if (uap->tp) {
  312                 microtime(&atv);
  313                 if ((error = copyout((caddr_t)&atv, (caddr_t)uap->tp,
  314                     sizeof (atv))))
  315                         return (error);
  316         }
  317         if (uap->tzp)
  318                 error = copyout((caddr_t)&tz, (caddr_t)uap->tzp,
  319                     sizeof (tz));
  320         return (error);
  321 }
  322 
  323 #ifndef _SYS_SYSPROTO_H_
  324 struct settimeofday_args {
  325         struct  timeval *tv;
  326         struct  timezone *tzp;
  327 };
  328 #endif
  329 /* ARGSUSED */
  330 int
  331 settimeofday(p, uap)
  332         struct proc *p;
  333         struct settimeofday_args *uap;
  334 {
  335         struct timeval atv;
  336         struct timezone atz;
  337         int error;
  338 
  339         if ((error = suser(p)))
  340                 return (error);
  341         /* Verify all parameters before changing time. */
  342         if (uap->tv) {
  343                 if ((error = copyin((caddr_t)uap->tv, (caddr_t)&atv,
  344                     sizeof(atv))))
  345                         return (error);
  346                 if (atv.tv_usec < 0 || atv.tv_usec >= 1000000)
  347                         return (EINVAL);
  348         }
  349         if (uap->tzp &&
  350             (error = copyin((caddr_t)uap->tzp, (caddr_t)&atz, sizeof(atz))))
  351                 return (error);
  352         if (uap->tv && (error = settime(&atv)))
  353                 return (error);
  354         if (uap->tzp)
  355                 tz = atz;
  356         return (0);
  357 }
  358 
  359 int     tickdelta;                      /* current clock skew, us. per tick */
  360 long    timedelta;                      /* unapplied time correction, us. */
  361 static long     bigadj = 1000000;       /* use 10x skew above bigadj us. */
  362 
  363 #ifndef _SYS_SYSPROTO_H_
  364 struct adjtime_args {
  365         struct timeval *delta;
  366         struct timeval *olddelta;
  367 };
  368 #endif
  369 /* ARGSUSED */
  370 int
  371 adjtime(p, uap)
  372         struct proc *p;
  373         register struct adjtime_args *uap;
  374 {
  375         struct timeval atv;
  376         register long ndelta, ntickdelta, odelta;
  377         int s, error;
  378 
  379         if ((error = suser(p)))
  380                 return (error);
  381         if ((error =
  382             copyin((caddr_t)uap->delta, (caddr_t)&atv, sizeof(struct timeval))))
  383                 return (error);
  384 
  385         /*
  386          * Compute the total correction and the rate at which to apply it.
  387          * Round the adjustment down to a whole multiple of the per-tick
  388          * delta, so that after some number of incremental changes in
  389          * hardclock(), tickdelta will become zero, lest the correction
  390          * overshoot and start taking us away from the desired final time.
  391          */
  392         ndelta = atv.tv_sec * 1000000 + atv.tv_usec;
  393         if (ndelta > bigadj || ndelta < -bigadj)
  394                 ntickdelta = 10 * tickadj;
  395         else
  396                 ntickdelta = tickadj;
  397         if (ndelta % ntickdelta)
  398                 ndelta = ndelta / ntickdelta * ntickdelta;
  399 
  400         /*
  401          * To make hardclock()'s job easier, make the per-tick delta negative
  402          * if we want time to run slower; then hardclock can simply compute
  403          * tick + tickdelta, and subtract tickdelta from timedelta.
  404          */
  405         if (ndelta < 0)
  406                 ntickdelta = -ntickdelta;
  407         s = splclock();
  408         odelta = timedelta;
  409         timedelta = ndelta;
  410         tickdelta = ntickdelta;
  411         splx(s);
  412 
  413         if (uap->olddelta) {
  414                 atv.tv_sec = odelta / 1000000;
  415                 atv.tv_usec = odelta % 1000000;
  416                 (void) copyout((caddr_t)&atv, (caddr_t)uap->olddelta,
  417                     sizeof(struct timeval));
  418         }
  419         return (0);
  420 }
  421 
  422 /*
  423  * Get value of an interval timer.  The process virtual and
  424  * profiling virtual time timers are kept in the p_stats area, since
  425  * they can be swapped out.  These are kept internally in the
  426  * way they are specified externally: in time until they expire.
  427  *
  428  * The real time interval timer is kept in the process table slot
  429  * for the process, and its value (it_value) is kept as an
  430  * absolute time rather than as a delta, so that it is easy to keep
  431  * periodic real-time signals from drifting.
  432  *
  433  * Virtual time timers are processed in the hardclock() routine of
  434  * kern_clock.c.  The real time timer is processed by a timeout
  435  * routine, called from the softclock() routine.  Since a callout
  436  * may be delayed in real time due to interrupt processing in the system,
  437  * it is possible for the real time timeout routine (realitexpire, given below),
  438  * to be delayed in real time past when it is supposed to occur.  It
  439  * does not suffice, therefore, to reload the real timer .it_value from the
  440  * real time timers .it_interval.  Rather, we compute the next time in
  441  * absolute time the timer should go off.
  442  */
  443 #ifndef _SYS_SYSPROTO_H_
  444 struct getitimer_args {
  445         u_int   which;
  446         struct  itimerval *itv;
  447 };
  448 #endif
  449 /* ARGSUSED */
  450 int
  451 getitimer(p, uap)
  452         struct proc *p;
  453         register struct getitimer_args *uap;
  454 {
  455         struct timeval ctv;
  456         struct itimerval aitv;
  457         int s;
  458 
  459         if (uap->which > ITIMER_PROF)
  460                 return (EINVAL);
  461         s = splclock(); /* XXX still needed ? */
  462         if (uap->which == ITIMER_REAL) {
  463                 /*
  464                  * Convert from absolute to relative time in .it_value
  465                  * part of real time timer.  If time for real time timer
  466                  * has passed return 0, else return difference between
  467                  * current time and time for the timer to go off.
  468                  */
  469                 aitv = p->p_realtimer;
  470                 if (timevalisset(&aitv.it_value)) {
  471                         getmicrouptime(&ctv);
  472                         if (timevalcmp(&aitv.it_value, &ctv, <))
  473                                 timevalclear(&aitv.it_value);
  474                         else
  475                                 timevalsub(&aitv.it_value, &ctv);
  476                 }
  477         } else
  478                 aitv = p->p_stats->p_timer[uap->which];
  479         splx(s);
  480         return (copyout((caddr_t)&aitv, (caddr_t)uap->itv,
  481             sizeof (struct itimerval)));
  482 }
  483 
  484 #ifndef _SYS_SYSPROTO_H_
  485 struct setitimer_args {
  486         u_int   which;
  487         struct  itimerval *itv, *oitv;
  488 };
  489 #endif
  490 /* ARGSUSED */
  491 int
  492 setitimer(p, uap)
  493         struct proc *p;
  494         register struct setitimer_args *uap;
  495 {
  496         struct itimerval aitv;
  497         struct timeval ctv;
  498         register struct itimerval *itvp;
  499         int s, error;
  500 
  501         if (uap->which > ITIMER_PROF)
  502                 return (EINVAL);
  503         itvp = uap->itv;
  504         if (itvp && (error = copyin((caddr_t)itvp, (caddr_t)&aitv,
  505             sizeof(struct itimerval))))
  506                 return (error);
  507         if ((uap->itv = uap->oitv) &&
  508             (error = getitimer(p, (struct getitimer_args *)uap)))
  509                 return (error);
  510         if (itvp == 0)
  511                 return (0);
  512         if (itimerfix(&aitv.it_value))
  513                 return (EINVAL);
  514         if (!timevalisset(&aitv.it_value))
  515                 timevalclear(&aitv.it_interval);
  516         else if (itimerfix(&aitv.it_interval))
  517                 return (EINVAL);
  518         s = splclock(); /* XXX: still needed ? */
  519         if (uap->which == ITIMER_REAL) {
  520                 if (timevalisset(&p->p_realtimer.it_value))
  521                         untimeout(realitexpire, (caddr_t)p, p->p_ithandle);
  522                 if (timevalisset(&aitv.it_value)) 
  523                         p->p_ithandle = timeout(realitexpire, (caddr_t)p,
  524                                                 tvtohz(&aitv.it_value));
  525                 getmicrouptime(&ctv);
  526                 timevaladd(&aitv.it_value, &ctv);
  527                 p->p_realtimer = aitv;
  528         } else
  529                 p->p_stats->p_timer[uap->which] = aitv;
  530         splx(s);
  531         return (0);
  532 }
  533 
  534 /*
  535  * Real interval timer expired:
  536  * send process whose timer expired an alarm signal.
  537  * If time is not set up to reload, then just return.
  538  * Else compute next time timer should go off which is > current time.
  539  * This is where delay in processing this timeout causes multiple
  540  * SIGALRM calls to be compressed into one.
  541  * tvtohz() always adds 1 to allow for the time until the next clock
  542  * interrupt being strictly less than 1 clock tick, but we don't want
  543  * that here since we want to appear to be in sync with the clock
  544  * interrupt even when we're delayed.
  545  */
  546 void
  547 realitexpire(arg)
  548         void *arg;
  549 {
  550         register struct proc *p;
  551         struct timeval ctv, ntv;
  552         int s;
  553 
  554         p = (struct proc *)arg;
  555         psignal(p, SIGALRM);
  556         if (!timevalisset(&p->p_realtimer.it_interval)) {
  557                 timevalclear(&p->p_realtimer.it_value);
  558                 return;
  559         }
  560         for (;;) {
  561                 s = splclock(); /* XXX: still neeeded ? */
  562                 timevaladd(&p->p_realtimer.it_value,
  563                     &p->p_realtimer.it_interval);
  564                 getmicrouptime(&ctv);
  565                 if (timevalcmp(&p->p_realtimer.it_value, &ctv, >)) {
  566                         ntv = p->p_realtimer.it_value;
  567                         timevalsub(&ntv, &ctv);
  568                         p->p_ithandle = timeout(realitexpire, (caddr_t)p,
  569                             tvtohz(&ntv) - 1);
  570                         splx(s);
  571                         return;
  572                 }
  573                 splx(s);
  574         }
  575 }
  576 
  577 /*
  578  * Check that a proposed value to load into the .it_value or
  579  * .it_interval part of an interval timer is acceptable, and
  580  * fix it to have at least minimal value (i.e. if it is less
  581  * than the resolution of the clock, round it up.)
  582  */
  583 int
  584 itimerfix(tv)
  585         struct timeval *tv;
  586 {
  587 
  588         if (tv->tv_sec < 0 || tv->tv_sec > 100000000 ||
  589             tv->tv_usec < 0 || tv->tv_usec >= 1000000)
  590                 return (EINVAL);
  591         if (tv->tv_sec == 0 && tv->tv_usec != 0 && tv->tv_usec < tick)
  592                 tv->tv_usec = tick;
  593         return (0);
  594 }
  595 
  596 /*
  597  * Decrement an interval timer by a specified number
  598  * of microseconds, which must be less than a second,
  599  * i.e. < 1000000.  If the timer expires, then reload
  600  * it.  In this case, carry over (usec - old value) to
  601  * reduce the value reloaded into the timer so that
  602  * the timer does not drift.  This routine assumes
  603  * that it is called in a context where the timers
  604  * on which it is operating cannot change in value.
  605  */
  606 int
  607 itimerdecr(itp, usec)
  608         register struct itimerval *itp;
  609         int usec;
  610 {
  611 
  612         if (itp->it_value.tv_usec < usec) {
  613                 if (itp->it_value.tv_sec == 0) {
  614                         /* expired, and already in next interval */
  615                         usec -= itp->it_value.tv_usec;
  616                         goto expire;
  617                 }
  618                 itp->it_value.tv_usec += 1000000;
  619                 itp->it_value.tv_sec--;
  620         }
  621         itp->it_value.tv_usec -= usec;
  622         usec = 0;
  623         if (timevalisset(&itp->it_value))
  624                 return (1);
  625         /* expired, exactly at end of interval */
  626 expire:
  627         if (timevalisset(&itp->it_interval)) {
  628                 itp->it_value = itp->it_interval;
  629                 itp->it_value.tv_usec -= usec;
  630                 if (itp->it_value.tv_usec < 0) {
  631                         itp->it_value.tv_usec += 1000000;
  632                         itp->it_value.tv_sec--;
  633                 }
  634         } else
  635                 itp->it_value.tv_usec = 0;              /* sec is already 0 */
  636         return (0);
  637 }
  638 
  639 /*
  640  * Add and subtract routines for timevals.
  641  * N.B.: subtract routine doesn't deal with
  642  * results which are before the beginning,
  643  * it just gets very confused in this case.
  644  * Caveat emptor.
  645  */
  646 void
  647 timevaladd(t1, t2)
  648         struct timeval *t1, *t2;
  649 {
  650 
  651         t1->tv_sec += t2->tv_sec;
  652         t1->tv_usec += t2->tv_usec;
  653         timevalfix(t1);
  654 }
  655 
  656 void
  657 timevalsub(t1, t2)
  658         struct timeval *t1, *t2;
  659 {
  660 
  661         t1->tv_sec -= t2->tv_sec;
  662         t1->tv_usec -= t2->tv_usec;
  663         timevalfix(t1);
  664 }
  665 
  666 static void
  667 timevalfix(t1)
  668         struct timeval *t1;
  669 {
  670 
  671         if (t1->tv_usec < 0) {
  672                 t1->tv_sec--;
  673                 t1->tv_usec += 1000000;
  674         }
  675         if (t1->tv_usec >= 1000000) {
  676                 t1->tv_sec++;
  677                 t1->tv_usec -= 1000000;
  678         }
  679 }
  680 
  681 /*
  682  * ratecheck(): simple time-based rate-limit checking.
  683  */
  684 int
  685 ratecheck(struct timeval *lasttime, const struct timeval *mininterval)
  686 {
  687         struct timeval tv, delta;
  688         int rv = 0;
  689 
  690         getmicrouptime(&tv);            /* NB: 10ms precision */
  691         delta = tv;
  692         timevalsub(&delta, lasttime);
  693 
  694         /*
  695          * check for 0,0 is so that the message will be seen at least once,
  696          * even if interval is huge.
  697          */
  698         if (timevalcmp(&delta, mininterval, >=) ||
  699             (lasttime->tv_sec == 0 && lasttime->tv_usec == 0)) {
  700                 *lasttime = tv;
  701                 rv = 1;
  702         }
  703 
  704         return (rv);
  705 }
  706 
  707 /*
  708  * ppsratecheck(): packets (or events) per second limitation.
  709  *
  710  * Return 0 if the limit is to be enforced (e.g. the caller
  711  * should drop a packet because of the rate limitation).
  712  *
  713  * maxpps of 0 always causes zero to be returned.  maxpps of -1
  714  * always causes 1 to be returned; this effectively defeats rate
  715  * limiting.
  716  *
  717  * Note that we maintain the struct timeval for compatibility
  718  * with other bsd systems.  We reuse the storage and just monitor
  719  * clock ticks for minimal overhead.  
  720  */
  721 int
  722 ppsratecheck(struct timeval *lasttime, int *curpps, int maxpps)
  723 {
  724         int now;
  725 
  726         /*
  727          * Reset the last time and counter if this is the first call
  728          * or more than a second has passed since the last update of
  729          * lasttime.
  730          */
  731         now = ticks;
  732         if (lasttime->tv_sec == 0 || (u_int)(now - lasttime->tv_sec) >= hz) {
  733                 lasttime->tv_sec = now;
  734                 *curpps = 1;
  735                 return (maxpps != 0);
  736         } else {
  737                 (*curpps)++;            /* NB: ignore potential overflow */
  738                 return (maxpps < 0 || *curpps < maxpps);
  739         }
  740 }
  741 

Cache object: dedcb3fa821c1358b51a047655dea1d8


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.