Annotation of kernel/kern/timer.c, revision 1.1.1.1

1.1       root        1: /*
                      2:  * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
                      3:  *
                      4:  * @APPLE_LICENSE_HEADER_START@
                      5:  * 
                      6:  * Portions Copyright (c) 1999 Apple Computer, Inc.  All Rights
                      7:  * Reserved.  This file contains Original Code and/or Modifications of
                      8:  * Original Code as defined in and that are subject to the Apple Public
                      9:  * Source License Version 1.1 (the "License").  You may not use this file
                     10:  * except in compliance with the License.  Please obtain a copy of the
                     11:  * License at http://www.apple.com/publicsource and read it before using
                     12:  * this file.
                     13:  * 
                     14:  * The Original Code and all software distributed under the License are
                     15:  * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
                     16:  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
                     17:  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
                     18:  * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT.  Please see the
                     19:  * License for the specific language governing rights and limitations
                     20:  * under the License.
                     21:  * 
                     22:  * @APPLE_LICENSE_HEADER_END@
                     23:  */
                     24: 
                     25: /* 
                     26:  * Mach Operating System
                     27:  * Copyright (c) 1989 Carnegie-Mellon University
                     28:  * Copyright (c) 1988 Carnegie-Mellon University
                     29:  * Copyright (c) 1987 Carnegie-Mellon University
                     30:  * All rights reserved.  The CMU software License Agreement specifies
                     31:  * the terms and conditions for use and redistribution.
                     32:  */
                     33: 
                     34: #import <cpus.h>
                     35: #import <stat_time.h>
                     36: 
                     37: #import <sys/param.h>
                     38: #import <sys/kernel.h>
                     39: #import <mach/kern_return.h>
                     40: #import <mach/port.h>
                     41: #import <kern/queue.h>
                     42: #import <kern/thread.h>
                     43: #import <mach/time_value.h>
                     44: #import <kern/timer.h>
                     45: #import <bsd/machine/cpu.h>
                     46: 
                     47: #import <kernserv/macro_help.h>
                     48: 
                     49: timer_t                current_timer[NCPUS];
                     50: timer_data_t   kernel_timer[NCPUS];
                     51: 
                     52: /*
                     53:  *     init_timers initializes all non-thread timers and puts the
                     54:  *     service routine on the callout queue.  All timers must be
                     55:  *     serviced by the callout routine once an hour.
                     56:  */
                     57: init_timers()
                     58: {
                     59:        register int    i;
                     60:        register timer_t        this_timer;
                     61: 
                     62:        /*
                     63:         *      Initialize all the kernel timers and start the one
                     64:         *      for this cpu (master) slaves start theirs later.
                     65:         */
                     66:        this_timer = &kernel_timer[0];
                     67:        for ( i=0 ; i<NCPUS ; i++, this_timer++) {
                     68:                timer_init(this_timer);
                     69:                current_timer[i] = (timer_t) 0;
                     70:        }
                     71: 
                     72:        start_timer(&kernel_timer[cpu_number()]);
                     73: }
                     74: 
                     75: /*
                     76:  *     timer_init initializes a single timer.
                     77:  */
                     78: timer_init(this_timer)
                     79: register
                     80: timer_t this_timer;
                     81: {
                     82:        this_timer->low_bits = 0;
                     83:        this_timer->high_bits = 0;
                     84:        this_timer->tstamp = 0;
                     85:        this_timer->high_bits_check = 0;
                     86: }
                     87: 
                     88: #if    STAT_TIME
                     89: #else  STAT_TIME
                     90: /*
                     91:  *     start_timer starts the given timer for this cpu. It is called
                     92:  *     exactly once for each cpu during the boot sequence.
                     93:  */
                     94: void
                     95: start_timer(timer)
                     96: timer_t timer;
                     97: {
                     98:        timer->tstamp = get_timestamp();
                     99:        current_timer[cpu_number()] = timer;
                    100: }
                    101: 
                    102: /*
                    103:  *     time_trap_uentry does trap entry timing.  Caller must lock out
                    104:  *     interrupts and take a timestamp.  ts is a timestamp taken after
                    105:  *     interrupts were locked out. Must only be called if trap was
                    106:  *     from user mode.
                    107:  */
                    108: void
                    109: time_trap_uentry(ts)
                    110: unsigned ts;
                    111: {
                    112:        int     elapsed;
                    113:        int     mycpu;
                    114:        timer_t mytimer;
                    115: 
                    116:        /*
                    117:         *      Calculate elapsed time.
                    118:         */
                    119:        mycpu = cpu_number();
                    120:        mytimer = current_timer[mycpu];
                    121:        elapsed = ts - mytimer->tstamp;
                    122: #ifdef TIMER_MAX
                    123:        if (elapsed < 0) elapsed += TIMER_MAX;
                    124: #endif TIMER_MAX
                    125: 
                    126:        /*
                    127:         *      Update current timer.
                    128:         */
                    129:        mytimer->low_bits += elapsed;
                    130:        mytimer->tstamp = 0;
                    131: 
                    132:        /*
                    133:         *      Record new timer.
                    134:         */
                    135:        mytimer = &(active_threads[mycpu]->system_timer);
                    136:        current_timer[mycpu] = mytimer;
                    137:        mytimer->tstamp = ts;
                    138: }
                    139: 
                    140: /*
                    141:  *     time_trap_uexit does trap exit timing.  Caller must lock out
                    142:  *     interrupts and take a timestamp.  ts is a timestamp taken after
                    143:  *     interrupts were locked out.  Must only be called if returning to
                    144:  *     user mode.
                    145:  */
                    146: void
                    147: time_trap_uexit(ts)
                    148: {
                    149:        int     elapsed;
                    150:        int     mycpu;
                    151:        timer_t mytimer;
                    152: 
                    153:        /*
                    154:         *      Calculate elapsed time.
                    155:         */
                    156:        mycpu = cpu_number();
                    157:        mytimer = current_timer[mycpu];
                    158:        elapsed = ts - mytimer->tstamp;
                    159: #ifdef TIMER_MAX
                    160:        if (elapsed < 0) elapsed += TIMER_MAX;
                    161: #endif TIMER_MAX
                    162: 
                    163:        /*
                    164:         *      Update current timer.
                    165:         */
                    166:        mytimer->low_bits += elapsed;
                    167:        mytimer->tstamp = 0;
                    168: 
                    169:        /*
                    170:         *      Normalize old and new timers if needed.
                    171:         */
                    172:        if (mytimer->low_bits & TIMER_LOW_FULL) {
                    173:                timer_normalize(mytimer);       /* SYSTEMMODE */
                    174:        }
                    175: 
                    176:        mytimer = &(active_threads[mycpu]->user_timer);
                    177: 
                    178:        if (mytimer->low_bits & TIMER_LOW_FULL) {
                    179:                timer_normalize(mytimer);       /* USERMODE */
                    180:        }
                    181: 
                    182:        /*
                    183:         *      Record new timer.
                    184:         */
                    185:        current_timer[mycpu] = mytimer;
                    186:        mytimer->tstamp = ts;
                    187: }
                    188: 
                    189: /*
                    190:  *     time_int_entry does interrupt entry timing.  Caller must lock out
                    191:  *     interrupts and take a timestamp. ts is a timestamp taken after
                    192:  *     interrupts were locked out.  new_timer is the new timer to
                    193:  *     switch to.  This routine returns the currently running timer,
                    194:  *     which MUST be pushed onto the stack by the caller, or otherwise
                    195:  *     saved for time_int_exit.
                    196:  */
                    197: timer_t
                    198: time_int_entry(ts,new_timer)
                    199: unsigned       ts;
                    200: timer_t        new_timer;
                    201: {
                    202:        int     elapsed;
                    203:        int     mycpu;
                    204:        timer_t mytimer;
                    205: 
                    206:        /*
                    207:         *      Calculate elapsed time.
                    208:         */
                    209:        mycpu = cpu_number();
                    210:        mytimer = current_timer[mycpu];
                    211: 
                    212:        elapsed = ts - mytimer->tstamp;
                    213: #ifdef TIMER_MAX
                    214:        if (elapsed < 0) elapsed += TIMER_MAX;
                    215: #endif TIMER_MAX
                    216: 
                    217:        /*
                    218:         *      Update current timer.
                    219:         */
                    220:        mytimer->low_bits += elapsed;
                    221:        mytimer->tstamp = 0;
                    222: 
                    223:        /*
                    224:         *      Switch to new timer, and save old one on stack.
                    225:         */
                    226:        new_timer->tstamp = ts;
                    227:        current_timer[mycpu] = new_timer;
                    228:        return(mytimer);
                    229: }
                    230: 
                    231: /*
                    232:  *     time_int_exit does interrupt exit timing.  Caller must lock out
                    233:  *     interrupts and take a timestamp.  ts is a timestamp taken after
                    234:  *     interrupts were locked out.  old_timer is the timer value pushed
                    235:  *     onto the stack or otherwise saved after time_int_entry returned
                    236:  *     it.
                    237:  */
                    238: void
                    239: time_int_exit(ts, old_timer)
                    240: unsigned       ts;
                    241: timer_t        old_timer;
                    242: {
                    243:        int     elapsed;
                    244:        int     mycpu;
                    245:        timer_t mytimer;
                    246: 
                    247:        /*
                    248:         *      Calculate elapsed time.
                    249:         */
                    250:        mycpu = cpu_number();
                    251:        mytimer = current_timer[mycpu];
                    252:        elapsed = ts - mytimer->tstamp;
                    253: #ifdef TIMER_MAX
                    254:        if (elapsed < 0) elapsed += TIMER_MAX;
                    255: #endif TIMER_MAX
                    256: 
                    257:        /*
                    258:         *      Update current timer.
                    259:         */
                    260:        mytimer->low_bits += elapsed;
                    261:        mytimer->tstamp = 0;
                    262: 
                    263:        /*
                    264:         *      If normalization requested, do it.
                    265:         */
                    266:        if (mytimer->low_bits & TIMER_LOW_FULL) {
                    267:                timer_normalize(mytimer);
                    268:        }
                    269:        if (old_timer->low_bits & TIMER_LOW_FULL) {
                    270:                timer_normalize(old_timer);
                    271:        }
                    272: 
                    273:        /*
                    274:         *      Start timer that was running before interrupt.
                    275:         */
                    276:        old_timer->tstamp = ts;
                    277:        current_timer[mycpu] = old_timer;
                    278: }
                    279: 
                    280: /*
                    281:  *     timer_switch switches to a new timer.  The machine
                    282:  *     dependent routine/macro get_timestamp must return a timestamp.
                    283:  *     Caller must lock out interrupts.
                    284:  */
                    285: void
                    286: timer_switch(new_timer)
                    287: timer_t new_timer;
                    288: {
                    289:        int             elapsed;
                    290:        int             mycpu;
                    291:        timer_t         mytimer;
                    292:        unsigned        ts;
                    293: 
                    294:        /*
                    295:         *      Calculate elapsed time.
                    296:         */
                    297:        mycpu = cpu_number();
                    298:        mytimer = current_timer[mycpu];
                    299:        ts = get_timestamp();
                    300:        elapsed = ts - mytimer->tstamp;
                    301: #ifdef TIMER_MAX
                    302:        if (elapsed < 0) elapsed += TIMER_MAX;
                    303: #endif TIMER_MAX
                    304: 
                    305:        /*
                    306:         *      Update current timer.
                    307:         */
                    308:        mytimer->low_bits += elapsed;
                    309:        mytimer->tstamp = 0;
                    310: 
                    311:        /*
                    312:         *      Normalization check
                    313:         */
                    314:        if (mytimer->low_bits & TIMER_LOW_FULL) {
                    315:                timer_normalize(mytimer);
                    316:        }
                    317: 
                    318:        /*
                    319:         *      Record new timer.
                    320:         */
                    321:        current_timer[mycpu] = new_timer;
                    322:        new_timer->tstamp = ts;
                    323: }
                    324: #endif STAT_TIME
                    325: 
                    326: /*
                    327:  *     timer_normalize normalizes the value of a timer.  It is
                    328:  *     called only rarely, to make sure low_bits never overflows.
                    329:  */
                    330: timer_normalize(timer)
                    331: register
                    332: timer_t        timer;
                    333: {
                    334:        unsigned int    high_increment;
                    335: 
                    336:        /*
                    337:         *      Calculate high_increment, then write high check field first
                    338:         *      followed by low and high.  timer_grab() reads these fields in
                    339:         *      reverse order so if high and high check match, we know
                    340:         *      that the values read are ok.
                    341:         */
                    342: 
                    343:        high_increment = timer->low_bits/TIMER_HIGH_UNIT;
                    344:        timer->high_bits_check += high_increment;
                    345:        timer->low_bits %= TIMER_HIGH_UNIT;
                    346:        timer->high_bits += high_increment;
                    347: }
                    348: 
                    349: /*
                    350:  *     timer_grab() is a macro to retrieve the value of a timer.
                    351:  */
                    352: 
                    353: #define timer_grab(timer, save)                                                \
                    354:        MACRO_BEGIN                                                     \
                    355:        do {                                                            \
                    356:                (save)->high = (timer)->high_bits;                      \
                    357:                (save)->low = (timer)->low_bits;                        \
                    358:        /*                                                              \
                    359:         *      If the timer was normalized while we were doing this,   \
                    360:         *      the high_bits value read above and the high_bits check  \
                    361:         *      value won't match because high_bits_check is the first  \
                    362:         *      field touched by the normalization procedure, and       \
                    363:         *      high_bits is the last.                                  \
                    364:         *
                    365:         *      Additions to timer only touch low bits and              \
                    366:         *      are therefore atomic with respect to this.              \
                    367:         */                                                             \
                    368:        } while ( (save)->high != (timer)->high_bits_check);            \
                    369:        MACRO_END
                    370: 
                    371: 
                    372: /*
                    373:  *     timer_read reads the value of a timer into a time_value_t.  If the
                    374:  *     timer was modified during the read, retry.  The value returned
                    375:  *     is accurate to the last update; time accumulated by a running
                    376:  *     timer since its last timestamp is not included.
                    377:  */
                    378: 
                    379: void
                    380: timer_read(timer, tv)
                    381: timer_t timer;
                    382: register
                    383: time_value_t *tv;
                    384: {
                    385:        timer_save_data_t       temp;
                    386: 
                    387:        timer_grab(timer,&temp);
                    388:        /*
                    389:         *      Normalize the result
                    390:         */
                    391: #ifdef TIMER_ADJUST
                    392:        TIMER_ADJUST(&temp);
                    393: #endif TIMER_ADJUST
                    394:        tv->seconds = temp.high + temp.low/1000000;
                    395:        tv->microseconds = temp.low%1000000;
                    396: 
                    397: }
                    398: 
                    399: /*
                    400:  *     thread_read_times reads the user and system times from a thread.
                    401:  *     Time accumulated since last timestamp is not included.  Should
                    402:  *     be called at splsched() to avoid having user and system times
                    403:  *     be out of step.  Doesn't care if caller locked thread.
                    404:  */
                    405: void   thread_read_times(thread, user_time_p, system_time_p)
                    406:        thread_t        thread;
                    407:        time_value_t    *user_time_p;
                    408:        time_value_t    *system_time_p;
                    409: {
                    410:        timer_save_data_t       temp;
                    411:        register timer_t        timer;
                    412: 
                    413:        timer = &thread->user_timer;
                    414:        timer_grab(timer, &temp);
                    415: 
                    416: #ifdef TIMER_ADJUST
                    417:        TIMER_ADJUST(&temp);
                    418: #endif TIMER_ADJUST
                    419:        user_time_p->seconds = temp.high + temp.low/1000000;
                    420:        user_time_p->microseconds = temp.low % 1000000;
                    421: 
                    422:        timer = &thread->system_timer;
                    423:        timer_grab(timer, &temp);
                    424: 
                    425: #ifdef TIMER_ADJUST
                    426:        TIMER_ADJUST(&temp);
                    427: #endif TIMER_ADJUST
                    428:        system_time_p->seconds = temp.high + temp.low/1000000;
                    429:        system_time_p->microseconds = temp.low % 1000000;
                    430: }
                    431: 
                    432: /*
                    433:  *     timer_delta takes the difference of a saved timer value
                    434:  *     and the current one, and updates the saved value to current.
                    435:  *     The difference is returned as a function value.  See
                    436:  *     TIMER_DELTA macro (timer.h) for optimization to this.
                    437:  */
                    438: 
                    439: unsigned
                    440: timer_delta(timer, save)
                    441: register
                    442: timer_t        timer;
                    443: timer_save_t   save;
                    444: {
                    445:        timer_save_data_t       new_save;
                    446:        register unsigned       result;
                    447: 
                    448:        timer_grab(timer,&new_save);
                    449:        result = (new_save.high - save->high) * TIMER_HIGH_UNIT +
                    450:                new_save.low - save->low;
                    451:        save->high = new_save.high;
                    452:        save->low = new_save.low;
                    453:        return(result);
                    454: }
                    455: 

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.