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

Cache object: b322b83057c01d5769a1ba8cf064fdcf


[ 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.