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

1.1       root        1: /*
                      2:  * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
                      3:  *
                      4:  * @APPLE_LICENSE_HEADER_START@
                      5:  * 
                      6:  * The contents of this file constitute Original Code as defined in and
                      7:  * are subject to the Apple Public Source License Version 1.1 (the
                      8:  * "License").  You may not use this file except in compliance with the
                      9:  * License.  Please obtain a copy of the License at
                     10:  * http://www.apple.com/publicsource and read it before using this file.
                     11:  * 
                     12:  * This Original Code and all software distributed under the License are
                     13:  * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
                     14:  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
                     15:  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
                     16:  * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT.  Please see the
                     17:  * License for the specific language governing rights and limitations
                     18:  * under the License.
                     19:  * 
                     20:  * @APPLE_LICENSE_HEADER_END@
                     21:  */
                     22: /*
                     23:  * @OSF_COPYRIGHT@
                     24:  */
                     25: /* 
                     26:  * Mach Operating System
                     27:  * Copyright (c) 1991,1990,1989,1988,1987 Carnegie Mellon University
                     28:  * All Rights Reserved.
                     29:  * 
                     30:  * Permission to use, copy, modify and distribute this software and its
                     31:  * documentation is hereby granted, provided that both the copyright
                     32:  * notice and this permission notice appear in all copies of the
                     33:  * software, derivative works or modified versions, and any portions
                     34:  * thereof, and that both notices appear in supporting documentation.
                     35:  * 
                     36:  * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
                     37:  * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
                     38:  * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
                     39:  * 
                     40:  * Carnegie Mellon requests users of this software to return to
                     41:  * 
                     42:  *  Software Distribution Coordinator  or  [email protected]
                     43:  *  School of Computer Science
                     44:  *  Carnegie Mellon University
                     45:  *  Pittsburgh PA 15213-3890
                     46:  * 
                     47:  * any improvements or extensions that they make and grant Carnegie Mellon
                     48:  * the rights to redistribute these changes.
                     49:  */
                     50: /*
                     51:  *     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.