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