Annotation of kernel/kern/timer.c, revision 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.