Annotation of XNU/osfmk/kern/lock.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:  *     File:   kern/lock.c
        !            52:  *     Author: Avadis Tevanian, Jr., Michael Wayne Young
        !            53:  *     Date:   1985
        !            54:  *
        !            55:  *     Locking primitives implementation
        !            56:  */
        !            57: 
        !            58: #include <cpus.h>
        !            59: #include <mach_kdb.h>
        !            60: #include <mach_ldebug.h>
        !            61: 
        !            62: #include <kern/lock.h>
        !            63: #include <kern/etap_macros.h>
        !            64: #include <kern/misc_protos.h>
        !            65: #include <kern/thread.h>
        !            66: #include <kern/sched_prim.h>
        !            67: #include <kern/xpr.h>
        !            68: #include <kern/debug.h>
        !            69: #include <string.h>
        !            70: 
        !            71: #if    MACH_KDB
        !            72: #include <ddb/db_command.h>
        !            73: #include <ddb/db_output.h>
        !            74: #include <ddb/db_sym.h>
        !            75: #include <ddb/db_print.h>
        !            76: #endif /* MACH_KDB */
        !            77: 
        !            78: #ifdef __ppc__
        !            79: #include <ppc/Firmware.h>
        !            80: #include <ppc/POWERMAC/mp/MPPlugIn.h>
        !            81: #endif
        !            82: 
        !            83: #define        ANY_LOCK_DEBUG  (USLOCK_DEBUG || LOCK_DEBUG || MUTEX_DEBUG)
        !            84: 
        !            85: /*
        !            86:  *     Some portions of the lock debugging code must run with
        !            87:  *     interrupts disabled.  This can be machine-dependent,
        !            88:  *     but we don't have any good hooks for that at the moment.
        !            89:  *     If your architecture is different, add a machine-dependent
        !            90:  *     ifdef here for these macros.            XXX
        !            91:  */
        !            92: 
        !            93: #define        DISABLE_INTERRUPTS(s)   s = ml_set_interrupts_enabled(FALSE)
        !            94: #define        ENABLE_INTERRUPTS(s)    (void)ml_set_interrupts_enabled(s)
        !            95: 
        !            96: #if    NCPUS > 1
        !            97: /* Time we loop without holding the interlock. 
        !            98:  * The former is for when we cannot sleep, the latter
        !            99:  * for when our thread can go to sleep (loop less)
        !           100:  * we shouldn't retake the interlock at all frequently
        !           101:  * if we cannot go to sleep, since it interferes with
        !           102:  * any other processors. In particular, 100 is too small
        !           103:  * a number for powerpc MP systems because of cache
        !           104:  * coherency issues and differing lock fetch times between
        !           105:  * the processors
        !           106:  */
        !           107: unsigned int lock_wait_time[2] = { (unsigned int)-1, 100 } ;
        !           108: #else  /* NCPUS > 1 */
        !           109: 
        !           110:        /*
        !           111:         *      It is silly to spin on a uni-processor as if we
        !           112:         *      thought something magical would happen to the
        !           113:         *      want_write bit while we are executing.
        !           114:         */
        !           115: 
        !           116: unsigned int lock_wait_time[2] = { 0, 0 };
        !           117: #endif /* NCPUS > 1 */
        !           118: 
        !           119: /* Forwards */
        !           120: 
        !           121: #if    MACH_KDB
        !           122: void   db_print_simple_lock(
        !           123:                        simple_lock_t   addr);
        !           124: 
        !           125: void   db_print_mutex(
        !           126:                        mutex_t         * addr);
        !           127: #endif /* MACH_KDB */
        !           128: 
        !           129: 
        !           130: #if    USLOCK_DEBUG
        !           131: /*
        !           132:  *     Perform simple lock checks.
        !           133:  */
        !           134: int    uslock_check = 1;
        !           135: int    max_lock_loops  = 100000000;
        !           136: decl_simple_lock_data(extern , printf_lock)
        !           137: decl_simple_lock_data(extern , panic_lock)
        !           138: #if    MACH_KDB && NCPUS > 1
        !           139: decl_simple_lock_data(extern , kdb_lock)
        !           140: #endif /* MACH_KDB && NCPUS >1 */
        !           141: #endif /* USLOCK_DEBUG */
        !           142: 
        !           143: 
        !           144: /*
        !           145:  *     We often want to know the addresses of the callers
        !           146:  *     of the various lock routines.  However, this information
        !           147:  *     is only used for debugging and statistics.
        !           148:  */
        !           149: typedef void   *pc_t;
        !           150: #define        INVALID_PC      ((void *) VM_MAX_KERNEL_ADDRESS)
        !           151: #define        INVALID_THREAD  ((void *) VM_MAX_KERNEL_ADDRESS)
        !           152: #if    ANY_LOCK_DEBUG || ETAP_LOCK_TRACE
        !           153: #define        OBTAIN_PC(pc,l) ((pc) = (void *) GET_RETURN_PC(&(l)))
        !           154: #else  /* ANY_LOCK_DEBUG || ETAP_LOCK_TRACE */
        !           155: #ifdef lint
        !           156: /*
        !           157:  *     Eliminate lint complaints about unused local pc variables.
        !           158:  */
        !           159: #define        OBTAIN_PC(pc,l) ++pc
        !           160: #else  /* lint */
        !           161: #define        OBTAIN_PC(pc,l)
        !           162: #endif /* lint */
        !           163: #endif /* USLOCK_DEBUG || ETAP_LOCK_TRACE */
        !           164: 
        !           165: 
        !           166: /* #ifndef     USIMPLE_LOCK_CALLS
        !           167:  * The i386 production version of usimple_locks isn't ready yet.
        !           168:  */
        !           169: /*
        !           170:  *     Portable lock package implementation of usimple_locks.
        !           171:  */
        !           172: 
        !           173: #if     ETAP_LOCK_TRACE
        !           174: #define        ETAPCALL(stmt)  stmt
        !           175: void           etap_simplelock_init(simple_lock_t, etap_event_t);
        !           176: void           etap_simplelock_unlock(simple_lock_t);
        !           177: void           etap_simplelock_hold(simple_lock_t, pc_t, etap_time_t);
        !           178: etap_time_t    etap_simplelock_miss(simple_lock_t);
        !           179: 
        !           180: void           etap_mutex_init(mutex_t*, etap_event_t);
        !           181: void           etap_mutex_unlock(mutex_t*);
        !           182: void           etap_mutex_hold(mutex_t*, pc_t, etap_time_t);
        !           183: etap_time_t    etap_mutex_miss(mutex_t*);
        !           184: #else   /* ETAP_LOCK_TRACE */
        !           185: #define        ETAPCALL(stmt)
        !           186: #endif  /* ETAP_LOCK_TRACE */
        !           187: 
        !           188: #if    USLOCK_DEBUG
        !           189: #define        USLDBG(stmt)    stmt
        !           190: void           usld_lock_init(usimple_lock_t, etap_event_t);
        !           191: void           usld_lock_pre(usimple_lock_t, pc_t);
        !           192: void           usld_lock_post(usimple_lock_t, pc_t);
        !           193: void           usld_unlock(usimple_lock_t, pc_t);
        !           194: void           usld_lock_try_pre(usimple_lock_t, pc_t);
        !           195: void           usld_lock_try_post(usimple_lock_t, pc_t);
        !           196: void           usld_lock_held(usimple_lock_t);
        !           197: void           usld_lock_none_held(void);
        !           198: int            usld_lock_common_checks(usimple_lock_t, char *);
        !           199: #else  /* USLOCK_DEBUG */
        !           200: #define        USLDBG(stmt)
        !           201: #endif /* USLOCK_DEBUG */
        !           202: 
        !           203: /*
        !           204:  *     Initialize a usimple_lock.
        !           205:  *
        !           206:  *     No change in preemption state.
        !           207:  */
        !           208: void
        !           209: usimple_lock_init(
        !           210:        usimple_lock_t  l,
        !           211:        etap_event_t    event)
        !           212: {
        !           213:        USLDBG(usld_lock_init(l, event));
        !           214:        ETAPCALL(etap_simplelock_init((l),(event)));
        !           215:        hw_lock_init(&l->interlock);
        !           216: }
        !           217: 
        !           218: 
        !           219: /*
        !           220:  *     Acquire a usimple_lock.
        !           221:  *
        !           222:  *     Returns with preemption disabled.  Note
        !           223:  *     that the hw_lock routines are responsible for
        !           224:  *     maintaining preemption state.
        !           225:  */
        !           226: void
        !           227: usimple_lock(
        !           228:        usimple_lock_t  l)
        !           229: {
        !           230:        int i;
        !           231:        pc_t            pc;
        !           232: #if    ETAP_LOCK_TRACE
        !           233:        etap_time_t     start_wait_time;
        !           234:        int             no_miss_info = 0;
        !           235: #endif /* ETAP_LOCK_TRACE */
        !           236: #if    USLOCK_DEBUG
        !           237:        int             count = 0;
        !           238: #endif         /* USLOCK_DEBUG */
        !           239: 
        !           240:        OBTAIN_PC(pc, l);
        !           241:        USLDBG(usld_lock_pre(l, pc));
        !           242: #if    ETAP_LOCK_TRACE
        !           243:        ETAP_TIME_CLEAR(start_wait_time);
        !           244: #endif /* ETAP_LOCK_TRACE */
        !           245: 
        !           246: #ifdef __ppc__
        !           247:        if(!hw_lock_to(&l->interlock, LockTimeOut)) {   /* Try to get the lock with a timeout */ 
        !           248:        
        !           249:                panic("simple lock deadlock detection - l=%08X, cpu=%d, ret=%08X", l, cpu_number(), pc);
        !           250: 
        !           251: #else /* __ppc__ */
        !           252:        while (!hw_lock_try(&l->interlock)) {
        !           253:                ETAPCALL(if (no_miss_info++ == 0)
        !           254:                        start_wait_time = etap_simplelock_miss(l));
        !           255:                while (hw_lock_held(&l->interlock)) {
        !           256:                        /*
        !           257:                         *      Spin watching the lock value in cache,
        !           258:                         *      without consuming external bus cycles.
        !           259:                         *      On most SMP architectures, the atomic
        !           260:                         *      instruction(s) used by hw_lock_try
        !           261:                         *      cost much, much more than an ordinary
        !           262:                         *      memory read.
        !           263:                         */
        !           264: #if    USLOCK_DEBUG
        !           265:                        if (count++ > max_lock_loops
        !           266: #if    MACH_KDB && NCPUS > 1
        !           267:                            && l != &kdb_lock
        !           268: #endif /* MACH_KDB && NCPUS > 1 */
        !           269:                            ) {
        !           270:                                if (l == &printf_lock) {
        !           271:                                        return;
        !           272:                                }
        !           273:                                mp_disable_preemption();
        !           274:                                panic("simple lock deadlock detection - l=%08X (=%08X), cpu=%d, ret=%08X", 
        !           275:                                   l, *hw_lock_addr(l->interlock), cpu_number(), pc);
        !           276:                                count = 0;
        !           277:                                mp_enable_preemption();
        !           278:                        }
        !           279: #endif         /* USLOCK_DEBUG */
        !           280:                }
        !           281: #endif /* 0 */
        !           282:        }
        !           283:        ETAPCALL(etap_simplelock_hold(l, pc, start_wait_time));
        !           284:        USLDBG(usld_lock_post(l, pc));
        !           285: }
        !           286: 
        !           287: 
        !           288: /*
        !           289:  *     Release a usimple_lock.
        !           290:  *
        !           291:  *     Returns with preemption enabled.  Note
        !           292:  *     that the hw_lock routines are responsible for
        !           293:  *     maintaining preemption state.
        !           294:  */
        !           295: void
        !           296: usimple_unlock(
        !           297:        usimple_lock_t  l)
        !           298: {
        !           299:        pc_t    pc;
        !           300: 
        !           301: //     checkNMI();                                                                             /* (TEST/DEBUG) */
        !           302:                
        !           303:        OBTAIN_PC(pc, l);
        !           304:        USLDBG(usld_unlock(l, pc));
        !           305:        ETAPCALL(etap_simplelock_unlock(l));
        !           306:        hw_lock_unlock(&l->interlock);
        !           307: }
        !           308: 
        !           309: 
        !           310: /*
        !           311:  *     Conditionally acquire a usimple_lock.
        !           312:  *
        !           313:  *     On success, returns with preemption disabled.
        !           314:  *     On failure, returns with preemption in the same state
        !           315:  *     as when first invoked.  Note that the hw_lock routines
        !           316:  *     are responsible for maintaining preemption state.
        !           317:  *
        !           318:  *     XXX No stats are gathered on a miss; I preserved this
        !           319:  *     behavior from the original assembly-language code, but
        !           320:  *     doesn't it make sense to log misses?  XXX
        !           321:  */
        !           322: unsigned int
        !           323: usimple_lock_try(
        !           324:        usimple_lock_t  l)
        !           325: {
        !           326:        pc_t            pc;
        !           327:        unsigned int    success;
        !           328:        etap_time_t     zero_time;
        !           329: 
        !           330:        OBTAIN_PC(pc, l);
        !           331:        USLDBG(usld_lock_try_pre(l, pc));
        !           332:        if (success = hw_lock_try(&l->interlock)) {
        !           333:                USLDBG(usld_lock_try_post(l, pc));
        !           334:                ETAP_TIME_CLEAR(zero_time);
        !           335:                ETAPCALL(etap_simplelock_hold(l, pc, zero_time));
        !           336:        }
        !           337:        return success;
        !           338: }
        !           339: 
        !           340: #if ETAP_LOCK_TRACE
        !           341: void
        !           342: simple_lock_no_trace(
        !           343:        simple_lock_t   l)
        !           344: {
        !           345:        pc_t            pc;
        !           346: 
        !           347:        OBTAIN_PC(pc, l);
        !           348:        USLDBG(usld_lock_pre(l, pc));
        !           349:        while (!hw_lock_try(&l->interlock)) {
        !           350:                while (hw_lock_held(&l->interlock)) {
        !           351:                        /*
        !           352:                         *      Spin watching the lock value in cache,
        !           353:                         *      without consuming external bus cycles.
        !           354:                         *      On most SMP architectures, the atomic
        !           355:                         *      instruction(s) used by hw_lock_try
        !           356:                         *      cost much, much more than an ordinary
        !           357:                         *      memory read.
        !           358:                         */
        !           359:                }
        !           360:        }
        !           361:        USLDBG(usld_lock_post(l, pc));
        !           362: }
        !           363: 
        !           364: void
        !           365: simple_unlock_no_trace(
        !           366:        simple_lock_t   l)
        !           367: {
        !           368:        pc_t    pc;
        !           369: 
        !           370:        OBTAIN_PC(pc, l);
        !           371:        USLDBG(usld_unlock(l, pc));
        !           372:        hw_lock_unlock(&l->interlock);
        !           373: }
        !           374: 
        !           375: int
        !           376: simple_lock_try_no_trace(
        !           377:        simple_lock_t   l)
        !           378: {
        !           379:        pc_t            pc;
        !           380:        unsigned int    success;
        !           381: 
        !           382:        OBTAIN_PC(pc, l);
        !           383:        USLDBG(usld_lock_try_pre(l, pc));
        !           384:        if (success = hw_lock_try(&l->interlock)) {
        !           385:                USLDBG(usld_lock_try_post(l, pc));
        !           386:        }
        !           387:        return success;
        !           388: }
        !           389: #endif /* ETAP_LOCK_TRACE */
        !           390: 
        !           391: 
        !           392: #if    USLOCK_DEBUG
        !           393: /*
        !           394:  *     Verify that the lock is locked and owned by
        !           395:  *     the current thread.
        !           396:  */
        !           397: void
        !           398: usimple_lock_held(
        !           399:        usimple_lock_t  l)
        !           400: {
        !           401:        usld_lock_held(l);
        !           402: }
        !           403: 
        !           404: 
        !           405: /*
        !           406:  *     Verify that no usimple_locks are held by
        !           407:  *     this processor.  Typically used in a
        !           408:  *     trap handler when returning to user mode
        !           409:  *     or in a path known to relinquish the processor.
        !           410:  */
        !           411: void
        !           412: usimple_lock_none_held(void)
        !           413: {
        !           414:        usld_lock_none_held();
        !           415: }
        !           416: #endif /* USLOCK_DEBUG */
        !           417: 
        !           418: 
        !           419: #if    USLOCK_DEBUG
        !           420: /*
        !           421:  *     States of a usimple_lock.  The default when initializing
        !           422:  *     a usimple_lock is setting it up for debug checking.
        !           423:  */
        !           424: #define        USLOCK_CHECKED          0x0001          /* lock is being checked */
        !           425: #define        USLOCK_TAKEN            0x0002          /* lock has been taken */
        !           426: #define        USLOCK_INIT             0xBAA0          /* lock has been initialized */
        !           427: #define        USLOCK_INITIALIZED      (USLOCK_INIT|USLOCK_CHECKED)
        !           428: #define        USLOCK_CHECKING(l)      (uslock_check &&                        \
        !           429:                                 ((l)->debug.state & USLOCK_CHECKED))
        !           430: 
        !           431: /*
        !           432:  *     Maintain a per-cpu stack of acquired usimple_locks.
        !           433:  */
        !           434: void   usl_stack_push(usimple_lock_t, int);
        !           435: void   usl_stack_pop(usimple_lock_t, int);
        !           436: 
        !           437: /*
        !           438:  *     Trace activities of a particularly interesting lock.
        !           439:  */
        !           440: void   usl_trace(usimple_lock_t, int, pc_t, const char *);
        !           441: 
        !           442: 
        !           443: /*
        !           444:  *     Initialize the debugging information contained
        !           445:  *     in a usimple_lock.
        !           446:  */
        !           447: void
        !           448: usld_lock_init(
        !           449:        usimple_lock_t  l,
        !           450:        etap_event_t    type)
        !           451: {
        !           452:        if (l == USIMPLE_LOCK_NULL)
        !           453:                panic("lock initialization:  null lock pointer");
        !           454:        l->lock_type = USLOCK_TAG;
        !           455:        l->debug.state = uslock_check ? USLOCK_INITIALIZED : 0;
        !           456:        l->debug.lock_cpu = l->debug.unlock_cpu = 0;
        !           457:        l->debug.lock_pc = l->debug.unlock_pc = INVALID_PC;
        !           458:        l->debug.lock_thread = l->debug.unlock_thread = INVALID_THREAD;
        !           459:        l->debug.duration[0] = l->debug.duration[1] = 0;
        !           460:        l->debug.unlock_cpu = l->debug.unlock_cpu = 0;
        !           461:        l->debug.unlock_pc = l->debug.unlock_pc = INVALID_PC;
        !           462:        l->debug.unlock_thread = l->debug.unlock_thread = INVALID_THREAD;
        !           463: }
        !           464: 
        !           465: 
        !           466: /*
        !           467:  *     These checks apply to all usimple_locks, not just
        !           468:  *     those with USLOCK_CHECKED turned on.
        !           469:  */
        !           470: int
        !           471: usld_lock_common_checks(
        !           472:        usimple_lock_t  l,
        !           473:        char            *caller)
        !           474: {
        !           475:        if (l == USIMPLE_LOCK_NULL)
        !           476:                panic("%s:  null lock pointer", caller);
        !           477:        if (l->lock_type != USLOCK_TAG)
        !           478:                panic("%s:  0x%x is not a usimple lock", caller, (integer_t) l);
        !           479:        if (!(l->debug.state & USLOCK_INIT))
        !           480:                panic("%s:  0x%x is not an initialized lock",
        !           481:                      caller, (integer_t) l);
        !           482:        return USLOCK_CHECKING(l);
        !           483: }
        !           484: 
        !           485: 
        !           486: /*
        !           487:  *     Debug checks on a usimple_lock just before attempting
        !           488:  *     to acquire it.
        !           489:  */
        !           490: /* ARGSUSED */
        !           491: void
        !           492: usld_lock_pre(
        !           493:        usimple_lock_t  l,
        !           494:        pc_t            pc)
        !           495: {
        !           496:        char            *caller = "usimple_lock";
        !           497: 
        !           498: 
        !           499: #if 0
        !           500:        printf("*** %08X %08X %04X %02X %08X %02X %08X - %s\n", /* (TEST/DEBUG) */
        !           501:                l->debug.lock_pc,
        !           502:                l->debug.lock_thread,
        !           503:                l->debug.state,
        !           504:                l->debug.lock_cpu,
        !           505:                l->debug.unlock_thread,
        !           506:                l->debug.unlock_cpu,
        !           507:                l->debug.unlock_pc,
        !           508:                caller);
        !           509: #endif
        !           510: 
        !           511:        if (!usld_lock_common_checks(l, caller))
        !           512:                return;
        !           513: 
        !           514:        if ((l->debug.state & USLOCK_TAKEN) &&
        !           515:            l->debug.lock_thread == (void *) current_thread()) {
        !           516:                printf("%s:  lock 0x%x already locked (at 0x%x) by",
        !           517:                      caller, (integer_t) l, l->debug.lock_pc);
        !           518:                printf(" current thread 0x%x (new attempt at pc 0x%x)\n",
        !           519:                       l->debug.lock_thread, pc);
        !           520:                panic(caller);
        !           521:        }
        !           522:        mp_disable_preemption();
        !           523:        usl_trace(l, cpu_number(), pc, caller);
        !           524:        mp_enable_preemption();
        !           525: }
        !           526: 
        !           527: 
        !           528: /*
        !           529:  *     Debug checks on a usimple_lock just after acquiring it.
        !           530:  *
        !           531:  *     Pre-emption has been disabled at this point,
        !           532:  *     so we are safe in using cpu_number.
        !           533:  */
        !           534: void
        !           535: usld_lock_post(
        !           536:        usimple_lock_t  l,
        !           537:        pc_t            pc)
        !           538: {
        !           539:        register int    mycpu;
        !           540:        char            *caller = "successful usimple_lock";
        !           541: 
        !           542: 
        !           543: #if 0
        !           544:        printf("*** %08X %08X %04X %02X %08X %02X %08X - %s\n", /* (TEST/DEBUG) */
        !           545:                l->debug.lock_pc,
        !           546:                l->debug.lock_thread,
        !           547:                l->debug.state,
        !           548:                l->debug.lock_cpu,
        !           549:                l->debug.unlock_thread,
        !           550:                l->debug.unlock_cpu,
        !           551:                l->debug.unlock_pc,
        !           552:                caller);
        !           553: #endif
        !           554: 
        !           555:        if (!usld_lock_common_checks(l, caller))
        !           556:                return;
        !           557: 
        !           558:        if (!((l->debug.state & ~USLOCK_TAKEN) == USLOCK_INITIALIZED))
        !           559:                panic("%s:  lock 0x%x became uninitialized",
        !           560:                      caller, (integer_t) l);
        !           561:        if ((l->debug.state & USLOCK_TAKEN))
        !           562:                panic("%s:  lock 0x%x became TAKEN by someone else",
        !           563:                      caller, (integer_t) l);
        !           564: 
        !           565:        mycpu = cpu_number();
        !           566:        l->debug.lock_thread = (void *)current_thread();
        !           567:        l->debug.state |= USLOCK_TAKEN;
        !           568:        l->debug.lock_pc = pc;
        !           569:        l->debug.lock_cpu = mycpu;
        !           570: 
        !           571:        usl_stack_push(l, mycpu);
        !           572:        usl_trace(l, mycpu, pc, caller);
        !           573: }
        !           574: 
        !           575: 
        !           576: /*
        !           577:  *     Debug checks on a usimple_lock just before
        !           578:  *     releasing it.  Note that the caller has not
        !           579:  *     yet released the hardware lock.
        !           580:  *
        !           581:  *     Preemption is still disabled, so there's
        !           582:  *     no problem using cpu_number.
        !           583:  */
        !           584: void
        !           585: usld_unlock(
        !           586:        usimple_lock_t  l,
        !           587:        pc_t            pc)
        !           588: {
        !           589:        register int    mycpu;
        !           590:        char            *caller = "usimple_unlock";
        !           591: 
        !           592: 
        !           593: #if 0
        !           594:        printf("*** %08X %08X %04X %02X %08X %02X %08X - %s\n", /* (TEST/DEBUG) */
        !           595:                l->debug.lock_pc,
        !           596:                l->debug.lock_thread,
        !           597:                l->debug.state,
        !           598:                l->debug.lock_cpu,
        !           599:                l->debug.unlock_thread,
        !           600:                l->debug.unlock_cpu,
        !           601:                l->debug.unlock_pc,
        !           602:                caller);
        !           603: #endif
        !           604: 
        !           605:        if (!usld_lock_common_checks(l, caller))
        !           606:                return;
        !           607: 
        !           608:        mycpu = cpu_number();
        !           609: 
        !           610:        if (!(l->debug.state & USLOCK_TAKEN))
        !           611:                panic("%s:  lock 0x%x hasn't been taken",
        !           612:                      caller, (integer_t) l);
        !           613:        if (l->debug.lock_thread != (void *) current_thread())
        !           614:                panic("%s:  unlocking lock 0x%x, owned by thread 0x%x",
        !           615:                      caller, (integer_t) l, l->debug.lock_thread);
        !           616:        if (l->debug.lock_cpu != mycpu) {
        !           617:                printf("%s:  unlocking lock 0x%x on cpu 0x%x",
        !           618:                       caller, (integer_t) l, mycpu);
        !           619:                printf(" (acquired on cpu 0x%x)\n", l->debug.lock_cpu);
        !           620:                panic(caller);
        !           621:        }
        !           622:        usl_trace(l, mycpu, pc, caller);
        !           623:        usl_stack_pop(l, mycpu);
        !           624: 
        !           625:        l->debug.unlock_thread = l->debug.lock_thread;
        !           626:        l->debug.lock_thread = INVALID_PC;
        !           627:        l->debug.state &= ~USLOCK_TAKEN;
        !           628:        l->debug.unlock_pc = pc;
        !           629:        l->debug.unlock_cpu = mycpu;
        !           630: }
        !           631: 
        !           632: 
        !           633: /*
        !           634:  *     Debug checks on a usimple_lock just before
        !           635:  *     attempting to acquire it.
        !           636:  *
        !           637:  *     Preemption isn't guaranteed to be disabled.
        !           638:  */
        !           639: void
        !           640: usld_lock_try_pre(
        !           641:        usimple_lock_t  l,
        !           642:        pc_t            pc)
        !           643: {
        !           644:        char            *caller = "usimple_lock_try";
        !           645: 
        !           646:        if (!usld_lock_common_checks(l, caller))
        !           647:                return;
        !           648:        mp_disable_preemption();
        !           649:        usl_trace(l, cpu_number(), pc, caller);
        !           650:        mp_enable_preemption();
        !           651: }
        !           652: 
        !           653: 
        !           654: /*
        !           655:  *     Debug checks on a usimple_lock just after
        !           656:  *     successfully attempting to acquire it.
        !           657:  *
        !           658:  *     Preemption has been disabled by the
        !           659:  *     lock acquisition attempt, so it's safe
        !           660:  *     to use cpu_number.
        !           661:  */
        !           662: void
        !           663: usld_lock_try_post(
        !           664:        usimple_lock_t  l,
        !           665:        pc_t            pc)
        !           666: {
        !           667:        register int    mycpu;
        !           668:        char            *caller = "successful usimple_lock_try";
        !           669: 
        !           670:        if (!usld_lock_common_checks(l, caller))
        !           671:                return;
        !           672: 
        !           673:        if (!((l->debug.state & ~USLOCK_TAKEN) == USLOCK_INITIALIZED))
        !           674:                panic("%s:  lock 0x%x became uninitialized",
        !           675:                      caller, (integer_t) l);
        !           676:        if ((l->debug.state & USLOCK_TAKEN))
        !           677:                panic("%s:  lock 0x%x became TAKEN by someone else",
        !           678:                      caller, (integer_t) l);
        !           679: 
        !           680:        mycpu = cpu_number();
        !           681:        l->debug.lock_thread = (void *) current_thread();
        !           682:        l->debug.state |= USLOCK_TAKEN;
        !           683:        l->debug.lock_pc = pc;
        !           684:        l->debug.lock_cpu = mycpu;
        !           685: 
        !           686: #if 0
        !           687:        printf("*** %08X %08X %04X %02X %08X %02X %08X - %s\n", /* (TEST/DEBUG) */
        !           688:                l->debug.lock_pc,
        !           689:                l->debug.lock_thread,
        !           690:                l->debug.state,
        !           691:                l->debug.lock_cpu,
        !           692:                l->debug.unlock_thread,
        !           693:                l->debug.unlock_cpu,
        !           694:                l->debug.unlock_pc,
        !           695:                caller);
        !           696: #endif
        !           697: 
        !           698:        usl_stack_push(l, mycpu);
        !           699:        usl_trace(l, mycpu, pc, caller);
        !           700: }
        !           701: 
        !           702: 
        !           703: /*
        !           704:  *     Determine whether the lock in question is owned
        !           705:  *     by the current thread.
        !           706:  */
        !           707: void
        !           708: usld_lock_held(
        !           709:        usimple_lock_t  l)
        !           710: {
        !           711:        char            *caller = "usimple_lock_held";
        !           712: 
        !           713: 
        !           714: #if 0
        !           715:        printf("*** %08X %08X %04X %02X %08X %02X %08X - %s\n", /* (TEST/DEBUG) */
        !           716:                l->debug.lock_pc,
        !           717:                l->debug.lock_thread,
        !           718:                l->debug.state,
        !           719:                l->debug.lock_cpu,
        !           720:                l->debug.unlock_thread,
        !           721:                l->debug.unlock_cpu,
        !           722:                l->debug.unlock_pc,
        !           723:                caller);
        !           724: #endif
        !           725: 
        !           726:        if (!usld_lock_common_checks(l, caller))
        !           727:                return;
        !           728: 
        !           729:        if (!(l->debug.state & USLOCK_TAKEN))
        !           730:                panic("%s:  lock 0x%x hasn't been taken",
        !           731:                      caller, (integer_t) l);
        !           732:        if (l->debug.lock_thread != (void *) current_thread())
        !           733:                panic("%s:  lock 0x%x is owned by thread 0x%x", caller,
        !           734:                      (integer_t) l, (integer_t) l->debug.lock_thread);
        !           735: 
        !           736:        /*
        !           737:         *      The usimple_lock is active, so preemption
        !           738:         *      is disabled and the current cpu should
        !           739:         *      match the one recorded at lock acquisition time.
        !           740:         */
        !           741:        if (l->debug.lock_cpu != cpu_number())
        !           742:                panic("%s:  current cpu 0x%x isn't acquiring cpu 0x%x",
        !           743:                      caller, cpu_number(), (integer_t) l->debug.lock_cpu);
        !           744: }
        !           745: 
        !           746: 
        !           747: /*
        !           748:  *     Per-cpu stack of currently active usimple_locks.
        !           749:  *     Requires spl protection so that interrupt-level
        !           750:  *     locks plug-n-play with their thread-context friends.
        !           751:  */
        !           752: #define        USLOCK_STACK_DEPTH      20
        !           753: usimple_lock_t uslock_stack[NCPUS][USLOCK_STACK_DEPTH];
        !           754: unsigned int   uslock_stack_index[NCPUS];
        !           755: boolean_t      uslock_stack_enabled = TRUE;
        !           756: 
        !           757: 
        !           758: /*
        !           759:  *     Record a usimple_lock just acquired on
        !           760:  *     the current processor.
        !           761:  *
        !           762:  *     Preemption has been disabled by lock
        !           763:  *     acquisition, so it's safe to use the cpu number
        !           764:  *     specified by the caller.
        !           765:  */
        !           766: void
        !           767: usl_stack_push(
        !           768:        usimple_lock_t  l,
        !           769:        int             mycpu)
        !           770: {
        !           771:        boolean_t       s;
        !           772: 
        !           773:        if (uslock_stack_enabled == FALSE)
        !           774:                return;
        !           775: 
        !           776:        DISABLE_INTERRUPTS(s);
        !           777:        assert(uslock_stack_index[mycpu] >= 0);
        !           778:        assert(uslock_stack_index[mycpu] < USLOCK_STACK_DEPTH);
        !           779:        if (uslock_stack_index[mycpu] >= USLOCK_STACK_DEPTH) {
        !           780:                printf("usl_stack_push (cpu 0x%x):  too many locks (%d)",
        !           781:                       mycpu, uslock_stack_index[mycpu]);
        !           782:                printf(" disabling stacks\n");
        !           783:                uslock_stack_enabled = FALSE;
        !           784:                ENABLE_INTERRUPTS(s);
        !           785:                return;
        !           786:        }
        !           787:        uslock_stack[mycpu][uslock_stack_index[mycpu]] = l;
        !           788:        uslock_stack_index[mycpu]++;
        !           789:        ENABLE_INTERRUPTS(s);
        !           790: }
        !           791: 
        !           792: 
        !           793: /*
        !           794:  *     Eliminate the entry for a usimple_lock
        !           795:  *     that had been active on the current processor.
        !           796:  *
        !           797:  *     Preemption has been disabled by lock
        !           798:  *     acquisition, and we haven't yet actually
        !           799:  *     released the hardware lock associated with
        !           800:  *     this usimple_lock, so it's safe to use the
        !           801:  *     cpu number supplied by the caller.
        !           802:  */
        !           803: void
        !           804: usl_stack_pop(
        !           805:        usimple_lock_t  l,
        !           806:        int             mycpu)
        !           807: {
        !           808:        unsigned int    i, index;
        !           809:        boolean_t       s;
        !           810: 
        !           811:        if (uslock_stack_enabled == FALSE)
        !           812:                return;
        !           813: 
        !           814:        DISABLE_INTERRUPTS(s);
        !           815:        assert(uslock_stack_index[mycpu] > 0);
        !           816:        assert(uslock_stack_index[mycpu] <= USLOCK_STACK_DEPTH);
        !           817:        if (uslock_stack_index[mycpu] == 0) {
        !           818:                printf("usl_stack_pop (cpu 0x%x):  not enough locks (%d)",
        !           819:                       mycpu, uslock_stack_index[mycpu]);
        !           820:                printf(" disabling stacks\n");
        !           821:                uslock_stack_enabled = FALSE;
        !           822:                ENABLE_INTERRUPTS(s);
        !           823:                return;
        !           824:        }
        !           825:        index = --uslock_stack_index[mycpu];
        !           826:        for (i = 0; i <= index; ++i) {
        !           827:                if (uslock_stack[mycpu][i] == l) {
        !           828:                        if (i != index)
        !           829:                                uslock_stack[mycpu][i] =
        !           830:                                        uslock_stack[mycpu][index];
        !           831:                        ENABLE_INTERRUPTS(s);
        !           832:                        return;
        !           833:                }
        !           834:        }
        !           835:        ENABLE_INTERRUPTS(s);
        !           836:        panic("usl_stack_pop:  can't find usimple_lock 0x%x", l);
        !           837: }
        !           838: 
        !           839: 
        !           840: /*
        !           841:  *     Determine whether any usimple_locks are currently held.
        !           842:  *
        !           843:  *     Caller's preemption state is uncertain.  If
        !           844:  *     preemption has been disabled, this check is accurate.
        !           845:  *     Otherwise, this check is just a guess.  We do the best
        !           846:  *     we can by disabling scheduler interrupts, so at least
        !           847:  *     the check is accurate w.r.t. whatever cpu we're running
        !           848:  *     on while in this routine.
        !           849:  */
        !           850: void
        !           851: usld_lock_none_held()
        !           852: {
        !           853:        register int    mycpu;
        !           854:        boolean_t       s;
        !           855:        unsigned int    locks_held;
        !           856:        char            *caller = "usimple_lock_none_held";
        !           857: 
        !           858:        DISABLE_INTERRUPTS(s);
        !           859:        mp_disable_preemption();
        !           860:        mycpu = cpu_number();
        !           861:        locks_held = uslock_stack_index[mycpu];
        !           862:        mp_enable_preemption();
        !           863:        ENABLE_INTERRUPTS(s);
        !           864:        if (locks_held > 0)
        !           865:                panic("%s:  no locks should be held (0x%x locks held)",
        !           866:                      caller, (integer_t) locks_held);
        !           867: }
        !           868: 
        !           869: 
        !           870: /*
        !           871:  *     For very special cases, set traced_lock to point to a
        !           872:  *     specific lock of interest.  The result is a series of
        !           873:  *     XPRs showing lock operations on that lock.  The lock_seq
        !           874:  *     value is used to show the order of those operations.
        !           875:  */
        !           876: usimple_lock_t         traced_lock;
        !           877: unsigned int           lock_seq;
        !           878: 
        !           879: void
        !           880: usl_trace(
        !           881:        usimple_lock_t  l,
        !           882:        int             mycpu,
        !           883:        pc_t            pc,
        !           884:        const char *    op_name)
        !           885: {
        !           886:        if (traced_lock == l) {
        !           887:                XPR(XPR_SLOCK,
        !           888:                    "seq %d, cpu %d, %s @ %x\n",
        !           889:                    (integer_t) lock_seq, (integer_t) mycpu,
        !           890:                    (integer_t) op_name, (integer_t) pc, 0);
        !           891:                lock_seq++;
        !           892:        }
        !           893: }
        !           894: 
        !           895: 
        !           896: 
        !           897: #if    MACH_KDB
        !           898: #define        printf  kdbprintf
        !           899: void   db_show_all_slocks(void);
        !           900: void
        !           901: db_show_all_slocks(void)
        !           902: {
        !           903:        unsigned int    i, index;
        !           904:        int             mycpu = cpu_number();
        !           905:        usimple_lock_t  l;
        !           906: 
        !           907:        if (uslock_stack_enabled == FALSE)
        !           908:                return;
        !           909: 
        !           910: #if    0
        !           911:        if (!mach_slocks_init)
        !           912:                iprintf("WARNING: simple locks stack may not be accurate\n");
        !           913: #endif
        !           914:        assert(uslock_stack_index[mycpu] >= 0);
        !           915:        assert(uslock_stack_index[mycpu] <= USLOCK_STACK_DEPTH);
        !           916:        index = uslock_stack_index[mycpu];
        !           917:        for (i = 0; i < index; ++i) {
        !           918:                l = uslock_stack[mycpu][i];
        !           919:                iprintf("%d: ", i);
        !           920:                db_printsym((vm_offset_t)l, DB_STGY_ANY);
        !           921:                if (l->debug.lock_pc != INVALID_PC) {
        !           922:                        printf(" locked by ");
        !           923:                        db_printsym((int)l->debug.lock_pc, DB_STGY_PROC);
        !           924:                }
        !           925:                printf("\n");
        !           926:        }
        !           927: }
        !           928: #endif /* MACH_KDB */
        !           929: 
        !           930: #endif /* USLOCK_DEBUG */
        !           931: 
        !           932: /* #endif      USIMPLE_LOCK_CALLS */
        !           933: 
        !           934: /*
        !           935:  *     Routine:        lock_alloc
        !           936:  *     Function:
        !           937:  *             Allocate a lock for external users who cannot
        !           938:  *             hard-code the structure definition into their
        !           939:  *             objects.
        !           940:  *             For now just use kalloc, but a zone is probably
        !           941:  *             warranted.
        !           942:  */
        !           943: lock_t *
        !           944: lock_alloc(
        !           945:        boolean_t       can_sleep,
        !           946:        etap_event_t    event,
        !           947:        etap_event_t    i_event)
        !           948: {
        !           949:        lock_t          *l;
        !           950: 
        !           951:        if ((l = (lock_t *)kalloc(sizeof(lock_t))) != 0)
        !           952:          lock_init(l, can_sleep, event, i_event);
        !           953:        return(l);
        !           954: }
        !           955: 
        !           956: /*
        !           957:  *     Routine:        lock_free
        !           958:  *     Function:
        !           959:  *             Free a lock allocated for external users.
        !           960:  *             For now just use kfree, but a zone is probably
        !           961:  *             warranted.
        !           962:  */
        !           963: void
        !           964: lock_free(
        !           965:        lock_t          *l)
        !           966: {
        !           967:        kfree((vm_offset_t)l, sizeof(lock_t));
        !           968: }
        !           969: 
        !           970:          
        !           971: /*
        !           972:  *     Routine:        lock_init
        !           973:  *     Function:
        !           974:  *             Initialize a lock; required before use.
        !           975:  *             Note that clients declare the "struct lock"
        !           976:  *             variables and then initialize them, rather
        !           977:  *             than getting a new one from this module.
        !           978:  */
        !           979: void
        !           980: lock_init(
        !           981:        lock_t          *l,
        !           982:        boolean_t       can_sleep,
        !           983:        etap_event_t    event,
        !           984:        etap_event_t    i_event)
        !           985: {
        !           986:        (void) memset((void *) l, 0, sizeof(lock_t));
        !           987: 
        !           988: #if     ETAP_LOCK_TRACE
        !           989:        etap_event_table_assign(&l->u.event_table_chain, event);
        !           990:        l->u.s.start_list = SD_ENTRY_NULL;
        !           991: #endif  /* ETAP_LOCK_TRACE */
        !           992: 
        !           993:        simple_lock_init(&l->interlock, i_event);
        !           994:        l->want_write = FALSE;
        !           995:        l->want_upgrade = FALSE;
        !           996:        l->read_count = 0;
        !           997:        l->can_sleep = can_sleep;
        !           998: 
        !           999: #if     ETAP_LOCK_ACCUMULATE
        !          1000:        l->cbuff_write = etap_cbuff_reserve(lock_event_table(l));
        !          1001:        if (l->cbuff_write != CBUFF_ENTRY_NULL) {
        !          1002:                l->cbuff_write->event    = event;
        !          1003:                l->cbuff_write->instance = (unsigned long) l;
        !          1004:                l->cbuff_write->kind     = WRITE_LOCK;
        !          1005:        }
        !          1006:        l->cbuff_read = CBUFF_ENTRY_NULL;
        !          1007: #endif  /* ETAP_LOCK_ACCUMULATE */
        !          1008: }
        !          1009: 
        !          1010: 
        !          1011: /*
        !          1012:  *     Sleep locks.  These use the same data structure and algorithm
        !          1013:  *     as the spin locks, but the process sleeps while it is waiting
        !          1014:  *     for the lock.  These work on uniprocessor systems.
        !          1015:  */
        !          1016: 
        !          1017: #define DECREMENTER_TIMEOUT 1000000
        !          1018: 
        !          1019: void
        !          1020: lock_write(
        !          1021:        register lock_t * l)
        !          1022: {
        !          1023:         register int      i;
        !          1024:        start_data_node_t  entry     = {0};
        !          1025:        boolean_t          lock_miss = FALSE;
        !          1026:        unsigned short     dynamic   = 0;
        !          1027:        unsigned short     trace     = 0;
        !          1028:        etap_time_t        total_time;
        !          1029:        etap_time_t        stop_wait_time;
        !          1030:        pc_t               pc;
        !          1031: #if    MACH_LDEBUG
        !          1032:        int                decrementer;
        !          1033: #endif /* MACH_LDEBUG */
        !          1034: 
        !          1035: 
        !          1036:        ETAP_STAMP(lock_event_table(l), trace, dynamic);
        !          1037:        ETAP_CREATE_ENTRY(entry, trace);
        !          1038:        MON_ASSIGN_PC(entry->start_pc, pc, trace);
        !          1039: 
        !          1040:        simple_lock(&l->interlock);
        !          1041: 
        !          1042:        /*
        !          1043:          *  Link the new start_list entry
        !          1044:          */
        !          1045:        ETAP_LINK_ENTRY(l, entry, trace);
        !          1046: 
        !          1047: #if    MACH_LDEBUG
        !          1048:        decrementer = DECREMENTER_TIMEOUT;
        !          1049: #endif /* MACH_LDEBUG */
        !          1050: 
        !          1051:        /*
        !          1052:         *      Try to acquire the want_write bit.
        !          1053:         */
        !          1054:        while (l->want_write) {
        !          1055:                if (!lock_miss) {
        !          1056:                        ETAP_CONTENTION_TIMESTAMP(entry, trace);
        !          1057:                        lock_miss = TRUE;
        !          1058:                }
        !          1059: 
        !          1060:                i = lock_wait_time[l->can_sleep ? 1 : 0];
        !          1061:                if (i != 0) {
        !          1062:                        simple_unlock(&l->interlock);
        !          1063: #if    MACH_LDEBUG
        !          1064:                        if (!--decrementer)
        !          1065:                                Debugger("timeout - want_write");
        !          1066: #endif /* MACH_LDEBUG */
        !          1067:                        while (--i != 0 && l->want_write)
        !          1068:                                continue;
        !          1069:                        simple_lock(&l->interlock);
        !          1070:                }
        !          1071: 
        !          1072:                if (l->can_sleep && l->want_write) {
        !          1073:                        l->waiting = TRUE;
        !          1074:                        ETAP_SET_REASON(current_thread(),
        !          1075:                                        BLOCKED_ON_COMPLEX_LOCK);
        !          1076:                        thread_sleep_simple_lock((event_t) l,
        !          1077:                                        simple_lock_addr(l->interlock), FALSE);
        !          1078:                        simple_lock(&l->interlock);
        !          1079:                }
        !          1080:        }
        !          1081:        l->want_write = TRUE;
        !          1082: 
        !          1083:        /* Wait for readers (and upgrades) to finish */
        !          1084: 
        !          1085: #if    MACH_LDEBUG
        !          1086:        decrementer = DECREMENTER_TIMEOUT;
        !          1087: #endif /* MACH_LDEBUG */
        !          1088:        while ((l->read_count != 0) || l->want_upgrade) {
        !          1089:                if (!lock_miss) {
        !          1090:                        ETAP_CONTENTION_TIMESTAMP(entry,trace);
        !          1091:                        lock_miss = TRUE;
        !          1092:                }
        !          1093: 
        !          1094:                i = lock_wait_time[l->can_sleep ? 1 : 0];
        !          1095:                if (i != 0) {
        !          1096:                        simple_unlock(&l->interlock);
        !          1097: #if    MACH_LDEBUG
        !          1098:                        if (!--decrementer)
        !          1099:                                Debugger("timeout - wait for readers");
        !          1100: #endif /* MACH_LDEBUG */
        !          1101:                        while (--i != 0 && (l->read_count != 0 ||
        !          1102:                                            l->want_upgrade))
        !          1103:                                continue;
        !          1104:                        simple_lock(&l->interlock);
        !          1105:                }
        !          1106: 
        !          1107:                if (l->can_sleep && (l->read_count != 0 || l->want_upgrade)) {
        !          1108:                        l->waiting = TRUE;
        !          1109:                         ETAP_SET_REASON(current_thread(),
        !          1110:                                         BLOCKED_ON_COMPLEX_LOCK);
        !          1111:                        thread_sleep_simple_lock((event_t) l,
        !          1112:                                simple_lock_addr(l->interlock), FALSE);
        !          1113:                        simple_lock(&l->interlock);
        !          1114:                }
        !          1115:        }
        !          1116: 
        !          1117:        /*
        !          1118:         *  do not collect wait data if either the lock
        !          1119:         *  was free or no wait traces are enabled.
        !          1120:         */
        !          1121: 
        !          1122:        if (lock_miss && ETAP_CONTENTION_ENABLED(trace)) {
        !          1123:                ETAP_TIMESTAMP(stop_wait_time);
        !          1124:                ETAP_TOTAL_TIME(total_time,
        !          1125:                                stop_wait_time,
        !          1126:                                entry->start_wait_time);
        !          1127:                CUM_WAIT_ACCUMULATE(l->cbuff_write, total_time, dynamic, trace);
        !          1128:                MON_DATA_COLLECT(l,
        !          1129:                                 entry,
        !          1130:                                 total_time,
        !          1131:                                 WRITE_LOCK,
        !          1132:                                 MON_CONTENTION,
        !          1133:                                 trace);
        !          1134:        }
        !          1135: 
        !          1136:        simple_unlock(&l->interlock);
        !          1137: 
        !          1138:        /*
        !          1139:         *  Set start hold time if some type of hold tracing is enabled.
        !          1140:         *
        !          1141:         *  Note: if the stop_wait_time was already stamped, use
        !          1142:         *      it as the start_hold_time instead of doing an
        !          1143:         *      expensive bus access.
        !          1144:         *
        !          1145:         */
        !          1146: 
        !          1147:        if (lock_miss && ETAP_CONTENTION_ENABLED(trace))
        !          1148:                ETAP_COPY_START_HOLD_TIME(entry, stop_wait_time, trace);
        !          1149:        else
        !          1150:                ETAP_DURATION_TIMESTAMP(entry, trace);
        !          1151: 
        !          1152: }
        !          1153: 
        !          1154: void
        !          1155: lock_done(
        !          1156:        register lock_t * l)
        !          1157: {
        !          1158:        boolean_t         do_wakeup = FALSE;
        !          1159:        start_data_node_t entry;
        !          1160:        unsigned short    dynamic   = 0;
        !          1161:        unsigned short    trace     = 0;
        !          1162:        etap_time_t       stop_hold_time;
        !          1163:        etap_time_t       total_time;
        !          1164:        unsigned long     lock_kind;
        !          1165:        pc_t              pc;
        !          1166: 
        !          1167: 
        !          1168:        ETAP_STAMP(lock_event_table(l), trace, dynamic);
        !          1169: 
        !          1170:        simple_lock(&l->interlock);
        !          1171: 
        !          1172:        if (l->read_count != 0) {
        !          1173:                l->read_count--;
        !          1174:                lock_kind = READ_LOCK;
        !          1175:        }
        !          1176:        else    
        !          1177:                if (l->want_upgrade) {
        !          1178:                        l->want_upgrade = FALSE;
        !          1179:                        lock_kind = WRITE_LOCK;
        !          1180:                }
        !          1181:        else {
        !          1182:                l->want_write = FALSE;
        !          1183:                lock_kind = WRITE_LOCK;
        !          1184:        }
        !          1185: 
        !          1186:        /*
        !          1187:         *      There is no reason to wakeup a waiting thread
        !          1188:         *      if the read-count is non-zero.  Consider:
        !          1189:         *              we must be dropping a read lock
        !          1190:         *              threads are waiting only if one wants a write lock
        !          1191:         *              if there are still readers, they can't proceed
        !          1192:         */
        !          1193: 
        !          1194:        if (l->waiting && (l->read_count == 0)) {
        !          1195:                l->waiting = FALSE;
        !          1196:                do_wakeup = TRUE;
        !          1197:        }
        !          1198:         /*
        !          1199:          *  Collect hold data if hold tracing is
        !          1200:          *  enabled.
        !          1201:          */
        !          1202: 
        !          1203:         /*
        !          1204:          *  NOTE: All complex locks whose tracing was on when the
        !          1205:          *  lock was acquired will have an entry in the start_data
        !          1206:          *  list.
        !          1207:          */
        !          1208: 
        !          1209:        ETAP_UNLINK_ENTRY(l,entry);
        !          1210:        if (ETAP_DURATION_ENABLED(trace) && entry != SD_ENTRY_NULL) {
        !          1211:                ETAP_TIMESTAMP (stop_hold_time);
        !          1212:                ETAP_TOTAL_TIME (total_time,
        !          1213:                                 stop_hold_time,
        !          1214:                                 entry->start_hold_time);
        !          1215: 
        !          1216:                if (lock_kind & WRITE_LOCK)
        !          1217:                        CUM_HOLD_ACCUMULATE (l->cbuff_write,
        !          1218:                                             total_time,
        !          1219:                                             dynamic,
        !          1220:                                             trace);
        !          1221:                else {
        !          1222:                        CUM_READ_ENTRY_RESERVE(l,l->cbuff_read,trace);
        !          1223:                        CUM_HOLD_ACCUMULATE (l->cbuff_read,
        !          1224:                                             total_time,
        !          1225:                                             dynamic,
        !          1226:                                             trace);
        !          1227:                }
        !          1228:                MON_ASSIGN_PC(entry->end_pc,pc,trace);
        !          1229:                MON_DATA_COLLECT(l,entry,
        !          1230:                                 total_time,
        !          1231:                                 lock_kind,
        !          1232:                                 MON_DURATION,
        !          1233:                                 trace);
        !          1234:        }
        !          1235: 
        !          1236:        simple_unlock(&l->interlock);
        !          1237: 
        !          1238:        ETAP_DESTROY_ENTRY(entry);
        !          1239: 
        !          1240:        if (do_wakeup)
        !          1241:                thread_wakeup((event_t) l);
        !          1242: }
        !          1243: 
        !          1244: void
        !          1245: lock_read(
        !          1246:        register lock_t * l)
        !          1247: {
        !          1248:        register int        i;
        !          1249:        start_data_node_t   entry     = {0};
        !          1250:        boolean_t           lock_miss = FALSE;
        !          1251:        unsigned short      dynamic   = 0;
        !          1252:        unsigned short      trace     = 0;
        !          1253:        etap_time_t         total_time;
        !          1254:        etap_time_t         stop_wait_time;
        !          1255:         pc_t               pc;
        !          1256: #if    MACH_LDEBUG
        !          1257:        int                decrementer;
        !          1258: #endif /* MACH_LDEBUG */
        !          1259: 
        !          1260:        ETAP_STAMP(lock_event_table(l), trace, dynamic);
        !          1261:        ETAP_CREATE_ENTRY(entry, trace);
        !          1262:        MON_ASSIGN_PC(entry->start_pc, pc, trace);
        !          1263: 
        !          1264:        simple_lock(&l->interlock);
        !          1265: 
        !          1266:        /*
        !          1267:         *  Link the new start_list entry
        !          1268:         */
        !          1269:        ETAP_LINK_ENTRY(l,entry,trace);
        !          1270: 
        !          1271: #if    MACH_LDEBUG
        !          1272:        decrementer = DECREMENTER_TIMEOUT;
        !          1273: #endif /* MACH_LDEBUG */
        !          1274:        while ((0 == l->read_count) && (l->want_write || l->want_upgrade)) {
        !          1275:                if (!lock_miss) {
        !          1276:                        ETAP_CONTENTION_TIMESTAMP(entry, trace);
        !          1277:                        lock_miss = TRUE;
        !          1278:                }
        !          1279: 
        !          1280:                i = lock_wait_time[l->can_sleep ? 1 : 0];
        !          1281: 
        !          1282:                if (i != 0) {
        !          1283:                        simple_unlock(&l->interlock);
        !          1284: #if    MACH_LDEBUG
        !          1285:                        if (!--decrementer)
        !          1286:                                Debugger("timeout - wait no writers");
        !          1287: #endif /* MACH_LDEBUG */
        !          1288:                        while (--i != 0 && 
        !          1289:                        ((0 == l->read_count) && (l->want_write || l->want_upgrade)))
        !          1290:                                continue;
        !          1291:                        simple_lock(&l->interlock);
        !          1292:                }
        !          1293: 
        !          1294:                if (l->can_sleep &&
        !          1295:                ((0 == l->read_count) && (l->want_write || l->want_upgrade))) {
        !          1296:                        l->waiting = TRUE;
        !          1297:                        thread_sleep_simple_lock((event_t) l,
        !          1298:                                        simple_lock_addr(l->interlock), FALSE);
        !          1299:                        simple_lock(&l->interlock);
        !          1300:                }
        !          1301:        }
        !          1302: 
        !          1303:        l->read_count++;
        !          1304: 
        !          1305:        /*
        !          1306:         *  Do not collect wait data if the lock was free
        !          1307:         *  or if no wait traces are enabled.
        !          1308:         */
        !          1309: 
        !          1310:        if (lock_miss && ETAP_CONTENTION_ENABLED(trace)) {
        !          1311:                ETAP_TIMESTAMP(stop_wait_time);
        !          1312:                ETAP_TOTAL_TIME(total_time,
        !          1313:                                stop_wait_time,
        !          1314:                                entry->start_wait_time);
        !          1315:                CUM_READ_ENTRY_RESERVE(l, l->cbuff_read, trace);
        !          1316:                CUM_WAIT_ACCUMULATE(l->cbuff_read, total_time, dynamic, trace);
        !          1317:                MON_DATA_COLLECT(l,
        !          1318:                                 entry,
        !          1319:                                 total_time,
        !          1320:                                 READ_LOCK,
        !          1321:                                 MON_CONTENTION,
        !          1322:                                 trace);
        !          1323:        }
        !          1324:        simple_unlock(&l->interlock);
        !          1325: 
        !          1326:        /*
        !          1327:         *  Set start hold time if some type of hold tracing is enabled.
        !          1328:         *
        !          1329:         *  Note: if the stop_wait_time was already stamped, use
        !          1330:         *        it instead of doing an expensive bus access.
        !          1331:         *
        !          1332:         */
        !          1333: 
        !          1334:        if (lock_miss && ETAP_CONTENTION_ENABLED(trace))
        !          1335:                ETAP_COPY_START_HOLD_TIME(entry, stop_wait_time, trace);
        !          1336:        else
        !          1337:                ETAP_DURATION_TIMESTAMP(entry,trace);
        !          1338: }
        !          1339: 
        !          1340: 
        !          1341: /*
        !          1342:  *     Routine:        lock_read_to_write
        !          1343:  *     Function:
        !          1344:  *             Improves a read-only lock to one with
        !          1345:  *             write permission.  If another reader has
        !          1346:  *             already requested an upgrade to a write lock,
        !          1347:  *             no lock is held upon return.
        !          1348:  *
        !          1349:  *             Returns TRUE if the upgrade *failed*.
        !          1350:  */
        !          1351: 
        !          1352: boolean_t
        !          1353: lock_read_to_write(
        !          1354:        register lock_t * l)
        !          1355: {
        !          1356:        register int        i;
        !          1357:        boolean_t           do_wakeup = FALSE;
        !          1358:        start_data_node_t   entry     = {0};
        !          1359:        boolean_t           lock_miss = FALSE;
        !          1360:        unsigned short      dynamic   = 0;
        !          1361:        unsigned short      trace     = 0;
        !          1362:        etap_time_t         total_time;
        !          1363:        etap_time_t         stop_time;
        !          1364:        pc_t                pc;
        !          1365: #if    MACH_LDEBUG
        !          1366:        int                decrementer;
        !          1367: #endif /* MACH_LDEBUG */
        !          1368: 
        !          1369: 
        !          1370:        ETAP_STAMP(lock_event_table(l), trace, dynamic);
        !          1371: 
        !          1372:        simple_lock(&l->interlock);
        !          1373: 
        !          1374:        l->read_count--;        
        !          1375: 
        !          1376:        /*
        !          1377:         *  Since the read lock is lost whether the write lock
        !          1378:         *  is acquired or not, read hold data is collected here.
        !          1379:         *  This, of course, is assuming some type of hold
        !          1380:         *  tracing is enabled.
        !          1381:         *
        !          1382:         *  Note: trace is set to zero if the entry does not exist.
        !          1383:         */
        !          1384: 
        !          1385:        ETAP_FIND_ENTRY(l, entry, trace);
        !          1386: 
        !          1387:        if (ETAP_DURATION_ENABLED(trace)) {
        !          1388:                ETAP_TIMESTAMP(stop_time);
        !          1389:                ETAP_TOTAL_TIME(total_time, stop_time, entry->start_hold_time);
        !          1390:                CUM_HOLD_ACCUMULATE(l->cbuff_read, total_time, dynamic, trace);
        !          1391:                MON_ASSIGN_PC(entry->end_pc, pc, trace);
        !          1392:                MON_DATA_COLLECT(l,
        !          1393:                                 entry,
        !          1394:                                 total_time,
        !          1395:                                 READ_LOCK,
        !          1396:                                 MON_DURATION,
        !          1397:                                 trace);
        !          1398:        }
        !          1399: 
        !          1400:        if (l->want_upgrade) {
        !          1401:                /*
        !          1402:                 *      Someone else has requested upgrade.
        !          1403:                 *      Since we've released a read lock, wake
        !          1404:                 *      him up.
        !          1405:                 */
        !          1406:                if (l->waiting && (l->read_count == 0)) {
        !          1407:                        l->waiting = FALSE;
        !          1408:                        do_wakeup = TRUE;
        !          1409:                }
        !          1410: 
        !          1411:                ETAP_UNLINK_ENTRY(l, entry);
        !          1412:                simple_unlock(&l->interlock);
        !          1413:                ETAP_DESTROY_ENTRY(entry);
        !          1414: 
        !          1415:                if (do_wakeup)
        !          1416:                        thread_wakeup((event_t) l);
        !          1417:                return (TRUE);
        !          1418:        }
        !          1419: 
        !          1420:        l->want_upgrade = TRUE;
        !          1421: 
        !          1422:        MON_ASSIGN_PC(entry->start_pc, pc, trace);
        !          1423: 
        !          1424: #if    MACH_LDEBUG
        !          1425:        decrementer = DECREMENTER_TIMEOUT;
        !          1426: #endif /* MACH_LDEBUG */
        !          1427:        while (l->read_count != 0) {
        !          1428:                if (!lock_miss) {
        !          1429:                        ETAP_CONTENTION_TIMESTAMP(entry, trace);
        !          1430:                        lock_miss = TRUE;
        !          1431:                }
        !          1432: 
        !          1433:                i = lock_wait_time[l->can_sleep ? 1 : 0];
        !          1434: 
        !          1435:                if (i != 0) {
        !          1436:                        simple_unlock(&l->interlock);
        !          1437: #if    MACH_LDEBUG
        !          1438:                        if (!--decrementer)
        !          1439:                                Debugger("timeout - read_count");
        !          1440: #endif /* MACH_LDEBUG */
        !          1441:                        while (--i != 0 && l->read_count != 0)
        !          1442:                                continue;
        !          1443:                        simple_lock(&l->interlock);
        !          1444:                }
        !          1445: 
        !          1446:                if (l->can_sleep && l->read_count != 0) {
        !          1447:                        l->waiting = TRUE;
        !          1448:                        thread_sleep_simple_lock((event_t) l,
        !          1449:                                        simple_lock_addr(l->interlock), FALSE);
        !          1450:                        simple_lock(&l->interlock);
        !          1451:                }
        !          1452:        }
        !          1453: 
        !          1454:        /*
        !          1455:         *  do not collect wait data if the lock was free
        !          1456:         *  or if no wait traces are enabled.
        !          1457:         */
        !          1458: 
        !          1459:        if (lock_miss && ETAP_CONTENTION_ENABLED(trace)) {
        !          1460:                ETAP_TIMESTAMP (stop_time);
        !          1461:                ETAP_TOTAL_TIME(total_time, stop_time, entry->start_wait_time);
        !          1462:                CUM_WAIT_ACCUMULATE(l->cbuff_write, total_time, dynamic, trace);
        !          1463:                MON_DATA_COLLECT(l,
        !          1464:                                 entry,
        !          1465:                                 total_time,
        !          1466:                                 WRITE_LOCK,
        !          1467:                                 MON_CONTENTION,
        !          1468:                                 trace);
        !          1469:        }
        !          1470: 
        !          1471:        simple_unlock(&l->interlock);
        !          1472: 
        !          1473:        /*
        !          1474:         *  Set start hold time if some type of hold tracing is enabled
        !          1475:         *
        !          1476:         *  Note: if the stop_time was already stamped, use
        !          1477:         *        it as the new start_hold_time instead of doing
        !          1478:         *        an expensive VME access.
        !          1479:         *
        !          1480:         */
        !          1481: 
        !          1482:        if (lock_miss && ETAP_CONTENTION_ENABLED(trace))
        !          1483:                ETAP_COPY_START_HOLD_TIME(entry, stop_time, trace);
        !          1484:        else
        !          1485:                ETAP_DURATION_TIMESTAMP(entry, trace);
        !          1486: 
        !          1487:        return (FALSE);
        !          1488: }
        !          1489: 
        !          1490: void
        !          1491: lock_write_to_read(
        !          1492:        register lock_t * l)
        !          1493: {
        !          1494:        boolean_t          do_wakeup = FALSE;
        !          1495:        start_data_node_t  entry   = {0};
        !          1496:        unsigned short     dynamic = 0;
        !          1497:        unsigned short     trace   = 0;
        !          1498:        etap_time_t        stop_hold_time;
        !          1499:        etap_time_t        total_time;
        !          1500:        pc_t               pc;
        !          1501: 
        !          1502:         ETAP_STAMP(lock_event_table(l), trace,dynamic);
        !          1503: 
        !          1504:        simple_lock(&l->interlock);
        !          1505: 
        !          1506:        l->read_count++;
        !          1507:        if (l->want_upgrade)
        !          1508:                l->want_upgrade = FALSE;
        !          1509:        else
        !          1510:                l->want_write = FALSE;
        !          1511: 
        !          1512:        if (l->waiting) {
        !          1513:                l->waiting = FALSE;
        !          1514:                do_wakeup = TRUE;
        !          1515:        }
        !          1516: 
        !          1517:         /*
        !          1518:          *  Since we are switching from a write lock to a read lock,
        !          1519:          *  the write lock data is stored and the read lock data
        !          1520:          *  collection begins.
        !          1521:          *
        !          1522:          *  Note: trace is set to zero if the entry does not exist.
        !          1523:          */
        !          1524: 
        !          1525:         ETAP_FIND_ENTRY(l, entry, trace);
        !          1526: 
        !          1527:         if (ETAP_DURATION_ENABLED(trace)) {
        !          1528:             ETAP_TIMESTAMP (stop_hold_time);
        !          1529:             ETAP_TOTAL_TIME(total_time, stop_hold_time, entry->start_hold_time);
        !          1530:             CUM_HOLD_ACCUMULATE(l->cbuff_write, total_time, dynamic, trace);
        !          1531:             MON_ASSIGN_PC(entry->end_pc, pc, trace);
        !          1532:             MON_DATA_COLLECT(l,
        !          1533:                             entry,
        !          1534:                             total_time,
        !          1535:                             WRITE_LOCK,
        !          1536:                             MON_DURATION,
        !          1537:                             trace);
        !          1538:         }
        !          1539: 
        !          1540:        simple_unlock(&l->interlock);
        !          1541: 
        !          1542:         /*
        !          1543:          *  Set start hold time if some type of hold tracing is enabled
        !          1544:          *
        !          1545:          *  Note: if the stop_hold_time was already stamped, use
        !          1546:          *        it as the new start_hold_time instead of doing
        !          1547:          *        an expensive bus access.
        !          1548:          *
        !          1549:          */
        !          1550: 
        !          1551:         if (ETAP_DURATION_ENABLED(trace))
        !          1552:                ETAP_COPY_START_HOLD_TIME(entry, stop_hold_time, trace);
        !          1553:         else
        !          1554:                ETAP_DURATION_TIMESTAMP(entry, trace);
        !          1555: 
        !          1556:         MON_ASSIGN_PC(entry->start_pc, pc, trace);
        !          1557: 
        !          1558:        if (do_wakeup)
        !          1559:                thread_wakeup((event_t) l);
        !          1560: }
        !          1561: 
        !          1562: 
        !          1563: #if    0       /* Unused */
        !          1564: /*
        !          1565:  *     Routine:        lock_try_write
        !          1566:  *     Function:
        !          1567:  *             Tries to get a write lock.
        !          1568:  *
        !          1569:  *             Returns FALSE if the lock is not held on return.
        !          1570:  */
        !          1571: 
        !          1572: boolean_t
        !          1573: lock_try_write(
        !          1574:        register lock_t * l)
        !          1575: {
        !          1576:        start_data_node_t  entry = {0};
        !          1577:        unsigned short     trace = 0;
        !          1578:        pc_t               pc;
        !          1579: 
        !          1580:         ETAP_STAMP(lock_event_table(l), trace, trace);
        !          1581:         ETAP_CREATE_ENTRY(entry, trace);
        !          1582: 
        !          1583:        simple_lock(&l->interlock);
        !          1584: 
        !          1585:        if (l->want_write || l->want_upgrade || l->read_count) {
        !          1586:                /*
        !          1587:                 *      Can't get lock.
        !          1588:                 */
        !          1589:                simple_unlock(&l->interlock);
        !          1590:                ETAP_DESTROY_ENTRY(entry);
        !          1591:                return(FALSE);
        !          1592:        }
        !          1593: 
        !          1594:        /*
        !          1595:         *      Have lock.
        !          1596:         */
        !          1597: 
        !          1598:        l->want_write = TRUE;
        !          1599: 
        !          1600:         ETAP_LINK_ENTRY(l, entry, trace);
        !          1601: 
        !          1602:        simple_unlock(&l->interlock);
        !          1603: 
        !          1604:         MON_ASSIGN_PC(entry->start_pc, pc, trace);
        !          1605:         ETAP_DURATION_TIMESTAMP(entry, trace);
        !          1606: 
        !          1607:        return(TRUE);
        !          1608: }
        !          1609: 
        !          1610: /*
        !          1611:  *     Routine:        lock_try_read
        !          1612:  *     Function:
        !          1613:  *             Tries to get a read lock.
        !          1614:  *
        !          1615:  *             Returns FALSE if the lock is not held on return.
        !          1616:  */
        !          1617: 
        !          1618: boolean_t
        !          1619: lock_try_read(
        !          1620:        register lock_t * l)
        !          1621: {
        !          1622:        start_data_node_t  entry = {0};
        !          1623:        unsigned short     trace = 0;
        !          1624:        pc_t               pc;
        !          1625: 
        !          1626:         ETAP_STAMP(lock_event_table(l), trace, trace);
        !          1627:         ETAP_CREATE_ENTRY(entry, trace);
        !          1628: 
        !          1629:        simple_lock(&l->interlock);
        !          1630: 
        !          1631:        if (l->want_write || l->want_upgrade) {
        !          1632:                simple_unlock(&l->interlock);
        !          1633:                 ETAP_DESTROY_ENTRY(entry);
        !          1634:                return(FALSE);
        !          1635:        }
        !          1636: 
        !          1637:        l->read_count++;
        !          1638: 
        !          1639:         ETAP_LINK_ENTRY(l, entry, trace);
        !          1640: 
        !          1641:        simple_unlock(&l->interlock);
        !          1642: 
        !          1643:         MON_ASSIGN_PC(entry->start_pc, pc, trace);
        !          1644:         ETAP_DURATION_TIMESTAMP(entry, trace);
        !          1645: 
        !          1646:        return(TRUE);
        !          1647: }
        !          1648: #endif         /* Unused */
        !          1649: 
        !          1650: #if    MACH_KDB
        !          1651: 
        !          1652: void   db_show_one_lock(lock_t  *);
        !          1653: 
        !          1654: 
        !          1655: void
        !          1656: db_show_one_lock(
        !          1657:        lock_t  *lock)
        !          1658: {
        !          1659:        db_printf("Read_count = 0x%x, %swant_upgrade, %swant_write, ",
        !          1660:                  lock->read_count,
        !          1661:                  lock->want_upgrade ? "" : "!",
        !          1662:                  lock->want_write ? "" : "!");
        !          1663:        db_printf("%swaiting, %scan_sleep\n", 
        !          1664:                  lock->waiting ? "" : "!", lock->can_sleep ? "" : "!");
        !          1665:        db_printf("Interlock:\n");
        !          1666:        db_show_one_simple_lock((db_expr_t)simple_lock_addr(lock->interlock),
        !          1667:                        TRUE, (db_expr_t)0, (char *)0);
        !          1668: }
        !          1669: #endif /* MACH_KDB */
        !          1670: 
        !          1671: /*
        !          1672:  * The C portion of the mutex package.  These routines are only invoked
        !          1673:  * if the optimized assembler routines can't do the work.
        !          1674:  */
        !          1675: 
        !          1676: /*
        !          1677:  *     Routine:        lock_alloc
        !          1678:  *     Function:
        !          1679:  *             Allocate a mutex for external users who cannot
        !          1680:  *             hard-code the structure definition into their
        !          1681:  *             objects.
        !          1682:  *             For now just use kalloc, but a zone is probably
        !          1683:  *             warranted.
        !          1684:  */
        !          1685: mutex_t *
        !          1686: mutex_alloc(
        !          1687:        etap_event_t    event)
        !          1688: {
        !          1689:        mutex_t         *m;
        !          1690: 
        !          1691:        if ((m = (mutex_t *)kalloc(sizeof(mutex_t))) != 0)
        !          1692:          mutex_init(m, event);
        !          1693:        return(m);
        !          1694: }
        !          1695: 
        !          1696: /*
        !          1697:  *     Routine:        mutex_free
        !          1698:  *     Function:
        !          1699:  *             Free a mutex allocated for external users.
        !          1700:  *             For now just use kfree, but a zone is probably
        !          1701:  *             warranted.
        !          1702:  */
        !          1703: void
        !          1704: mutex_free(
        !          1705:        mutex_t         *m)
        !          1706: {
        !          1707:        kfree((vm_offset_t)m, sizeof(mutex_t));
        !          1708: }
        !          1709: 
        !          1710: 
        !          1711: /*
        !          1712:  * mutex_lock_wait: Invoked if the assembler routine mutex_lock () fails
        !          1713:  * because the mutex is already held by another thread.  Called with the
        !          1714:  * interlock locked and returns with the interlock unlocked.
        !          1715:  */
        !          1716: 
        !          1717: void
        !          1718: mutex_lock_wait (
        !          1719:        mutex_t         * m)
        !          1720: {
        !          1721:        m->waiters++;
        !          1722:        ETAP_SET_REASON(current_thread(), BLOCKED_ON_MUTEX_LOCK);
        !          1723:        thread_sleep_interlock ((event_t) m, &m->interlock, THREAD_UNINT);
        !          1724: }
        !          1725: 
        !          1726: /*
        !          1727:  * mutex_unlock_wakeup: Invoked if the assembler routine mutex_unlock ()
        !          1728:  * fails because there are thread(s) waiting for this mutex.  Called and
        !          1729:  * returns with the interlock locked.
        !          1730:  */
        !          1731: 
        !          1732: void
        !          1733: mutex_unlock_wakeup (
        !          1734:        mutex_t         * m)
        !          1735: {
        !          1736:        assert(m->waiters);
        !          1737:        m->waiters--;
        !          1738:        thread_wakeup_one ((event_t) m);
        !          1739: }
        !          1740: 
        !          1741: /*
        !          1742:  * mutex_pause: Called by former callers of simple_lock_pause().
        !          1743:  */
        !          1744: 
        !          1745: void
        !          1746: mutex_pause(void)
        !          1747: {
        !          1748:        assert_wait_timeout( 1, THREAD_INTERRUPTIBLE);
        !          1749:        ETAP_SET_REASON(current_thread(), BLOCKED_ON_MUTEX_LOCK);
        !          1750:        thread_block(0);
        !          1751:        thread_cancel_timer();
        !          1752: }
        !          1753: 
        !          1754: #if    MACH_KDB
        !          1755: /*
        !          1756:  * Routines to print out simple_locks and mutexes in a nicely-formatted
        !          1757:  * fashion.
        !          1758:  */
        !          1759: 
        !          1760: char *simple_lock_labels =     "ENTRY    ILK THREAD   DURATION CALLER";
        !          1761: char *mutex_labels =           "ENTRY    LOCKED WAITERS   THREAD CALLER";
        !          1762: 
        !          1763: void
        !          1764: db_show_one_simple_lock (
        !          1765:        db_expr_t       addr,
        !          1766:        boolean_t       have_addr,
        !          1767:        db_expr_t       count,
        !          1768:        char            * modif)
        !          1769: {
        !          1770:        simple_lock_t   saddr = (simple_lock_t)addr;
        !          1771: 
        !          1772:        if (saddr == (simple_lock_t)0 || !have_addr) {
        !          1773:                db_error ("No simple_lock\n");
        !          1774:        }
        !          1775: #if    USLOCK_DEBUG
        !          1776:        else if (saddr->lock_type != USLOCK_TAG)
        !          1777:                db_error ("Not a simple_lock\n");
        !          1778: #endif /* USLOCK_DEBUG */
        !          1779: 
        !          1780:        db_printf ("%s\n", simple_lock_labels);
        !          1781:        db_print_simple_lock (saddr);
        !          1782: }
        !          1783: 
        !          1784: void
        !          1785: db_print_simple_lock (
        !          1786:        simple_lock_t   addr)
        !          1787: {
        !          1788: 
        !          1789:        db_printf ("%08x %3d", addr, *hw_lock_addr(addr->interlock));
        !          1790: #if    USLOCK_DEBUG
        !          1791:        db_printf (" %08x", addr->debug.lock_thread);
        !          1792:        db_printf (" %08x ", addr->debug.duration[1]);
        !          1793:        db_printsym ((int)addr->debug.lock_pc, DB_STGY_ANY);
        !          1794: #endif /* USLOCK_DEBUG */
        !          1795:        db_printf ("\n");
        !          1796: }
        !          1797: 
        !          1798: void
        !          1799: db_show_one_mutex (
        !          1800:        db_expr_t       addr,
        !          1801:        boolean_t       have_addr,
        !          1802:        db_expr_t       count,
        !          1803:        char            * modif)
        !          1804: {
        !          1805:        mutex_t         * maddr = (mutex_t *)addr;
        !          1806: 
        !          1807:        if (maddr == (mutex_t *)0 || !have_addr)
        !          1808:                db_error ("No mutex\n");
        !          1809: #if    MACH_LDEBUG
        !          1810:        else if (maddr->type != MUTEX_TAG)
        !          1811:                db_error ("Not a mutex\n");
        !          1812: #endif /* MACH_LDEBUG */
        !          1813: 
        !          1814:        db_printf ("%s\n", mutex_labels);
        !          1815:        db_print_mutex (maddr);
        !          1816: }
        !          1817: 
        !          1818: void
        !          1819: db_print_mutex (
        !          1820:        mutex_t         * addr)
        !          1821: {
        !          1822:        db_printf ("%08x %6d %7d",
        !          1823:                   addr, *hw_lock_addr(addr->locked), addr->waiters);
        !          1824: #if    MACH_LDEBUG
        !          1825:        db_printf (" %08x ", addr->thread);
        !          1826:        db_printsym (addr->pc, DB_STGY_ANY);
        !          1827: #endif /* MACH_LDEBUG */
        !          1828:        db_printf ("\n");
        !          1829: }
        !          1830: #endif /* MACH_KDB */
        !          1831: 
        !          1832: #if    MACH_LDEBUG
        !          1833: extern void    meter_simple_lock (
        !          1834:                        simple_lock_t   l);
        !          1835: extern void    meter_simple_unlock (
        !          1836:                        simple_lock_t   l);
        !          1837: extern void    cyctm05_stamp (
        !          1838:                        unsigned long   * start);
        !          1839: extern void    cyctm05_diff (
        !          1840:                        unsigned long   * start,
        !          1841:                        unsigned long   * end,
        !          1842:                        unsigned long   * diff);
        !          1843: 
        !          1844: #if 0
        !          1845: simple_lock_data_t     loser;
        !          1846: #endif
        !          1847: 
        !          1848: void
        !          1849: meter_simple_lock(
        !          1850:                simple_lock_t   lp)
        !          1851: {
        !          1852: #if 0
        !          1853:        cyctm05_stamp (lp->duration);
        !          1854: #endif
        !          1855: }
        !          1856: 
        !          1857: int                    long_simple_lock_crash;
        !          1858: int                    long_simple_lock_time = 0x600;
        !          1859: /*
        !          1860:  *     This is pretty gawd-awful.  XXX
        !          1861:  */
        !          1862: decl_simple_lock_data(extern,kd_tty)
        !          1863: 
        !          1864: void
        !          1865: meter_simple_unlock(
        !          1866:                simple_lock_t   lp)
        !          1867: {
        !          1868: #if 0
        !          1869:        unsigned long   stime[2], etime[2], delta[2];
        !          1870: 
        !          1871:        if (lp == &kd_tty)                      /* XXX */
        !          1872:                return;                         /* XXX */
        !          1873: 
        !          1874:        stime[0] = lp->duration[0];
        !          1875:        stime[1] = lp->duration[1];
        !          1876: 
        !          1877:        cyctm05_stamp (etime);
        !          1878: 
        !          1879:        if (etime[1] < stime[1])                /* XXX */
        !          1880:                return;                         /* XXX */
        !          1881: 
        !          1882:        cyctm05_diff (stime, etime, delta);
        !          1883: 
        !          1884:        if (delta[1] >= 0x10000)                /* XXX */
        !          1885:                return;                         /* XXX */
        !          1886: 
        !          1887:        lp->duration[0] = delta[0];
        !          1888:        lp->duration[1] = delta[1];
        !          1889: 
        !          1890:        if (loser.duration[1] < lp->duration[1])
        !          1891:                loser = *lp;
        !          1892: 
        !          1893:        assert (!long_simple_lock_crash || delta[1] < long_simple_lock_time);
        !          1894: #endif
        !          1895: }
        !          1896: #endif /* MACH_LDEBUG */
        !          1897: 
        !          1898: 
        !          1899: #if ETAP_LOCK_TRACE
        !          1900: 
        !          1901: /*
        !          1902:  *  ==============================================================
        !          1903:  *  ETAP hook when initializing a usimple_lock.  May be invoked
        !          1904:  *  from the portable lock package or from an optimized machine-
        !          1905:  *  dependent implementation.
        !          1906:  *  ==============================================================
        !          1907:  */
        !          1908: 
        !          1909: void
        !          1910: etap_simplelock_init (
        !          1911:        simple_lock_t   l,
        !          1912:        etap_event_t    event)
        !          1913: {
        !          1914:        ETAP_CLEAR_TRACE_DATA(l);
        !          1915:        etap_event_table_assign(&l->u.event_table_chain, event);
        !          1916: 
        !          1917: #if    ETAP_LOCK_ACCUMULATE
        !          1918:         /* reserve an entry in the cumulative buffer */
        !          1919:         l->cbuff_entry = etap_cbuff_reserve(lock_event_table(l));
        !          1920:         /* initialize the entry if one was returned  */
        !          1921:         if (l->cbuff_entry != CBUFF_ENTRY_NULL) {
        !          1922:                 l->cbuff_entry->event    = event;
        !          1923:                 l->cbuff_entry->instance = (unsigned long) l;
        !          1924:                 l->cbuff_entry->kind     = SPIN_LOCK;
        !          1925:         }
        !          1926: #endif  /* ETAP_LOCK_ACCUMULATE */
        !          1927: }
        !          1928: 
        !          1929: 
        !          1930: void
        !          1931: etap_simplelock_unlock(
        !          1932:        simple_lock_t   l)
        !          1933: {
        !          1934:         unsigned short dynamic = 0;
        !          1935:         unsigned short trace   = 0;
        !          1936:         etap_time_t    total_time;
        !          1937:         etap_time_t    stop_hold_time;
        !          1938:         pc_t           pc;
        !          1939: 
        !          1940:        OBTAIN_PC(pc, l);
        !          1941:         ETAP_STAMP(lock_event_table(l), trace, dynamic);
        !          1942: 
        !          1943:         /*
        !          1944:          *  Calculate & collect hold time data only if
        !          1945:          *  the hold tracing was enabled throughout the
        !          1946:          *  whole operation.  This prevents collection of
        !          1947:          *  bogus data caused by mid-operation trace changes.
        !          1948:          *
        !          1949:          */
        !          1950: 
        !          1951:        if (ETAP_DURATION_ENABLED(trace) && ETAP_WHOLE_OP(l)) {
        !          1952:                ETAP_TIMESTAMP (stop_hold_time);
        !          1953:                ETAP_TOTAL_TIME(total_time, stop_hold_time,
        !          1954:                                l->u.s.start_hold_time);
        !          1955:                CUM_HOLD_ACCUMULATE(l->cbuff_entry, total_time, dynamic, trace);
        !          1956:                MON_ASSIGN_PC(l->end_pc, pc, trace);
        !          1957:                MON_DATA_COLLECT(l,
        !          1958:                                 l,
        !          1959:                                 total_time,
        !          1960:                                 SPIN_LOCK,
        !          1961:                                 MON_DURATION,
        !          1962:                                 trace);
        !          1963:        }
        !          1964:         ETAP_CLEAR_TRACE_DATA(l);
        !          1965: }
        !          1966: 
        !          1967: /*  ========================================================================
        !          1968:  *  Since the the simple_lock() routine is machine dependant, it must always
        !          1969:  *  be coded in assembly.  The two hook routines below are used to collect
        !          1970:  *  lock_stat data.
        !          1971:  *  ========================================================================
        !          1972:  */
        !          1973: 
        !          1974: /*
        !          1975:  *  ROUTINE:    etap_simplelock_miss()
        !          1976:  *
        !          1977:  *  FUNCTION:   This spin lock routine is called upon the first
        !          1978:  *              spin (miss) of the lock.
        !          1979:  *
        !          1980:  *              A timestamp is taken at the beginning of the wait period,
        !          1981:  *              if wait tracing is enabled.
        !          1982:  *
        !          1983:  *
        !          1984:  *  PARAMETERS:
        !          1985:  *              - lock address.
        !          1986:  *              - timestamp address.
        !          1987:  *
        !          1988:  *  RETURNS:    Wait timestamp value.  The timestamp value is later used
        !          1989:  *              by etap_simplelock_hold().
        !          1990:  *
        !          1991:  *  NOTES:      This routine is NOT ALWAYS called.  The lock may be free
        !          1992:  *              (never spinning).  For this reason the pc is collected in
        !          1993:  *              etap_simplelock_hold().
        !          1994:  *
        !          1995:  */
        !          1996: etap_time_t
        !          1997: etap_simplelock_miss (
        !          1998:        simple_lock_t   l)
        !          1999: 
        !          2000: {
        !          2001:         unsigned short trace     = 0;
        !          2002:         unsigned short dynamic   = 0;
        !          2003:        etap_time_t    start_miss_time;
        !          2004: 
        !          2005:         ETAP_STAMP(lock_event_table(l), trace, dynamic);
        !          2006: 
        !          2007:         if (trace & ETAP_CONTENTION)
        !          2008:                ETAP_TIMESTAMP(start_miss_time);
        !          2009: 
        !          2010:        return(start_miss_time);
        !          2011: }
        !          2012: 
        !          2013: /*
        !          2014:  *  ROUTINE:    etap_simplelock_hold()
        !          2015:  *
        !          2016:  *  FUNCTION:   This spin lock routine is ALWAYS called once the lock
        !          2017:  *              is acquired.  Here, the contention time is calculated and
        !          2018:  *              the start hold time is stamped.
        !          2019:  *
        !          2020:  *  PARAMETERS:
        !          2021:  *              - lock address.
        !          2022:  *              - PC of the calling function.
        !          2023:  *              - start wait timestamp.
        !          2024:  *
        !          2025:  */
        !          2026: 
        !          2027: void
        !          2028: etap_simplelock_hold (
        !          2029:        simple_lock_t   l,
        !          2030:        pc_t            pc,
        !          2031:        etap_time_t     start_hold_time)
        !          2032: {
        !          2033:         unsigned short         dynamic = 0;
        !          2034:         unsigned short         trace   = 0;
        !          2035:         etap_time_t    total_time;
        !          2036:         etap_time_t    stop_hold_time;
        !          2037: 
        !          2038:         ETAP_STAMP(lock_event_table(l), trace, dynamic);
        !          2039: 
        !          2040:         MON_ASSIGN_PC(l->start_pc, pc, trace);
        !          2041: 
        !          2042:         /* do not collect wait data if lock was free */
        !          2043:         if (ETAP_TIME_IS_ZERO(start_hold_time) && (trace & ETAP_CONTENTION)) {
        !          2044:                ETAP_TIMESTAMP(stop_hold_time);
        !          2045:                ETAP_TOTAL_TIME(total_time,
        !          2046:                                 stop_hold_time,
        !          2047:                                 start_hold_time);
        !          2048:                 CUM_WAIT_ACCUMULATE(l->cbuff_entry, total_time, dynamic, trace);
        !          2049:                MON_DATA_COLLECT(l,
        !          2050:                                 l,
        !          2051:                                 total_time,
        !          2052:                                 SPIN_LOCK,
        !          2053:                                 MON_CONTENTION,
        !          2054:                                 trace);
        !          2055:                ETAP_COPY_START_HOLD_TIME(&l->u.s, stop_hold_time, trace);
        !          2056:         }
        !          2057:         else
        !          2058:                ETAP_DURATION_TIMESTAMP(&l->u.s, trace);
        !          2059: }
        !          2060: 
        !          2061: void
        !          2062: etap_mutex_init (
        !          2063:        mutex_t         *l,
        !          2064:        etap_event_t    event)
        !          2065: {
        !          2066:        ETAP_CLEAR_TRACE_DATA(l);
        !          2067:        etap_event_table_assign(&l->u.event_table_chain, event);
        !          2068: 
        !          2069: #if    ETAP_LOCK_ACCUMULATE
        !          2070:         /* reserve an entry in the cumulative buffer */
        !          2071:         l->cbuff_entry = etap_cbuff_reserve(lock_event_table(l));
        !          2072:         /* initialize the entry if one was returned  */
        !          2073:         if (l->cbuff_entry != CBUFF_ENTRY_NULL) {
        !          2074:                l->cbuff_entry->event    = event;
        !          2075:                l->cbuff_entry->instance = (unsigned long) l;
        !          2076:                l->cbuff_entry->kind     = MUTEX_LOCK;
        !          2077:        }
        !          2078: #endif  /* ETAP_LOCK_ACCUMULATE */
        !          2079: }
        !          2080: 
        !          2081: etap_time_t
        !          2082: etap_mutex_miss (
        !          2083:        mutex_t    *l)
        !          2084: {
        !          2085:         unsigned short trace       = 0;
        !          2086:         unsigned short dynamic     = 0;
        !          2087:        etap_time_t     start_miss_time;
        !          2088: 
        !          2089:         ETAP_STAMP(lock_event_table(l), trace, dynamic);
        !          2090: 
        !          2091:         if (trace & ETAP_CONTENTION)
        !          2092:                ETAP_TIMESTAMP(start_miss_time);
        !          2093:        else
        !          2094:                ETAP_TIME_CLEAR(start_miss_time);
        !          2095: 
        !          2096:        return(start_miss_time);
        !          2097: }
        !          2098: 
        !          2099: void
        !          2100: etap_mutex_hold (
        !          2101:        mutex_t         *l,
        !          2102:        pc_t            pc,
        !          2103:        etap_time_t     start_hold_time)
        !          2104: {
        !          2105:         unsigned short         dynamic = 0;
        !          2106:         unsigned short         trace   = 0;
        !          2107:         etap_time_t    total_time;
        !          2108:         etap_time_t    stop_hold_time;
        !          2109: 
        !          2110:         ETAP_STAMP(lock_event_table(l), trace, dynamic);
        !          2111: 
        !          2112:         MON_ASSIGN_PC(l->start_pc, pc, trace);
        !          2113: 
        !          2114:         /* do not collect wait data if lock was free */
        !          2115:         if (!ETAP_TIME_IS_ZERO(start_hold_time) && (trace & ETAP_CONTENTION)) {
        !          2116:                ETAP_TIMESTAMP(stop_hold_time);
        !          2117:                ETAP_TOTAL_TIME(total_time,
        !          2118:                                stop_hold_time,
        !          2119:                                start_hold_time);
        !          2120:                CUM_WAIT_ACCUMULATE(l->cbuff_entry, total_time, dynamic, trace);
        !          2121:                MON_DATA_COLLECT(l,
        !          2122:                                 l,
        !          2123:                                 total_time,
        !          2124:                                 MUTEX_LOCK,
        !          2125:                                 MON_CONTENTION,
        !          2126:                                 trace);
        !          2127:                ETAP_COPY_START_HOLD_TIME(&l->u.s, stop_hold_time, trace);
        !          2128:         }
        !          2129:         else
        !          2130:                ETAP_DURATION_TIMESTAMP(&l->u.s, trace);
        !          2131: }
        !          2132: 
        !          2133: void
        !          2134: etap_mutex_unlock(
        !          2135:        mutex_t         *l)
        !          2136: {
        !          2137:         unsigned short dynamic = 0;
        !          2138:         unsigned short trace   = 0;
        !          2139:         etap_time_t    total_time;
        !          2140:         etap_time_t    stop_hold_time;
        !          2141:         pc_t           pc;
        !          2142: 
        !          2143:        OBTAIN_PC(pc, l);
        !          2144:         ETAP_STAMP(lock_event_table(l), trace, dynamic);
        !          2145: 
        !          2146:         /*
        !          2147:          *  Calculate & collect hold time data only if
        !          2148:          *  the hold tracing was enabled throughout the
        !          2149:          *  whole operation.  This prevents collection of
        !          2150:          *  bogus data caused by mid-operation trace changes.
        !          2151:          *
        !          2152:          */
        !          2153: 
        !          2154:         if (ETAP_DURATION_ENABLED(trace) && ETAP_WHOLE_OP(l)) {
        !          2155:                ETAP_TIMESTAMP(stop_hold_time);
        !          2156:                ETAP_TOTAL_TIME(total_time, stop_hold_time,
        !          2157:                                l->u.s.start_hold_time);
        !          2158:                CUM_HOLD_ACCUMULATE(l->cbuff_entry, total_time, dynamic, trace);
        !          2159:                MON_ASSIGN_PC(l->end_pc, pc, trace);
        !          2160:                MON_DATA_COLLECT(l,
        !          2161:                                 l,
        !          2162:                                 total_time,
        !          2163:                                 MUTEX_LOCK,
        !          2164:                                 MON_DURATION,
        !          2165:                                 trace);
        !          2166:         }
        !          2167:         ETAP_CLEAR_TRACE_DATA(l);
        !          2168: }
        !          2169: 
        !          2170: #endif  /* ETAP_LOCK_TRACE */

unix.superglobalmegacorp.com

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