Annotation of XNU/osfmk/kern/timer.c, revision 1.1.1.1

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

unix.superglobalmegacorp.com

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