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: src/sys/kern/kern_time.c,v 1.18.2.3 1999/09/05 08:15:07 peter Exp $
   35  */
   36 
   37 #include <sys/param.h>
   38 #include <sys/sysproto.h>
   39 #include <sys/resourcevar.h>
   40 #include <sys/signalvar.h>
   41 #include <sys/kernel.h>
   42 #include <sys/systm.h>
   43 #include <sys/proc.h>
   44 #include <sys/vnode.h>
   45 
   46 struct timezone tz;
   47 
   48 /*
   49  * Time of day and interval timer support.
   50  *
   51  * These routines provide the kernel entry points to get and set
   52  * the time-of-day and per-process interval timers.  Subroutines
   53  * here provide support for adding and subtracting timeval structures
   54  * and decrementing interval timers, optionally reloading the interval
   55  * timers when they expire.
   56  */
   57 
   58 static void     timevalfix __P((struct timeval *));
   59 
   60 #ifndef _SYS_SYSPROTO_H_
   61 struct gettimeofday_args {
   62         struct  timeval *tp;
   63         struct  timezone *tzp;
   64 };
   65 #endif
   66 /* ARGSUSED */
   67 int
   68 gettimeofday(p, uap, retval)
   69         struct proc *p;
   70         register struct gettimeofday_args *uap;
   71         int *retval;
   72 {
   73         struct timeval atv;
   74         int error = 0;
   75 
   76         if (uap->tp) {
   77                 microtime(&atv);
   78                 if ((error = copyout((caddr_t)&atv, (caddr_t)uap->tp,
   79                     sizeof (atv))))
   80                         return (error);
   81         }
   82         if (uap->tzp)
   83                 error = copyout((caddr_t)&tz, (caddr_t)uap->tzp,
   84                     sizeof (tz));
   85         return (error);
   86 }
   87 
   88 #ifndef _SYS_SYSPROTO_H_
   89 struct settimeofday_args {
   90         struct  timeval *tv;
   91         struct  timezone *tzp;
   92 };
   93 #endif
   94 /* ARGSUSED */
   95 int
   96 settimeofday(p, uap, retval)
   97         struct proc *p;
   98         struct settimeofday_args *uap;
   99         int *retval;
  100 {
  101         struct timeval atv, delta;
  102         struct timezone atz;
  103         int error, s;
  104 
  105         if ((error = suser(p->p_ucred, &p->p_acflag)))
  106                 return (error);
  107         /* Verify all parameters before changing time. */
  108         if (uap->tv &&
  109             (error = copyin((caddr_t)uap->tv, (caddr_t)&atv, sizeof(atv))))
  110                 return (error);
  111         if (atv.tv_usec < 0 || atv.tv_usec >= 1000000)
  112                 return (EINVAL);
  113         if (uap->tzp &&
  114             (error = copyin((caddr_t)uap->tzp, (caddr_t)&atz, sizeof(atz))))
  115                 return (error);
  116         if (uap->tv) {
  117                 s = splclock();
  118                 /*
  119                  * Calculate delta directly to minimize clock interrupt
  120                  * latency.  Fix it after the ipl has been lowered.
  121                  */
  122                 delta.tv_sec = atv.tv_sec - time.tv_sec;
  123                 delta.tv_usec = atv.tv_usec - time.tv_usec;
  124                 time = atv;
  125                 /*
  126                  * XXX should arrange for microtime() to agree with atv if
  127                  * it is called now.  As it is, it may add up to about
  128                  * `tick' unwanted usec.
  129                  * Another problem is that clock interrupts may occur at
  130                  * other than multiples of `tick'.  It's not worth fixing
  131                  * this here, since the problem is also caused by tick
  132                  * adjustments.
  133                  */
  134                 (void) splsoftclock();
  135                 timevalfix(&delta);
  136                 timevaladd(&boottime, &delta);
  137                 timevaladd(&runtime, &delta);
  138                 /* re-use 'p' */
  139                 for (p = allproc.lh_first; p != 0; p = p->p_list.le_next)
  140                         if (timerisset(&p->p_realtimer.it_value))
  141                                 timevaladd(&p->p_realtimer.it_value, &delta);
  142                 LEASE_UPDATETIME(delta.tv_sec);
  143                 splx(s);
  144                 resettodr();
  145         }
  146         if (uap->tzp)
  147                 tz = atz;
  148         return (0);
  149 }
  150 
  151 extern  int tickadj;                    /* "standard" clock skew, us./tick */
  152 int     tickdelta;                      /* current clock skew, us. per tick */
  153 long    timedelta;                      /* unapplied time correction, us. */
  154 static long     bigadj = 1000000;       /* use 10x skew above bigadj us. */
  155 
  156 #ifndef _SYS_SYSPROTO_H_
  157 struct adjtime_args {
  158         struct timeval *delta;
  159         struct timeval *olddelta;
  160 };
  161 #endif
  162 /* ARGSUSED */
  163 int
  164 adjtime(p, uap, retval)
  165         struct proc *p;
  166         register struct adjtime_args *uap;
  167         int *retval;
  168 {
  169         struct timeval atv;
  170         register long ndelta, ntickdelta, odelta;
  171         int s, error;
  172 
  173         if ((error = suser(p->p_ucred, &p->p_acflag)))
  174                 return (error);
  175         if ((error =
  176             copyin((caddr_t)uap->delta, (caddr_t)&atv, sizeof(struct timeval))))
  177                 return (error);
  178 
  179         /*
  180          * Compute the total correction and the rate at which to apply it.
  181          * Round the adjustment down to a whole multiple of the per-tick
  182          * delta, so that after some number of incremental changes in
  183          * hardclock(), tickdelta will become zero, lest the correction
  184          * overshoot and start taking us away from the desired final time.
  185          */
  186         ndelta = atv.tv_sec * 1000000 + atv.tv_usec;
  187         if (ndelta > bigadj || ndelta < -bigadj)
  188                 ntickdelta = 10 * tickadj;
  189         else
  190                 ntickdelta = tickadj;
  191         if (ndelta % ntickdelta)
  192                 ndelta = ndelta / ntickdelta * ntickdelta;
  193 
  194         /*
  195          * To make hardclock()'s job easier, make the per-tick delta negative
  196          * if we want time to run slower; then hardclock can simply compute
  197          * tick + tickdelta, and subtract tickdelta from timedelta.
  198          */
  199         if (ndelta < 0)
  200                 ntickdelta = -ntickdelta;
  201         s = splclock();
  202         odelta = timedelta;
  203         timedelta = ndelta;
  204         tickdelta = ntickdelta;
  205         splx(s);
  206 
  207         if (uap->olddelta) {
  208                 atv.tv_sec = odelta / 1000000;
  209                 atv.tv_usec = odelta % 1000000;
  210                 (void) copyout((caddr_t)&atv, (caddr_t)uap->olddelta,
  211                     sizeof(struct timeval));
  212         }
  213         return (0);
  214 }
  215 
  216 /*
  217  * Get value of an interval timer.  The process virtual and
  218  * profiling virtual time timers are kept in the p_stats area, since
  219  * they can be swapped out.  These are kept internally in the
  220  * way they are specified externally: in time until they expire.
  221  *
  222  * The real time interval timer is kept in the process table slot
  223  * for the process, and its value (it_value) is kept as an
  224  * absolute time rather than as a delta, so that it is easy to keep
  225  * periodic real-time signals from drifting.
  226  *
  227  * Virtual time timers are processed in the hardclock() routine of
  228  * kern_clock.c.  The real time timer is processed by a timeout
  229  * routine, called from the softclock() routine.  Since a callout
  230  * may be delayed in real time due to interrupt processing in the system,
  231  * it is possible for the real time timeout routine (realitexpire, given below),
  232  * to be delayed in real time past when it is supposed to occur.  It
  233  * does not suffice, therefore, to reload the real timer .it_value from the
  234  * real time timers .it_interval.  Rather, we compute the next time in
  235  * absolute time the timer should go off.
  236  */
  237 #ifndef _SYS_SYSPROTO_H_
  238 struct getitimer_args {
  239         u_int   which;
  240         struct  itimerval *itv;
  241 };
  242 #endif
  243 /* ARGSUSED */
  244 int
  245 getitimer(p, uap, retval)
  246         struct proc *p;
  247         register struct getitimer_args *uap;
  248         int *retval;
  249 {
  250         struct itimerval aitv;
  251         int s;
  252 
  253         if (uap->which > ITIMER_PROF)
  254                 return (EINVAL);
  255         s = splclock();
  256         if (uap->which == ITIMER_REAL) {
  257                 /*
  258                  * Convert from absoulte to relative time in .it_value
  259                  * part of real time timer.  If time for real time timer
  260                  * has passed return 0, else return difference between
  261                  * current time and time for the timer to go off.
  262                  */
  263                 aitv = p->p_realtimer;
  264                 if (timerisset(&aitv.it_value))
  265                         if (timercmp(&aitv.it_value, &time, <))
  266                                 timerclear(&aitv.it_value);
  267                         else
  268                                 timevalsub(&aitv.it_value,
  269                                     (struct timeval *)&time);
  270         } else
  271                 aitv = p->p_stats->p_timer[uap->which];
  272         splx(s);
  273         return (copyout((caddr_t)&aitv, (caddr_t)uap->itv,
  274             sizeof (struct itimerval)));
  275 }
  276 
  277 #ifndef _SYS_SYSPROTO_H_
  278 struct setitimer_args {
  279         u_int   which;
  280         struct  itimerval *itv, *oitv;
  281 };
  282 #endif
  283 /* ARGSUSED */
  284 int
  285 setitimer(p, uap, retval)
  286         struct proc *p;
  287         register struct setitimer_args *uap;
  288         int *retval;
  289 {
  290         struct itimerval aitv;
  291         register struct itimerval *itvp;
  292         int s, error;
  293 
  294         if (uap->which > ITIMER_PROF)
  295                 return (EINVAL);
  296         itvp = uap->itv;
  297         if (itvp && (error = copyin((caddr_t)itvp, (caddr_t)&aitv,
  298             sizeof(struct itimerval))))
  299                 return (error);
  300         if ((uap->itv = uap->oitv) &&
  301             (error = getitimer(p, (struct getitimer_args *)uap, retval)))
  302                 return (error);
  303         if (itvp == 0)
  304                 return (0);
  305         if (itimerfix(&aitv.it_value) || itimerfix(&aitv.it_interval))
  306                 return (EINVAL);
  307         s = splclock();
  308         if (uap->which == ITIMER_REAL) {
  309                 untimeout(realitexpire, (caddr_t)p);
  310                 if (timerisset(&aitv.it_value)) {
  311                         timevaladd(&aitv.it_value, (struct timeval *)&time);
  312                         timeout(realitexpire, (caddr_t)p, hzto(&aitv.it_value));
  313                 }
  314                 p->p_realtimer = aitv;
  315         } else
  316                 p->p_stats->p_timer[uap->which] = aitv;
  317         splx(s);
  318         return (0);
  319 }
  320 
  321 /*
  322  * Real interval timer expired:
  323  * send process whose timer expired an alarm signal.
  324  * If time is not set up to reload, then just return.
  325  * Else compute next time timer should go off which is > current time.
  326  * This is where delay in processing this timeout causes multiple
  327  * SIGALRM calls to be compressed into one.
  328  * hzto() always adds 1 to allow for the time until the next clock
  329  * interrupt being strictly less than 1 clock tick, but we don't want
  330  * that here since we want to appear to be in sync with the clock
  331  * interrupt even when we're delayed.
  332  */
  333 void
  334 realitexpire(arg)
  335         void *arg;
  336 {
  337         register struct proc *p;
  338         int s;
  339 
  340         p = (struct proc *)arg;
  341         psignal(p, SIGALRM);
  342         if (!timerisset(&p->p_realtimer.it_interval)) {
  343                 timerclear(&p->p_realtimer.it_value);
  344                 return;
  345         }
  346         for (;;) {
  347                 s = splclock();
  348                 timevaladd(&p->p_realtimer.it_value,
  349                     &p->p_realtimer.it_interval);
  350                 if (timercmp(&p->p_realtimer.it_value, &time, >)) {
  351                         timeout(realitexpire, (caddr_t)p,
  352                             hzto(&p->p_realtimer.it_value) - 1);
  353                         splx(s);
  354                         return;
  355                 }
  356                 splx(s);
  357         }
  358 }
  359 
  360 /*
  361  * Check that a proposed value to load into the .it_value or
  362  * .it_interval part of an interval timer is acceptable, and
  363  * fix it to have at least minimal value (i.e. if it is less
  364  * than the resolution of the clock, round it up.)
  365  */
  366 int
  367 itimerfix(tv)
  368         struct timeval *tv;
  369 {
  370 
  371         if (tv->tv_sec < 0 || tv->tv_sec > 100000000 ||
  372             tv->tv_usec < 0 || tv->tv_usec >= 1000000)
  373                 return (EINVAL);
  374         if (tv->tv_sec == 0 && tv->tv_usec != 0 && tv->tv_usec < tick)
  375                 tv->tv_usec = tick;
  376         return (0);
  377 }
  378 
  379 /*
  380  * Decrement an interval timer by a specified number
  381  * of microseconds, which must be less than a second,
  382  * i.e. < 1000000.  If the timer expires, then reload
  383  * it.  In this case, carry over (usec - old value) to
  384  * reduce the value reloaded into the timer so that
  385  * the timer does not drift.  This routine assumes
  386  * that it is called in a context where the timers
  387  * on which it is operating cannot change in value.
  388  */
  389 int
  390 itimerdecr(itp, usec)
  391         register struct itimerval *itp;
  392         int usec;
  393 {
  394 
  395         if (itp->it_value.tv_usec < usec) {
  396                 if (itp->it_value.tv_sec == 0) {
  397                         /* expired, and already in next interval */
  398                         usec -= itp->it_value.tv_usec;
  399                         goto expire;
  400                 }
  401                 itp->it_value.tv_usec += 1000000;
  402                 itp->it_value.tv_sec--;
  403         }
  404         itp->it_value.tv_usec -= usec;
  405         usec = 0;
  406         if (timerisset(&itp->it_value))
  407                 return (1);
  408         /* expired, exactly at end of interval */
  409 expire:
  410         if (timerisset(&itp->it_interval)) {
  411                 itp->it_value = itp->it_interval;
  412                 itp->it_value.tv_usec -= usec;
  413                 if (itp->it_value.tv_usec < 0) {
  414                         itp->it_value.tv_usec += 1000000;
  415                         itp->it_value.tv_sec--;
  416                 }
  417         } else
  418                 itp->it_value.tv_usec = 0;              /* sec is already 0 */
  419         return (0);
  420 }
  421 
  422 /*
  423  * Add and subtract routines for timevals.
  424  * N.B.: subtract routine doesn't deal with
  425  * results which are before the beginning,
  426  * it just gets very confused in this case.
  427  * Caveat emptor.
  428  */
  429 void
  430 timevaladd(t1, t2)
  431         struct timeval *t1, *t2;
  432 {
  433 
  434         t1->tv_sec += t2->tv_sec;
  435         t1->tv_usec += t2->tv_usec;
  436         timevalfix(t1);
  437 }
  438 
  439 void
  440 timevalsub(t1, t2)
  441         struct timeval *t1, *t2;
  442 {
  443 
  444         t1->tv_sec -= t2->tv_sec;
  445         t1->tv_usec -= t2->tv_usec;
  446         timevalfix(t1);
  447 }
  448 
  449 static void
  450 timevalfix(t1)
  451         struct timeval *t1;
  452 {
  453 
  454         if (t1->tv_usec < 0) {
  455                 t1->tv_sec--;
  456                 t1->tv_usec += 1000000;
  457         }
  458         if (t1->tv_usec >= 1000000) {
  459                 t1->tv_sec++;
  460                 t1->tv_usec -= 1000000;
  461         }
  462 }

Cache object: f5c74ea3136b3b9091446edde085a2d5


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