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

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

unix.superglobalmegacorp.com

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