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

Cache object: fff07ba491ef2fd9b565ad5f42b3ca6c


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