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/bsd/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) 2000 Apple Computer, Inc. All rights reserved.
    3  *
    4  * @APPLE_LICENSE_HEADER_START@
    5  * 
    6  * Copyright (c) 1999-2003 Apple Computer, Inc.  All Rights Reserved.
    7  * 
    8  * This file contains Original Code and/or Modifications of Original Code
    9  * as defined in and that are subject to the Apple Public Source License
   10  * Version 2.0 (the 'License'). You may not use this file except in
   11  * compliance with the License. Please obtain a copy of the License at
   12  * http://www.opensource.apple.com/apsl/ and read it before using this
   13  * file.
   14  * 
   15  * The Original Code and all software distributed under the License are
   16  * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
   17  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
   18  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
   19  * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
   20  * Please see the License for the specific language governing rights and
   21  * limitations under the License.
   22  * 
   23  * @APPLE_LICENSE_HEADER_END@
   24  */
   25 /* Copyright (c) 1995 NeXT Computer, Inc. All Rights Reserved */
   26 /*
   27  * Copyright (c) 1982, 1986, 1989, 1993
   28  *      The Regents of the University of California.  All rights reserved.
   29  *
   30  * Redistribution and use in source and binary forms, with or without
   31  * modification, are permitted provided that the following conditions
   32  * are met:
   33  * 1. Redistributions of source code must retain the above copyright
   34  *    notice, this list of conditions and the following disclaimer.
   35  * 2. Redistributions in binary form must reproduce the above copyright
   36  *    notice, this list of conditions and the following disclaimer in the
   37  *    documentation and/or other materials provided with the distribution.
   38  * 3. All advertising materials mentioning features or use of this software
   39  *    must display the following acknowledgement:
   40  *      This product includes software developed by the University of
   41  *      California, Berkeley and its contributors.
   42  * 4. Neither the name of the University nor the names of its contributors
   43  *    may be used to endorse or promote products derived from this software
   44  *    without specific prior written permission.
   45  *
   46  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
   47  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   48  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   49  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
   50  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   51  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   52  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   53  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   54  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   55  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   56  * SUCH DAMAGE.
   57  *
   58  *      @(#)kern_time.c 8.4 (Berkeley) 5/26/95
   59  */
   60 
   61 #include <sys/param.h>
   62 #include <sys/resourcevar.h>
   63 #include <sys/kernel.h>
   64 #include <sys/systm.h>
   65 #include <sys/proc.h>
   66 #include <sys/vnode.h>
   67 
   68 #include <sys/mount.h>
   69 
   70 #include <kern/clock.h>
   71 
   72 #define HZ      100     /* XXX */
   73 
   74 volatile struct timeval         time;
   75 /* simple lock used to access timezone, tz structure */
   76 decl_simple_lock_data(, tz_slock);
   77 /* 
   78  * Time of day and interval timer support.
   79  *
   80  * These routines provide the kernel entry points to get and set
   81  * the time-of-day and per-process interval timers.  Subroutines
   82  * here provide support for adding and subtracting timeval structures
   83  * and decrementing interval timers, optionally reloading the interval
   84  * timers when they expire.
   85  */
   86 struct gettimeofday_args{
   87         struct timeval *tp;
   88         struct timezone *tzp;
   89 };
   90 /* ARGSUSED */
   91 int
   92 gettimeofday(p, uap, retval)
   93         struct proc *p;
   94         register struct gettimeofday_args *uap;
   95         register_t *retval;
   96 {
   97         struct timeval atv;
   98         int error = 0;
   99         extern simple_lock_data_t tz_slock;
  100         struct timezone ltz; /* local copy */
  101 
  102 /*  NOTE THIS implementation is for non ppc architectures only */
  103 
  104         if (uap->tp) {
  105                 clock_get_calendar_microtime(&atv.tv_sec, &atv.tv_usec);
  106                 if (error = copyout((caddr_t)&atv, (caddr_t)uap->tp,
  107                         sizeof (atv)))
  108                         return(error);
  109         }
  110         
  111         if (uap->tzp) {
  112                 usimple_lock(&tz_slock);
  113                 ltz = tz;
  114                 usimple_unlock(&tz_slock);
  115                 error = copyout((caddr_t)&ltz, (caddr_t)uap->tzp,
  116                     sizeof (tz));
  117         }
  118 
  119         return(error);
  120 }
  121 
  122 struct settimeofday_args {
  123         struct timeval *tv;
  124         struct timezone *tzp;
  125 };
  126 /* ARGSUSED */
  127 int
  128 settimeofday(p, uap, retval)
  129         struct proc *p;
  130         struct settimeofday_args  *uap;
  131         register_t *retval;
  132 {
  133         struct timeval atv;
  134         struct timezone atz;
  135         int error, s;
  136         extern simple_lock_data_t tz_slock;
  137 
  138         if (error = suser(p->p_ucred, &p->p_acflag))
  139                 return (error);
  140         /* Verify all parameters before changing time. */
  141         if (uap->tv && (error = copyin((caddr_t)uap->tv,
  142             (caddr_t)&atv, sizeof(atv))))
  143                 return (error);
  144         if (uap->tzp && (error = copyin((caddr_t)uap->tzp,
  145             (caddr_t)&atz, sizeof(atz))))
  146                 return (error);
  147         if (uap->tv)
  148                 setthetime(&atv);
  149         if (uap->tzp) {
  150                 usimple_lock(&tz_slock);
  151                 tz = atz;
  152                 usimple_unlock(&tz_slock);
  153         }
  154         return (0);
  155 }
  156 
  157 setthetime(tv)
  158         struct timeval *tv;
  159 {
  160         long delta = tv->tv_sec - time.tv_sec;
  161 
  162         clock_set_calendar_microtime(tv->tv_sec, tv->tv_usec);
  163         boottime.tv_sec += delta;
  164 #if NFSCLIENT || NFSSERVER
  165         lease_updatetime(delta);
  166 #endif
  167 }
  168 
  169 struct adjtime_args {
  170         struct timeval *delta;
  171         struct timeval *olddelta;
  172 };
  173 /* ARGSUSED */
  174 int
  175 adjtime(p, uap, retval)
  176         struct proc *p;
  177         register struct adjtime_args *uap;
  178         register_t *retval;
  179 {
  180         struct timeval atv;
  181         int error;
  182 
  183         if (error = suser(p->p_ucred, &p->p_acflag))
  184                 return (error);
  185         if (error = copyin((caddr_t)uap->delta,
  186                                                         (caddr_t)&atv, sizeof (struct timeval)))
  187                 return (error);
  188                 
  189     /*
  190      * Compute the total correction and the rate at which to apply it.
  191      */
  192         clock_adjtime(&atv.tv_sec, &atv.tv_usec);
  193 
  194         if (uap->olddelta) {
  195                 (void) copyout((caddr_t)&atv,
  196                                                         (caddr_t)uap->olddelta, sizeof (struct timeval));
  197         }
  198 
  199         return (0);
  200 }
  201 
  202 /*
  203  * Initialze the time of day register. 
  204  * Trust the RTC except for the case where it is set before 
  205  * the UNIX epoch. In that case use the the UNIX epoch.
  206  * The argument passed in is ignored.
  207  */
  208 void
  209 inittodr(base)
  210         time_t base;
  211 {
  212         struct timeval  tv;
  213 
  214         /*
  215          * Assertion:
  216          * The calendar has already been
  217          * set up from the battery clock.
  218          *
  219          * The value returned by microtime()
  220          * is gotten from the calendar.
  221          */
  222         microtime(&tv);
  223 
  224         time = tv;
  225         boottime.tv_sec = tv.tv_sec;
  226         boottime.tv_usec = 0;
  227 
  228         /*
  229          * If the RTC does not have acceptable value, i.e. time before
  230          * the UNIX epoch, set it to the UNIX epoch
  231          */
  232         if (tv.tv_sec < 0) {
  233                 printf ("WARNING: preposterous time in Real Time Clock");
  234                 time.tv_sec = 0;        /* the UNIX epoch */
  235                 time.tv_usec = 0;
  236                 setthetime(&time);
  237                 boottime = time;
  238                 printf(" -- CHECK AND RESET THE DATE!\n");
  239         }
  240 
  241         return;
  242 }
  243 
  244 void    timevaladd(
  245                         struct timeval  *t1,
  246                         struct timeval  *t2);
  247 void    timevalsub(
  248                         struct timeval  *t1,
  249                         struct timeval  *t2);
  250 void    timevalfix(
  251                         struct timeval  *t1);
  252 
  253 uint64_t
  254                 tvtoabstime(
  255                         struct timeval  *tvp);
  256 
  257 /*
  258  * Get value of an interval timer.  The process virtual and
  259  * profiling virtual time timers are kept internally in the
  260  * way they are specified externally: in time until they expire.
  261  *
  262  * The real time interval timer expiration time (p_rtime)
  263  * is kept as an absolute time rather than as a delta, so that
  264  * it is easy to keep periodic real-time signals from drifting.
  265  *
  266  * Virtual time timers are processed in the hardclock() routine of
  267  * kern_clock.c.  The real time timer is processed by a callout
  268  * routine.  Since a callout may be delayed in real time due to
  269  * other processing in the system, it is possible for the real
  270  * time callout routine (realitexpire, given below), to be delayed
  271  * in real time past when it is supposed to occur.  It does not
  272  * suffice, therefore, to reload the real time .it_value from the
  273  * real time .it_interval.  Rather, we compute the next time in
  274  * absolute time when the timer should go off.
  275  */
  276  
  277 struct getitimer_args {
  278         u_int   which;
  279         struct itimerval *itv;
  280 }; 
  281 /* ARGSUSED */
  282 int
  283 getitimer(p, uap, retval)
  284         struct proc *p;
  285         register struct getitimer_args *uap;
  286         register_t *retval;
  287 {
  288         struct itimerval aitv;
  289 
  290         if (uap->which > ITIMER_PROF)
  291                 return(EINVAL);
  292         if (uap->which == ITIMER_REAL) {
  293                 /*
  294                  * If time for real time timer has passed return 0,
  295                  * else return difference between current time and
  296                  * time for the timer to go off.
  297                  */
  298                 aitv = p->p_realtimer;
  299                 if (timerisset(&p->p_rtime)) {
  300                         struct timeval          now;
  301 
  302                         microuptime(&now);
  303                         if (timercmp(&p->p_rtime, &now, <))
  304                                 timerclear(&aitv.it_value);
  305                         else {
  306                                 aitv.it_value = p->p_rtime;
  307                                 timevalsub(&aitv.it_value, &now);
  308                         }
  309                 }
  310                 else
  311                         timerclear(&aitv.it_value);
  312         }
  313         else
  314                 aitv = p->p_stats->p_timer[uap->which];
  315 
  316         return (copyout((caddr_t)&aitv,
  317                                                 (caddr_t)uap->itv, sizeof (struct itimerval)));
  318 }
  319 
  320 struct setitimer_args {
  321         u_int   which;
  322         struct  itimerval *itv;
  323         struct  itimerval *oitv;
  324 };
  325 /* ARGSUSED */
  326 int
  327 setitimer(p, uap, retval)
  328         struct proc *p;
  329         register struct setitimer_args *uap;
  330         register_t *retval;
  331 {
  332         struct itimerval aitv;
  333         register struct itimerval *itvp;
  334         int error;
  335 
  336         if (uap->which > ITIMER_PROF)
  337                 return (EINVAL);
  338         if ((itvp = uap->itv) &&
  339                 (error = copyin((caddr_t)itvp,
  340                                                         (caddr_t)&aitv, sizeof (struct itimerval))))
  341                 return (error);
  342         if ((uap->itv = uap->oitv) && (error = getitimer(p, uap, retval)))
  343                 return (error);
  344         if (itvp == 0)
  345                 return (0);
  346         if (itimerfix(&aitv.it_value) || itimerfix(&aitv.it_interval))
  347                 return (EINVAL);
  348         if (uap->which == ITIMER_REAL) {
  349                 thread_call_func_cancel(realitexpire, (void *)p->p_pid, FALSE);
  350                 if (timerisset(&aitv.it_value)) {
  351                         microuptime(&p->p_rtime);
  352                         timevaladd(&p->p_rtime, &aitv.it_value);
  353                         thread_call_func_delayed(
  354                                                                 realitexpire, (void *)p->p_pid,
  355                                                                                 tvtoabstime(&p->p_rtime));
  356                 }
  357                 else
  358                         timerclear(&p->p_rtime);
  359 
  360                 p->p_realtimer = aitv;
  361         }
  362         else
  363                 p->p_stats->p_timer[uap->which] = aitv;
  364 
  365         return (0);
  366 }
  367 
  368 /*
  369  * Real interval timer expired:
  370  * send process whose timer expired an alarm signal.
  371  * If time is not set up to reload, then just return.
  372  * Else compute next time timer should go off which is > current time.
  373  * This is where delay in processing this timeout causes multiple
  374  * SIGALRM calls to be compressed into one.
  375  */
  376 void
  377 realitexpire(
  378         void            *pid)
  379 {
  380         register struct proc *p;
  381         struct timeval  now;
  382         boolean_t               funnel_state = thread_funnel_set(kernel_flock, TRUE);
  383 
  384         p = pfind((pid_t)pid);
  385         if (p == NULL) {
  386                 (void) thread_funnel_set(kernel_flock, FALSE);
  387                 return;
  388         }
  389 
  390         if (!timerisset(&p->p_realtimer.it_interval)) {
  391                 timerclear(&p->p_rtime);
  392                 psignal(p, SIGALRM);
  393 
  394                 (void) thread_funnel_set(kernel_flock, FALSE);
  395                 return;
  396         }
  397 
  398         microuptime(&now);
  399         timevaladd(&p->p_rtime, &p->p_realtimer.it_interval);
  400         if (timercmp(&p->p_rtime, &now, <=)) {
  401                 if ((p->p_rtime.tv_sec + 2) >= now.tv_sec) {
  402                         for (;;) {
  403                                 timevaladd(&p->p_rtime, &p->p_realtimer.it_interval);
  404                                 if (timercmp(&p->p_rtime, &now, >))
  405                                         break;
  406                         }
  407                 }
  408                 else {
  409                         p->p_rtime = p->p_realtimer.it_interval;
  410                         timevaladd(&p->p_rtime, &now);
  411                 }
  412         }
  413 
  414         psignal(p, SIGALRM);
  415 
  416         thread_call_func_delayed(realitexpire, pid, tvtoabstime(&p->p_rtime));
  417 
  418         (void) thread_funnel_set(kernel_flock, FALSE);
  419 }
  420 
  421 /*
  422  * Check that a proposed value to load into the .it_value or
  423  * .it_interval part of an interval timer is acceptable, and
  424  * fix it to have at least minimal value (i.e. if it is less
  425  * than the resolution of the clock, round it up.)
  426  */
  427 int
  428 itimerfix(tv)
  429         struct timeval *tv;
  430 {
  431 
  432         if (tv->tv_sec < 0 || tv->tv_sec > 100000000 ||
  433             tv->tv_usec < 0 || tv->tv_usec >= 1000000)
  434                 return (EINVAL);
  435         if (tv->tv_sec == 0 && tv->tv_usec != 0 && tv->tv_usec < tick)
  436                 tv->tv_usec = tick;
  437         return (0);
  438 }
  439 
  440 /*
  441  * Decrement an interval timer by a specified number
  442  * of microseconds, which must be less than a second,
  443  * i.e. < 1000000.  If the timer expires, then reload
  444  * it.  In this case, carry over (usec - old value) to
  445  * reducint the value reloaded into the timer so that
  446  * the timer does not drift.  This routine assumes
  447  * that it is called in a context where the timers
  448  * on which it is operating cannot change in value.
  449  */
  450 int
  451 itimerdecr(itp, usec)
  452         register struct itimerval *itp;
  453         int usec;
  454 {
  455 
  456         if (itp->it_value.tv_usec < usec) {
  457                 if (itp->it_value.tv_sec == 0) {
  458                         /* expired, and already in next interval */
  459                         usec -= itp->it_value.tv_usec;
  460                         goto expire;
  461                 }
  462                 itp->it_value.tv_usec += 1000000;
  463                 itp->it_value.tv_sec--;
  464         }
  465         itp->it_value.tv_usec -= usec;
  466         usec = 0;
  467         if (timerisset(&itp->it_value))
  468                 return (1);
  469         /* expired, exactly at end of interval */
  470 expire:
  471         if (timerisset(&itp->it_interval)) {
  472                 itp->it_value = itp->it_interval;
  473                 itp->it_value.tv_usec -= usec;
  474                 if (itp->it_value.tv_usec < 0) {
  475                         itp->it_value.tv_usec += 1000000;
  476                         itp->it_value.tv_sec--;
  477                 }
  478         } else
  479                 itp->it_value.tv_usec = 0;              /* sec is already 0 */
  480         return (0);
  481 }
  482 
  483 /*
  484  * Add and subtract routines for timevals.
  485  * N.B.: subtract routine doesn't deal with
  486  * results which are before the beginning,
  487  * it just gets very confused in this case.
  488  * Caveat emptor.
  489  */
  490 void
  491 timevaladd(
  492         struct timeval *t1,
  493         struct timeval *t2)
  494 {
  495 
  496         t1->tv_sec += t2->tv_sec;
  497         t1->tv_usec += t2->tv_usec;
  498         timevalfix(t1);
  499 }
  500 void
  501 timevalsub(
  502         struct timeval *t1,
  503         struct timeval *t2)
  504 {
  505 
  506         t1->tv_sec -= t2->tv_sec;
  507         t1->tv_usec -= t2->tv_usec;
  508         timevalfix(t1);
  509 }
  510 void
  511 timevalfix(
  512         struct timeval *t1)
  513 {
  514 
  515         if (t1->tv_usec < 0) {
  516                 t1->tv_sec--;
  517                 t1->tv_usec += 1000000;
  518         }
  519         if (t1->tv_usec >= 1000000) {
  520                 t1->tv_sec++;
  521                 t1->tv_usec -= 1000000;
  522         }
  523 }
  524 
  525 /*
  526  * Return the best possible estimate of the time in the timeval
  527  * to which tvp points.
  528  */
  529 void
  530 microtime(
  531         struct timeval  *tvp)
  532 {
  533         clock_get_calendar_microtime(&tvp->tv_sec, &tvp->tv_usec);
  534 }
  535 
  536 void
  537 microuptime(
  538         struct timeval  *tvp)
  539 {
  540         clock_get_system_microtime(&tvp->tv_sec, &tvp->tv_usec);
  541 }
  542 
  543 /*
  544  * Ditto for timespec.
  545  */
  546 void
  547 nanotime(
  548         struct timespec *tsp)
  549 {
  550         clock_get_calendar_nanotime((uint32_t *)&tsp->tv_sec, &tsp->tv_nsec);
  551 }
  552 
  553 void
  554 nanouptime(
  555         struct timespec *tsp)
  556 {
  557         clock_get_system_nanotime((uint32_t *)&tsp->tv_sec, &tsp->tv_nsec);
  558 }
  559 
  560 uint64_t
  561 tvtoabstime(
  562         struct timeval  *tvp)
  563 {
  564         uint64_t        result, usresult;
  565 
  566         clock_interval_to_absolutetime_interval(
  567                                                 tvp->tv_sec, NSEC_PER_SEC, &result);
  568         clock_interval_to_absolutetime_interval(
  569                                                 tvp->tv_usec, NSEC_PER_USEC, &usresult);
  570 
  571         return (result + usresult);
  572 }
  573 void
  574 time_zone_slock_init(void)
  575 {
  576         extern simple_lock_data_t tz_slock;
  577 
  578         simple_lock_init(&tz_slock);
  579 
  580 
  581 }

Cache object: 1d00b5d97b6a000d52276b1e54f0457e


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