Annotation of OSKit-Mach/kern/timer.c, revision 1.1.1.1

1.1       root        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  [email protected]
                     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: #include <cpus.h>
                     28: #include <stat_time.h>
                     29: 
                     30: #include <mach/kern_return.h>
                     31: #include <mach/port.h>
                     32: #include <kern/queue.h>
                     33: #include <kern/thread.h>
                     34: #include <mach/time_value.h>
                     35: #include <kern/timer.h>
                     36: #include <kern/cpu_number.h>
                     37: 
                     38: #include <kern/assert.h>
                     39: #include <kern/macro_help.h>
                     40: 
                     41: 
                     42: 
                     43: timer_t                current_timer[NCPUS];
                     44: timer_data_t   kernel_timer[NCPUS];
                     45: 
                     46: void timer_init(); /* forward */
                     47: 
                     48: /*
                     49:  *     init_timers initializes all non-thread timers and puts the
                     50:  *     service routine on the callout queue.  All timers must be
                     51:  *     serviced by the callout routine once an hour.
                     52:  */
                     53: void init_timers()
                     54: {
                     55:        register int    i;
                     56:        register timer_t        this_timer;
                     57: 
                     58:        /*
                     59:         *      Initialize all the kernel timers and start the one
                     60:         *      for this cpu (master) slaves start theirs later.
                     61:         */
                     62:        this_timer = &kernel_timer[0];
                     63:        for ( i=0 ; i<NCPUS ; i++, this_timer++) {
                     64:                timer_init(this_timer);
                     65:                current_timer[i] = (timer_t) 0;
                     66:        }
                     67: 
                     68:        start_timer(&kernel_timer[cpu_number()]);
                     69: }
                     70: 
                     71: /*
                     72:  *     timer_init initializes a single timer.
                     73:  */
                     74: void timer_init(this_timer)
                     75: register
                     76: timer_t this_timer;
                     77: {
                     78:        this_timer->low_bits = 0;
                     79:        this_timer->high_bits = 0;
                     80:        this_timer->tstamp = 0;
                     81:        this_timer->high_bits_check = 0;
                     82: }
                     83: 
                     84: #if    STAT_TIME
                     85: #else  /* STAT_TIME */
                     86: 
                     87: #ifdef MACHINE_TIMER_ROUTINES
                     88: 
                     89: /*
                     90:  *     Machine-dependent code implements the timer routines.
                     91:  */
                     92: 
                     93: #else  /* MACHINE_TIMER_ROUTINES */
                     94: 
                     95: /*
                     96:  *     start_timer starts the given timer for this cpu. It is called
                     97:  *     exactly once for each cpu during the boot sequence.
                     98:  */
                     99: void
                    100: start_timer(timer)
                    101: timer_t timer;
                    102: {
                    103:        timer->tstamp = get_timestamp();
                    104:        current_timer[cpu_number()] = timer;
                    105: }
                    106: 
                    107: /*
                    108:  *     time_trap_uentry does trap entry timing.  Caller must lock out
                    109:  *     interrupts and take a timestamp.  ts is a timestamp taken after
                    110:  *     interrupts were locked out. Must only be called if trap was
                    111:  *     from user mode.
                    112:  */
                    113: void
                    114: time_trap_uentry(ts)
                    115: unsigned ts;
                    116: {
                    117:        int     elapsed;
                    118:        int     mycpu;
                    119:        timer_t mytimer;
                    120: 
                    121:        /*
                    122:         *      Calculate elapsed time.
                    123:         */
                    124:        mycpu = cpu_number();
                    125:        mytimer = current_timer[mycpu];
                    126:        elapsed = ts - mytimer->tstamp;
                    127: #ifdef TIMER_MAX
                    128:        if (elapsed < 0) elapsed += TIMER_MAX;
                    129: #endif /* TIMER_MAX */
                    130: 
                    131:        /*
                    132:         *      Update current timer.
                    133:         */
                    134:        mytimer->low_bits += elapsed;
                    135:        mytimer->tstamp = 0;
                    136: 
                    137:        if (mytimer->low_bits & TIMER_LOW_FULL) {
                    138:                timer_normalize(mytimer);
                    139:        }
                    140: 
                    141:        /*
                    142:         *      Record new timer.
                    143:         */
                    144:        mytimer = &(active_threads[mycpu]->system_timer);
                    145:        current_timer[mycpu] = mytimer;
                    146:        mytimer->tstamp = ts;
                    147: }
                    148: 
                    149: /*
                    150:  *     time_trap_uexit does trap exit timing.  Caller must lock out
                    151:  *     interrupts and take a timestamp.  ts is a timestamp taken after
                    152:  *     interrupts were locked out.  Must only be called if returning to
                    153:  *     user mode.
                    154:  */
                    155: void
                    156: time_trap_uexit(ts)
                    157: {
                    158:        int     elapsed;
                    159:        int     mycpu;
                    160:        timer_t mytimer;
                    161: 
                    162:        /*
                    163:         *      Calculate elapsed time.
                    164:         */
                    165:        mycpu = cpu_number();
                    166:        mytimer = current_timer[mycpu];
                    167:        elapsed = ts - mytimer->tstamp;
                    168: #ifdef TIMER_MAX
                    169:        if (elapsed < 0) elapsed += TIMER_MAX;
                    170: #endif /* TIMER_MAX */
                    171: 
                    172:        /*
                    173:         *      Update current timer.
                    174:         */
                    175:        mytimer->low_bits += elapsed;
                    176:        mytimer->tstamp = 0;
                    177: 
                    178:        if (mytimer->low_bits & TIMER_LOW_FULL) {
                    179:                timer_normalize(mytimer);       /* SYSTEMMODE */
                    180:        }
                    181: 
                    182:        mytimer = &(active_threads[mycpu]->user_timer);
                    183: 
                    184:        /*
                    185:         *      Record new timer.
                    186:         */
                    187:        current_timer[mycpu] = mytimer;
                    188:        mytimer->tstamp = ts;
                    189: }
                    190: 
                    191: /*
                    192:  *     time_int_entry does interrupt entry timing.  Caller must lock out
                    193:  *     interrupts and take a timestamp. ts is a timestamp taken after
                    194:  *     interrupts were locked out.  new_timer is the new timer to
                    195:  *     switch to.  This routine returns the currently running timer,
                    196:  *     which MUST be pushed onto the stack by the caller, or otherwise
                    197:  *     saved for time_int_exit.
                    198:  */
                    199: timer_t
                    200: time_int_entry(ts,new_timer)
                    201: unsigned       ts;
                    202: timer_t        new_timer;
                    203: {
                    204:        int     elapsed;
                    205:        int     mycpu;
                    206:        timer_t mytimer;
                    207: 
                    208:        /*
                    209:         *      Calculate elapsed time.
                    210:         */
                    211:        mycpu = cpu_number();
                    212:        mytimer = current_timer[mycpu];
                    213: 
                    214:        elapsed = ts - mytimer->tstamp;
                    215: #ifdef TIMER_MAX
                    216:        if (elapsed < 0) elapsed += TIMER_MAX;
                    217: #endif /* TIMER_MAX */
                    218: 
                    219:        /*
                    220:         *      Update current timer.
                    221:         */
                    222:        mytimer->low_bits += elapsed;
                    223:        mytimer->tstamp = 0;
                    224: 
                    225:        /*
                    226:         *      Switch to new timer, and save old one on stack.
                    227:         */
                    228:        new_timer->tstamp = ts;
                    229:        current_timer[mycpu] = new_timer;
                    230:        return(mytimer);
                    231: }
                    232: 
                    233: /*
                    234:  *     time_int_exit does interrupt exit timing.  Caller must lock out
                    235:  *     interrupts and take a timestamp.  ts is a timestamp taken after
                    236:  *     interrupts were locked out.  old_timer is the timer value pushed
                    237:  *     onto the stack or otherwise saved after time_int_entry returned
                    238:  *     it.
                    239:  */
                    240: void
                    241: time_int_exit(ts, old_timer)
                    242: unsigned       ts;
                    243: timer_t        old_timer;
                    244: {
                    245:        int     elapsed;
                    246:        int     mycpu;
                    247:        timer_t mytimer;
                    248: 
                    249:        /*
                    250:         *      Calculate elapsed time.
                    251:         */
                    252:        mycpu = cpu_number();
                    253:        mytimer = current_timer[mycpu];
                    254:        elapsed = ts - mytimer->tstamp;
                    255: #ifdef TIMER_MAX
                    256:        if (elapsed < 0) elapsed += TIMER_MAX;
                    257: #endif /* TIMER_MAX */
                    258: 
                    259:        /*
                    260:         *      Update current timer.
                    261:         */
                    262:        mytimer->low_bits += elapsed;
                    263:        mytimer->tstamp = 0;
                    264: 
                    265:        /*
                    266:         *      If normalization requested, do it.
                    267:         */
                    268:        if (mytimer->low_bits & TIMER_LOW_FULL) {
                    269:                timer_normalize(mytimer);
                    270:        }
                    271:        if (old_timer->low_bits & TIMER_LOW_FULL) {
                    272:                timer_normalize(old_timer);
                    273:        }
                    274: 
                    275:        /*
                    276:         *      Start timer that was running before interrupt.
                    277:         */
                    278:        old_timer->tstamp = ts;
                    279:        current_timer[mycpu] = old_timer;
                    280: }
                    281: 
                    282: /*
                    283:  *     timer_switch switches to a new timer.  The machine
                    284:  *     dependent routine/macro get_timestamp must return a timestamp.
                    285:  *     Caller must lock out interrupts.
                    286:  */
                    287: void
                    288: timer_switch(new_timer)
                    289: timer_t new_timer;
                    290: {
                    291:        int             elapsed;
                    292:        int             mycpu;
                    293:        timer_t         mytimer;
                    294:        unsigned        ts;
                    295: 
                    296:        /*
                    297:         *      Calculate elapsed time.
                    298:         */
                    299:        mycpu = cpu_number();
                    300:        mytimer = current_timer[mycpu];
                    301:        ts = get_timestamp();
                    302:        elapsed = ts - mytimer->tstamp;
                    303: #ifdef TIMER_MAX
                    304:        if (elapsed < 0) elapsed += TIMER_MAX;
                    305: #endif /* TIMER_MAX */
                    306: 
                    307:        /*
                    308:         *      Update current timer.
                    309:         */
                    310:        mytimer->low_bits += elapsed;
                    311:        mytimer->tstamp = 0;
                    312: 
                    313:        /*
                    314:         *      Normalization check
                    315:         */
                    316:        if (mytimer->low_bits & TIMER_LOW_FULL) {
                    317:                timer_normalize(mytimer);
                    318:        }
                    319: 
                    320:        /*
                    321:         *      Record new timer.
                    322:         */
                    323:        current_timer[mycpu] = new_timer;
                    324:        new_timer->tstamp = ts;
                    325: }
                    326: 
                    327: #endif /* MACHINE_TIMER_ROUTINES */
                    328: #endif /* STAT_TIME */
                    329: 
                    330: /*
                    331:  *     timer_normalize normalizes the value of a timer.  It is
                    332:  *     called only rarely, to make sure low_bits never overflows.
                    333:  */
                    334: void timer_normalize(timer)
                    335: register
                    336: timer_t        timer;
                    337: {
                    338:        unsigned int    high_increment;
                    339: 
                    340:        /*
                    341:         *      Calculate high_increment, then write high check field first
                    342:         *      followed by low and high.  timer_grab() reads these fields in
                    343:         *      reverse order so if high and high check match, we know
                    344:         *      that the values read are ok.
                    345:         */
                    346: 
                    347:        high_increment = timer->low_bits/TIMER_HIGH_UNIT;
                    348:        timer->high_bits_check += high_increment;
                    349:        timer->low_bits %= TIMER_HIGH_UNIT;
                    350:        timer->high_bits += high_increment;
                    351: }
                    352: 
                    353: /*
                    354:  *     timer_grab() retrieves the value of a timer.
                    355:  *
                    356:  *     Critical scheduling code uses TIMER_DELTA macro in timer.h
                    357:  *     (called from thread_timer_delta in sched.h).
                    358:  *
                    359:  *      Keep coherent with db_time_grab below.
                    360:  */
                    361: 
                    362: static void timer_grab(timer, save)
                    363: timer_t                timer;
                    364: timer_save_t   save;
                    365: {
                    366: #if MACH_ASSERT
                    367:   unsigned int passes=0;
                    368: #endif
                    369:        do {
                    370:                (save)->high = (timer)->high_bits;
                    371:                (save)->low = (timer)->low_bits;
                    372:        /*
                    373:         *      If the timer was normalized while we were doing this,
                    374:         *      the high_bits value read above and the high_bits check
                    375:         *      value will not match because high_bits_check is the first
                    376:         *      field touched by the normalization procedure, and
                    377:         *      high_bits is the last.
                    378:         *
                    379:         *      Additions to timer only touch low bits and
                    380:         *      are therefore atomic with respect to this.
                    381:         */
                    382: #if MACH_ASSERT
                    383:                passes++;
                    384:                assert((passes < 10000) ? (1) : ((timer->high_bits_check = save->high), 0));
                    385: #endif
                    386:        } while ( (save)->high != (timer)->high_bits_check);
                    387: }
                    388: 
                    389: /*
                    390:  *
                    391:  *     Db_timer_grab(): used by db_thread_read_times. An nonblocking
                    392:  *      version of db_thread_get_times. Keep coherent with timer_grab
                    393:  *      above.
                    394:  *
                    395:  */
                    396: void db_timer_grab(timer, save)
                    397: timer_t                timer;
                    398: timer_save_t   save;
                    399: {
                    400:   /* Don't worry about coherency */
                    401: 
                    402:   (save)->high = (timer)->high_bits;
                    403:   (save)->low = (timer)->low_bits;
                    404: }
                    405: 
                    406: 
                    407: /*
                    408:  *     timer_read reads the value of a timer into a time_value_t.  If the
                    409:  *     timer was modified during the read, retry.  The value returned
                    410:  *     is accurate to the last update; time accumulated by a running
                    411:  *     timer since its last timestamp is not included.
                    412:  */
                    413: 
                    414: void
                    415: timer_read(timer, tv)
                    416: timer_t timer;
                    417: register
                    418: time_value_t *tv;
                    419: {
                    420:        timer_save_data_t       temp;
                    421: 
                    422:        timer_grab(timer,&temp);
                    423:        /*
                    424:         *      Normalize the result
                    425:         */
                    426: #ifdef TIMER_ADJUST
                    427:        TIMER_ADJUST(&temp);
                    428: #endif /* TIMER_ADJUST */
                    429:        tv->seconds = temp.high + temp.low/1000000;
                    430:        tv->microseconds = temp.low%1000000;
                    431: 
                    432: }
                    433: 
                    434: /*
                    435:  *     thread_read_times reads the user and system times from a thread.
                    436:  *     Time accumulated since last timestamp is not included.  Should
                    437:  *     be called at splsched() to avoid having user and system times
                    438:  *     be out of step.  Doesn't care if caller locked thread.
                    439:  *
                    440:  *      Needs to be kept coherent with thread_read_times ahead.
                    441:  */
                    442: void   thread_read_times(thread, user_time_p, system_time_p)
                    443:        thread_t        thread;
                    444:        time_value_t    *user_time_p;
                    445:        time_value_t    *system_time_p;
                    446: {
                    447:        timer_save_data_t       temp;
                    448:        register timer_t        timer;
                    449: 
                    450:        timer = &thread->user_timer;
                    451:        timer_grab(timer, &temp);
                    452: 
                    453: #ifdef TIMER_ADJUST
                    454:        TIMER_ADJUST(&temp);
                    455: #endif /* TIMER_ADJUST */
                    456:        user_time_p->seconds = temp.high + temp.low/1000000;
                    457:        user_time_p->microseconds = temp.low % 1000000;
                    458: 
                    459:        timer = &thread->system_timer;
                    460:        timer_grab(timer, &temp);
                    461: 
                    462: #ifdef TIMER_ADJUST
                    463:        TIMER_ADJUST(&temp);
                    464: #endif /* TIMER_ADJUST */
                    465:        system_time_p->seconds = temp.high + temp.low/1000000;
                    466:        system_time_p->microseconds = temp.low % 1000000;
                    467: }
                    468: 
                    469: /*
                    470:  *      Db_thread_read_times: A version of thread_read_times that
                    471:  *      can be called by the debugger. This version does not call
                    472:  *      timer_grab, which can block. Please keep it up to date with
                    473:  *      thread_read_times above.
                    474:  *
                    475:  */
                    476: void   db_thread_read_times(thread, user_time_p, system_time_p)
                    477:        thread_t        thread;
                    478:        time_value_t    *user_time_p;
                    479:        time_value_t    *system_time_p;
                    480: {
                    481:        timer_save_data_t       temp;
                    482:        register timer_t        timer;
                    483: 
                    484:        timer = &thread->user_timer;
                    485:        db_timer_grab(timer, &temp);
                    486: 
                    487: #ifdef TIMER_ADJUST
                    488:        TIMER_ADJUST(&temp);
                    489: #endif /* TIMER_ADJUST */
                    490:        user_time_p->seconds = temp.high + temp.low/1000000;
                    491:        user_time_p->microseconds = temp.low % 1000000;
                    492: 
                    493:        timer = &thread->system_timer;
                    494:        timer_grab(timer, &temp);
                    495: 
                    496: #ifdef TIMER_ADJUST
                    497:        TIMER_ADJUST(&temp);
                    498: #endif /* TIMER_ADJUST */
                    499:        system_time_p->seconds = temp.high + temp.low/1000000;
                    500:        system_time_p->microseconds = temp.low % 1000000;
                    501: }
                    502: 
                    503: /*
                    504:  *     timer_delta takes the difference of a saved timer value
                    505:  *     and the current one, and updates the saved value to current.
                    506:  *     The difference is returned as a function value.  See
                    507:  *     TIMER_DELTA macro (timer.h) for optimization to this.
                    508:  */
                    509: 
                    510: unsigned
                    511: timer_delta(timer, save)
                    512: register
                    513: timer_t        timer;
                    514: timer_save_t   save;
                    515: {
                    516:        timer_save_data_t       new_save;
                    517:        register unsigned       result;
                    518: 
                    519:        timer_grab(timer,&new_save);
                    520:        result = (new_save.high - save->high) * TIMER_HIGH_UNIT +
                    521:                new_save.low - save->low;
                    522:        save->high = new_save.high;
                    523:        save->low = new_save.low;
                    524:        return(result);
                    525: }

unix.superglobalmegacorp.com

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