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