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/timer.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  * Mach Operating System
    3  * Copyright (c) 1991,1990,1989,1988,1987 Carnegie Mellon University
    4  * All Rights Reserved.
    5  * 
    6  * Permission to use, copy, modify and distribute this software and its
    7  * documentation is hereby granted, provided that both the copyright
    8  * notice and this permission notice appear in all copies of the
    9  * software, derivative works or modified versions, and any portions
   10  * thereof, and that both notices appear in supporting documentation.
   11  * 
   12  * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
   13  * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
   14  * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
   15  * 
   16  * Carnegie Mellon requests users of this software to return to
   17  * 
   18  *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
   19  *  School of Computer Science
   20  *  Carnegie Mellon University
   21  *  Pittsburgh PA 15213-3890
   22  * 
   23  * any improvements or extensions that they make and grant Carnegie Mellon
   24  * the rights to redistribute these changes.
   25  */
   26 /* 
   27  * HISTORY
   28  * $Log:        timer.c,v $
   29  * Revision 2.9  93/11/17  17:32:33  dbg
   30  *      If no machine-dependent timer is used: maintain timer in seconds
   31  *      and nanoseconds, and use microseconds (or the nearest binary
   32  *      approximation thereof) for the scheduling units.
   33  *      [93/01/25            dbg]
   34  * 
   35  * Revision 2.8  92/08/03  17:40:24  jfriedl
   36  *      removed silly prototypes
   37  *      [92/08/02            jfriedl]
   38  * 
   39  * Revision 2.7  92/05/21  17:17:02  jfriedl
   40  *      Made fcns void that needed it.
   41  *      [92/05/16            jfriedl]
   42  * 
   43  * Revision 2.6  92/02/19  13:43:42  elf
   44  *      Add include of <kern/assert.h>. Under MACH_ASSERT conditionals,
   45  *       make the loop in timer_grab fail assertion fail if it loops more
   46  *       than 10000 times.
   47  *      [92/01/15            danner]
   48  *      Added version to timer grab that can be called by the kernel debugger.
   49  *      Will work even if the time is not normalized.
   50  *      [91/09/19  13:47:32  danner]
   51  * 
   52  * Revision 2.6  92/02/18  18:00:20  elf
   53  *      Merged up.
   54  *      [92/01/22  18:45:01  danner]
   55  * 
   56  * Revision 2.5  91/07/31  17:51:35  dbg
   57  *      Allow all routines to be defined in machine-dependent code.
   58  *      [91/07/30  17:08:39  dbg]
   59  * 
   60  * Revision 2.4  91/05/14  16:49:52  mrt
   61  *      Correcting copyright
   62  * 
   63  * Revision 2.3  91/02/05  17:31:02  mrt
   64  *      Changed to new Mach copyright
   65  *      [91/02/01  16:20:58  mrt]
   66  * 
   67  * Revision 2.2  90/08/07  17:59:21  rpd
   68  *      Converted timer_grab to a real function.
   69  *      Picked up optimized timer_normalize and timer_grab,
   70  *      based on new timer representation.
   71  *      [90/08/07            rpd]
   72  * 
   73  * Revision 2.1  89/08/03  15:47:54  rwd
   74  * Created.
   75  * 
   76  *  8-Dec-88  David Golub (dbg) at Carnegie-Mellon University
   77  *      Fixed include files for MACH_KERNEL.
   78  *
   79  * 26-Oct-88  David Black (dlb) at Carnegie-Mellon University
   80  *      New overflow logic.  Check low_bits directly for risk of
   81  *      overflow.  Gets rid of service_timers().  Suggested by dbg.
   82  *
   83  * 20-Oct-88  David Golub (dbg) at Carnegie-Mellon University
   84  *      Use macro_help to avoid lint.
   85  *
   86  * 18-May-88  David Golub (dbg) at Carnegie-Mellon University
   87  *      HC compiler does not consider '| =' to be the same as '|='.
   88  *
   89  *  9-May-88  David Golub (dbg) at Carnegie-Mellon University
   90  *      Added register declarations.  Not all machines enjoy the luxury
   91  *      of a reasonable compiler.
   92  *
   93  * 20-Apr-88  David Black (dlb) at Carnegie-Mellon University
   94  *      Removed thread_times system call.
   95  *
   96  * 29-Mar-88  David Black (dlb) at Carnegie-Mellon University
   97  *      Normalize old timer on interrupt exit if needed.
   98  *
   99  * 19-Feb-88  David Black (dlb) at Carnegie-Mellon University
  100  *      Massive changes - parametrize most constants to deal with
  101  *      different clock frequencies, field name changes in timer
  102  *      structure.  Replace array in thread structure with individual
  103  *      timers.  Implemented timer_delta and timer_current_delta routines
  104  *      to efficiently read timing information for scheduler.
  105  *
  106  * 12-Feb-88  David Black (dlb) at Carnegie-Mellon University
  107  *      Use time_value_t's instead of struct timeval's.
  108  *
  109  * 28-Jan-88  David Black (dlb) at Carnegie-Mellon University
  110  *      Rewrote thread_times for new port naming and thread referencing
  111  *      logic.
  112  *
  113  * 26-Mar-87  David Black (dlb) at Carnegie-Mellon University
  114  *      Changed trap entry and exit routines to always set correct timer
  115  *      regardless of current timer.
  116  *
  117  * 18-Mar-87  David L. Black (dlb) at Carnegie-Mellon University
  118  *      Moved kickoff of service_timers() into init_main.c because
  119  *      callout queue is not initialized when init_timers is called.
  120  *
  121  * 23-Feb-87  David L. Black (dlb) at Carnegie-Mellon University
  122  *      Created.
  123  */ 
  124 
  125 #include <cpus.h>
  126 #include <stat_time.h>
  127 
  128 #include <mach/kern_return.h>
  129 #include <mach/port.h>
  130 #include <kern/queue.h>
  131 #include <kern/thread.h>
  132 #include <mach/time_spec.h>
  133 #include <kern/timer.h>
  134 #include <kern/cpu_number.h>
  135 
  136 #include <kern/assert.h>
  137 #include <kern/macro_help.h>
  138 
  139 
  140 
  141 timer_t         current_timer[NCPUS];
  142 timer_data_t    kernel_timer[NCPUS];
  143 
  144 /*
  145  *      init_timers initializes all non-thread timers.
  146  */
  147 void init_timers(void)
  148 {
  149         register int    i;
  150         register timer_t        this_timer;
  151 
  152         /*
  153          *      Initialize all the kernel timers and start the one
  154          *      for this cpu (master) slaves start theirs later.
  155          */
  156         this_timer = &kernel_timer[0];
  157         for ( i=0 ; i<NCPUS ; i++, this_timer++) {
  158                 timer_init(this_timer);
  159                 current_timer[i] = (timer_t) 0;
  160         }
  161 
  162         start_timer(&kernel_timer[cpu_number()]);
  163 }
  164 
  165 /*
  166  *      timer_init initializes a single timer.
  167  */
  168 void timer_init(
  169         register timer_t this_timer)
  170 {
  171         this_timer->low_bits = 0;
  172         this_timer->high_bits = 0;
  173         this_timer->tstamp = 0;
  174         this_timer->high_bits_check = 0;
  175 }
  176 
  177 #if     STAT_TIME
  178 #else   /* STAT_TIME */
  179 
  180 #ifdef  MACHINE_TIMER_ROUTINES
  181 
  182 /*
  183  *      Machine-dependent code implements the timer routines.
  184  */
  185 
  186 #else   /* MACHINE_TIMER_ROUTINES */
  187 
  188 /*
  189  *      start_timer starts the given timer for this cpu. It is called
  190  *      exactly once for each cpu during the boot sequence.
  191  */
  192 void
  193 start_timer(
  194         timer_t timer)
  195 {
  196         timer->tstamp = get_timestamp();
  197         current_timer[cpu_number()] = timer;
  198 }
  199 
  200 /*
  201  *      time_trap_uentry does trap entry timing.  Caller must lock out
  202  *      interrupts and take a timestamp.  ts is a timestamp taken after
  203  *      interrupts were locked out. Must only be called if trap was
  204  *      from user mode.
  205  */
  206 void
  207 time_trap_uentry(
  208         unsigned int    ts)
  209 {
  210         int     elapsed;
  211         int     mycpu;
  212         timer_t mytimer;
  213 
  214         /*
  215          *      Calculate elapsed time.
  216          */
  217         mycpu = cpu_number();
  218         mytimer = current_timer[mycpu];
  219         elapsed = ts - mytimer->tstamp;
  220 #ifdef  TIMER_MAX
  221         if (elapsed < 0) elapsed += TIMER_MAX;
  222 #endif  /* TIMER_MAX */
  223 
  224         /*
  225          *      Update current timer.
  226          */
  227         mytimer->low_bits += elapsed;
  228         mytimer->tstamp = 0;
  229 
  230         if (mytimer->low_bits & TIMER_LOW_FULL) {
  231                 timer_normalize(mytimer);
  232         }
  233 
  234         /*
  235          *      Record new timer.
  236          */
  237         mytimer = &(active_threads[mycpu]->system_timer);
  238         current_timer[mycpu] = mytimer;
  239         mytimer->tstamp = ts;
  240 }
  241 
  242 /*
  243  *      time_trap_uexit does trap exit timing.  Caller must lock out
  244  *      interrupts and take a timestamp.  ts is a timestamp taken after
  245  *      interrupts were locked out.  Must only be called if returning to
  246  *      user mode.
  247  */
  248 void
  249 time_trap_uexit(
  250         unsigned int    ts)
  251 {
  252         int     elapsed;
  253         int     mycpu;
  254         timer_t mytimer;
  255 
  256         /*
  257          *      Calculate elapsed time.
  258          */
  259         mycpu = cpu_number();
  260         mytimer = current_timer[mycpu];
  261         elapsed = ts - mytimer->tstamp;
  262 #ifdef  TIMER_MAX
  263         if (elapsed < 0) elapsed += TIMER_MAX;
  264 #endif  /* TIMER_MAX */
  265 
  266         /*
  267          *      Update current timer.
  268          */
  269         mytimer->low_bits += elapsed;
  270         mytimer->tstamp = 0;
  271 
  272         if (mytimer->low_bits & TIMER_LOW_FULL) {
  273                 timer_normalize(mytimer);       /* SYSTEMMODE */
  274         }
  275 
  276         mytimer = &(active_threads[mycpu]->user_timer);
  277 
  278         /*
  279          *      Record new timer.
  280          */
  281         current_timer[mycpu] = mytimer;
  282         mytimer->tstamp = ts;
  283 }
  284 
  285 /*
  286  *      time_int_entry does interrupt entry timing.  Caller must lock out
  287  *      interrupts and take a timestamp. ts is a timestamp taken after
  288  *      interrupts were locked out.  new_timer is the new timer to
  289  *      switch to.  This routine returns the currently running timer,
  290  *      which MUST be pushed onto the stack by the caller, or otherwise
  291  *      saved for time_int_exit.
  292  */
  293 timer_t
  294 time_int_entry(
  295         unsigned int    ts,
  296         timer_t         new_timer)
  297 {
  298         int     elapsed;
  299         int     mycpu;
  300         timer_t mytimer;
  301 
  302         /*
  303          *      Calculate elapsed time.
  304          */
  305         mycpu = cpu_number();
  306         mytimer = current_timer[mycpu];
  307 
  308         elapsed = ts - mytimer->tstamp;
  309 #ifdef  TIMER_MAX
  310         if (elapsed < 0) elapsed += TIMER_MAX;
  311 #endif  /* TIMER_MAX */
  312 
  313         /*
  314          *      Update current timer.
  315          */
  316         mytimer->low_bits += elapsed;
  317         mytimer->tstamp = 0;
  318 
  319         /*
  320          *      Switch to new timer, and save old one on stack.
  321          */
  322         new_timer->tstamp = ts;
  323         current_timer[mycpu] = new_timer;
  324         return mytimer;
  325 }
  326 
  327 /*
  328  *      time_int_exit does interrupt exit timing.  Caller must lock out
  329  *      interrupts and take a timestamp.  ts is a timestamp taken after
  330  *      interrupts were locked out.  old_timer is the timer value pushed
  331  *      onto the stack or otherwise saved after time_int_entry returned
  332  *      it.
  333  */
  334 void
  335 time_int_exit(
  336         unsigned int    ts,
  337         timer_t         old_timer)
  338 {
  339         int     elapsed;
  340         int     mycpu;
  341         timer_t mytimer;
  342 
  343         /*
  344          *      Calculate elapsed time.
  345          */
  346         mycpu = cpu_number();
  347         mytimer = current_timer[mycpu];
  348         elapsed = ts - mytimer->tstamp;
  349 #ifdef  TIMER_MAX
  350         if (elapsed < 0) elapsed += TIMER_MAX;
  351 #endif  /* TIMER_MAX */
  352 
  353         /*
  354          *      Update current timer.
  355          */
  356         mytimer->low_bits += elapsed;
  357         mytimer->tstamp = 0;
  358 
  359         /*
  360          *      If normalization requested, do it.
  361          */
  362         if (mytimer->low_bits & TIMER_LOW_FULL) {
  363                 timer_normalize(mytimer);
  364         }
  365         if (old_timer->low_bits & TIMER_LOW_FULL) {
  366                 timer_normalize(old_timer);
  367         }
  368 
  369         /*
  370          *      Start timer that was running before interrupt.
  371          */
  372         old_timer->tstamp = ts;
  373         current_timer[mycpu] = old_timer;
  374 }
  375 
  376 /*
  377  *      timer_switch switches to a new timer.  The machine
  378  *      dependent routine/macro get_timestamp must return a timestamp.
  379  *      Caller must lock out interrupts.
  380  */
  381 void
  382 timer_switch(
  383         timer_t new_timer)
  384 {
  385         int             elapsed;
  386         int             mycpu;
  387         timer_t         mytimer;
  388         unsigned        ts;
  389 
  390         /*
  391          *      Calculate elapsed time.
  392          */
  393         mycpu = cpu_number();
  394         mytimer = current_timer[mycpu];
  395         ts = get_timestamp();
  396         elapsed = ts - mytimer->tstamp;
  397 #ifdef  TIMER_MAX
  398         if (elapsed < 0) elapsed += TIMER_MAX;
  399 #endif  /* TIMER_MAX */
  400 
  401         /*
  402          *      Update current timer.
  403          */
  404         mytimer->low_bits += elapsed;
  405         mytimer->tstamp = 0;
  406 
  407         /*
  408          *      Normalization check
  409          */
  410         if (mytimer->low_bits & TIMER_LOW_FULL) {
  411                 timer_normalize(mytimer);
  412         }
  413 
  414         /*
  415          *      Record new timer.
  416          */
  417         current_timer[mycpu] = new_timer;
  418         new_timer->tstamp = ts;
  419 }
  420 
  421 #endif  /* MACHINE_TIMER_ROUTINES */
  422 #endif  /* STAT_TIME */
  423 
  424 /*
  425  *      timer_normalize normalizes the value of a timer.  It is
  426  *      called only rarely, to make sure low_bits never overflows.
  427  */
  428 void timer_normalize(
  429         register timer_t        timer)
  430 {
  431         unsigned int    high_increment;
  432 
  433         /*
  434          *      Calculate high_increment, then write high check field first
  435          *      followed by low and high.  timer_grab() reads these fields in
  436          *      reverse order so if high and high check match, we know
  437          *      that the values read are ok.
  438          */
  439 
  440         high_increment = timer->low_bits/TIMER_HIGH_UNIT;
  441         timer->high_bits_check += high_increment;
  442         timer->low_bits %= TIMER_HIGH_UNIT;
  443         timer->high_bits += high_increment;
  444 }
  445 
  446 /*
  447  *      timer_grab() retrieves the value of a timer.
  448  *
  449  *      Critical scheduling code uses TIMER_DELTA macro in timer.h
  450  *      (called from thread_timer_delta in sched.h).
  451  *    
  452  *      Keep coherent with db_time_grab below.
  453  */
  454 
  455 void timer_grab(
  456         timer_t         timer,
  457         timer_save_t    save)
  458 {
  459 #if MACH_ASSERT
  460         unsigned int    passes = 0;
  461 #endif
  462         do {
  463                 save->high = timer->high_bits;
  464                 save->low  = timer->low_bits;
  465         /*
  466          *      If the timer was normalized while we were doing this,
  467          *      the high_bits value read above and the high_bits check
  468          *      value will not match because high_bits_check is the first
  469          *      field touched by the normalization procedure, and
  470          *      high_bits is the last.
  471          *
  472          *      Additions to timer only touch low bits and
  473          *      are therefore atomic with respect to this.
  474          */
  475 #if MACH_ASSERT
  476                 passes++;
  477                 assert(passes < 10000);
  478 #endif          
  479         } while (save->high != timer->high_bits_check);
  480 }
  481 
  482 /*
  483  *
  484  *      Db_timer_grab(): used by db_thread_read_times. An nonblocking
  485  *      version of db_thread_get_times. Keep coherent with timer_grab
  486  *      above.
  487  *
  488  */
  489 void db_timer_grab(
  490         timer_t         timer,
  491         timer_save_t    save)
  492 {
  493         /* Don't worry about coherency */
  494 
  495         save->high = timer->high_bits;
  496         save->low  = timer->low_bits;
  497 }
  498 
  499 
  500 /*
  501  *      timer_read reads the value of a timer into a time_spec_t.  If the
  502  *      timer was modified during the read, retry.  The value returned
  503  *      is accurate to the last update; time accumulated by a running
  504  *      timer since its last timestamp is not included.
  505  */
  506 
  507 void
  508 timer_read(
  509         timer_t         timer,
  510         register time_spec_t *tv)
  511 {
  512         timer_save_data_t       temp;
  513 
  514         timer_grab(timer,&temp);
  515 
  516 #ifdef  TIMER_TO_TIMESPEC
  517         TIMER_TO_TIMESPEC(&temp);       /* convert to seconds/nanos */
  518 #endif
  519 
  520         /*
  521          *      Normalize the result
  522          */
  523         tv->seconds = temp.high + temp.low/1000000000;
  524         tv->nanoseconds = temp.low%1000000000;
  525 
  526 }
  527 
  528 /*
  529  *      thread_read_times reads the user and system times from a thread.
  530  *      Time accumulated since last timestamp is not included.  Should
  531  *      be called at splsched() to avoid having user and system times
  532  *      be out of step.  Doesn't care if caller locked thread.
  533  *
  534  *      Needs to be kept coherent with thread_read_times ahead.
  535  */
  536 void thread_read_times(
  537         thread_t        thread,
  538         time_spec_t     *user_time_p,
  539         time_spec_t     *system_time_p)
  540 {
  541         timer_save_data_t       temp;
  542         register timer_t        timer;
  543 
  544         timer = &thread->user_timer;
  545         timer_grab(timer, &temp);
  546 
  547 #ifdef  TIMER_TO_TIMESPEC
  548         TIMER_TO_TIMESPEC(&temp);       /* convert to seconds/nanos */
  549 #endif
  550 
  551         user_time_p->seconds = temp.high + temp.low/1000000000;
  552         user_time_p->nanoseconds = temp.low % 1000000000;
  553 
  554         timer = &thread->system_timer;
  555         timer_grab(timer, &temp);
  556 
  557 #ifdef  TIMER_TO_TIMESPEC
  558         TIMER_TO_TIMESPEC(&temp);       /* convert to seconds/nanos */
  559 #endif
  560         system_time_p->seconds = temp.high + temp.low/1000000000;
  561         system_time_p->nanoseconds = temp.low % 1000000000;
  562 }
  563 
  564 /*
  565  *      Db_thread_read_times: A version of thread_read_times that
  566  *      can be called by the debugger. This version does not call
  567  *      timer_grab, which can block. Please keep it up to date with
  568  *      thread_read_times above.
  569  *
  570  */
  571 void db_thread_read_times(
  572         thread_t        thread,
  573         time_spec_t     *user_time_p,
  574         time_spec_t     *system_time_p)
  575 {
  576         timer_save_data_t       temp;
  577         register timer_t        timer;
  578 
  579         timer = &thread->user_timer;
  580         db_timer_grab(timer, &temp);
  581 
  582 #ifdef  TIMER_TO_TIMESPEC
  583         TIMER_TO_TIMESPEC(&temp);       /* convert to seconds/nanos */
  584 #endif
  585         user_time_p->seconds = temp.high + temp.low/1000000000;
  586         user_time_p->nanoseconds = temp.low % 1000000000;
  587 
  588         timer = &thread->system_timer;
  589         timer_grab(timer, &temp);
  590 
  591 #ifdef  TIMER_TO_TIMESPEC
  592         TIMER_TO_TIMESPEC(&temp);       /* convert to seconds/nanos */
  593 #endif
  594         system_time_p->seconds = temp.high + temp.low/1000000000;
  595         system_time_p->nanoseconds = temp.low % 1000000000;
  596 }
  597 
  598 /*
  599  *      timer_delta takes the difference of a saved timer value
  600  *      and the current one, and updates the saved value to current.
  601  *      The difference is returned as a function value.  See
  602  *      TIMER_DELTA macro (timer.h) for optimization to this.
  603  */
  604 
  605 unsigned int
  606 timer_delta(
  607         register timer_t        timer,
  608         timer_save_t            save)
  609 {
  610         timer_save_data_t       new_save;
  611         register unsigned       result;
  612 
  613         timer_grab(timer,&new_save);
  614         result = TIMER_HIGH_TO_USAGE(new_save.high - save->high) +
  615                  TIMER_LOW_TO_USAGE(new_save.low - save->low);
  616         save->high = new_save.high;
  617         save->low = new_save.low;
  618         return result;
  619 }

Cache object: da2e95cbbb5c3593f604365c234fcddb


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