Annotation of Gnu-Mach/kern/timer.c, revision 1.1.1.3

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

unix.superglobalmegacorp.com

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