Annotation of coherent/f/etc/conf/streams/src/ksynch.c, revision 1.1.1.1

1.1       root        1: #define        _DDI_DKI        1
                      2: #define        _SYSV4          1
                      3: 
                      4: 
                      5: /*
                      6:  * System V DDI/DKI compatible synchronisation functions
                      7:  *
                      8:  * This implements the synchronisation functions introduced in the System V
                      9:  * DDI/DKI multiprocessor edition for a simple uniprocessor. The locking
                     10:  * implementations given here are totally unsuitable for multiprocessor use.
                     11:  *
                     12:  * Some good multiprocessor lock algorithms can be found in:
                     13:  *     "Synchronisation Without Contention"
                     14:  *     John M. Mellor-Crummey & Michael L. Scott,
                     15:  *     Proceedings 4th International Conference on Architectural Support for
                     16:  *             Programming Languages and Operating Systems (ASPLOS 4)
                     17:  *     1991, ACM
                     18:  */
                     19: 
                     20: /*
                     21:  *-IMPORTS:
                     22:  *     <common/ccompat.h>
                     23:  *             __CONST__
                     24:  *             __USE_PROTO__
                     25:  *             __ARGS ()
                     26:  *     <common/xdebug.h>
                     27:  *             __LOCAL__
                     28:  *     <kernel/x86lock.h>
                     29:  *             atomic_uchar_t
                     30:  *             atomic_ushort_t
                     31:  *             __atomic_uchar_t
                     32:  *             ATOMIC_TEST_AND_SET_UCHAR ()
                     33:  *             ATOMIC_FETCH_AND_STORE_USHORT ();
                     34:  *             ATOMIC_FETCH_UCHAR ();
                     35:  *             ATOMIC_FETCH_USHORT ();
                     36:  *             ATOMIC_CLEAR_UCHAR ();
                     37:  *             ATOMIC_CLEAR_USHORT ();
                     38:  *     <kernel/ddi_cpu.h>
                     39:  *             ASSERT_BASE_LEVEL ();
                     40:  *             ddi_cpu_data ()
                     41:  *     <kernel/v_proc.h>
                     42:  *             plist_t
                     43:  *             PROCESS_WOKEN
                     44:  *             PROCESS_SIGNALLED
                     45:  *             MAKE_SLEEPING ()
                     46:  *             WAKE_ONE ()
                     47:  *             WAKE_ALL ()
                     48:  *             PROC_HANDLE ()
                     49:  *     <sys/debug.h>
                     50:  *             ASSERT ()
                     51:  *     <sys/types.h>
                     52:  *             pl_t
                     53:  *             uchar_t
                     54:  *             uint_t
                     55:  *     <sys/inline.h>
                     56:  *             splhi ()
                     57:  *             splx ()
                     58:  *             splcmp ()
                     59:  *     <sys/cmn_err.h>
                     60:  *             cmn_err ()
                     61:  *     <sys/kmem.h>
                     62:  *             KM_SLEEP
                     63:  *             KM_NOSLEEP
                     64:  */
                     65: 
                     66: #include <common/ccompat.h>
                     67: #include <kernel/ddi_cpu.h>
                     68: #include <kernel/ddi_lock.h>
                     69: #include <kernel/v_proc.h>
                     70: #include <sys/debug.h>
                     71: #include <sys/types.h>
                     72: #include <sys/inline.h>
                     73: #include <sys/cmn_err.h>
                     74: #include <sys/kmem.h>
                     75: 
                     76: #include <sys/ksynch.h>
                     77: 
                     78: 
                     79: /*
                     80:  * The actual content definitions of the following data structures has been
                     81:  * kept totally private to this file in order to reduce the temptation of
                     82:  * allocating or accessing the definitions in other subsystems.
                     83:  *
                     84:  * Note that for efficiency considerations it might eventually become
                     85:  * necessary to export these definitions elsewhere to allow locks to be
                     86:  * statically defined (to break dependencies) or incorporated directly as
                     87:  * members of other data structures (to reduce allocation overheads).
                     88:  * (Of course, that means we have to define ...._INIT () routines).
                     89:  *
                     90:  * For now, we'll try very very hard to resist the temptation to optimize
                     91:  * too early and violate our encapsulation.
                     92:  */
                     93: 
                     94: /*
                     95:  * Configuration issue: DDI/DKI sleep locks don't really map well onto any
                     96:  * old-style Unix kernel functionality, nor does the "wake one" feature of
                     97:  * DDI/DKI synchronization variables. Sleep locks and synchronization
                     98:  * variables need to interface intimately with the kernel scheduling services
                     99:  * (in ways that were usually not anticipated by the original authors of those
                    100:  * services). This requires us to confront some key aspects of the difference
                    101:  * between the old and new styles to discover why we really *need* to
                    102:  * introduce a different way of doing things.
                    103:  *
                    104:  * Some features of the old sleep ()/wakeup () model:
                    105:  *     a) These functions correspond exactly to the SV_WAIT[_SIG] () and
                    106:  *        SV_BROADCAST () functions in the DDI/DKI, except that they do not
                    107:  *        incorporate the basic-lock functionality of SV_WAIT[_SIG] ().
                    108:  *
                    109:  *     b) Whether sleep was interruptible or not was related to the
                    110:  *        "priority" indication passed to SV_WAIT[_SIG] () rather than being
                    111:  *        orthogonal issue. This need not be vital, except that the
                    112:  *        "priority" for sleep ()/wakeup () calls was expressed in magic,
                    113:  *        highly implementation-dependent numbers. [*]
                    114:  *
                    115:  *     c) On many systems, if sleep () was interrupted by a signal the result
                    116:  *        was that the sleep was aborted by a non-local return. This is not
                    117:  *        necessarily a problem *if* the caller was allowed to form a chain
                    118:  *        of handlers to provide unwind-protection facilities. Sadly, this
                    119:  *        is usually not the case.
                    120:  *
                    121:  *     d) The ability to awaken only *one* process at a time was not
                    122:  *        considered an issue; firstly, because contention was normally only
                    123:  *        associated with actions involving long delay, such as I/O, and
                    124:  *        because processes could only be run sequentially anyway. In other
                    125:  *        words, even if contention happened, the fact that after a wakeup ()
                    126:  *        processes were run one at a time meant that often by the time a
                    127:  *        process was run after a wakeup () the lock had been acquired *and*
                    128:  *        released by any process with higher priority.
                    129:  *
                    130:  * [*] For instance, I have no idea what the three (!) different numbers that
                    131:  * have to be passed to a sleep () call in Coherent really do. There is no
                    132:  * internal documentation in the kernel source that clearly explicates the
                    133:  * roles that each number plays, nor what effect it has on the overall picture
                    134:  * of process scheduling.
                    135:  *
                    136:  * Each of features requires modification to the sleep ()/wakeup () model, as
                    137:  * outlined below:
                    138:  *     a) In a uniprocessor kernel, sleep ()/wakeup () could function without
                    139:  *        basic locks since the caller could gain equivalent protection by
                    140:  *        simply manipulating the interrupt priority level, which would be
                    141:  *        reset during the course of the dispatch process after the caller
                    142:  *        had been safely put to sleep. In a multiprocessor, an unlock call
                    143:  *        occuring *during* a call to sleep () might occur before the
                    144:  *        process status had been changed, thus causing the caller to never
                    145:  *        see the unlock...
                    146:  *
                    147:  *        This suggests the following basic model for sleep locks:
                    148:  *
                    149:  *             for (;;) {
                    150:  *                     acquire_basic_lock ();
                    151:  *                     if (resource_available ())
                    152:  *                             break;
                    153:  *                     if (MAKE_SLEEPING () == PROCESS_SLEPT) {
                    154:  *                             release_basic_lock ();
                    155:  *                             RUN_NEXT ();    // does not return
                    156:  *                     }
                    157:  *             }
                    158:  *
                    159:  *        where MAKE_SLEEPING () and RUN_NEXT () together form the same kind
                    160:  *        of actions as sleep (), but broken into a pair that makes the
                    161:  *        setjmp ()-style behaviour of rescheduling apparent and useful. In
                    162:  *        particular, this keeps the desirable property that the low-level
                    163:  *        scheduling system leaves the locking system in the hands of the
                    164:  *        client code.
                    165:  *
                    166:  *        Of course, there are various ways that this can be achieved. The
                    167:  *        preferred style would be for MAKE_SLEEPING () to (optionally) test
                    168:  *        for signals and to return some discriminating value. The values
                    169:  *        returned from MAKE_SLEEPING () could be
                    170:  *
                    171:  *             PROCESS_SLEPT           slept
                    172:  *             PROCESS_WOKEN           woken normally
                    173:  *             PROCESS_SIGNALLED       woken by signal
                    174:  *
                    175:  *        but for practical reasons this is difficult. While it is desirable
                    176:  *        to expose at least part of the context-saving behaviour of the
                    177:  *        inner scheduling layer, most of these facilities have the same
                    178:  *        limitations as the setjmp () facility in that if the context which
                    179:  *        directly called the context-save routine exits, all bets are off.
                    180:  *        See (c) below for further discussion, and the final form will be
                    181:  *        introduced at the end.
                    182:  *
                    183:  *     b) This can be generally dealt with as-is by introducing appropriate
                    184:  *        magic to map the abstract priorities into numbers for passing to
                    185:  *        MAKE_SLEEPING ().
                    186:  *
                    187:  *     c) The old style of signal handling is forbidden in the DDI/DKI
                    188:  *        envinronment due to the locking style in use. In fact, the only
                    189:  *        way that a driver can detect that a signal has been sent to a
                    190:  *        process is by performing SV_WAIT_SIG () or SLEEP_LOCK_SIG () and
                    191:  *        testing the return value.
                    192:  *
                    193:  *        Moreover, signalling introduces one deficiency in the model
                    194:  *        presented in a) above, namely that if a process is signalled, the
                    195:  *        wakeup done in the signalling process knows nothing about the
                    196:  *        locking system being used above (and in fact, if we layer on top of
                    197:  *        old sleep ()/wakeup () code, our entire queueing system is ignored,
                    198:  *        which would be easily fixable but for that locking problem).
                    199:  *
                    200:  *        The simple solution would be to introduce an extra lock on part of
                    201:  *        the process table than can ameliorate some of the problems, but
                    202:  *        too many basic locks leads to hierarchy/ordering problems, and is
                    203:  *        especially wasteful given that approriate row-level locking on
                    204:  *        list headers should be completely sufficient without having to
                    205:  *        introduce node-level locks.
                    206:  *
                    207:  *        Essentially, we define the basic lock as being part of the list
                    208:  *        head that sleeping processes are queued on and put a back-pointer
                    209:  *        to the list head in the process table so that signal wakeup. This
                    210:  *        complicates the generic sleep-lock and synchronization variable
                    211:  *        functions a little, but we should be able to impose the semantics
                    212:  *        we want (namely being able to guarantee deterministic ordering
                    213:  *        on locks, which requires that the generic functions be accurately
                    214:  *        able to determine the status of processes threaded on the sleep
                    215:  *        queues).
                    216:  *
                    217:  *        This definition of responsibilty for the queue head w.r.t. locking
                    218:  *        behaviour allows us to fold the release_basic_lock () and
                    219:  *        RUN_NEXT () behaviour into MAKE_SLEEPING (), which also helps to
                    220:  *        solve the problem of dealing with the scope of context-save
                    221:  *        introduced in (a). Note that we have to be careful about using the
                    222:  *        process-table pointer to the list head since in order to find the
                    223:  *        list head to lock it we have to read this information which is
                    224:  *        potentially being modified as we access it.
                    225:  *
                    226:  *        [ Note that it is possible to write a macro for MAKE_SLEEPING ()
                    227:  *          that does the context save in the caller's scope, but since it is
                    228:  *          possible for a routine to *not* sleep at all (due to a pending
                    229:  *          signal), that would mean it had to take the form:
                    230:  *             FINALIZE_SLEEP (SAVE_CONTEXT (BEGIN_SLEEP (...)), ...)
                    231:  *          in order to avoid introducing auxiliaries. ]
                    232:  *
                    233:  *     d) The assumptions on which the old-style behaviour is based are no
                    234:  *        longer valid on multiprocessing systems. Firstly, the more con-
                    235:  *        current nature of multiprocessor systems increases the likelihood
                    236:  *        of contention for locks. Secondly, broadcast wakeup is likely to
                    237:  *        cause several of the woken processes to be run simultaneously on
                    238:  *        different processors, resulting in timelines like this (measured
                    239:  *        from a broadcast wakeup of processes waiting for a resource):
                    240:  *
                    241:  *             CPU A : |-<acquire----------release>...............
                    242:  *             CPU n : .|--*|--*|--*|--*...........|--<acquire ---
                    243:  *
                    244:  *        where '|' indicates selection of a process, '-' indicates CPU time
                    245:  *        consumed, and '*' indicates a process sleeping due to resource
                    246:  *        unavailability, and '.' represents CPU time spent on unrelated
                    247:  *        activity. Clearly, broadcast wakeup is not an optimal way of
                    248:  *        implementing one-at-a-time lock functionality on a multiprocessor.
                    249:  *
                    250:  *        Of course, implementing one-at-a-time wakeup facilities is not a
                    251:  *        trivial matter. While awakening a single waiting process is fairly
                    252:  *        simple, the matter of selecting *which* process to awaken is a
                    253:  *        complex one that can have considerable impact on other kernel
                    254:  *        systems such as the virtual memory system. In addition, there is
                    255:  *        extra information available in the DDI/DKI system whose relation
                    256:  *        to scheduling has not been studied (such as the number of locks
                    257:  *        held by a context). Clearly, the internal layering of the DDI/DKI
                    258:  *        implementation should be designed to make it easy to export this
                    259:  *        information to the low-level kernel scheduling system.
                    260:  *
                    261:  *        Of course, the worst case is that normal kernel scheduling policy
                    262:  *        is completely supplanted in the DDI/DKI case. There looks to be
                    263:  *        little alternative for the multiprocessor case, but it seems to
                    264:  *        be a good idea to design the DDI/DKI implementation to support the
                    265:  *        old-style broadcast functionality as a fallback.
                    266:  */
                    267: 
                    268: 
                    269: /*
                    270:  * Common inital part of a lock that is used to queue locks and hold the
                    271:  * statistics information. We use this definition to simplify the process of
                    272:  * keeping lists of all the allocated locks and to permit simple generic
                    273:  * operations on such lists.
                    274:  *
                    275:  * Downcast operators should be provided for the lock structures so that the
                    276:  * mapping from the node to the lock can be done in a fully portable fashion.
                    277:  */
                    278: 
                    279: typedef struct lock_node lnode_t;
                    280: 
                    281: struct lock_node {
                    282:        lnode_t       * ln_next;        /* pointer to successor */
                    283:        lnode_t       * ln_prev;        /* pointer to predecessor */
                    284:        lkinfo_t      * ln_lkinfo;      /* statistics information */
                    285: };
                    286: 
                    287: 
                    288: /*
                    289:  * Internal structure of a basic lock
                    290:  */
                    291: 
                    292: struct __basic_lock {
                    293:        lnode_t         bl_node;        /* generic information */
                    294: 
                    295: #ifdef __TICKET_LOCK__
                    296:        atomic_ushort_t bl_next_ticket; /* next ticket number to be granted */
                    297:        atomic_ushort_t bl_lock_holder; /* ticket number of lock holder */
                    298: #endif
                    299: 
                    300:        atomic_uchar_t  bl_locked;      /* is the basic lock acquired? */
                    301: 
                    302:        pl_t            bl_min_pl;      /* minimum pl to be used in LOCK () */
                    303: 
                    304:        uchar_t         bl_hierarchy;   /* acquisition order constraint */
                    305: };
                    306: 
                    307: 
                    308: /*
                    309:  * Internal structure of a read/write lock.
                    310:  *
                    311:  * Due to the shared nature of read locks, they are naturally expressed by
                    312:  * a count of outstanding readers maintained by atomic increment and
                    313:  * decrement operations. The exclusive (write) mode of such locks are best
                    314:  * expressed via the "ticket" mechanism if FIFO ordering is desired and/or
                    315:  * contention is to be minimized.
                    316:  *
                    317:  * The following implementation consists of a basic (exclusive) lock simply
                    318:  * augmented by a count; the use of a "ticket gate" test-and-set lock to
                    319:  * control access to the lock internal data reduces dependency on atomic
                    320:  * facilities such as fetch_and_increment and compare_and_swap that are not
                    321:  * widely available. If such facilities are available, consider using the
                    322:  * lock algorithm outlined in the paper referenced in the file header comment
                    323:  * above.
                    324:  */
                    325: 
                    326: struct readwrite_lock {
                    327:        lnode_t         rw_node;        /* generic information */
                    328: 
                    329:        atomic_ushort_t rw_next_ticket; /* next ticket number to be granted */
                    330:        atomic_ushort_t rw_lock_holder; /* ticket number of lock holder */
                    331: 
                    332:        atomic_ushort_t rw_readers;
                    333: 
                    334:        atomic_uchar_t  rw_locked;
                    335: 
                    336:        pl_t            rw_min_pl;      /* min pl to acquire the lock with */
                    337: 
                    338:        uchar_t         rw_hierarchy;   /* acquisition order constraint */
                    339: };
                    340: 
                    341: 
                    342: /*
                    343:  * Internal structure of a synchronisation variable
                    344:  */
                    345: 
                    346: struct synch_var {
                    347:        lnode_t         sv_node;        /* generic information */
                    348: 
                    349:        plist_t         sv_plist [1];   /* list of blocked processes */
                    350: };
                    351: 
                    352: 
                    353: /*
                    354:  * Internal structure of a sleep lock.
                    355:  *
                    356:  * Note that the "sl_holder" member exists purely to support the debugging
                    357:  * SLEEP_LOCKOWNED () function, nothing else. What the System V documentation
                    358:  * fails to discuss is that sleep locks don't have to be owned by *any*
                    359:  * process. Sleep locks can be acquired at interrupt level via
                    360:  * SLEEP_TRYLOCK (), and released by interrupts as well. There doesn't appear
                    361:  * to be any mechanism to prevent locks being passed between processes by
                    362:  * various methods, and so on and so forth.
                    363:  *
                    364:  * Therefore, the flag members are the only members actually used by the
                    365:  * implementations of the sleep-lock functions, and the "sl_holder" member
                    366:  * may not be correct if the lock was acquired by an interrupt context.
                    367:  *
                    368:  * As discussed elsewhere, the main focus of activity for sleep locks is the
                    369:  * list of waiting processes, which contains a test-and-set lock that should
                    370:  * be used to control most aspects of lock state.
                    371:  */
                    372: 
                    373: struct sleep_lock {
                    374:        lnode_t         sl_node;        /* generic information */
                    375: 
                    376:        atomic_uchar_t  sl_locked;      /* is sleep lock held? */
                    377: 
                    378:        plist_t         sl_plist [1];   /* process list */
                    379: 
                    380:        _VOID         * sl_holder;      /* ID of process holding lock */
                    381: };
                    382: 
                    383: 
                    384: /*
                    385:  * Downcasting operators. Hopefully we won't need these.
                    386:  */
                    387: 
                    388: #define        lnode_to_basic(n)       ((lock_t *) ((char *) (n) - \
                    389:                                             offsetof (lock_t, bl_node)))
                    390: 
                    391: #define        lnode_to_rw(n)          ((rwlock_t *) ((char *) (n) - \
                    392:                                               offsetof (rwlock_t, rw_node)))
                    393: 
                    394: #define        lnode_to_sv(n)          ((sv_t *) ((char *) (n) - \
                    395:                                           offsetof (sv_t, sv_node)))
                    396: 
                    397: #define        lnode_to_sleep(n)       ((sleep_t *) ((char *) (n) - \
                    398:                                              offsetof (sleep_t, sl_node)))
                    399: 
                    400: 
                    401: /*
                    402:  * For debugging purposes, we want to keep lists of all the allocated locks.
                    403:  *
                    404:  * In the absence of atomic compare-and-swap operations, it's hard to define
                    405:  * good list-manipulation code, so we'll protect our list operations with
                    406:  * simple test-and-set locks. As usual on a uniprocessor these are still
                    407:  * useful for detecting potential inconsistency.
                    408:  *
                    409:  * There are no init or destroy methods/macros for this structure since there
                    410:  * are only the following static instances defined.
                    411:  */
                    412: 
                    413: __LOCAL__ struct lock_list {
                    414:        __CONST__ char * ll_name;       /* name of list */
                    415: 
                    416:        atomic_uchar_t  ll_locked;      /* single-thread list operations */
                    417:        lnode_t       * ll_head;        /* head of list */
                    418: } basic_locks = { "basic lock" },
                    419:   rw_locks = { "read/write lock" },
                    420:   synch_vars = { "synchronisation variable" },
                    421:   sleep_locks = { "sleep lock" };
                    422: 
                    423: #define        LOCKLIST_LOCK(l,n)      (TEST_AND_SET_LOCK ((l)->ll_locked, plhi, n))
                    424: #define        LOCKLIST_UNLOCK(l,p)    (ATOMIC_CLEAR_UCHAR ((l)->ll_locked),\
                    425:                                 (void) splx (p))
                    426: 
                    427: /*
                    428:  * We must abstract the linkage between locks and memory allocation; the lock
                    429:  * system requires memory allocation services which require lock services...
                    430:  * certain definitions below (and presumably similar definitions in the memory
                    431:  * management system) can be used to resolve this dependency. In addition,
                    432:  * the abstraction provided can be used to decouple the provided systems (and
                    433:  * this aids portability) or to increase their coupling (to increase
                    434:  * performance).
                    435:  *
                    436:  * The definitions (which may be macros):
                    437:  *     _lock_malloc ()
                    438:  *     _lock_free ()
                    439:  * define an internal interface to the memory management system. If the memory
                    440:  * allocation system uses LOCK_ALLOC () to allocate the locks used to
                    441:  * coordinate access to the memory pool(s), the functions above will work as
                    442:  * expected even during the memory system's call to LOCK_ALLOC (), and will
                    443:  * coordinate access as necessary with other memory allocation interfaces
                    444:  * thereafter.
                    445:  */
                    446: 
                    447: __EXTERN_C_BEGIN__
                    448: 
                    449: _VOID        * _lock_malloc    __PROTO ((size_t size, int flag));
                    450: void           _lock_free      __PROTO ((_VOID * mem, size_t size));
                    451: 
                    452: __EXTERN_C_END__
                    453: 
                    454: 
                    455: /*
                    456:  * For now, we just map these functions onto the kmem_ interface and deal
                    457:  * with startup issues there.
                    458:  */
                    459: 
                    460: #define        _lock_malloc(s,f)       kmem_alloc (s, f)
                    461: #define        _lock_free(s,f)         kmem_free (s, f)
                    462: 
                    463: 
                    464: /*
                    465:  * This file-local function encapsulates the hierarchy-recording function that
                    466:  * deals with the bookkeeping necessary to ensure that locks are acquired
                    467:  * strictly in the order defined (to avoid deadlock).
                    468:  *
                    469:  * Due to the way in which the DDI/DKI locking functions are defined, it might
                    470:  * be possible on some architectures for a basic or read/write lock acquired
                    471:  * on one CPU to eventually be released on another.
                    472:  *
                    473:  * In a multi-processor system where this might be possible, it might be more
                    474:  * sensible to record the hierarchy information in some per-priority-level
                    475:  * fashion (as the DDI/DKI alludes to). Since this is currently not
                    476:  * necessary, we'll elect to design that ability later.
                    477:  */
                    478: 
                    479: #if    __USE_PROTO__
                    480: __LOCAL__ void (LOCK_COUNT_HIERARCHY) (__lkhier_t hierarchy)
                    481: #else
                    482: __LOCAL__ void
                    483: LOCK_COUNT_HIERARCHY __ARGS ((hierarchy))
                    484: __lkhier_t     hierarchy;
                    485: #endif
                    486: {
                    487:        dcdata_t      * dcdata = ddi_cpu_data ();
                    488:        pl_t            prev_pl = splhi ();
                    489: 
                    490:        /*
                    491:         * We'll skip the usual paranoid ASSERT () tests since this is purely
                    492:         * a local function.
                    493:         */
                    494: 
                    495:        dcdata->dc_hierarchy_cnt [hierarchy - __MIN_HIERARCHY__] ++;
                    496: 
                    497:        if (dcdata->dc_max_hierarchy < hierarchy)
                    498:                dcdata->dc_max_hierarchy = hierarchy;
                    499: 
                    500:        (void) splx (prev_pl);
                    501: }
                    502: 
                    503: 
                    504: /*
                    505:  * This file-local function is the dual to the above, for adjusting the
                    506:  * hierarchy information for a lock release.
                    507:  */
                    508: 
                    509: #define        ARRAY_MAX(array)        (sizeof (array) / sizeof ((array) [0])
                    510: 
                    511: #if    __USE_PROTO__
                    512: __LOCAL__ void (LOCK_FREE_HIERARCHY) (__lkhier_t hierarchy)
                    513: #else
                    514: __LOCAL__ void
                    515: LOCK_FREE_HIERARCHY __ARGS ((hierarchy))
                    516: __lkhier_t     hierarchy;
                    517: #endif
                    518: {
                    519:        dcdata_t      * dcdata = ddi_cpu_data ();
                    520:        pl_t            prev_pl = splhi ();
                    521: 
                    522:        /*
                    523:         * We'll skip the usual paranoid ASSERT () tests since this is purely
                    524:         * a local function.
                    525:         */
                    526: 
                    527:        dcdata->dc_hierarchy_cnt [hierarchy - __MIN_HIERARCHY__] --;
                    528: 
                    529:        /*
                    530:         * Work out the lowest occupied priority level.
                    531:         */
                    532: 
                    533:        do {
                    534:                if (dcdata->dc_hierarchy_cnt [dcdata->dc_max_hierarchy -
                    535:                                              __MIN_HIERARCHY__] > 0)
                    536:                        break;
                    537:        } while (-- dcdata->dc_max_hierarchy >= __MIN_HIERARCHY__);
                    538: 
                    539:        (void) splx (prev_pl);
                    540: }
                    541: 
                    542: 
                    543: #if 0
                    544: /*
                    545:  * This file-local function takes care of recording debugging information and
                    546:  * statistics relating to lock acquisition.
                    547:  */
                    548: 
                    549: #if    __USE_PROTO__
                    550: __LOCAL__ void (TRACE_BASIC_LOCK) (lock_t * lockp)
                    551: #else
                    552: __LOCAL__ void
                    553: TRACE_BASIC_LOCK __ARGS ((lockp))
                    554: lock_t       * lockp;
                    555: #endif
                    556: {
                    557:        /*
                    558:         * We'll skip the usual paranoid ASSERT () tests since this is purely
                    559:         * a local function.
                    560:         */
                    561: }
                    562: 
                    563: 
                    564: 
                    565: /*
                    566:  * This file-local function takes care of undoing any data-structure changes
                    567:  * made by the above and recording additional statistics when a lock is
                    568:  * released
                    569:  */
                    570: 
                    571: #if    __USE_PROTO__
                    572: __LOCAL__ void (UNTRACE_BASIC_LOCK) (lock_t * lockp)
                    573: #else
                    574: __LOCAL__ void
                    575: UNTRACE_BASIC_LOCK __ARGS ((lockp))
                    576: lock_t       * lockp;
                    577: #endif
                    578: {
                    579:        /*
                    580:         * We'll skip the usual paranoid ASSERT () tests since this is purely
                    581:         * a local function.
                    582:         */
                    583: }
                    584: 
                    585: 
                    586: /*
                    587:  * This file-local function takes care of recording debugging information and
                    588:  * statistics relating to lock acquisition.
                    589:  */
                    590: 
                    591: #if    __USE_PROTO__
                    592: __LOCAL__ void (TRACE_RW_LOCK) (rwlock_t * lockp)
                    593: #else
                    594: __LOCAL__ void
                    595: TRACE_RW_LOCK __ARGS ((lockp))
                    596: rwlock_t      *        lockp;
                    597: #endif
                    598: {
                    599:        /*
                    600:         * We'll skip the usual paranoid ASSERT () tests since this is purely
                    601:         * a local function.
                    602:         */
                    603: }
                    604: 
                    605: 
                    606: 
                    607: /*
                    608:  * This file-local function takes care of undoing any data-structure changes
                    609:  * made by the above and recording additional statistics when a lock is
                    610:  * released.
                    611:  */
                    612: 
                    613: #if    __USE_PROTO__
                    614: __LOCAL__ void (UNTRACE_RW_LOCK) (rwlock_t * lockp)
                    615: #else
                    616: __LOCAL__ void
                    617: UNTRACE_RW_LOCK __ARGS ((lockp))
                    618: rwlock_t      *        lockp;
                    619: #endif
                    620: {
                    621:        /*
                    622:         * We'll skip the usual paranoid ASSERT () tests since this is purely
                    623:         * a local function.
                    624:         */
                    625: }
                    626: 
                    627: #else
                    628: 
                    629: /*
                    630:  * Since all the above functions have empty bodies, we'll define empty macros
                    631:  * to get around the warnings.
                    632:  */
                    633: 
                    634: #define        TRACE_BASIC_LOCK(l)
                    635: #define        UNTRACE_BASIC_LOCK(l)
                    636: 
                    637: #define        TRACE_RW_LOCK(l)
                    638: #define        UNTRACE_RW_LOCK(l)
                    639: 
                    640: #endif
                    641: 
                    642: 
                    643: 
                    644: /*
                    645:  * Simple common function to acquire a simple test-and-set lock.
                    646:  *
                    647:  * TEST_AND_SET_LOCK () uses the splraise () private function defined in
                    648:  * <sys/inline.h> to raise the processor priority level to "pl". This ensures
                    649:  * maximum safety in the use of this function, and certain DDI/DKI facilities
                    650:  * such as freezestr () require this behaviour.
                    651:  */
                    652: 
                    653: #if    __USE_PROTO__
                    654: pl_t (TEST_AND_SET_LOCK) (__atomic_uchar_t locked, pl_t pl,
                    655:                          __CONST__ char * name)
                    656: #else
                    657: pl_t
                    658: TEST_AND_SET_LOCK __ARGS ((locked, pl, name))
                    659: __atomic_uchar_t       locked;
                    660: pl_t                   pl;
                    661: __CONST__ char       * name;
                    662: #endif
                    663: {
                    664:        for (;;) {
                    665:                pl_t            prev_pl = splraise (pl);
                    666: 
                    667:                if (ATOMIC_TEST_AND_SET_UCHAR (locked) == 0)
                    668:                        return prev_pl;         /* all OK */
                    669: 
                    670: 
                    671:                /*
                    672:                 * While we spin for the lock, we can allow interrupts that
                    673:                 * were permissible at entry to this routine.
                    674:                 */
                    675: 
                    676:                (void) splx (prev_pl);
                    677: 
                    678: #ifdef __UNIPROCESSOR__
                    679:                cmn_err (CE_PANIC, "%s : test-and-set deadlock", name);
                    680: #elif  defined (__TEST_AND_TEST__)
                    681:                /*
                    682:                 * To reduce contention, we wait until the test-and-set lock
                    683:                 * is free before attempting to re-acquire it. Of course, more
                    684:                 * sophisticated backoff schemes might also help, even for
                    685:                 * this approach.
                    686:                 */
                    687: 
                    688:                while (ATOMIC_FETCH_UCHAR (locked) != 0)
                    689:                        /* DO NOTHING */;
                    690: #endif
                    691:        }
                    692: }
                    693: 
                    694: 
                    695: 
                    696: /*
                    697:  * File-local function to initialise the generic part of a lock; this normally
                    698:  * enqueues the lock on a list. This function also has the responsibility of
                    699:  * allocating any needed statistics buffers, which requires that it be passed
                    700:  * the flag which indicates whether it is allowed to block or not.
                    701:  */
                    702: 
                    703: #if    __USE_PROTO__
                    704: __LOCAL__ void (INIT_LNODE) (lnode_t * lnode, lkinfo_t * lkinfop,
                    705:                             struct lock_list * list, int __NOTUSED (flag))
                    706: #else
                    707: __LOCAL__ void
                    708: INIT_LNODE __ARGS ((lnode, lkinfop, list, flag))
                    709: lnode_t              * lnode;
                    710: lkinfo_t      *        lkinfop;
                    711: struct lock_list
                    712:              * list;
                    713: int            flag;
                    714: #endif
                    715: {
                    716:        pl_t            prev_pl;
                    717: 
                    718:        ASSERT (lnode != NULL && list != NULL);
                    719: 
                    720:        /*
                    721:         * Here we allocate and initialise any needed statistics information,
                    722:         * currently nothing.
                    723:         */
                    724: 
                    725:        lnode->ln_lkinfo = lkinfop;
                    726:        lnode->ln_prev = NULL;
                    727: 
                    728: 
                    729:        /*
                    730:         * Lock the list, enqueue the node, and unlock the list.
                    731:         */
                    732: 
                    733:        prev_pl = LOCKLIST_LOCK (list, list->ll_name);
                    734: 
                    735:        if ((lnode->ln_next = list->ll_head) != NULL)
                    736:                lnode->ln_next->ln_prev = lnode;
                    737:        list->ll_head = lnode;
                    738: 
                    739:        LOCKLIST_UNLOCK (list, prev_pl);
                    740: }
                    741: 
                    742: 
                    743: 
                    744: /*
                    745:  * The dual to the above, this file-local function dequeues the node from the
                    746:  * given list of locks and frees any statistics buffer memory.
                    747:  */
                    748: 
                    749: #if    __USE_PROTO__
                    750: __LOCAL__ void (FREE_LNODE) (lnode_t * lnode, struct lock_list * list)
                    751: #else
                    752: __LOCAL__ void
                    753: FREE_LNODE __ARGS ((lnode, list))
                    754: lnode_t              * lnode;
                    755: struct lock_list
                    756:              * list;
                    757: #endif
                    758: {
                    759:        pl_t            prev_pl;
                    760: 
                    761:        /*
                    762:         * We'll skip the paranoid assertions on this one, since the function
                    763:         * is file-local.
                    764:         *
                    765:         * Lock the list, dequeue the node, unlock the list. After that we
                    766:         * can free any statistics buffers.
                    767:         */
                    768: 
                    769:        prev_pl = LOCKLIST_LOCK (list, list->ll_name);
                    770: 
                    771:        if (lnode->ln_prev == NULL)
                    772:                list->ll_head = lnode->ln_next;
                    773:        else
                    774:                lnode->ln_prev->ln_next = lnode->ln_next;
                    775: 
                    776:        if (lnode->ln_next != NULL)
                    777:                lnode->ln_next->ln_prev = lnode->ln_prev;
                    778: 
                    779:        LOCKLIST_UNLOCK (list, prev_pl);
                    780: }
                    781: 
                    782: 
                    783: /*
                    784:  *-STATUS:
                    785:  *     DDI/DKI
                    786:  *
                    787:  *-NAME:
                    788:  *     LOCK_ALLOC ()   Allocate a basic lock
                    789:  *
                    790:  *-SYNOPSIS:
                    791:  *     #include <sys/types.h>
                    792:  *     #include <sys/kmem.h>
                    793:  *     #include <sys/ksynch.h>
                    794:  *
                    795:  *     lock_t * LOCK_ALLOC (uchar_t hierarchy, pl_t min_pl,
                    796:  *                          lkinfo_t * lkinfop, int flag);
                    797:  *
                    798:  *-ARGUMENTS:
                    799:  *     hierarchy       Hierarchy value which asserts the order in which this
                    800:  *                     lock will be acquired relative to other basic and
                    801:  *                     read/write locks. "hierarchy" must be within the range
                    802:  *                     of 1 through 32 inclusive and must be chosen such that
                    803:  *                     locks are normally acquired in order of increasing
                    804:  *                     "hierarchy" number. In other words, when acquiring a
                    805:  *                     basic lock using any function other than TRYLOCK (),
                    806:  *                     the lock being acquired must have a "hierarchy" value
                    807:  *                     that is strictly greater than the "hierarchy" values
                    808:  *                     associated with all locks currently held by the
                    809:  *                     calling context.
                    810:  *
                    811:  *                     Implementations of lock testing may differ in whether
                    812:  *                     they assume a separate range of "hierarchy" values for
                    813:  *                     each interrupt priority level or a single range that
                    814:  *                     spans all interrupt priority levels. In order to be
                    815:  *                     portable across different implementations, drivers
                    816:  *                     which may acquire locks at more than one interrupt
                    817:  *                     priority level should define the "hierarchy" among
                    818:  *                     those locks such that the "hierarchy" is strictly
                    819:  *                     increasing with increasing priority level (eg. if M
                    820:  *                     is the maximum "hierarchy" value defined for any lock
                    821:  *                     that may be acquired at priority level N, then M + 1
                    822:  *                     should be the minimum hierarchy value for any lock
                    823:  *                     that may be acquired at any priority level greater
                    824:  *                     than N).
                    825:  *
                    826:  *     min_pl          Minimum priority level argument which asserts the
                    827:  *                     minimum priority leel that will be passed in with any
                    828:  *                     attempt to acquire this lock [see LOCK ()].
                    829:  *                     Implementations which do not require that the
                    830:  *                     interrupt priority level be raised during lock
                    831:  *                     acquisition may choose not to enforce the "min_pl"
                    832:  *                     assertion. The valid values for this argument are as
                    833:  *                     follows:
                    834:  *
                    835:  *                       plbase        Block no interrupts
                    836:  *                       pltimeout     Block functions scheduled by itimeout
                    837:  *                                     and dtimeout
                    838:  *                       pldisk        Block disk device interrupts
                    839:  *                       plstr         Block STREAMS interrupts
                    840:  *                       plhi          Block all interrupts
                    841:  *
                    842:  *                     The notion of a "min_pl" assumes a defined order of
                    843:  *                     priority levels. The following partial order is
                    844:  *                     defined:
                    845:  *                       plbase < pltimeout <= pldisk, plstr <= plhi
                    846:  *
                    847:  *                     The ordering of pldisk and plstr relative to each
                    848:  *                     other is not defined.
                    849:  *
                    850:  *                     Setting a given priority level will block interrupts
                    851:  *                     associated with that level as well as all levels that
                    852:  *                     are defined to be less than or equal to the specified
                    853:  *                     level. In order to be portable a driver should not
                    854:  *                     acquire locks at different priority levels where the
                    855:  *                     relative order of those priority levels is not defined
                    856:  *                     above.
                    857:  *
                    858:  *                     The "min_pl" argument should specify a priority level
                    859:  *                     that would be sufficient to block out any interrupt
                    860:  *                     handler that might attempt to acquire this lock. In
                    861:  *                     addition, potential deadlock problems involving
                    862:  *                     multiple locks should be considered when defining the
                    863:  *                     "min_pl" value. For example, if the normal order of
                    864:  *                     acquisition of locks A and B (as defined by the lock
                    865:  *                     hierarchy) is to acquire A first and then B, lock B
                    866:  *                     should never be acquired at a priority level less
                    867:  *                     than the "min_pl" for lock A. Therefore, the "min_pl"
                    868:  *                     for lock B should be greater than or equal to the
                    869:  *                     "min_pl" for lock A.
                    870:  *
                    871:  *                     Note that the specification of a "min_pl" with a
                    872:  *                     LOCK_ALLOC () call does not actually cause any
                    873:  *                     interrupts to be blocked upon lock acquisition, it
                    874:  *                     simply asserts that subsequent LOCK () calls to
                    875:  *                     acquire this lock will pass in a priority level at
                    876:  *                     least as great as "min_pl".
                    877:  *
                    878:  *     lkinfop         Pointer to a lkinfo structure. The "lk_name" member of
                    879:  *                     the "lkinfo" structure points to a character string
                    880:  *                     defining a name that will be associated with the lock
                    881:  *                     for the purposes of statistics gathering. The name
                    882:  *                     should begin with the driver prefix and should be
                    883:  *                     unique to the lock or group of locks for which the
                    884:  *                     driver wishes to collect a uniquely identifiable set
                    885:  *                     of statistics (ie, if a given name is shared by a
                    886:  *                     group of locks, the statistics of the individual locks
                    887:  *                     within the group will not be uniquely identifiable).
                    888:  *                     There are no flags within the lk_flags member of the
                    889:  *                     lkinfo structure defined for use with LOCK_ALLOC ().
                    890:  *
                    891:  *                     A given lkinfo structure may be shared among multiple
                    892:  *                     basic locks and read/write locks but a lkinfo
                    893:  *                     structure may not be shared between a basic lock and
                    894:  *                     a sleep lock. The called must ensure that the lk_flags
                    895:  *                     and lk_pad members of the lkinfo structure are zeroed
                    896:  *                     out before passing it to LOCK_ALLOC ().
                    897:  *
                    898:  *     flag            Specifies whether the caller is willing to sleep
                    899:  *                     waiting for memory. If "flag" is set to KM_SLEEP, the
                    900:  *                     caller will sleep if necessary until sufficient memory
                    901:  *                     is available. If "flag" is set to KM_NOSLEEP, the
                    902:  *                     caller will not sleep, but LOCK_ALLOC () will return
                    903:  *                     NULL if sufficient memory is not immediately
                    904:  *                     available.
                    905:  *
                    906:  *-DESCRIPTION:
                    907:  *     LOCK_ALLOC () dynamically allocates and initialises an instance of a
                    908:  *     basic lock. The lock is initialised to the unlocked state.
                    909:  *
                    910:  *-RETURN VALUE:
                    911:  *     Upon successful completion, LOCK_ALLOC () returns a pointer to the
                    912:  *     newly allocated lock. If KM_NOSLEEP is specified and sufficient
                    913:  *     memory is not immediately available, LOCK_ALLOC () returns a NULL
                    914:  *     pointer.
                    915:  *
                    916:  *-LEVEL:
                    917:  *     Base only if "flag" is set to KM_SLEEP. Base or Interrupt if "flag" is
                    918:  *     set to KM_NOSLEEP.
                    919:  *
                    920:  *-NOTES:
                    921:  *     May sleep if "flag" is set to KM_NOSLEEP.
                    922:  *
                    923:  *     Driver-defined basic locks and read/write locks may be held across
                    924:  *     calls to this function if "flag" is set to KM_NOSLEEP but may not be
                    925:  *     held if "flag" is KM_SLEEP.
                    926:  *
                    927:  *     Driver-defined sleep locks may be held across calls to this function
                    928:  *     regardless of the value of "flag".
                    929:  *
                    930:  *-SEE ALSO:
                    931:  *     LOCK (), LOCK_DEALLOC (), TRYLOCK (), UNLOCK (), lkinfo
                    932:  */
                    933: 
                    934: #define        ASSERT_HIERARCHY_OK(h,lk) \
                    935:                ASSERT ((lk) != NULL), \
                    936:                ASSERT ((h) >= __MIN_HIERARCHY__ && \
                    937:                        (h) <= (((lk)->lk_flags & INTERNAL_LOCK) != 0 ? \
                    938:                                  __MAX_HIERARCHY__ : __MAX_DDI_HIERARCHY__))
                    939: 
                    940: #if    __USE_PROTO__
                    941: lock_t * (LOCK_ALLOC) (__lkhier_t hierarchy, pl_t min_pl, lkinfo_t * lkinfop,
                    942:                       int flag)
                    943: #else
                    944: lock_t *
                    945: LOCK_ALLOC __ARGS ((hierarchy, min_pl, lkinfop, flag))
                    946: __lkhier_t     hierarchy;
                    947: pl_t           min_pl;
                    948: lkinfo_t      *        lkinfop;
                    949: int            flag;
                    950: #endif
                    951: {
                    952:        lock_t        * lockp;
                    953: 
                    954:        ASSERT_HIERARCHY_OK (hierarchy, lkinfop);
                    955:        ASSERT (splcmp (plbase, min_pl) <= 0 && splcmp (min_pl, plhi) <= 0);
                    956:        ASSERT (flag == KM_SLEEP || flag == KM_NOSLEEP);
                    957: 
                    958:        /*
                    959:         * Allocate and initialise the data, possibly waiting for enough
                    960:         * memory to become available.
                    961:         */
                    962: 
                    963:        if ((lockp = (lock_t *) _lock_malloc (sizeof (* lockp),
                    964:                                              flag)) != NULL) {
                    965:                INIT_LNODE (& lockp->bl_node, lkinfop, & basic_locks, flag);
                    966: 
                    967:                lockp->bl_min_pl = min_pl;
                    968:                lockp->bl_hierarchy = hierarchy;
                    969: 
                    970:                ATOMIC_CLEAR_UCHAR (lockp->bl_locked);
                    971: 
                    972: #ifdef __TICKET_LOCK__
                    973:                ATOMIC_CLEAR_USHORT (lockp->bl_next_ticket);
                    974:                ATOMIC_CLEAR_USHORT (lockp->bl_lock_holder);
                    975: #endif
                    976:        }
                    977: 
                    978:        return lockp;
                    979: }
                    980: 
                    981: 
                    982: /*
                    983:  *-STATUS:
                    984:  *     DDI/DKI
                    985:  *
                    986:  *-NAME:
                    987:  *     LOCK_DEALLOC () Deallocate an instance of a basic lock.
                    988:  *
                    989:  *-SYNOPSIS:
                    990:  *     #include <sys/ksynch.h>
                    991:  *
                    992:  *     void LOCK_DEALLOC (lock_t * lockp);
                    993:  *
                    994:  *-ARGUMENTS:
                    995:  *     lockp           Pointer to the basic lock to be deallocated.
                    996:  *
                    997:  *-DESCRIPTION:
                    998:  *     LOCK_DEALLOC () deallocates the basic lock specified by "lockp".
                    999:  *
                   1000:  *-RETURN VALUE:
                   1001:  *     None.
                   1002:  *
                   1003:  *-LEVEL:
                   1004:  *     Base or Interrupt.
                   1005:  *
                   1006:  *-NOTES:
                   1007:  *     Does not sleep.
                   1008:  *
                   1009:  *     Attempting to deallocate a lock that is currently locked or is being
                   1010:  *     waited for is an error and will result in undefined behavior.
                   1011:  *
                   1012:  *     Driver-defined basic locks (other than the one being deallocated),
                   1013:  *     read/write locks and sleep locks may be held across calls to this
                   1014:  *     function.
                   1015:  *
                   1016:  *-SEE ALSO:
                   1017:  *     LOCK (), LOCK_ALLOC (), TRYLOCK (), UNLOCK ()
                   1018:  */
                   1019: 
                   1020: #if    __USE_PROTO__
                   1021: void (LOCK_DEALLOC) (lock_t * lockp)
                   1022: #else
                   1023: void
                   1024: LOCK_DEALLOC __ARGS ((lockp))
                   1025: lock_t       * lockp;
                   1026: #endif
                   1027: {
                   1028:        ASSERT (lockp != NULL);
                   1029:        ASSERT (ATOMIC_FETCH_UCHAR (lockp->bl_locked) == 0);
                   1030: 
                   1031: #ifdef __TICKET_LOCK__
                   1032:        ASSERT (ATOMIC_FETCH_USHORT (lockp->bl_next_ticket) ==
                   1033:                ATOMIC_FETCH_USHORT (lockp->bl_lock_holder));
                   1034: #endif
                   1035: 
                   1036:        /*
                   1037:         * Remove from the list of all basic locks and free any statistics
                   1038:         * buffer space before freeing the lock itself.
                   1039:         */
                   1040: 
                   1041:        FREE_LNODE (& lockp->bl_node, & basic_locks);
                   1042: 
                   1043:        _lock_free (lockp, sizeof (* lockp));
                   1044: }
                   1045: 
                   1046: 
                   1047: /*
                   1048:  *-STATUS:
                   1049:  *     DDI/DKI
                   1050:  *
                   1051:  *-NAME:
                   1052:  *     LOCK ()         Acquire a basic lock
                   1053:  *
                   1054:  *-SYNOPSIS:
                   1055:  *     #include <sys/types.h>
                   1056:  *     #include <sys/ksynch.h>
                   1057:  *
                   1058:  *     pl_t LOCK (lock_t * lockp, pl_t pl);
                   1059:  *
                   1060:  *-ARGUMENTS:
                   1061:  *     lockp           Pointer to the basic lock to be acquired.
                   1062:  *
                   1063:  *     pl              The interrupt priority level to be set while the lock
                   1064:  *                     is held by the caller. Because some implementations
                   1065:  *                     require that interrupts that might attempt to acquire
                   1066:  *                     the lock be blocked on which the lock is held,
                   1067:  *                     portable drivers must specify a "pl" value that is
                   1068:  *                     sufficient to block out any interrupt handler that
                   1069:  *                     might attempt to acquire this lock. See the
                   1070:  *                     description of the "min_pl" argument to LOCK_ALLOC ()
                   1071:  *                     for additional discussion. Implementations that do
                   1072:  *                     not require that the interrupt priority level be
                   1073:  *                     raised during lock acquisition may choose to ignore
                   1074:  *                     this argument.
                   1075:  *
                   1076:  *-DESCRIPTION:
                   1077:  *     LOCK () sets the interrupt priority level in accordance with the
                   1078:  *     value specified by "pl" (if required by the implementation) and
                   1079:  *     acquires the lock specified by "lockp". If the lock is not currently
                   1080:  *     available, the caller will wait until the lock is available. It is
                   1081:  *     implementation-defined whether the caller will block during the wait.
                   1082:  *     Some implementations may cause the caller to spin for the duration of
                   1083:  *     the wait, while on others the caller may block at some point.
                   1084:  *
                   1085:  *-RETURN VALUE:
                   1086:  *     Upon acquiring the lock, LOCK () returns the previous interrupt
                   1087:  *     priority level.
                   1088:  *
                   1089:  *-LEVEL:
                   1090:  *     Base or Interrupt.
                   1091:  *
                   1092:  *-NOTES:
                   1093:  *     Basic locks are not recursive. A call to LOCK () attempting to
                   1094:  *     acquire a lock that is already held by the calling context will
                   1095:  *     result in deadlock.
                   1096:  *
                   1097:  *     Calls to LOCK () should honor the ordering defined by the lock
                   1098:  *     hierarchy [see LOCK_ALLOC ()] in order to avoid deadlock.
                   1099:  *
                   1100:  *     Driver-defined sleep locks may be held across calls to this function.
                   1101:  *
                   1102:  *     Driver-defined basic locks and read/write locks may be held across
                   1103:  *     calls to this function subject to the hierarchy and recursion
                   1104:  *     restrictions described above.
                   1105:  *
                   1106:  *     When called from interrupt level, the "pl" argument must not specify
                   1107:  *     a priority below the level at which the interrupt handler is running.
                   1108:  *
                   1109:  *-SEE ALSO:
                   1110:  *     LOCK_ALLOC (), LOCK_DEALLOC (), TRYLOCK (), UNLOCK ()
                   1111:  */
                   1112: 
                   1113: #if    __USE_PROTO__
                   1114: pl_t (LOCK) (lock_t * lockp, pl_t pl)
                   1115: #else
                   1116: pl_t
                   1117: LOCK __ARGS ((lockp, pl))
                   1118: lock_t       * lockp;
                   1119: pl_t           pl;
                   1120: #endif
                   1121: {
                   1122:        pl_t            prev_pl;
                   1123: #ifdef __TICKET_LOCK__
                   1124:        ushort_t        ticket_no;
                   1125: #endif
                   1126: 
                   1127:        ASSERT (lockp != NULL);
                   1128:        ASSERT (splcmp (pl, plhi) <= 0);
                   1129: 
                   1130: 
                   1131:        /*
                   1132:         * Enforce minimum-priority assertion, pl >= lockp->bl_min_pl. Note
                   1133:         * that splcmp () abstracts subtraction-for-comparison of priority
                   1134:         * levels, which explains the form of the assertion.
                   1135:         */
                   1136: 
                   1137:        ASSERT (splcmp (pl, lockp->bl_min_pl) >= 0);
                   1138: 
                   1139: 
                   1140:        /*
                   1141:         * On a uniprocessor, encountering a basic lock that is already
                   1142:         * locked is *always* an error, even on machines with many different
                   1143:         * interrupt priority levels. The hierarchy-assertion mechanism
                   1144:         * cannot always deal with this, since TRYLOCK () can acquire locks
                   1145:         * in a different order.
                   1146:         *
                   1147:         * On a multiprocessor, we can just spin here. Note that since LOCK ()
                   1148:         * is defined as requiring values of "pl" greater than the current
                   1149:         * interrupt priority level, the use of splraise () by
                   1150:         * TEST_AND_SET_LOCK () is legitimate.
                   1151:         */
                   1152: 
                   1153:        prev_pl = TEST_AND_SET_LOCK (lockp->bl_locked, pl, "LOCK");
                   1154: 
                   1155: #ifdef __TICKET_LOCK__
                   1156:        /*
                   1157:         * If we are working with a ticket-lock scheme, we now take a ticket
                   1158:         * and release the test-and-set lock. After that, we can just wait for
                   1159:         * our number to come up...
                   1160:         */
                   1161: 
                   1162:        ticket_no = ATOMIC_FETCH_USHORT (lockp->bl_next_ticket);
                   1163: 
                   1164:        if (ATOMIC_FETCH_AND_STORE_USHORT (lockp->bl_next_ticket,
                   1165:                                           ticket_no + 1) != ticket_no) {
                   1166:                /*
                   1167:                 * If we didn't read the same number twice, then the basic
                   1168:                 * lock protection isn't doing its job.
                   1169:                 */
                   1170: 
                   1171:                cmn_err (CE_PANIC, "LOCK : Ticket-lock gate failure");
                   1172:        }
                   1173: 
                   1174:        ATOMIC_CLEAR_UCHAR (lockp->bl_locked);
                   1175: 
                   1176:        while (ATOMIC_FETCH_USHORT (lockp->bl_lock_holder) != ticket_no) {
                   1177:                /*
                   1178:                 * At this point we might want to implement some form of
                   1179:                 * proportional backoff to reduce memory traffic. Later.
                   1180:                 *
                   1181:                 * Another hot contender for this spot is detecting failures
                   1182:                 * on other CPUs...
                   1183:                 */
                   1184: 
                   1185: #ifdef __UNIPROCESSOR__
                   1186:                cmn_err (CE_PANIC, "LOCK : deadlock on ticket");
                   1187: #endif
                   1188:        }
                   1189: 
                   1190: #endif /* defined (__TICKET_LOCK__) */
                   1191: 
                   1192: 
                   1193:        /*
                   1194:         * Now would be an appropriate time to check that the requested level
                   1195:         * is >= the current level on entry. The architectures that we are
                   1196:         * likely to target require this to be true, although some novel
                   1197:         * schemes which reduce interrupt latency do not.
                   1198:         *
                   1199:         * Since the TEST_AND_SET_LOCK () function which set our priority
                   1200:         * level uses splraise (), we are safe making this test at this late
                   1201:         * stage.
                   1202:         */
                   1203: 
                   1204:        ASSERT (splcmp (pl, prev_pl) >= 0);
                   1205: 
                   1206: 
                   1207:        /*
                   1208:         * Test the lock-acquisition-hierarchy assertions.
                   1209:         */
                   1210: 
                   1211:        ASSERT (ddi_cpu_data ()->dc_max_hierarchy < lockp->bl_hierarchy);
                   1212: 
                   1213:        LOCK_COUNT_HIERARCHY (lockp->bl_hierarchy);
                   1214: 
                   1215: 
                   1216:        /*
                   1217:         * Since it may be useful for post-mortem debugging to record some
                   1218:         * information about the context which acquired the lock, we defer
                   1219:         * to some generic recorder function or macro.
                   1220:         *
                   1221:         * Note that in general it does not appear to be possible to make
                   1222:         * detailed assertions about the relation between the contexts in
                   1223:         * which a lock is acquired and/or released. In particular, it
                   1224:         * might be possible for a basic lock to be tied to some device
                   1225:         * hardware-related operation where a lock might be acquired on one
                   1226:         * CPU and released on another.
                   1227:         *
                   1228:         * In addition, any lock statistics are kept by this operation.
                   1229:         */
                   1230: 
                   1231:        TRACE_BASIC_LOCK (lockp);
                   1232: 
                   1233:        return prev_pl;
                   1234: }
                   1235: 
                   1236: 
                   1237: /*
                   1238:  *-STATUS:
                   1239:  *     DDI/DKI
                   1240:  *
                   1241:  *-NAME:
                   1242:  *     TRYLOCK ()      Try to acquire a basic lock
                   1243:  *
                   1244:  *-SYNOPSIS:
                   1245:  *     #include <sys/types.h>
                   1246:  *     #include <sys/ksynch.h>
                   1247:  *
                   1248:  *     pl_t TRYLOCK (lock_t * lockp, pl_t pl);
                   1249:  *
                   1250:  *-ARGUMENTS:
                   1251:  *     lockp           Pointer to the basic lock to be acquired.
                   1252:  *
                   1253:  *     pl              The interrupt priority level to be set while the lock
                   1254:  *                     is held by the caller. Because some implementations
                   1255:  *                     require that interrupts that might attempt to acquire
                   1256:  *                     the lock be blocked on the processor on which the
                   1257:  *                     lock is held, portable drivers must specify a "pl"
                   1258:  *                     value that is sufficient to block out and interrupt
                   1259:  *                     handler that might attempt to acquire this lock. See
                   1260:  *                     the description of LOCK_ALLOC () for additional
                   1261:  *                     discussion and a list of the valid values for "pl".
                   1262:  *                     Implementations that do not require that the interrupt
                   1263:  *                     priority level be raised during lock acquisition may
                   1264:  *                     choose to ignore this argument.
                   1265:  *
                   1266:  *-DESCRIPTION:
                   1267:  *     If the lock specified by "lockp" is immediately available (can be
                   1268:  *     acquired without waiting) TRYLOCK () sets the interrupt priority level
                   1269:  *     in accordance with the value specified by "pl" (if required by the
                   1270:  *     implementation) and acquires the lock. If the lock is not immediately
                   1271:  *     available, the function returns without acquiring the lock.
                   1272:  *
                   1273:  *-RETURN VALUE:
                   1274:  *     If the lock is acquired, TRYLOCK () returns the previous interrupt
                   1275:  *     priority level ("plbase" - "plhi"). If the lock is not acquired the
                   1276:  *     value "invpl" is returned.
                   1277:  *
                   1278:  *-LEVEL:
                   1279:  *     Base or Interrupt.
                   1280:  *
                   1281:  *-NOTES:
                   1282:  *     Does not sleep.
                   1283:  *
                   1284:  *     TRYLOCK () may be used to acquire a lock in a different order from
                   1285:  *     the order defined by the lock hierarchy.
                   1286:  *
                   1287:  *     Driver-defined basic locks, read/write locks, and sleep locks may be
                   1288:  *     held across calls to this function.
                   1289:  *
                   1290:  *     When called from interrupt level, the "pl" argument must not specify
                   1291:  *     a priority level below the level at which the interrupt handler is
                   1292:  *     running.
                   1293:  *
                   1294:  *-SEE ALSO:
                   1295:  *     LOCK (), LOCK_ALLOC (), LOCK_DEALLOC (), UNLOCK ()
                   1296:  */
                   1297: 
                   1298: #if    __USE_PROTO__
                   1299: pl_t (TRYLOCK) (lock_t * lockp, pl_t pl)
                   1300: #else
                   1301: pl_t
                   1302: TRYLOCK __ARGS ((lockp, pl))
                   1303: lock_t       * lockp;
                   1304: pl_t           pl;
                   1305: #endif
                   1306: {
                   1307:        pl_t            prev_pl;
                   1308: #ifdef __TICKET_LOCK__
                   1309:        ushort_t        ticket_no;
                   1310: #endif
                   1311: 
                   1312:        ASSERT (lockp != NULL);
                   1313:        ASSERT (splcmp (pl, plhi) <= 0);
                   1314: 
                   1315: 
                   1316:        /*
                   1317:         * Enforce minimum-priority assertion, pl >= lockp->bl_min_pl. Note
                   1318:         * that splcmp () abstracts subtraction-for-comparison of priority
                   1319:         * levels, which explains the form of the assertion.
                   1320:         */
                   1321: 
                   1322:        ASSERT (splcmp (pl, lockp->bl_min_pl) >= 0);
                   1323: 
                   1324: 
                   1325: #ifdef __TICKET_LOCK__
                   1326:        /*
                   1327:         * If this is a ticket-lock, we test the ticket numbers to see
                   1328:         * whether there is any reason to even try acquiring the test-and-set
                   1329:         * lock that forms the ticket gate.
                   1330:         *
                   1331:         * We read the "lock holder" and "next ticket" entries in that
                   1332:         * sequence to be pessimistic, since we can assume that other CPUs
                   1333:         * might be looking at this...
                   1334:         */
                   1335: 
                   1336:        ticket_no = ATOMIC_FETCH_USHORT (lockp->bl_lock_holder);
                   1337: 
                   1338:        if (ticket_no != ATOMIC_FETCH_USHORT (lockp->bl_next_ticket))
                   1339:                return invpl;
                   1340: #endif
                   1341: 
                   1342: 
                   1343:        /*
                   1344:         * We block out interrupts at this point to allow the following
                   1345:         * operations room to do their stuff in, since interrupts at an
                   1346:         * inappropriate moment can cause deadlock... of course, if the
                   1347:         * definition of the lock is such that interrupts can proceed, then
                   1348:         * that's OK, since the lock acquisition is atomic.
                   1349:         */
                   1350: 
                   1351:        prev_pl = splx (pl);
                   1352: 
                   1353: 
                   1354:        /*
                   1355:         * Now would be an appropriate time to check that the
                   1356:         * requested level is >= the current level on entry. Strictly
                   1357:         * speaking, this does not have to be true if the processor is
                   1358:         * currently at base level, but for now we'll discourage that
                   1359:         * behaviour.
                   1360:         */
                   1361: 
                   1362:        ASSERT (splcmp (pl, prev_pl) >= 0);
                   1363: 
                   1364: 
                   1365:        /*
                   1366:         * Test to see whether the lock in question is already taken, and if
                   1367:         * not, we take it. We don't spin if this is a ticket lock, since if
                   1368:         * the basic lock is taken there is *no way* that the lock will be
                   1369:         * free for us immediately.
                   1370:         */
                   1371: 
                   1372:        if (ATOMIC_TEST_AND_SET_UCHAR (lockp->bl_locked) == 0) {
                   1373: #ifdef __TICKET_LOCK__
                   1374:                /*
                   1375:                 * If this is a ticket lock, now would be a good time to
                   1376:                 * check the ticket numbers to ensure that the lock *really*
                   1377:                 * is free.
                   1378:                 */
                   1379: 
                   1380:                ticket_no = ATOMIC_FETCH_USHORT (lockp->bl_next_ticket);
                   1381: 
                   1382:                if (ticket_no != ATOMIC_FETCH_USHORT (lockp->bl_lock_holder)) {
                   1383: 
                   1384:                        ATOMIC_CLEAR_UCHAR (lockp->bl_locked);
                   1385:                        goto try_failed;
                   1386:                }
                   1387: 
                   1388:                if (ATOMIC_FETCH_AND_STORE_USHORT (lockp->bl_next_ticket,
                   1389:                                                   ticket_no + 1) != ticket_no) {
                   1390:                        /*
                   1391:                         * If we didn't read the same number twice, then the
                   1392:                         * test-and-set lock protection isn't doing its job.
                   1393:                         */
                   1394: 
                   1395:                        cmn_err (CE_PANIC, "TRYLOCK : Ticket-lock gate failure");
                   1396:                }
                   1397: 
                   1398: 
                   1399:                /*
                   1400:                 * Now we have the lock, we can release the ticket-gate lock.
                   1401:                 */
                   1402: 
                   1403:                ATOMIC_CLEAR_UCHAR (lockp->bl_locked);
                   1404: 
                   1405: #endif /* defined (__TICKET_LOCK__) */
                   1406: 
                   1407: 
                   1408:                /*
                   1409:                 * TRYLOCK () bypasses the hierarchy-assertion mechanism,
                   1410:                 * although we record the maximum acquired hierarchy level for
                   1411:                 * maximum strictness checking in inner LOCK () attempts.
                   1412:                 *
                   1413:                 * We also record debugging and statistics information here
                   1414:                 * with TRACE_BASIC_LOCK ().
                   1415:                 */
                   1416: 
                   1417:                LOCK_COUNT_HIERARCHY (lockp->bl_hierarchy);
                   1418: 
                   1419:                TRACE_BASIC_LOCK (lockp);
                   1420: 
                   1421:                return prev_pl;
                   1422:        }
                   1423: 
                   1424: try_failed:
                   1425:        /*
                   1426:         * We cannot acquire the lock, so reset the priority and exit with
                   1427:         * the flag value.
                   1428:         */
                   1429: 
                   1430:        (void) splx (prev_pl);
                   1431: 
                   1432:        return invpl;
                   1433: }
                   1434: 
                   1435: 
                   1436: /*
                   1437:  *-STATUS:
                   1438:  *     DDI/DKI
                   1439:  *
                   1440:  *-NAME:
                   1441:  *     UNLOCK ()       Release a basic lock.
                   1442:  *
                   1443:  *-SYNOPSIS:
                   1444:  *     #include <sys/types.h>
                   1445:  *     #include <sys/ksynch.h>
                   1446:  *
                   1447:  *     void UNLOCK (lock_t * lockp, pl_t pl);
                   1448:  *
                   1449:  *-ARGUMENTS:
                   1450:  *     lockp           Pointer to the basic lock to be released.
                   1451:  *
                   1452:  *     pl              The interrupt priority level to be set after releasing
                   1453:  *                     the lock. See the description of the "min_pl" argument
                   1454:  *                     to LOCK_ALLOC () for a list of the valid values for
                   1455:  *                     "pl". If lock calls are not being nested or if the
                   1456:  *                     caller is unlocking in the reverse order that locks
                   1457:  *                     were acquired, the "pl" argument will typically be the
                   1458:  *                     value that was returned from the corresponding call to
                   1459:  *                     acquire the lock. The caller may need to specify a
                   1460:  *                     different value for "pl" if nested locks are being
                   1461:  *                     released in some order other that the reverse order of
                   1462:  *                     acquisition, so as to ensure that the interrupt
                   1463:  *                     priority level is kept sufficiently high to block
                   1464:  *                     interrupt code that might attempt to acquire locks
                   1465:  *                     which are still held. Although portable drivers must
                   1466:  *                     always specify an appropriate "pl" argument,
                   1467:  *                     implementations which do not require that the
                   1468:  *                     interrupt priority level be raised during lock
                   1469:  *                     acquisition may choose to ignore this argument.
                   1470:  *
                   1471:  *-DESCRIPTION:
                   1472:  *     UNLOCK () releases the basic lock specified by "lockp" and then sets
                   1473:  *     the interrupt priority level in accordance with the value specified by
                   1474:  *     "pl" (if required by the implementation).
                   1475:  *
                   1476:  *-RETURN VALUE:
                   1477:  *     None.
                   1478:  *
                   1479:  *-LEVEL:
                   1480:  *     Base or Interrupt.
                   1481:  *
                   1482:  *-NOTES:
                   1483:  *     Does not sleep.
                   1484:  *
                   1485:  *     Driver-defined basic locks, read/write locks, and sleep locks may be
                   1486:  *     held across calls to this function.
                   1487:  *
                   1488:  *-SEE ALSO:
                   1489:  *     LOCK (), LOCK_ALLOC (), LOCK_DEALLOC (), TRYLOCK ()
                   1490:  */
                   1491: 
                   1492: #if    __USE_PROTO__
                   1493: void (UNLOCK) (lock_t * lockp, pl_t pl)
                   1494: #else
                   1495: void
                   1496: UNLOCK __ARGS ((lockp, pl))
                   1497: lock_t       * lockp;
                   1498: pl_t           pl;
                   1499: #endif
                   1500: {
                   1501: #ifdef __TICKET_LOCK__
                   1502:        ushort_t        ticket_no;
                   1503: #endif
                   1504: 
                   1505:        ASSERT (lockp != NULL);
                   1506:        ASSERT (splcmp (plbase, pl) <= 0 && splcmp (pl, plhi) <= 0);
                   1507: 
                   1508: 
                   1509:        /*
                   1510:         * We assert that the lock is actually held by someone... in the case
                   1511:         * of the ticket lock, we fetch the ticket number now since we don't
                   1512:         * have an increment instruction and we'll need it later anyway.
                   1513:         */
                   1514: 
                   1515: #ifdef __TICKET_LOCK__
                   1516:        ticket_no = ATOMIC_FETCH_USHORT (lockp->bl_lock_holder);
                   1517: 
                   1518:        ASSERT (ticket_no != ATOMIC_FETCH_USHORT (lockp->bl_next_ticket));
                   1519: #else
                   1520:        ASSERT (ATOMIC_FETCH_UCHAR (lockp->bl_locked) != 0);
                   1521: #endif
                   1522: 
                   1523:        /*
                   1524:         * Do whatever we need to do to undo the hierarchy-assertion and
                   1525:         * debugging/statistics data structures.
                   1526:         */
                   1527: 
                   1528:        LOCK_FREE_HIERARCHY (lockp->bl_hierarchy);
                   1529: 
                   1530:        UNTRACE_BASIC_LOCK (lockp);
                   1531: 
                   1532: 
                   1533:        /*
                   1534:         * Now release the lock, either to the next ticket-holder or to
                   1535:         * whoever gets in first, depending on the locking system.
                   1536:         */
                   1537: 
                   1538: #ifdef __TICKET_LOCK__
                   1539:        if (ATOMIC_FETCH_AND_STORE_USHORT (lockp->bl_lock_holder,
                   1540:                                           ticket_no + 1) != ticket_no) {
                   1541:                /*
                   1542:                 * If we didn't read the same number twice, then someone has
                   1543:                 * released the lock that we own!
                   1544:                 */
                   1545: 
                   1546:                cmn_err (CE_PANIC, "UNLOCK : Ticket-lock sequence problem");
                   1547:        }
                   1548: #else
                   1549:        ATOMIC_CLEAR_UCHAR (lockp->bl_locked);
                   1550: #endif
                   1551: 
                   1552:        /*
                   1553:         * And lower out priority level to finish up.
                   1554:         */
                   1555: 
                   1556:        (void) splx (pl);
                   1557: }
                   1558: 
                   1559: 
                   1560: /*
                   1561:  *-STATUS:
                   1562:  *     DDI/DKI
                   1563:  *
                   1564:  *-NAME:
                   1565:  *     RW_ALLOC ()     Allocate and initialize a read/write lock
                   1566:  *
                   1567:  *-SYNOPSIS:
                   1568:  *     #include <sys/types.h>
                   1569:  *     #include <sys/kmem.h>
                   1570:  *     #include <sys/ksynch.h>
                   1571:  *
                   1572:  *     rwlock_t * RW_ALLOC (uchar_t hierarchy, pl_t min_pl,
                   1573:  *                          lkinfo_t * lkinfop, int flag);
                   1574:  *
                   1575:  *-ARGUMENTS:
                   1576:  *     hierarchy       Hierarchy value which asserts the order in which this
                   1577:  *                     lock will be acquired relative to other basic and
                   1578:  *                     read/write locks. "hierarchy" must be within the range
                   1579:  *                     of 1 through 32 inclusive and must be chosen such that
                   1580:  *                     locks are normally acquired in order of increasing
                   1581:  *                     "hierarchy" number. In other words, when acquiring a
                   1582:  *                     basic lock using any function other than
                   1583:  *                     RW_TRYRDLOCK () or RW_TRYWRLOCK () the lock being
                   1584:  *                     acquired must have a "hierarchy" value that is
                   1585:  *                     strictly greater than the "hierarchy" values
                   1586:  *                     associated with all locks currently held by the
                   1587:  *                     calling context.
                   1588:  *
                   1589:  *                     Implementations of lock testing may differ in whether
                   1590:  *                     they assume a separate range of "hierarchy" values for
                   1591:  *                     each interrupt priority level or a single range that
                   1592:  *                     spans all interrupt priority levels. In order to be
                   1593:  *                     portable across different implementations, drivers
                   1594:  *                     which may acquire locks at more than one interrupt
                   1595:  *                     priority level should define the "hierarchy" among
                   1596:  *                     those locks such that the "hierarchy" is strictly
                   1597:  *                     increasing with increasing priority level (eg. if M
                   1598:  *                     is the maximum "hierarchy" value defined for any lock
                   1599:  *                     that may be acquired at priority level N, then M + 1
                   1600:  *                     should be the minimum hierarchy value for any lock
                   1601:  *                     that may be acquired at any priority level greater
                   1602:  *                     than N).
                   1603:  *
                   1604:  *     min_pl          Minimum priority level argument which asserts the
                   1605:  *                     minimum priority leel that will be passed in with any
                   1606:  *                     attempt to acquire this lock [see RW_RDLOCK () and
                   1607:  *                     RW_WRLOCK ()]. Implementations which do not require
                   1608:  *                     that the interrupt priority level be raised during
                   1609:  *                     lock acquisition may choose not to enforce the
                   1610:  *                     "min_pl" assertion. The valid values for this
                   1611:  *                     argument are as follows:
                   1612:  *
                   1613:  *                       plbase        Block no interrupts
                   1614:  *                       pltimeout     Block functions scheduled by itimeout
                   1615:  *                                     and dtimeout
                   1616:  *                       pldisk        Block disk device interrupts
                   1617:  *                       plstr         Block STREAMS interrupts
                   1618:  *                       plhi          Block all interrupts
                   1619:  *
                   1620:  *                     The notion of a "min_pl" assumes a defined order of
                   1621:  *                     priority levels. The following partial order is
                   1622:  *                     defined:
                   1623:  *                       plbase < pltimeout <= pldisk, plstr <= plhi
                   1624:  *
                   1625:  *                     The ordering of pldisk and plstr relative to each
                   1626:  *                     other is not defined.
                   1627:  *
                   1628:  *                     Setting a given priority level will block interrupts
                   1629:  *                     associated with that level as well as all levels that
                   1630:  *                     are defined to be less than or equal to the specified
                   1631:  *                     level. In order to be portable a driver should not
                   1632:  *                     acquire locks at different priority levels where the
                   1633:  *                     relative order of those priority levels is not defined
                   1634:  *                     above.
                   1635:  *
                   1636:  *                     The "min_pl" argument should specify a priority level
                   1637:  *                     that would be sufficient to block out any interrupt
                   1638:  *                     handler that might attempt to acquire this lock. In
                   1639:  *                     addition, potential deadlock problems involving
                   1640:  *                     multiple locks should be considered when defining the
                   1641:  *                     "min_pl" value. For example, if the normal order of
                   1642:  *                     acquisition of locks A and B (as defined by the lock
                   1643:  *                     hierarchy) is to acquire A first and then B, lock B
                   1644:  *                     should never be acquired at a priority level less
                   1645:  *                     than the "min_pl" for lock A. Therefore, the "min_pl"
                   1646:  *                     for lock B should be greater than or equal to the
                   1647:  *                     "min_pl" for lock A.
                   1648:  *
                   1649:  *                     Note that the specification of a "min_pl" with a
                   1650:  *                     RW_ALLOC () call does not actually cause any
                   1651:  *                     interrupts to be blocked upon lock acquisition, it
                   1652:  *                     simply asserts that subsequent RW_RDLOCK () or
                   1653:  *                     RW_WRLOCK () calls to acquire this lock will pass in a
                   1654:  *                     priority level at least as great as "min_pl".
                   1655:  *
                   1656:  *     lkinfop         Pointer to a lkinfo structure. The lk_name member of
                   1657:  *                     the lkinfo structure points to a character string
                   1658:  *                     defining a name that will be associated with the lock
                   1659:  *                     for the purposes of statistics gathering. The name
                   1660:  *                     should begin with the driver prefix and should be
                   1661:  *                     unique to the lock or group of locks for which the
                   1662:  *                     driver wishes to collect a uniquely identifiable set
                   1663:  *                     of statistics (ie, if a given name is shared by a
                   1664:  *                     group of locks, the statistics of the individual locks
                   1665:  *                     within the group will not be uniquely identifiable).
                   1666:  *                     There are no flags within the lk_flags member of the
                   1667:  *                     lkinfo structure defined for use with RW_ALLOC ().
                   1668:  *
                   1669:  *                     A given lkinfo structure may be shared among multiple
                   1670:  *                     basic locks and read/write locks but a lkinfo
                   1671:  *                     structure may not be shared between a basic lock and
                   1672:  *                     a sleep lock. The called must ensure that the lk_flags
                   1673:  *                     and lk_pad members of the lkinfo structure are zeroed
                   1674:  *                     out before passing it to RW_ALLOC ().
                   1675:  *
                   1676:  *     flag            Specifies whether the caller is willing to sleep
                   1677:  *                     waiting for memory. If "flag" is set to KM_SLEEP, the
                   1678:  *                     caller will sleep if necessary until sufficient memory
                   1679:  *                     is available. If "flag" is set to KM_NOSLEEP, the
                   1680:  *                     caller will not sleep, but RW_ALLOC () will return
                   1681:  *                     NULL if sufficient memory is not immediately
                   1682:  *                     available.
                   1683:  *
                   1684:  *-DESCRIPTION:
                   1685:  *     RW_ALLOC () dynamically allocates and initialises an instance of a
                   1686:  *     read/write lock. The lock is initialised to the unlocked state.
                   1687:  *
                   1688:  *-RETURN VALUE:
                   1689:  *     Upon successful completion, RW_ALLOC () returns a pointer to the
                   1690:  *     newly allocated lock. If KM_NOSLEEP is specified and sufficient
                   1691:  *     memory is not immediately available, RW_ALLOC () returns a NULL
                   1692:  *     pointer.
                   1693:  *
                   1694:  *-LEVEL:
                   1695:  *     Base only if "flag" is set to KM_SLEEP. Base or Interrupt if "flag" is
                   1696:  *     set to KM_NOSLEEP.
                   1697:  *
                   1698:  *-NOTES:
                   1699:  *     May sleep if "flag" is set to KM_NOSLEEP.
                   1700:  *
                   1701:  *     Driver-defined basic locks and read/write locks may be held across
                   1702:  *     calls to this function if "flag" is set to KM_NOSLEEP but may not be
                   1703:  *     held if "flag" is KM_SLEEP.
                   1704:  *
                   1705:  *     Driver-defined sleep locks may be held across calls to this function
                   1706:  *     regardless of the value of "flag".
                   1707:  *
                   1708:  *-SEE_ALSO:
                   1709:  *     RW_DEALLOC (), RW_RDLOCK (), RW_TRYRDLOCK (), RW_TRYWRLOCK (),
                   1710:  *     RW_UNLOCK (), RW_WRLOCK (), lkinfo
                   1711:  */
                   1712: 
                   1713: #if    __USE_PROTO__
                   1714: rwlock_t * (RW_ALLOC) (__lkhier_t hierarchy, pl_t min_pl, lkinfo_t * lkinfop,
                   1715:                       int flag)
                   1716: #else
                   1717: rwlock_t *
                   1718: RW_ALLOC __ARGS ((hierarchy, min_pl, lkinfop, flag))
                   1719: __lkhier_t     hierarchy;
                   1720: pl_t           min_pl;
                   1721: lkinfo_t      *        lkinfop;
                   1722: int            flag;
                   1723: #endif
                   1724: {
                   1725:        rwlock_t      * lockp;
                   1726: 
                   1727:        ASSERT_HIERARCHY_OK (hierarchy, lkinfop);
                   1728:        ASSERT (splcmp (plbase, min_pl) <= 0 && splcmp (min_pl, plhi) <= 0);
                   1729:        ASSERT (flag == KM_SLEEP || flag == KM_NOSLEEP);
                   1730: 
                   1731: 
                   1732:        /*
                   1733:         * Allocate and initialise the data, possibly waiting for enough
                   1734:         * memory to become available.
                   1735:         */
                   1736: 
                   1737:        if ((lockp = (rwlock_t *) _lock_malloc (sizeof (* lockp),
                   1738:                                                flag)) != NULL) {
                   1739:                INIT_LNODE (& lockp->rw_node, lkinfop, & rw_locks, flag);
                   1740: 
                   1741:                lockp->rw_min_pl = min_pl;
                   1742:                lockp->rw_hierarchy = hierarchy;
                   1743: 
                   1744:                ATOMIC_CLEAR_UCHAR (lockp->rw_locked);
                   1745: 
                   1746:                ATOMIC_CLEAR_USHORT (lockp->rw_readers);
                   1747: 
                   1748:                ATOMIC_CLEAR_USHORT (lockp->rw_next_ticket);
                   1749:                ATOMIC_CLEAR_USHORT (lockp->rw_lock_holder);
                   1750:        }
                   1751: 
                   1752:        return lockp;
                   1753: }
                   1754: 
                   1755: 
                   1756: /*
                   1757:  *-STATUS:
                   1758:  *     DDI/DKI
                   1759:  *
                   1760:  *-NAME:
                   1761:  *     RW_DEALLOC ()   Deallocate an instance of a read/write lock.
                   1762:  *
                   1763:  *-SYNOPSIS:
                   1764:  *     #include <sys/ksynch.h>
                   1765:  *
                   1766:  *     void RW_DEALLOC (rwlock_t * lockp);
                   1767:  *
                   1768:  *-ARGUMENTS:
                   1769:  *     lockp           Pointer to the read/write lock to be deallocated.
                   1770:  *
                   1771:  *-DESCRIPTION:
                   1772:  *     RW_DEALLOC () deallocates the read/write lock specified by "lockp".
                   1773:  *
                   1774:  *-RETURN VALUE:
                   1775:  *     None.
                   1776:  *
                   1777:  *-LEVEL:
                   1778:  *     Base or Interrupt.
                   1779:  *
                   1780:  *-NOTES:
                   1781:  *     Does not sleep.
                   1782:  *
                   1783:  *     Attempting to deallocate a lock that is currently locked or is being
                   1784:  *     waited for is an error and will result in undefined behavior.
                   1785:  *
                   1786:  *     Driver-defined basic locks, read/write locks (other than the one being
                   1787:  *     deallocated), and sleep locks may be held across calls to this
                   1788:  *     function.
                   1789:  *
                   1790:  *-SEE_ALSO:
                   1791:  *     RW_ALLOC (), RW_RDLOCK (), RW_TRYRDLOCK (), RW_TRYWRLOCK (),
                   1792:  *     RW_UNLOCK (), RW_WRLOCK ()
                   1793:  */
                   1794: 
                   1795: #if    __USE_PROTO__
                   1796: void (RW_DEALLOC) (rwlock_t * lockp)
                   1797: #else
                   1798: void
                   1799: RW_DEALLOC __ARGS ((lockp))
                   1800: rwlock_t      *        lockp;
                   1801: #endif
                   1802: {
                   1803:        ASSERT (lockp != NULL);
                   1804:        ASSERT (ATOMIC_FETCH_UCHAR (lockp->rw_locked) == 0);
                   1805:        ASSERT (ATOMIC_FETCH_USHORT (lockp->rw_readers) == 0);
                   1806: 
                   1807:        ASSERT (ATOMIC_FETCH_USHORT (lockp->rw_next_ticket) ==
                   1808:                ATOMIC_FETCH_USHORT (lockp->rw_lock_holder));
                   1809: 
                   1810: 
                   1811:        /*
                   1812:         * Remove from the list of all read/write locks and free any
                   1813:         * statistics buffer space before freeing the lock itself.
                   1814:         */
                   1815: 
                   1816:        FREE_LNODE (& lockp->rw_node, & rw_locks);
                   1817: 
                   1818:        _lock_free (lockp, sizeof (* lockp));
                   1819: }
                   1820: 
                   1821: 
                   1822: /*
                   1823:  *-STATUS:
                   1824:  *     DDI/DKI
                   1825:  *
                   1826:  *-NAME:
                   1827:  *     RW_RDLOCK ()    Acquire a read/write lock in read mode.
                   1828:  *
                   1829:  *-SYNOPSIS:
                   1830:  *     #include <sys/types.h>
                   1831:  *     #include <sys/ksynch.h>
                   1832:  *
                   1833:  *     pl_t RW_RDLOCK (rwlock_t * lockp, pl_t pl);
                   1834:  *
                   1835:  *-ARGUMENTS:
                   1836:  *     lockp           Pointer to the read/write lock to be acquired.
                   1837:  *
                   1838:  *     pl              The interrupt priority level to be set while the lock
                   1839:  *                     is held by the caller. Because some implementations
                   1840:  *                     require that interrupts that might attempt to acquire
                   1841:  *                     the lock be blocked on which the lock is held,
                   1842:  *                     portable drivers must specify a "pl" value that is
                   1843:  *                     sufficient to block out any interrupt handler that
                   1844:  *                     might attempt to acquire this lock. See the
                   1845:  *                     description of the "min_pl" argument to RW_ALLOC ()
                   1846:  *                     for additional discussion. Implementations that do
                   1847:  *                     not require that the interrupt priority level be
                   1848:  *                     raised during lock acquisition may choose to ignore
                   1849:  *                     this argument.
                   1850:  *
                   1851:  *-DESCRIPTION:
                   1852:  *     RW_RDLOCK () sets the interrupt priority level in accordance with the
                   1853:  *     value specified by "pl" (if required by the implementation) and
                   1854:  *     acquires the lock specified by "lockp". If the lock is not currently
                   1855:  *     available, the caller will wait until the lock is available in read
                   1856:  *     mode. A read/write lock is available in read mode when the lock is
                   1857:  *     not held by any context or when the lock is held by one or more
                   1858:  *     readers and there are no waiting writers. It is implementation-defined
                   1859:  *     whether the caller will block during the wait. Some implementations
                   1860:  *     may cause the caller to spin for the duration of the wait, while on
                   1861:  *     others the caller may block at some point.
                   1862:  *
                   1863:  *-RETURN VALUE:
                   1864:  *     Upon acquiring the lock, RW_RDLOCK () returns the previous interrupt
                   1865:  *     priority level.
                   1866:  *
                   1867:  *-LEVEL:
                   1868:  *     Base or Interrupt.
                   1869:  *
                   1870:  *-NOTES:
                   1871:  *     Read/write locks are not recursive. A call to RW_RDLOCK () attempting
                   1872:  *     to acquire a lock that is already held by the calling context may
                   1873:  *     result in deadlock.
                   1874:  *
                   1875:  *     Calls to RD_RDLOCK () should honor the ordering defined by the lock
                   1876:  *     hierarchy [see RW_ALLOC ()] in order to avoid deadlock.
                   1877:  *
                   1878:  *     Driver-defined sleep locks may be held across calls to this function.
                   1879:  *
                   1880:  *     Driver-defined basic locks and read/write locks may be held across
                   1881:  *     calls to this function subject to the hierarchy and recursion
                   1882:  *     restrictions described above.
                   1883:  *
                   1884:  *     When called from interrupt level, the "pl" argument must not specify
                   1885:  *     a priority below the level at which the interrupt handler is running.
                   1886:  *
                   1887:  *-SEE_ALSO:
                   1888:  *     RW_ALLOC (), RW_DEALLOC (), RW_TRYRDLOCK (), RW_TRYWRLOCK (),
                   1889:  *     RW_UNLOCK (), RW_WRLOCK ()
                   1890:  */
                   1891: 
                   1892: #if    __USE_PROTO__
                   1893: pl_t (RW_RDLOCK) (rwlock_t * lockp, pl_t pl)
                   1894: #else
                   1895: pl_t
                   1896: RW_RDLOCK __ARGS ((lockp, pl))
                   1897: rwlock_t      *        lockp;
                   1898: pl_t           pl;
                   1899: #endif
                   1900: {
                   1901:        pl_t            prev_pl;
                   1902:        ushort_t        ticket_no;
                   1903: 
                   1904:        ASSERT (lockp != NULL);
                   1905:        ASSERT (splcmp (pl, plhi) <= 0);
                   1906: 
                   1907: 
                   1908:        /*
                   1909:         * Enforce minimum-priority assertion, pl >= lockp->rw_min_pl. Note
                   1910:         * that splcmp () abstracts subtraction-for-comparison of priority
                   1911:         * levels, which explains the form of the assertion.
                   1912:         */
                   1913: 
                   1914:        ASSERT (splcmp (pl, lockp->rw_min_pl) >= 0);
                   1915: 
                   1916: 
                   1917:        /*
                   1918:         * On a uniprocessor, encountering a read/write lock that is already
                   1919:         * locked is *always* an error, even on machines with many different
                   1920:         * interrupt priority levels. The hierarchy-assertion mechanism
                   1921:         * cannot always deal with this, since RW_TRYRDLOCK () can acquire
                   1922:         * locks in a different order.
                   1923:         *
                   1924:         * On a multiprocessor, we can just spin here.
                   1925:         */
                   1926: 
                   1927:        for (;;) {
                   1928: 
                   1929: 
                   1930:                /*
                   1931:                 * We block out merely the necessary interrupts at this point;
                   1932:                 * we don't need a blanket interrupt blockage since the lock
                   1933:                 * system works as atomically as possible.
                   1934:                 */
                   1935: 
                   1936:                prev_pl = splx (pl);
                   1937: 
                   1938:                if (ATOMIC_TEST_AND_SET_UCHAR (lockp->rw_locked) == 0) {
                   1939:                        /*
                   1940:                         * Now we have acquired the test-and-set part, see
                   1941:                         * if there are any waiting writers preventing us
                   1942:                         * from acquiring a shared read lock.
                   1943:                         *
                   1944:                         * We read the "lock holder" and "next ticket" entries
                   1945:                         * in that sequence to be pessimistic, since we can
                   1946:                         * assume that other CPUs might be writing to this...
                   1947:                         */
                   1948: 
                   1949:                        ticket_no = ATOMIC_FETCH_USHORT (lockp->rw_lock_holder);
                   1950: 
                   1951:                        if (ticket_no == ATOMIC_FETCH_USHORT (lockp->rw_next_ticket))
                   1952:                                break;
                   1953: 
                   1954:                        /*
                   1955:                         * The read/write lock is held exclusively, release
                   1956:                         * the test-and-set sub-lock.
                   1957:                         */
                   1958: 
                   1959:                        ATOMIC_CLEAR_UCHAR (lockp->rw_locked);
                   1960:                }
                   1961: 
                   1962:                /*
                   1963:                 * We can return the interrupt priority to whatever it was
                   1964:                 * upon entry to this routine since we can't acquire the
                   1965:                 * initial test-and-set lock.
                   1966:                 */
                   1967: 
                   1968:                (void) splx (prev_pl);
                   1969: 
                   1970: #ifdef __UNIPROCESSOR__
                   1971:                cmn_err (CE_PANIC, "RW_RDLOCK : deadlock!");
                   1972: #elif  defined (__TEST_AND_TEST__)
                   1973:                /*
                   1974:                 * In order to reduce contention on the test-and-set part of
                   1975:                 * the read/write lock, we defer attempting to acquire that
                   1976:                 * lock until there appear to be no waiting writers, and until
                   1977:                 * the test-and-set lock is free before attempting to re-
                   1978:                 * acquire it. Of course, more sophisticated backoff schemes
                   1979:                 * might also help this approach.
                   1980:                 */
                   1981: 
                   1982:                do {
                   1983:                        /*
                   1984:                         * We use this idiom to ensure that the lock holder
                   1985:                         * item is read before the next ticket item for
                   1986:                         * maximum pessimism.
                   1987:                         */
                   1988: 
                   1989:                        ticket_no = ATOMIC_FETCH_USHORT (lockp->rw_lock_holder);
                   1990: 
                   1991:                } while (ticket_no !=
                   1992:                            ATOMIC_FETCH_USHORT (lockp->rw_next_ticket) ||
                   1993:                         ATOMIC_FETCH_UCHAR (lockp->rw_locked) != 0);
                   1994: #endif
                   1995:        }
                   1996: 
                   1997: 
                   1998:        /*
                   1999:         * There are no waiting writers yet, so acquire the lock in read mode
                   2000:         * by incrementing the count of readers.
                   2001:         */
                   2002: 
                   2003:        ticket_no = ATOMIC_FETCH_USHORT (lockp->rw_readers);
                   2004: 
                   2005:        if (ATOMIC_FETCH_AND_STORE_USHORT (lockp->rw_readers, ticket_no + 1)
                   2006:            != ticket_no) {
                   2007:                /*
                   2008:                 * If we didn't read the same number twice, then the
                   2009:                 * test-and-set lock protection isn't doing its job.
                   2010:                 */
                   2011: 
                   2012:                cmn_err (CE_PANIC, "RW_RDLOCK : lock increment failure");
                   2013:        }
                   2014: 
                   2015: 
                   2016: #if 0
                   2017: #ifdef __UNIPROCESSOR__
                   2018:        if (ticket_no != 0)
                   2019:                cmn_err (CE_WARN, "RW_RDLOCK : Recursive read-lock attempt");
                   2020: #endif
                   2021: #endif
                   2022: 
                   2023:        /*
                   2024:         * And allow other CPUs to try and acquire tickets or increment the
                   2025:         * reader count by releasing the test-and-set lock.
                   2026:         */
                   2027: 
                   2028:        ATOMIC_CLEAR_UCHAR (lockp->rw_locked);
                   2029: 
                   2030: 
                   2031:        /*
                   2032:         * Here we check and maintain the hierarchy assertions, and record
                   2033:         * any required debugging/statistics information about the lock.
                   2034:         */
                   2035: 
                   2036:        LOCK_COUNT_HIERARCHY (lockp->rw_hierarchy);
                   2037: 
                   2038:        TRACE_RW_LOCK (lockp);
                   2039: 
                   2040: 
                   2041:        /*
                   2042:         * Now would be an appropriate time to check that the requested level
                   2043:         * is >= the current level on entry. Strictly speaking, this does not
                   2044:         * have to be true if the processor is currently at base level, but
                   2045:         * for now we'll discourage that behaviour.
                   2046:         */
                   2047: 
                   2048:        ASSERT (splcmp (pl, prev_pl) >= 0);
                   2049: 
                   2050:        return prev_pl;
                   2051: }
                   2052: 
                   2053: 
                   2054: /*
                   2055:  *-STATUS:
                   2056:  *     DDI/DKI
                   2057:  *
                   2058:  *-NAME:
                   2059:  *     RW_TRYRDLOCK () Try to acquire a read/write lock in read mode.
                   2060:  *
                   2061:  *-SYNOPSIS:
                   2062:  *     #include <sys/types.h>
                   2063:  *     #include <sys/ksynch.h>
                   2064:  *
                   2065:  *     pl_t RW_TRYRDLOCK (rwlock_t * lockp, pl_t pl);
                   2066:  *
                   2067:  *-ARGUMENTS:
                   2068:  *     lockp           Pointer to the read/write lock to be acquired.
                   2069:  *
                   2070:  *     pl              The interrupt priority level to be set while the lock
                   2071:  *                     is held by the caller. Because some implementations
                   2072:  *                     require that interrupts that might attempt to acquire
                   2073:  *                     the lock be blocked on the processor on which the
                   2074:  *                     lock is held, portable drivers must specify a "pl"
                   2075:  *                     value that is sufficient to block out and interrupt
                   2076:  *                     handler that might attempt to acquire this lock. See
                   2077:  *                     the description of RW_ALLOC () for additional
                   2078:  *                     discussion and a list of the valid values for "pl".
                   2079:  *                     Implementations that do not require that the interrupt
                   2080:  *                     priority level be raised during lock acquisition may
                   2081:  *                     choose to ignore this argument.
                   2082:  *
                   2083:  *-DESCRIPTION:
                   2084:  *     If the lock specified by "lockp" is immediately available in read mode
                   2085:  *     (there is not a writer holding the lock and there are no waiting
                   2086:  *     writers) RW_TRYRDLOCK () sets the interrupt priority level in
                   2087:  *     accordance with the value specified by "pl" (if required by the
                   2088:  *     implementation) and acquires the lock in read mode. If the lock is not
                   2089:  *     immediately available in read mode, the function returns without
                   2090:  *     acquiring the lock.
                   2091:  *
                   2092:  *-RETURN VALUE:
                   2093:  *     If the lock is acquired, RW_TRYRDLOCK () returns the previous
                   2094:  *     interrupt priority level ("plbase" - "plhi"). If the lock is not
                   2095:  *     acquired the value "invpl" is returned.
                   2096:  *
                   2097:  *-LEVEL:
                   2098:  *     Base or Interrupt.
                   2099:  *
                   2100:  *-NOTES:
                   2101:  *     Does not sleep.
                   2102:  *
                   2103:  *     RW_TRYRDLOCK () may be used to acquire a lock in a different order
                   2104:  *     from the order defined by the lock hierarchy.
                   2105:  *
                   2106:  *     Driver-defined basic locks, read/write locks, and sleep locks may be
                   2107:  *     held across calls to this function.
                   2108:  *
                   2109:  *     When called from interrupt level, the "pl" argument must not specify
                   2110:  *     a priority level below the level at which the interrupt handler is
                   2111:  *     running.
                   2112:  *
                   2113:  *-SEE_ALSO:
                   2114:  *     RW_ALLOC (), RW_DEALLOC (), RW_RDLOCK (), RW_TRYWRLOCK (),
                   2115:  *     RW_UNLOCK (), RW_WRLOCK ()
                   2116:  */
                   2117: 
                   2118: #if    __USE_PROTO__
                   2119: pl_t (RW_TRYRDLOCK) (rwlock_t * lockp, pl_t pl)
                   2120: #else
                   2121: pl_t
                   2122: RW_TRYRDLOCK __ARGS ((lockp, pl))
                   2123: rwlock_t      *        lockp;
                   2124: pl_t           pl;
                   2125: #endif
                   2126: {
                   2127:        pl_t            prev_pl;
                   2128:        ushort_t        ticket_no;
                   2129: 
                   2130:        ASSERT (lockp != NULL);
                   2131:        ASSERT (splcmp (pl, plhi) <= 0);
                   2132: 
                   2133: 
                   2134:        /*
                   2135:         * Enforce minimum-priority assertion, pl >= lockp->bl_min_pl. Note
                   2136:         * that splcmp () abstracts subtraction-for-comparison of priority
                   2137:         * levels, which explains the form of the assertion.
                   2138:         */
                   2139: 
                   2140:        ASSERT (splcmp (pl, lockp->rw_min_pl) >= 0);
                   2141: 
                   2142: 
                   2143: #ifdef __TEST_AND_TEST__
                   2144:        /*
                   2145:         * We test the ticket numbers to see whether there is any reason to
                   2146:         * even try acquiring the test-and-set lock that forms the ticket
                   2147:         * gate.
                   2148:         *
                   2149:         * We read the "lock holder" and "next ticket" entries in that
                   2150:         * sequence to be pessimistic, since we can assume that other CPUs
                   2151:         * might be looking at this...
                   2152:         */
                   2153: 
                   2154:        ticket_no = ATOMIC_FETCH_USHORT (lockp->rw_lock_holder);
                   2155: 
                   2156:        if (ticket_no != ATOMIC_FETCH_USHORT (lockp->rw_next_ticket))
                   2157:                return invpl;
                   2158: #endif
                   2159: 
                   2160: 
                   2161:        /*
                   2162:         * We block out interrupts at this point to allow the following
                   2163:         * operations room to do their stuff in, since interrupts at an
                   2164:         * inappropriate moment can cause deadlock... of course, if the
                   2165:         * definition of the lock is such that interrupts can proceed, then
                   2166:         * that's OK, since the lock acquisition is atomic.
                   2167:         */
                   2168: 
                   2169:        prev_pl = splx (pl);
                   2170: 
                   2171: 
                   2172:        /*
                   2173:         * Now would be an appropriate time to check that the requested level
                   2174:         * is >= the current level on entry.
                   2175:         */
                   2176: 
                   2177:        ASSERT (splcmp (pl, prev_pl) >= 0);
                   2178: 
                   2179: 
                   2180:        /*
                   2181:         * Test to see whether the lock in question is already taken, and if
                   2182:         * not, we take it. We don't spin if this is a ticket lock, since if
                   2183:         * the basic lock is taken there is *no way* that the lock will be
                   2184:         * free for us immediately.
                   2185:         */
                   2186: 
                   2187:        if (ATOMIC_TEST_AND_SET_UCHAR (lockp->rw_locked) == 0) {
                   2188:                /*
                   2189:                 * Check the ticket numbers to ensure that the lock *really*
                   2190:                 * is free.
                   2191:                 */
                   2192: 
                   2193:                ticket_no = ATOMIC_FETCH_USHORT (lockp->rw_next_ticket);
                   2194: 
                   2195:                if (ticket_no != ATOMIC_FETCH_USHORT (lockp->rw_lock_holder)) {
                   2196: 
                   2197:                        ATOMIC_CLEAR_UCHAR (lockp->rw_locked);
                   2198:                        goto try_failed;
                   2199:                }
                   2200: 
                   2201:                /*
                   2202:                 * Now acquire the lock in read mode by incrementing the
                   2203:                 * count of readers.
                   2204:                 */
                   2205: 
                   2206:                ticket_no = ATOMIC_FETCH_USHORT (lockp->rw_readers);
                   2207: 
                   2208:                if (ATOMIC_FETCH_AND_STORE_USHORT (lockp->rw_readers,
                   2209:                                                   ticket_no + 1) != ticket_no) {
                   2210:                        /*
                   2211:                         * If we didn't read the same number twice, then the
                   2212:                         * test-and-set lock protection isn't doing its job.
                   2213:                         */
                   2214: 
                   2215:                        cmn_err (CE_PANIC, "RW_TRYRDLOCK : Increment failure");
                   2216:                }
                   2217: 
                   2218: 
                   2219:                /*
                   2220:                 * Now we have the lock, we can release the test-and-set lock.
                   2221:                 */
                   2222: 
                   2223:                ATOMIC_CLEAR_UCHAR (lockp->rw_locked);
                   2224: 
                   2225: 
                   2226:                /*
                   2227:                 * RW_TRYRDLOCK () bypasses the hierarchy-assertion tests,
                   2228:                 * but we record the maximum acquired hierarchy level for
                   2229:                 * maximum strictness checking in inner lock attempts.
                   2230:                 *
                   2231:                 * We also record debugging and statistics information here
                   2232:                 * with TRACE_RW_LOCK ().
                   2233:                 */
                   2234: 
                   2235:                LOCK_COUNT_HIERARCHY (lockp->rw_hierarchy);
                   2236: 
                   2237:                TRACE_RW_LOCK (lockp);
                   2238: 
                   2239: 
                   2240:                /*
                   2241:                 * All done! Return successfully.
                   2242:                 */
                   2243: 
                   2244:                return prev_pl;
                   2245:        }
                   2246: 
                   2247: try_failed:
                   2248:        /*
                   2249:         * We cannot acquire the lock, so reset the priority and exit with
                   2250:         * the flag value.
                   2251:         */
                   2252: 
                   2253:        (void) splx (prev_pl);
                   2254: 
                   2255:        return invpl;
                   2256: }
                   2257: 
                   2258: 
                   2259: /*
                   2260:  *-STATUS:
                   2261:  *     DDI/DKI
                   2262:  *
                   2263:  *-NAME:
                   2264:  *     RW_TRYWRLOCK () Try to acquire a read/write lock in write mode.
                   2265:  *
                   2266:  *-SYNOPSIS:
                   2267:  *     #include <sys/types.h>
                   2268:  *     #include <sys/ksynch.h>
                   2269:  *
                   2270:  *     pl_t RW_TRYWRLOCK (rwlock_t * lockp, pl_t pl);
                   2271:  *
                   2272:  *-ARGUMENTS:
                   2273:  *     lockp           Pointer to the read/write lock to be acquired.
                   2274:  *
                   2275:  *     pl              The interrupt priority level to be set while the lock
                   2276:  *                     is held by the caller. Because some implementations
                   2277:  *                     require that interrupts that might attempt to acquire
                   2278:  *                     the lock be blocked on the processor on which the
                   2279:  *                     lock is held, portable drivers must specify a "pl"
                   2280:  *                     value that is sufficient to block out and interrupt
                   2281:  *                     handler that might attempt to acquire this lock. See
                   2282:  *                     the description of RW_ALLOC () for additional
                   2283:  *                     discussion and a list of the valid values for "pl".
                   2284:  *                     Implementations that do not require that the interrupt
                   2285:  *                     priority level be raised during lock acquisition may
                   2286:  *                     choose to ignore this argument.
                   2287:  *
                   2288:  *-DESCRIPTION:
                   2289:  *     If the lock specified by "lockp" is immediately available in write
                   2290:  *     mode (no context is holding the lock in read mode or write mode),
                   2291:  *     RW_TRYWRLOCK () sets the interrupt priority level in accordance with
                   2292:  *     the value specified by "pl" (if required by the implementation) and
                   2293:  *     acquires the lock in write mode. If the lock is not immediately
                   2294:  *     available in write mode, the function returns without acquiring the
                   2295:  *     lock.
                   2296:  *
                   2297:  *-RETURN VALUE:
                   2298:  *     If the lock is acquired, RW_TRYWRLOCK () returns the previous
                   2299:  *     interrupt priority level ("plbase" - "plhi"). If the lock is not
                   2300:  *     acquired the value "invpl" is returned.
                   2301:  *
                   2302:  *-LEVEL:
                   2303:  *     Base or Interrupt.
                   2304:  *
                   2305:  *-NOTES:
                   2306:  *     Does not sleep.
                   2307:  *
                   2308:  *     RW_TRYWRLOCK () may be used to acquire a lock in a different order
                   2309:  *     from the order defined by the lock hierarchy.
                   2310:  *
                   2311:  *     Driver-defined basic locks, read/write locks, and sleep locks may be
                   2312:  *     held across calls to this function.
                   2313:  *
                   2314:  *     When called from interrupt level, the "pl" argument must not specify
                   2315:  *     a priority level below the level at which the interrupt handler is
                   2316:  *     running.
                   2317:  *
                   2318:  *-SEE_ALSO:
                   2319:  *     RW_ALLOC (), RW_DEALLOC (), RW_RDLOCK (), RW_TRYRDLOCK (),
                   2320:  *     RW_UNLOCK (), RW_WRLOCK ()
                   2321:  */
                   2322: 
                   2323: #if    __USE_PROTO__
                   2324: pl_t (RW_TRYWRLOCK) (rwlock_t * lockp, pl_t pl)
                   2325: #else
                   2326: pl_t
                   2327: RW_TRYWRLOCK __ARGS ((lockp, pl))
                   2328: rwlock_t      *        lockp;
                   2329: pl_t           pl;
                   2330: #endif
                   2331: {
                   2332:        pl_t            prev_pl;
                   2333:        ushort_t        ticket_no;
                   2334: 
                   2335:        ASSERT (lockp != NULL);
                   2336:        ASSERT (splcmp (pl, plhi) <= 0);
                   2337: 
                   2338: 
                   2339:        /*
                   2340:         * Enforce minimum-priority assertion, pl >= lockp->bl_min_pl. Note
                   2341:         * that splcmp () abstracts subtraction-for-comparison of priority
                   2342:         * levels, which explains the form of the assertion.
                   2343:         */
                   2344: 
                   2345:        ASSERT (splcmp (pl, lockp->rw_min_pl) >= 0);
                   2346: 
                   2347: 
                   2348: #ifdef __TEST_AND_TEST__
                   2349:        /*
                   2350:         * We test the ticket numbers and reader count to see whether there
                   2351:         * is any reason to even try acquiring the test-and-set lock that
                   2352:         * forms the ticket gate.
                   2353:         *
                   2354:         * We read the "lock holder" and "next ticket" entries in that
                   2355:         * sequence to be pessimistic, since we can assume that other CPUs
                   2356:         * might be looking at this...
                   2357:         */
                   2358: 
                   2359:        ticket_no = ATOMIC_FETCH_USHORT (lockp->rw_lock_holder);
                   2360: 
                   2361:        if (ticket_no != ATOMIC_FETCH_USHORT (lockp->rw_next_ticket) ||
                   2362:            ATOMIC_FETCH_USHORT (lockp->rw_readers) != 0)
                   2363:                return invpl;
                   2364: #endif
                   2365: 
                   2366: 
                   2367:        /*
                   2368:         * We block out interrupts at this point to allow the following
                   2369:         * operations room to do their stuff in, since interrupts at an
                   2370:         * inappropriate moment can cause deadlock... of course, if the
                   2371:         * definition of the lock is such that interrupts can proceed, then
                   2372:         * that's OK, since the lock acquisition is atomic.
                   2373:         */
                   2374: 
                   2375:        prev_pl = splx (pl);
                   2376: 
                   2377: 
                   2378:        /*
                   2379:         * Now would be an appropriate time to check that the requested level
                   2380:         * is >= the current level on entry.
                   2381:         */
                   2382: 
                   2383:        ASSERT (splcmp (pl, prev_pl) >= 0);
                   2384: 
                   2385: 
                   2386:        /*
                   2387:         * Test to see whether the lock in question is already taken, and if
                   2388:         * not, we take it. We don't spin if this is a ticket lock, since if
                   2389:         * the basic lock is taken there is *no way* that the lock will be
                   2390:         * free for us immediately.
                   2391:         */
                   2392: 
                   2393:        if (ATOMIC_TEST_AND_SET_UCHAR (lockp->rw_locked) == 0) {
                   2394:                /*
                   2395:                 * Check the ticket numbers and the reader count to ensure
                   2396:                 * that the lock *really* is free.
                   2397:                 */
                   2398: 
                   2399:                ticket_no = ATOMIC_FETCH_USHORT (lockp->rw_next_ticket);
                   2400: 
                   2401:                if (ticket_no != ATOMIC_FETCH_USHORT (lockp->rw_lock_holder) ||
                   2402:                    ATOMIC_FETCH_USHORT (lockp->rw_readers) != 0) {
                   2403: 
                   2404:                        ATOMIC_CLEAR_UCHAR (lockp->rw_locked);
                   2405:                        goto try_failed;
                   2406:                }
                   2407: 
                   2408:                /*
                   2409:                 * Now acquire the lock in write mode by incrementing the
                   2410:                 * ticket counter.
                   2411:                 */
                   2412: 
                   2413:                if (ATOMIC_FETCH_AND_STORE_USHORT (lockp->rw_next_ticket,
                   2414:                                                   ticket_no + 1) != ticket_no) {
                   2415:                        /*
                   2416:                         * If we didn't read the same number twice, then the
                   2417:                         * test-and-set lock protection isn't doing its job.
                   2418:                         */
                   2419: 
                   2420:                        cmn_err (CE_PANIC, "RW_TRYWRLOCK : Increment failure");
                   2421:                }
                   2422: 
                   2423: 
                   2424:                /*
                   2425:                 * Now we have the lock, we can release the test-and-set lock.
                   2426:                 */
                   2427: 
                   2428:                ATOMIC_CLEAR_UCHAR (lockp->rw_locked);
                   2429: 
                   2430: 
                   2431:                /*
                   2432:                 * RW_TRYWRLOCK () bypasses the hierarchy-assertion tests,
                   2433:                 * but we record the maximum acquired hierarchy level for
                   2434:                 * maximum strictness checking in inner lock attempts.
                   2435:                 *
                   2436:                 * We also record and debugging and statistics information
                   2437:                 * here with TRACE_RW_LOCK ().
                   2438:                 */
                   2439: 
                   2440:                LOCK_COUNT_HIERARCHY (lockp->rw_hierarchy);
                   2441: 
                   2442:                TRACE_RW_LOCK (lockp);
                   2443: 
                   2444: 
                   2445:                /*
                   2446:                 * All done! Return success...
                   2447:                 */
                   2448: 
                   2449:                return prev_pl;
                   2450:        }
                   2451: 
                   2452: try_failed:
                   2453:        /*
                   2454:         * We cannot acquire the lock, so reset the priority and exit with
                   2455:         * the flag value.
                   2456:         */
                   2457: 
                   2458:        (void) splx (prev_pl);
                   2459: 
                   2460:        return invpl;
                   2461: }
                   2462: 
                   2463: 
                   2464: /*
                   2465:  *-STATUS:
                   2466:  *     DDI/DKI
                   2467:  *
                   2468:  *-NAME:
                   2469:  *     RW_UNLOCK ()    Release a read/write lock.
                   2470:  *
                   2471:  *-SYNOPSIS:
                   2472:  *     #include <sys/types.h>
                   2473:  *     #include <sys/ksynch.h>
                   2474:  *
                   2475:  *     pl_t RW_UNLOCK (rwlock_t * lockp, pl_t pl);
                   2476:  *
                   2477:  *-ARGUMENTS:
                   2478:  *     lockp           Pointer to the read/write lock to be released.
                   2479:  *
                   2480:  *     pl              The interrupt priority level to be set after releasing
                   2481:  *                     the lock. See the description of the "min_pl" argument
                   2482:  *                     to RW_ALLOC () for a list of the valid values for
                   2483:  *                     "pl". If lock calls are not being nested or if the
                   2484:  *                     caller is unlocking in the reverse order that locks
                   2485:  *                     were acquired, the "pl" argument will typically be the
                   2486:  *                     value that was returned from the corresponding call to
                   2487:  *                     acquire the lock. The caller may need to specify a
                   2488:  *                     different value for "pl" if nested locks are being
                   2489:  *                     released in some order other that the reverse order of
                   2490:  *                     acquisition, so as to ensure that the interrupt
                   2491:  *                     priority level is kept sufficiently high to block
                   2492:  *                     interrupt code that might attempt to acquire locks
                   2493:  *                     which are still held. Although portable drivers must
                   2494:  *                     always specify an appropriate "pl" argument,
                   2495:  *                     implementations which do not require that the
                   2496:  *                     interrupt priority level be raised during lock
                   2497:  *                     acquisition may choose to ignore this argument.
                   2498:  *
                   2499:  *-DESCRIPTION:
                   2500:  *     RW_UNLOCK () releases the basic lock specified by "lockp" and then
                   2501:  *     sets the interrupt priority level in accordance with the value
                   2502:  *     specified by "pl" (if required by the implementation).
                   2503:  *
                   2504:  *-RETURN VALUE:
                   2505:  *     None.
                   2506:  *
                   2507:  *-LEVEL:
                   2508:  *     Base or Interrupt.
                   2509:  *
                   2510:  *-NOTES:
                   2511:  *     Does not sleep.
                   2512:  *
                   2513:  *     Driver-defined basic locks, read/write locks, and sleep locks may be
                   2514:  *     held across calls to this function.
                   2515:  *
                   2516:  *-SEE_ALSO:
                   2517:  *     RW_ALLOC (), RW_DEALLOC (), RW_RDLOCK (), RW_TRYRDLOCK (),
                   2518:  *     RW_TRYWRLOCK (), RW_WRLOCK ()
                   2519:  */
                   2520: 
                   2521: #if    __USE_PROTO__
                   2522: void (RW_UNLOCK) (rwlock_t * lockp, pl_t pl)
                   2523: #else
                   2524: void
                   2525: RW_UNLOCK __ARGS ((lockp, pl))
                   2526: rwlock_t      *        lockp;
                   2527: pl_t           pl;
                   2528: #endif
                   2529: {
                   2530:        ushort_t        ticket_no;
                   2531: 
                   2532:        ASSERT (lockp != NULL);
                   2533:        ASSERT (splcmp (plbase, pl) <= 0 && splcmp (pl, plhi) <= 0);
                   2534: 
                   2535: 
                   2536:        /*
                   2537:         * Undo whatever the hierarchy-assertion and debugging/statistics
                   2538:         * mechanisms do.
                   2539:         */
                   2540: 
                   2541:        LOCK_FREE_HIERARCHY (lockp->rw_hierarchy);
                   2542: 
                   2543:        UNTRACE_RW_LOCK (lockp);
                   2544: 
                   2545: 
                   2546:        /*
                   2547:         * Now release the lock... since writers have to wait for all readers
                   2548:         * to release the lock, if there any readers then we are releasing
                   2549:         * in read mode.
                   2550:         */
                   2551: 
                   2552:        if (ATOMIC_FETCH_USHORT (lockp->rw_readers) != 0) {
                   2553:                /*
                   2554:                 * In order to safely decrement the reader count, we have to
                   2555:                 * acquire the test-and-set lock in the absence of an
                   2556:                 * atomic decrement facility.
                   2557:                 */
                   2558: 
                   2559:                while (ATOMIC_TEST_AND_SET_UCHAR (lockp->rw_locked) != 0) {
                   2560: 
                   2561: #ifdef __UNIPROCESSOR__
                   2562:                        cmn_err (CE_PANIC, "RW_UNLOCK : deadlock!");
                   2563: #elif  defined (__TEST_AND_TEST__)
                   2564:                        /*
                   2565:                         * To reduce contention, we wait until the test-and-
                   2566:                         * set lock is free before attempting to re-acquire
                   2567:                         * it.
                   2568:                         */
                   2569: 
                   2570:                        while (ATOMIC_FETCH_UCHAR (lockp->rw_locked) != 0)
                   2571:                                /* DO NOTHING */;
                   2572: #endif
                   2573:                }
                   2574: 
                   2575:                ticket_no = ATOMIC_FETCH_USHORT (lockp->rw_readers);
                   2576: 
                   2577:                if (ATOMIC_FETCH_AND_STORE_USHORT (lockp->rw_readers,
                   2578:                                                   ticket_no - 1) != ticket_no ) {
                   2579:                        /*
                   2580:                         * If we didn't read the same number twice, then the
                   2581:                         * test-and-set lock protection isn't doing its job.
                   2582:                         */
                   2583: 
                   2584:                        cmn_err (CE_PANIC, "RW_UNLOCK : Decrement failure");
                   2585:                }
                   2586: 
                   2587:                /*
                   2588:                 * Now free the test-and-set lock.
                   2589:                 */
                   2590: 
                   2591:                ATOMIC_CLEAR_UCHAR (lockp->rw_locked);
                   2592: 
                   2593:        } else if (ticket_no = ATOMIC_FETCH_USHORT (lockp->rw_lock_holder),
                   2594:                   ticket_no != ATOMIC_FETCH_USHORT (lockp->rw_next_ticket)) {
                   2595:                /*
                   2596:                 * Release the lock to the next ticket holder or the waiting
                   2597:                 * readers if there are no waiting ticket-holders.
                   2598:                 */
                   2599: 
                   2600: 
                   2601:                if (ATOMIC_FETCH_AND_STORE_USHORT (lockp->rw_lock_holder,
                   2602:                                                   ticket_no + 1) != ticket_no ) {
                   2603:                        /*
                   2604:                         * If we didn't read the same number twice, then the
                   2605:                         * test-and-set lock protection isn't doing its job.
                   2606:                         */
                   2607: 
                   2608:                        cmn_err (CE_PANIC, "RW_UNLOCK : Increment failure");
                   2609:                }
                   2610: 
                   2611:        } else
                   2612:                cmn_err (CE_PANIC, "RW_UNLOCK : not locked");
                   2613: 
                   2614: 
                   2615:        /*
                   2616:         * And lower out priority level to finish up.
                   2617:         */
                   2618: 
                   2619:        (void) splx (pl);
                   2620: }
                   2621: 
                   2622: 
                   2623: /*
                   2624:  *-STATUS:
                   2625:  *     DDI/DKI
                   2626:  *
                   2627:  *-NAME:
                   2628:  *     RW_WRLOCK ()    Acquire a read/write lock in write mode.
                   2629:  *
                   2630:  *-SYNOPSIS:
                   2631:  *     #include <sys/types.h>
                   2632:  *     #include <sys/ksynch.h>
                   2633:  *
                   2634:  *     pl_t RW_WRLOCK (rwlock_t * lockp, pl_t pl);
                   2635:  *
                   2636:  *-ARGUMENTS:
                   2637:  *     lockp           Pointer to the read/write lock to be acquired.
                   2638:  *
                   2639:  *     pl              The interrupt priority level to be set while the lock
                   2640:  *                     is held by the caller. Because some implementations
                   2641:  *                     require that interrupts that might attempt to acquire
                   2642:  *                     the lock be blocked on which the lock is held,
                   2643:  *                     portable drivers must specify a "pl" value that is
                   2644:  *                     sufficient to block out any interrupt handler that
                   2645:  *                     might attempt to acquire this lock. See the
                   2646:  *                     description of the "min_pl" argument to RW_ALLOC ()
                   2647:  *                     for additional discussion. Implementations that do
                   2648:  *                     not require that the interrupt priority level be
                   2649:  *                     raised during lock acquisition may choose to ignore
                   2650:  *                     this argument.
                   2651:  *
                   2652:  *-DESCRIPTION:
                   2653:  *     RW_WRLOCK () sets the interrupt priority level in accordance with the
                   2654:  *     value specified by "pl" (if required by the implementation) and
                   2655:  *     acquires the lock specified by "lockp". If the lock is not currently
                   2656:  *     available, the caller will wait until the lock is available in write
                   2657:  *     mode. A read/write lock is available in write mode when the lock is
                   2658:  *     not held by any context. It is implementation-defined whether the
                   2659:  *     caller will block during the wait. Some implementations may cause the
                   2660:  *     caller to spin for the duration of the wait, while on others the
                   2661:  *     caller may block at some point.
                   2662:  *
                   2663:  *-RETURN VALUE:
                   2664:  *     Upon acquiring the lock, RW_WRLOCK () returns the previous interrupt
                   2665:  *     priority level.
                   2666:  *
                   2667:  *-LEVEL:
                   2668:  *     Base or Interrupt.
                   2669:  *
                   2670:  *-NOTES:
                   2671:  *     Read/write locks are not recursive. A call to RW_WRLOCK () attempting
                   2672:  *     to acquire a lock that is already held by the calling context may
                   2673:  *     result in deadlock.
                   2674:  *
                   2675:  *     Calls to RD_WRLOCK () should honor the ordering defined by the lock
                   2676:  *     hierarchy [see RW_ALLOC ()] in order to avoid deadlock.
                   2677:  *
                   2678:  *     Driver-defined sleep locks may be held across calls to this function.
                   2679:  *
                   2680:  *     Driver-defined basic locks and read/write locks may be held across
                   2681:  *     calls to this function subject to the hierarchy and recursion
                   2682:  *     restrictions described above.
                   2683:  *
                   2684:  *     When called from interrupt level, the "pl" argument must not specify
                   2685:  *     a priority below the level at which the interrupt handler is running.
                   2686:  *
                   2687:  *-SEE_ALSO:
                   2688:  *     RW_ALLOC (), RW_DEALLOC (), RW_RDLOCK (), RW_TRYRDLOCK (),
                   2689:  *     RW_TRYWRLOCK (), RW_UNLOCK ()
                   2690:  */
                   2691: 
                   2692: #if    __USE_PROTO__
                   2693: pl_t (RW_WRLOCK) (rwlock_t * lockp, pl_t pl)
                   2694: #else
                   2695: pl_t
                   2696: RW_WRLOCK __ARGS ((lockp, pl))
                   2697: rwlock_t      *        lockp;
                   2698: pl_t           pl;
                   2699: #endif
                   2700: {
                   2701:        pl_t            prev_pl;
                   2702:        ushort_t        ticket_no;
                   2703: 
                   2704:        ASSERT (lockp != NULL);
                   2705:        ASSERT (splcmp (pl, plhi) <= 0);
                   2706: 
                   2707: 
                   2708:        /*
                   2709:         * Enforce minimum-priority assertion, pl >= lockp->rw_min_pl. Note
                   2710:         * that splcmp () abstracts subtraction-for-comparison of priority
                   2711:         * levels, which explains the form of the assertion.
                   2712:         */
                   2713: 
                   2714:        ASSERT (splcmp (pl, lockp->rw_min_pl) >= 0);
                   2715: 
                   2716: 
                   2717:        /*
                   2718:         * On a uniprocessor, encountering a read/write lock that is already
                   2719:         * locked is *always* an error, even on machines with many different
                   2720:         * interrupt priority levels. The hierarchy-assertion mechanism
                   2721:         * cannot always deal with this, since RW_TRYRDLOCK () can acquire
                   2722:         * locks in a different order.
                   2723:         *
                   2724:         * On a multiprocessor, we can just spin here. Note that since LOCK ()
                   2725:         * is defined as requiring values of "pl" greater than the current
                   2726:         * interrupt priority level, the use of splraise () by
                   2727:         * TEST_AND_SET_LOCK () is legitimate.
                   2728:         */
                   2729: 
                   2730:        prev_pl = TEST_AND_SET_LOCK (lockp->rw_locked, pl, "RW_WRLOCK");
                   2731: 
                   2732: 
                   2733:        /*
                   2734:         * Take a ticket...
                   2735:         */
                   2736: 
                   2737:        ticket_no = ATOMIC_FETCH_USHORT (lockp->rw_next_ticket);
                   2738: 
                   2739:        if (ATOMIC_FETCH_AND_STORE_USHORT (lockp->rw_next_ticket,
                   2740:                                           ticket_no + 1) != ticket_no) {
                   2741:                /*
                   2742:                 * If we didn't read the same number twice, then the
                   2743:                 * test-and-set lock protection isn't doing its job.
                   2744:                 */
                   2745: 
                   2746:                cmn_err (CE_PANIC, "RW_WRLOCK : ticket increment failure");
                   2747:        }
                   2748: 
                   2749: 
                   2750:        /*
                   2751:         * Allow other CPUs access to the lock data structures by releasing
                   2752:         * the test-and-set lock.
                   2753:         */
                   2754: 
                   2755:        ATOMIC_CLEAR_UCHAR (lockp->rw_locked);
                   2756: 
                   2757: 
                   2758:        /*
                   2759:         * Now, let's wait for our number to come up and for all the readers
                   2760:         * to release their shared locks.
                   2761:         */
                   2762: 
                   2763:        while (ATOMIC_FETCH_USHORT (lockp->rw_lock_holder) != ticket_no ||
                   2764:               ATOMIC_FETCH_USHORT (lockp->rw_readers) != 0) {
                   2765:                /*
                   2766:                 * At this point we might want to implement some form of
                   2767:                 * proportional backoff to reduce memory traffic. Later.
                   2768:                 *
                   2769:                 * Another hot contender for this spot is detecting failures
                   2770:                 * on other CPUs...
                   2771:                 */
                   2772: 
                   2773: #ifdef __UNIPROCESSOR__
                   2774:                cmn_err (CE_PANIC, "RW_WRLOCK : deadlock on ticket");
                   2775: #endif
                   2776:        }
                   2777: 
                   2778: 
                   2779:        /*
                   2780:         * Now would be an appropriate time to check that the requested level
                   2781:         * is >= the current level on entry. Strictly speaking, this does not
                   2782:         * have to be true if the processor is currently at base level, but
                   2783:         * for now we'll discourage that behaviour.
                   2784:         */
                   2785: 
                   2786:        ASSERT (splcmp (pl, prev_pl) >= 0);
                   2787: 
                   2788: 
                   2789:        /*
                   2790:         * Test the lock-acquisition-hierarchy assertions.
                   2791:         */
                   2792: 
                   2793:        ASSERT (ddi_cpu_data ()->dc_max_hierarchy < lockp->rw_hierarchy);
                   2794: 
                   2795:        LOCK_COUNT_HIERARCHY (lockp->rw_hierarchy);
                   2796: 
                   2797: 
                   2798:        /*
                   2799:         * Since it may be useful for post-mortem debugging to record some
                   2800:         * information about the context which acquired the lock, we defer
                   2801:         * to some generic recorder function or macro.
                   2802:         *
                   2803:         * Note that in general it does not appear to be possible to make
                   2804:         * detailed assertions about the relation between the contexts in
                   2805:         * which a lock is acquired and/or released. In particular, it
                   2806:         * might be possible for a basic lock to be tied to some device
                   2807:         * hardware-related operation where a lock might be acquired on one
                   2808:         * CPU and released on another.
                   2809:         *
                   2810:         * In addition, any lock statistics are kept by this operation.
                   2811:         */
                   2812: 
                   2813:        TRACE_RW_LOCK (lockp);
                   2814: 
                   2815:        return prev_pl;
                   2816: }
                   2817: 
                   2818: 
                   2819: /*
                   2820:  *-STATUS:
                   2821:  *     DDI/DKI
                   2822:  *
                   2823:  *-NAME:
                   2824:  *     SLEEP_ALLOC ()  Allocate and initialize a sleep lock.
                   2825:  *
                   2826:  *-SYNOPSIS:
                   2827:  *     #include <sys/types.h>
                   2828:  *     #include <sys/kmem.h>
                   2829:  *     #include <sys/ksynch.h>
                   2830:  *
                   2831:  *     sleep_t * SLEEP_ALLOC (int arg, lkinfo_t * lkinfop, int flag);
                   2832:  *
                   2833:  *-ARGUMENTS:
                   2834:  *     arg             Placeholder for future use. "arg" must be equal to
                   2835:  *                     zero.
                   2836:  *
                   2837:  *
                   2838:  *     lkinfop         Pointer to a lkinfo structure. The lk_name member of
                   2839:  *                     the lkinfo structure points to a character string
                   2840:  *                     defining a name that will be associated with the lock
                   2841:  *                     for the purposes of statistics gathering. The name
                   2842:  *                     should begin with the driver prefix and should be
                   2843:  *                     unique to the lock or group of locks for which the
                   2844:  *                     driver wishes to collect a uniquely identifiable set
                   2845:  *                     of statistics (ie, if a given name is shared by a
                   2846:  *                     group of locks, the statistics of the individual locks
                   2847:  *                     within the group will not be uniquely identifiable).
                   2848:  *
                   2849:  *                     The only bit flag currently specified within the
                   2850:  *                     "lk_flags" member of the lkinfo structure is the
                   2851:  *                     LK_NOSTATS flag, which specifies that statistics are
                   2852:  *                     not to be collected for this particular lock.
                   2853:  *
                   2854:  *                     A given lkinfo structure may be shared among multiple
                   2855:  *                     sleep but a lkinfo structure may not be shared between
                   2856:  *                     a sleep lock and a basic or read/write lock. The
                   2857:  *                     called must ensure that the "lk_pad" member of the
                   2858:  *                     "lkinfo" structure is zeroed out before passing it to
                   2859:  *                     SLEEP_ALLOC ().
                   2860:  *
                   2861:  *     flag            Specifies whether the caller is willing to sleep
                   2862:  *                     waiting for memory. If "flag" is set to KM_SLEEP, the
                   2863:  *                     caller will sleep if necessary until sufficient memory
                   2864:  *                     is available. If "flag" is set to KM_NOSLEEP, the
                   2865:  *                     caller will not sleep, but SLEEP_ALLOC () will return
                   2866:  *                     NULL if sufficient memory is not immediately
                   2867:  *                     available.
                   2868:  *
                   2869:  *-DESCRIPTION:
                   2870:  *     SLEEP_ALLOC () dynamically allocates and initialises an instance of a
                   2871:  *     sleep lock. The lock is initialised to the unlocked state.
                   2872:  *
                   2873:  *-RETURN VALUE:
                   2874:  *     Upon successful completion, SLEEP_ALLOC () returns a pointer to the
                   2875:  *     newly allocated lock. If KM_NOSLEEP is specified and sufficient
                   2876:  *     memory is not immediately available, SLEEP_ALLOC () returns a NULL
                   2877:  *     pointer.
                   2878:  *
                   2879:  *-LEVEL:
                   2880:  *     Base only if "flag" is set to KM_SLEEP. Base or Interrupt if "flag" is
                   2881:  *     set to KM_NOSLEEP.
                   2882:  *
                   2883:  *-NOTES:
                   2884:  *     May sleep if "flag" is set to KM_NOSLEEP.
                   2885:  *
                   2886:  *     Driver-defined basic locks and read/write locks may be held across
                   2887:  *     calls to this function if "flag" is set to KM_NOSLEEP but may not be
                   2888:  *     held if "flag" is KM_SLEEP.
                   2889:  *
                   2890:  *     Driver-defined sleep locks may be held across calls to this function
                   2891:  *     regardless of the value of "flag".
                   2892:  *
                   2893:  *-SEE_ALSO:
                   2894:  *     SLEEP_DEALLOC (), SLEEP_LOCK (), SLEEP_LOCK_SIG (),
                   2895:  *     SLEEP_LOCKAVAIL (), SLEEP_LOCKOWNED (), SLEEP_TRYLOCK (),
                   2896:  *     SLEEP_UNLOCK (), lkinfo
                   2897:  */
                   2898: 
                   2899: #if    __USE_PROTO__
                   2900: sleep_t * (SLEEP_ALLOC) (int arg, lkinfo_t * lkinfop, int flag)
                   2901: #else
                   2902: sleep_t *
                   2903: SLEEP_ALLOC __ARGS ((arg, lkinfop, flag))
                   2904: int            arg;
                   2905: lkinfo_t      *        lkinfop;
                   2906: int            flag;
                   2907: #endif
                   2908: {
                   2909:        sleep_t       * lockp;
                   2910: 
                   2911:        ASSERT (arg == 0);
                   2912:        ASSERT (flag == KM_SLEEP || flag == KM_NOSLEEP);
                   2913:        ASSERT (lkinfop != NULL);
                   2914: 
                   2915: 
                   2916:        /*
                   2917:         * Allocate and initialise the data, possibly waiting for enough
                   2918:         * memory to become available.
                   2919:         */
                   2920: 
                   2921:        if ((lockp = (sleep_t *) _lock_malloc (sizeof (* lockp),
                   2922:                                               flag)) != NULL) {
                   2923:                INIT_LNODE (& lockp->sl_node, lkinfop, & sleep_locks, flag);
                   2924:                PLIST_INIT (lockp->sl_plist);
                   2925:        }
                   2926: 
                   2927:        return lockp;
                   2928: }
                   2929: 
                   2930: 
                   2931: /*
                   2932:  *-STATUS:
                   2933:  *     DDI/DKI
                   2934:  *
                   2935:  *-NAME:
                   2936:  *     SLEEP_DEALLOC ()        Deallocate an instance of a sleep lock.
                   2937:  *
                   2938:  *-SYNOPSIS:
                   2939:  *     #include <sys/ksynch.h>
                   2940:  *
                   2941:  *     void SLEEP_DEALLOC (sleep_t * lockp);
                   2942:  *
                   2943:  *-ARGUMENTS:
                   2944:  *     lockp           Pointer to the sleep lock to be deallocated.
                   2945:  *
                   2946:  *-DESCRIPTION:
                   2947:  *     SLEEP_DEALLOC () deallocates the sleep lock specified by "lockp".
                   2948:  *
                   2949:  *-RETURN VALUE:
                   2950:  *     None.
                   2951:  *
                   2952:  *-LEVEL:
                   2953:  *     Base or Interrupt.
                   2954:  *
                   2955:  *-NOTES:
                   2956:  *     Does not sleep.
                   2957:  *
                   2958:  *     Attempting to deallocate a lock that is currently locked or is being
                   2959:  *     waited for is an error and will result in undefined behavior.
                   2960:  *
                   2961:  *     Driver-defined basic locks, read/write locks, and sleep locks (other
                   2962:  *     than the one being deallocated) may be held across calls to this
                   2963:  *     function.
                   2964:  *
                   2965:  *-SEE_ALSO:
                   2966:  *     SLEEP_ALLOC (), SLEEP_LOCK (), SLEEP_LOCK_SIG (), SLEEP_LOCKAVAIL (),
                   2967:  *     SLEEP_LOCKOWNED (), SLEEP_TRYLOCK (), SLEEP_UNLOCK ()
                   2968:  */
                   2969: 
                   2970: #if    __USE_PROTO__
                   2971: void (SLEEP_DEALLOC) (sleep_t * lockp)
                   2972: #else
                   2973: void
                   2974: SLEEP_DEALLOC __ARGS ((lockp))
                   2975: sleep_t              * lockp;
                   2976: #endif
                   2977: {
                   2978:        ASSERT (lockp != NULL);
                   2979: 
                   2980:        /*
                   2981:         * Remove from the list of all sleep locks and free any statistics
                   2982:         * buffer space before freeing the lock itself.
                   2983:         */
                   2984: 
                   2985:        PLIST_DESTROY (lockp->sl_plist);
                   2986: 
                   2987:        FREE_LNODE (& lockp->sl_node, & sleep_locks);
                   2988: 
                   2989:        _lock_free (lockp, sizeof (* lockp));
                   2990: }
                   2991: 
                   2992: 
                   2993: /*
                   2994:  *-STATUS:
                   2995:  *     DDI/DKI
                   2996:  *
                   2997:  *-NAME:
                   2998:  *     SLEEP_LOCK ()   Acquire a sleep lock.
                   2999:  *
                   3000:  *-SYNOPSIS:
                   3001:  *     #include <sys/ksynch.h>
                   3002:  *
                   3003:  *     void SLEEP_LOCK (sleep_t * lockp, int priority);
                   3004:  *
                   3005:  *-ARGUMENTS:
                   3006:  *     lockp           Pointer to the sleep lock to be acquired.
                   3007:  *
                   3008:  *     priority        A hint to the scheduling policy as to the relative
                   3009:  *                     priority the caller wishes to be assigned while
                   3010:  *                     running in the kernel after waking up. The valid
                   3011:  *                     values for this argument are as follows:
                   3012:  *
                   3013:  *                     pridisk     Priority appropriate for disk driver
                   3014:  *                     prinet      Priority appropriate for network driver.
                   3015:  *                     pritty      Priority appropriate for terminal driver.
                   3016:  *                     pritape     Priority appropriate for tape driver.
                   3017:  *                     prihi       High priority.
                   3018:  *                     primed      Medium priority.
                   3019:  *                     prilo       Low priority.
                   3020:  *
                   3021:  *                     Drivers may use these values to request a priority
                   3022:  *                     appropriate to a given type of device or to request a
                   3023:  *                     priority that is high, medium or low relative to other
                   3024:  *                     activities within the kernel.
                   3025:  *
                   3026:  *                     It is also permissible to specify positive or negative
                   3027:  *                     offsets from the values defined above. Positive
                   3028:  *                     offsets result in favourable priority. The maximum
                   3029:  *                     allowable offset in all cases is 3 (eg. pridisk+3
                   3030:  *                     and pridisk-3 are valid values by pridisk+4 and
                   3031:  *                     pridisk-4 are not valid). Offsets can be useful in
                   3032:  *                     defining the relative importance of different locks or
                   3033:  *                     resources that may be hald by a given driver. In
                   3034:  *                     general, a higher relative priority should be used
                   3035:  *                     when the caller is attempting to acquire a highly-
                   3036:  *                     contended lock or resource, or when the caller is
                   3037:  *                     already holding one or more locks or kernel resources
                   3038:  *                     upon entry to SLEEP_LOCK ().
                   3039:  *
                   3040:  *                     The exact semantics of the "priority" argument is
                   3041:  *                     specific to the scheduling class of the caller, and
                   3042:  *                     some scheduling classes may choose to ignore the
                   3043:  8                     argument for the purposes of assigning a scheduling
                   3044:  *                     priority.
                   3045:  *
                   3046:  *-DESCRIPTION:
                   3047:  *     SLEEP_LOCK () acquires the sleep lock specified by "lockp". If the
                   3048:  *     lock is not immediately available, the caller is put to sleep (the
                   3049:  *     caller's execution is suspended and other processes may be scheduled)
                   3050:  *     until the lock becomes available to the caller, at which point the
                   3051:  *     caller wakes up and returns with the lock held.
                   3052:  *
                   3053:  *     The caller will not be interrupted by signals while sleeping inside
                   3054:  *     SLEEP_LOCK ().
                   3055:  *
                   3056:  *-RETURN VALUE:
                   3057:  *     None.
                   3058:  *
                   3059:  *-LEVEL:
                   3060:  *     Base level only.
                   3061:  *
                   3062:  *-NOTES:
                   3063:  *     May sleep.
                   3064:  *
                   3065:  *     Sleep locks are not recursive. A call to SLEEP_LOCK () attempting to
                   3066:  *     acquire a lock that is currently held by the calling context will
                   3067:  *     result in deadlock.
                   3068:  *
                   3069:  *     Driver-defined basic locks and read/write locks may not be held across
                   3070:  *     calls to this function.
                   3071:  *
                   3072:  *     Driver-defined sleep locks may be held across calls to this function
                   3073:  *     subject to the recursion restrictions described above.
                   3074:  *
                   3075:  *-SEE_ALSO:
                   3076:  *     SLEEP_ALLOC (), SLEEP_DEALLOC (), SLEEP_LOCK_SIG (),
                   3077:  *     SLEEP_LOCKAVAIL (), SLEEP_LOCKOWNED (), SLEEP_TRYLOCK (),
                   3078:  *     SLEEP_UNLOCK ()
                   3079:  */
                   3080: 
                   3081: #if    __USE_PROTO__
                   3082: void (SLEEP_LOCK) (sleep_t * lockp, int priority)
                   3083: #else
                   3084: void
                   3085: SLEEP_LOCK __ARGS ((lockp, priority))
                   3086: sleep_t              * lockp;
                   3087: int            priority;
                   3088: #endif
                   3089: {
                   3090:        pl_t            prev_pl;
                   3091: 
                   3092:        ASSERT (lockp != NULL);
                   3093:        ASSERT_BASE_LEVEL ();
                   3094: 
                   3095: 
                   3096:        /*
                   3097:         * Take the path of least resistance; if the sleep lock is not
                   3098:         * currently held, then just acquire it and get out.
                   3099:         */
                   3100: 
                   3101:        if (ATOMIC_TEST_AND_SET_UCHAR (lockp->sl_locked) == 0) {
                   3102:                /*
                   3103:                 * We successfully acquired it! Just leave after writing in
                   3104:                 * the info for SLEEP_LOCKAVAIL ().
                   3105:                 */
                   3106: 
                   3107:                lockp->sl_holder = PROC_HANDLE ();
                   3108:                return;
                   3109:        }
                   3110: 
                   3111: 
                   3112:        /*
                   3113:         * OK, we do it the hard way.
                   3114:         *
                   3115:         * The sleep lock might have been unlocked while we waited to lock
                   3116:         * the process list, so we retest the item.
                   3117:         */
                   3118: 
                   3119:        prev_pl = PLIST_LOCK (lockp->sl_plist, "SLEEP_LOCK");
                   3120: 
                   3121:        if (ATOMIC_TEST_AND_SET_UCHAR (lockp->sl_locked) != 0) {
                   3122:                /*
                   3123:                 * No, we need to wait. Note the cast to void... we assume
                   3124:                 * that MAKE_SLEEPING () will filter out all improper attempts
                   3125:                 * to wake us.
                   3126:                 *
                   3127:                 * We assert that whoever woke us up will have left the sleep
                   3128:                 * locked in the "locked" state for us. While *we* won't have
                   3129:                 * the process-list locked, someone else might so we can't
                   3130:                 * make an assertion on that.
                   3131:                 */
                   3132: 
                   3133:                (void) MAKE_SLEEPING (lockp->sl_plist, priority,
                   3134:                                      SLEEP_NO_SIGNALS);
                   3135: 
                   3136:                ASSERT (lockp->sl_holder == PROC_HANDLE ());
                   3137:                ASSERT (ATOMIC_FETCH_UCHAR (lockp->sl_locked) != 0);
                   3138: 
                   3139:                (void) splx (prev_pl);
                   3140:        } else {
                   3141:                /*
                   3142:                 * Write the owner information for SLEEP_LOCKOWNED () and
                   3143:                 * release the test-and-set lock on the process list.
                   3144:                 */
                   3145: 
                   3146:                lockp->sl_holder = PROC_HANDLE ();
                   3147: 
                   3148:                PLIST_UNLOCK (lockp->sl_plist, prev_pl);
                   3149:        }
                   3150: }
                   3151: 
                   3152: 
                   3153: /*
                   3154:  *-STATUS:
                   3155:  *     DDI/DKI
                   3156:  *
                   3157:  *-NAME:
                   3158:  *     SLEEP_LOCKAVAIL ()      Query whether a sleep lock is available.
                   3159:  *
                   3160:  *-SYNOPSIS:
                   3161:  *     #include <sys/types.h>
                   3162:  *     #include <sys/ksynch.h>
                   3163:  *
                   3164:  *     bool_t SLEEP_LOCKAVAIL (sleep_t * lockp);
                   3165:  *
                   3166:  *-ARGUMENTS:
                   3167:  *     lockp           Pointer to the sleep lock to be queried.
                   3168:  *
                   3169:  *-DESCRIPTION:
                   3170:  *     SLEEP_LOCKAVAIL () returns an indication of whether the sleep lock
                   3171:  *     specified by "lockp" is currently available.
                   3172:  *
                   3173:  *     The state of the lock may change and the value returned may no longer
                   3174:  *     be valid by the time the caller sees it. The caller is expected to
                   3175:  *     understand that this is "stale data" and is either using it as a
                   3176:  *     heuristic or has arranged for the data to be meaningful by other
                   3177:  *     means.
                   3178:  *
                   3179:  *-RETURN VALUE:
                   3180:  *     SLEEP_LOCKAVAIL () returns TRUE (a non-zero value) if the lock was
                   3181:  *     available or FALSE (zero) if the lock was not available.
                   3182:  *
                   3183:  *-LEVEL:
                   3184:  *     Base or Interrupt.
                   3185:  *
                   3186:  *-NOTES:
                   3187:  *     Does not sleep.
                   3188:  *
                   3189:  *     Driver-defined basic locks, read/write locks and sleep locks may be
                   3190:  *     held across calls to this function.
                   3191:  *
                   3192:  *-SEE_ALSO:
                   3193:  *     SLEEP_ALLOC (), SLEEP_DEALLOC (), SLEEP_LOCK (), SLEEP_LOCK_SIG (),
                   3194:  *     SLEEP_LOCKOWNED (), SLEEP_TRYLOCK (), SLEEP_UNLOCK ()
                   3195:  */
                   3196: 
                   3197: #if    __USE_PROTO__
                   3198: bool_t (SLEEP_LOCKAVAIL) (sleep_t * lockp)
                   3199: #else
                   3200: bool_t
                   3201: SLEEP_LOCKAVAIL __ARGS ((lockp))
                   3202: sleep_t              * lockp;
                   3203: #endif
                   3204: {
                   3205:        ASSERT (lockp != NULL);
                   3206: 
                   3207:        return ATOMIC_FETCH_UCHAR (lockp->sl_locked) == 0;
                   3208: }
                   3209: 
                   3210: 
                   3211: /*
                   3212:  *-STATUS:
                   3213:  *     DDI/DKI
                   3214:  *
                   3215:  *-NAME:
                   3216:  *     SLEEP_LOCKOWNED ()  Query whether a sleep lock is held by the caller.
                   3217:  *
                   3218:  *-SYNOPSIS:
                   3219:  *     #include <sys/types.h>
                   3220:  *     #include <sys/ksynch.h>
                   3221:  *
                   3222:  *     bool_t SLEEP_LOCKOWNED (sleep_t * lockp);
                   3223:  *
                   3224:  *-ARGUMENTS:
                   3225:  *     lockp           Pointer to the sleep lock to be queried.
                   3226:  *
                   3227:  *-DESCRIPTION:
                   3228:  *     SLEEP_LOCKOWNED () returns an indication of whether the sleep lock
                   3229:  *     specified by "lockp" is held by the calling context.
                   3230:  *
                   3231:  *     SLEEP_LOCKOWNED () is intended for use only within ASSERT ()
                   3232:  *     expressions [see ASSERT ()] and other code that is conditionally
                   3233:  *     compiled under the DEBUG compilation option. The SLEEP_LOCKOWNED ()
                   3234:  *     function is only defined under the DEBUG compilation option, and
                   3235:  *     therefore calls to SLEEP_LOCKOWNED () will not compile when DEBUG is
                   3236:  *     not defined.
                   3237:  *
                   3238:  *-RETURN VALUE:
                   3239:  *     SLEEP_LOCKOWNED () returns TRUE (a non-zero value) if the lock is
                   3240:  *     currently held by the calling context or FALSE (zero) if the lock is
                   3241:  *     not currently held by the calling context.
                   3242:  *
                   3243:  *-LEVEL:
                   3244:  *     Base or Interrupt.
                   3245:  *
                   3246:  *-NOTES:
                   3247:  *     Does not sleep.
                   3248:  *
                   3249:  *     Driver-defined basic locks, read/write locks and sleep locks may be
                   3250:  *     held across calls to this function.
                   3251:  *
                   3252:  *-SEE_ALSO:
                   3253:  *     SLEEP_ALLOC (), SLEEP_DEALLOC (), SLEEP_LOCK (), SLEEP_LOCK_SIG (),
                   3254:  *     SLEEP_LOCKAVAIL (), SLEEP_TRYLOCK (), SLEEP_UNLOCK ()
                   3255:  */
                   3256: 
                   3257: #if    __USE_PROTO__
                   3258: bool_t (SLEEP_LOCKOWNED) (sleep_t * lockp)
                   3259: #else
                   3260: bool_t
                   3261: SLEEP_LOCKOWNED __ARGS ((lockp))
                   3262: sleep_t              * lockp;
                   3263: #endif
                   3264: {
                   3265:        ASSERT (lockp != NULL);
                   3266: 
                   3267:        return lockp->sl_holder == PROC_HANDLE ();
                   3268: }
                   3269: 
                   3270: 
                   3271: /*
                   3272:  *-STATUS:
                   3273:  *     DDI/DKI
                   3274:  *
                   3275:  *-NAME:
                   3276:  *     SLEEP_LOCK_SIG ()       Acquire a sleep lock.
                   3277:  *
                   3278:  *-SYNOPSIS:
                   3279:  *     #include <sys/types.h>
                   3280:  *     #include <sys/ksynch.h>
                   3281:  *
                   3282:  *     bool_t SLEEP_LOCK_SIG (sleep_t * lockp, int priority);
                   3283:  *
                   3284:  *-ARGUMENTS:
                   3285:  *     lockp           Pointer to the sleep lock to be acquired.
                   3286:  *
                   3287:  *     priority        A hint to the scheduling policy as to the relative
                   3288:  *                     priority the caller wishes to be assigned while
                   3289:  *                     running in the kernel after waking up. The valid
                   3290:  *                     values for this argument are as follows:
                   3291:  *
                   3292:  *                     pridisk     Priority appropriate for disk driver
                   3293:  *                     prinet      Priority appropriate for network driver.
                   3294:  *                     pritty      Priority appropriate for terminal driver.
                   3295:  *                     pritape     Priority appropriate for tape driver.
                   3296:  *                     prihi       High priority.
                   3297:  *                     primed      Medium priority.
                   3298:  *                     prilo       Low priority.
                   3299:  *
                   3300:  *                     Drivers may use these values to request a priority
                   3301:  *                     appropriate to a given type of device or to request a
                   3302:  *                     priority that is high, medium or low relative to other
                   3303:  *                     activities within the kernel.
                   3304:  *
                   3305:  *                     It is also permissible to specify positive or negative
                   3306:  *                     offsets from the values defined above. Positive
                   3307:  *                     offsets result in favourable priority. The maximum
                   3308:  *                     allowable offset in all cases is 3 (eg. pridisk+3
                   3309:  *                     and pridisk-3 are valid values by pridisk+4 and
                   3310:  *                     pridisk-4 are not valid). Offsets can be useful in
                   3311:  *                     defining the relative importance of different locks or
                   3312:  *                     resources that may be hald by a given driver. In
                   3313:  *                     general, a higher relative priority should be used
                   3314:  *                     when the caller is attempting to acquire a highly-
                   3315:  *                     contended lock or resource, or when the caller is
                   3316:  *                     already holding one or more locks or kernel resources
                   3317:  *                     upon entry to SLEEP_LOCK_SIG ().
                   3318:  *
                   3319:  *                     The exact semantics of the "priority" argument to the
                   3320:  *                     scheduling class of the caller, and some scheduling
                   3321:  *                     classes may choose to ignore the argument for the
                   3322:  *                     purposes of assigning a scheduling priority.
                   3323:  *
                   3324:  *-DESCRIPTION:
                   3325:  *     SLEEP_LOCK_SIG () acquires the sleep lock specified by "lockp". If the
                   3326:  *     lock is not immediately available, the caller is put to sleep (the
                   3327:  *     caller's execution is suspended and other processes may be scheduled)
                   3328:  *     until the lock becomes available to the caller, at which point the
                   3329:  *     caller wakes up and returns with the lock held.
                   3330:  *
                   3331:  *     SLEEP_LOCK_SIG () may be interrupted by a signal, in which case it may
                   3332:  *     return early without acquiring the lock.
                   3333:  *
                   3334:  *     If the function is interrupted by a job control stop signal (eg
                   3335:  *     SIGSTOP, SIGTSTP, SIGTTIN, SIGTTOU) which results in the caller
                   3336:  *     entering a stopped state, the SLEEP_LOCK_SIG () function will
                   3337:  *     transparently retry the lock operation upon continuing (the caller
                   3338:  *     will not return without the lock).
                   3339:  *
                   3340:  *     If the function is interrupted by a signal other than a job control
                   3341:  *     signal, or by a job control signal that does not result in the caller
                   3342:  *     stopping (because the signal has a non-default disposition), the
                   3343:  *     SLEEP_LOCK_SIG () function will return early without acquiring the
                   3344:  *     lock.
                   3345:  *
                   3346:  *-RETURN VALUE:
                   3347:  *     SLEEP_LOCK_SIG () returns TRUE (a non-zero value) if the lock is
                   3348:  *     successfully acquired or FALSE (zero) if the function returned early
                   3349:  *     because of a signal.
                   3350:  *
                   3351:  *-LEVEL:
                   3352:  *     Base level only.
                   3353:  *
                   3354:  *-NOTES:
                   3355:  *     May sleep.
                   3356:  *
                   3357:  *     Sleep locks are not recursive. A call to SLEEP_LOCK_SIG () attempting
                   3358:  *     to acquire a lock that is currently held by the calling context will
                   3359:  *     result in deadlock.
                   3360:  *
                   3361:  *     Driver-defined basic locks and read/write locks may not be held across
                   3362:  *     calls to this function.
                   3363:  *
                   3364:  *     Driver-defined sleep locks may be held across calls to this function
                   3365:  *     subject to the recursion restrictions described above.
                   3366:  *
                   3367:  *-SEE_ALSO:
                   3368:  *     SLEEP_ALLOC (), SLEEP_DEALLOC (), SLEEP_LOCK (), SLEEP_LOCKAVAIL (),
                   3369:  *     SLEEP_LOCKOWNED (), SLEEP_TRYLOCK (), SLEEP_UNLOCK (), signals
                   3370:  */
                   3371: 
                   3372: #if    __USE_PROTO__
                   3373: bool_t (SLEEP_LOCK_SIG) (sleep_t * lockp, int priority)
                   3374: #else
                   3375: bool_t
                   3376: SLEEP_LOCK_SIG __ARGS ((lockp, priority))
                   3377: sleep_t              * lockp;
                   3378: int            priority;
                   3379: #endif
                   3380: {
                   3381:        pl_t            prev_pl;
                   3382: 
                   3383:        ASSERT (lockp != NULL);
                   3384:        ASSERT_BASE_LEVEL ();
                   3385: 
                   3386:        /*
                   3387:         * Take the path of least resistance; if the sleep lock is not
                   3388:         * currently held, then just acquire it and get out.
                   3389:         */
                   3390: 
                   3391:        if (ATOMIC_TEST_AND_SET_UCHAR (lockp->sl_locked) == 0) {
                   3392:                /*
                   3393:                 * We successfully acquired it! Just leave after writing in
                   3394:                 * the info for SLEEP_LOCKAVAIL ().
                   3395:                 */
                   3396: 
                   3397:                lockp->sl_holder = PROC_HANDLE ();
                   3398:                return TRUE;
                   3399:        }
                   3400: 
                   3401: 
                   3402:        /*
                   3403:         * OK, we do it the hard way.
                   3404:         *
                   3405:         * The sleep lock might have been unlocked while we waited to lock
                   3406:         * the process list, so we retest that member.
                   3407:         */
                   3408: 
                   3409:        prev_pl = PLIST_LOCK (lockp->sl_plist, "SLEEP_LOCK");
                   3410: 
                   3411:        if (ATOMIC_TEST_AND_SET_UCHAR (lockp->sl_locked) != 0) {
                   3412:                /*
                   3413:                 * No, we need to wait.
                   3414:                 */
                   3415: 
                   3416:                if (MAKE_SLEEPING (lockp->sl_plist, priority,
                   3417:                                   SLEEP_INTERRUPTIBLE) == PROCESS_SIGNALLED) {
                   3418:                        /*
                   3419:                         * We were signalled. MAKE_SLEEPING () will have
                   3420:                         * released the test-and-set lock on the process list,
                   3421:                         * so we just have to reset the interrupt priority
                   3422:                         * level and return an indication to the caller.
                   3423:                         */
                   3424: 
                   3425:                        (void) splx (prev_pl);
                   3426: 
                   3427:                        return FALSE;
                   3428:                }
                   3429: 
                   3430:                /*
                   3431:                 * We assert that whoever woke us up will have left the sleep
                   3432:                 * locked in the "locked" state for us. While *we* won't have
                   3433:                 * the process-list locked, someone else might so we can't
                   3434:                 * make an assertion on that.
                   3435:                 */
                   3436: 
                   3437:                ASSERT (lockp->sl_holder == PROC_HANDLE ());
                   3438:                ASSERT (ATOMIC_FETCH_UCHAR (lockp->sl_locked) != 0);
                   3439: 
                   3440:                (void) splx (prev_pl);
                   3441:        } else {
                   3442:                /*
                   3443:                 * Write the owner information for SLEEP_LOCKAVAIL () and
                   3444:                 * release the test-and-set lock on the process list.
                   3445:                 */
                   3446: 
                   3447:                lockp->sl_holder = PROC_HANDLE ();
                   3448: 
                   3449:                PLIST_UNLOCK (lockp->sl_plist, prev_pl);
                   3450:        }
                   3451: 
                   3452:        return TRUE;
                   3453: }
                   3454: 
                   3455: 
                   3456: /*
                   3457:  *-STATUS:
                   3458:  *     DDI/DKI
                   3459:  *
                   3460:  *-NAME:
                   3461:  *     SLEEP_TRYLOCK ()        Try to acquire a sleep lock.
                   3462:  *
                   3463:  *-SYNOPSIS:
                   3464:  *     #include <sys/types.h>
                   3465:  *     #include <sys/ksynch.h>
                   3466:  *
                   3467:  *     bool_t SLEEP_TRYLOCK (sleep_t * lockp);
                   3468:  *
                   3469:  *-ARGUMENTS:
                   3470:  *     lockp           Pointer to the sleep lock to be acquired.
                   3471:  *
                   3472:  *-DESCRIPTION:
                   3473:  *     If the lock specified by "lockp" is immediately available (can be
                   3474:  *     acquired without sleeping) SLEEP_TRYLOCK () acquires the lock. If the
                   3475:  *     lock is not immediately available, the function returns without
                   3476:  *     acquiring the lock.
                   3477:  *
                   3478:  *-RETURN VALUE:
                   3479:  *     SLEEP_TRYLOCK () returns TRUE (a non-zero value) if the lock is
                   3480:  *     successfully acquired or FALSE (zero) if the lock is not acquired.
                   3481:  *
                   3482:  *-LEVEL:
                   3483:  *     Base or interrupt.
                   3484:  *
                   3485:  *-NOTES:
                   3486:  *     Does not sleep.
                   3487:  *
                   3488:  *     Driver-defined basic locks, read/write locks and sleep locks may be
                   3489:  *     held across calls to this function.
                   3490:  *
                   3491:  *-SEE_ALSO:
                   3492:  *     SLEEP_ALLOC (), SLEEP_DEALLOC (), SLEEP_LOCK (), SLEEP_LOCK_SIG (),
                   3493:  *     SLEEP_LOCKAVAIL (), SLEEP_LOCKOWNED (), SLEEP_UNLOCK ()
                   3494:  */
                   3495: 
                   3496: #if    __USE_PROTO__
                   3497: bool_t (SLEEP_TRYLOCK) (sleep_t * lockp)
                   3498: #else
                   3499: bool_t
                   3500: SLEEP_TRYLOCK __ARGS ((lockp))
                   3501: sleep_t              * lockp;
                   3502: #endif
                   3503: {
                   3504:        ASSERT (lockp != NULL);
                   3505: 
                   3506:        if (ATOMIC_TEST_AND_SET_UCHAR (lockp->sl_locked) == 0) {
                   3507:                lockp->sl_holder = PROC_HANDLE ();
                   3508:                return TRUE;
                   3509:        }
                   3510: 
                   3511:        return FALSE;
                   3512: }
                   3513: 
                   3514: 
                   3515: /*
                   3516:  *-STATUS:
                   3517:  *     DDI/DKI
                   3518:  *
                   3519:  *-NAME:
                   3520:  *     SLEEP_UNLOCK () Release a sleep lock.
                   3521:  *
                   3522:  *-SYNOPSIS:
                   3523:  *     #include <sys/ksynch.h>
                   3524:  *
                   3525:  *     void SLEEP_UNLOCK (sleep_t * lockp);
                   3526:  *
                   3527:  *-ARGUMENTS:
                   3528:  *     lockp           Pointer to the sleep lock to be released.
                   3529:  *
                   3530:  *-DESCRIPTION:
                   3531:  *     SLEEP_UNLOCK () releases the sleep lock specified by "lockp". If there
                   3532:  *     are processes waiting for the lock, one of the waiting processes is
                   3533:  *     awakened.
                   3534:  *
                   3535:  *-RETURN VALUE:
                   3536:  *     None.
                   3537:  *
                   3538:  *-LEVEL:
                   3539:  *     Base or interrupt.
                   3540:  *
                   3541:  *-NOTES:
                   3542:  *     Does not sleep.
                   3543:  *
                   3544:  *     Driver-defined basic locks, read/write locks and sleep locks may be
                   3545:  *     held across calls to this function.
                   3546:  *
                   3547:  *-SEE_ALSO:
                   3548:  *     SLEEP_ALLOC (), SLEEP_DEALLOC (), SLEEP_LOCK (), SLEEP_LOCK_SIG (),
                   3549:  *     SLEEP_LOCKAVAIL (), SLEEP_LOCKOWNED (), SLEEP_TRYLOCK ()
                   3550:  */
                   3551: 
                   3552: #if    __USE_PROTO__
                   3553: void (SLEEP_UNLOCK) (sleep_t * lockp)
                   3554: #else
                   3555: void
                   3556: SLEEP_UNLOCK __ARGS ((lockp))
                   3557: sleep_t              * lockp;
                   3558: #endif
                   3559: {
                   3560:        pl_t            prev_pl;
                   3561: 
                   3562:        /*
                   3563:         * Make some assertions. Note that we *don't* assert that our
                   3564:         * PROC_HANDLE () matches "sl_holder", since thanks to
                   3565:         * SLEEP_TRYLOCK () allowing interrupt contexts to acquire sleep
                   3566:         * locks we can't rely on that.
                   3567:         */
                   3568: 
                   3569:        ASSERT (lockp != NULL);
                   3570:        ASSERT (ATOMIC_FETCH_UCHAR (lockp->sl_locked));
                   3571: 
                   3572: 
                   3573:        /*
                   3574:         * When we are unlocking the sleep lock, we must lock the process
                   3575:         * list so we can test whether there are any waiting processes to
                   3576:         * be given the lock.
                   3577:         */
                   3578: 
                   3579:        prev_pl = PLIST_LOCK (lockp->sl_plist, "SLEEP_UNLOCK");
                   3580: 
                   3581: 
                   3582:        /*
                   3583:         * If there are no waiters, we unlock the sleep lock, otherwise we
                   3584:         * wake the first waiting process and leave the lock in the locked
                   3585:         * state for the process to simply take over from us later.
                   3586:         *
                   3587:         * In order to cross-check things with the sleep function, we write
                   3588:         * the expected processes' identity into the lock.
                   3589:         */
                   3590: 
                   3591:        if ((lockp->sl_holder = WAKE_ONE (lockp->sl_plist)) == NULL) {
                   3592:                /*
                   3593:                 * No waiting processes, give the lock away.
                   3594:                 */
                   3595: 
                   3596:                ATOMIC_CLEAR_UCHAR (lockp->sl_locked);
                   3597:        }
                   3598: 
                   3599:        PLIST_UNLOCK (lockp->sl_plist, prev_pl);
                   3600: }
                   3601: 
                   3602: 
                   3603: /*
                   3604:  *-STATUS:
                   3605:  *     DDI/DKI
                   3606:  *
                   3607:  *-NAME:
                   3608:  *     SV_ALLOC ()     Allocate and initialize a synchronization variable.
                   3609:  *
                   3610:  *-SYNOPSIS:
                   3611:  *     #include <sys/kmem.h>
                   3612:  *     #include <sys/ksynch.h>
                   3613:  *
                   3614:  *     sv_t * SV_ALLOC (int flag);
                   3615:  *
                   3616:  *-ARGUMENTS:
                   3617:  *     flag            Specifies whether the caller is willing to sleep
                   3618:  *                     waiting for memory. If "flag" is set to KM_SLEEP, the
                   3619:  *                     caller will sleep if necessary until sufficient memory
                   3620:  *                     is available. If "flag" is set to KM_NOSLEEP, the
                   3621:  *                     caller will not sleep, but SLEEP_ALLOC () will return
                   3622:  *                     NULL if sufficient memory is not immediately
                   3623:  *                     available.
                   3624:  *
                   3625:  *-DESCRIPTION:
                   3626:  *     SV_ALLOC () dynamically allocates and initialises an instance of a
                   3627:  *     synchronization variable.
                   3628:  *
                   3629:  *-RETURN VALUE:
                   3630:  *     Upon successful completion, SV_ALLOC () returns a pointer to the newly
                   3631:  *     allocated synchronization variable. If KM_NOSLEEP is specified and
                   3632:  *     sufficient memory is not immediately available, SV_ALLOC () returns a
                   3633:  *     NULL pointer.
                   3634:  *
                   3635:  *-LEVEL:
                   3636:  *     Base only if "flag" is set to KM_SLEEP. Base or Interrupt if "flag" is
                   3637:  *     set to KM_NOSLEEP.
                   3638:  *
                   3639:  *-NOTES:
                   3640:  *     May sleep if "flag" is set to KM_NOSLEEP.
                   3641:  *
                   3642:  *     Driver-defined basic locks and read/write locks may be held across
                   3643:  *     calls to this function if "flag" is set to KM_NOSLEEP but may not be
                   3644:  *     held if "flag" is KM_SLEEP.
                   3645:  *
                   3646:  *     Driver-defined sleep locks may be held across calls to this function
                   3647:  *     regardless of the value of "flag".
                   3648:  *
                   3649:  *-SEE_ALSO:
                   3650:  *     SV_BROADCAST (), SV_DEALLOC (), SV_SIGNAL (), SV_WAIT (),
                   3651:  *     SV_WAIT_SIG ()
                   3652:  */
                   3653: 
                   3654: #if    __USE_PROTO__
                   3655: sv_t * (SV_ALLOC) (int flag)
                   3656: #else
                   3657: sv_t *
                   3658: SV_ALLOC __ARGS ((flag))
                   3659: int            flag;
                   3660: #endif
                   3661: {
                   3662:        sv_t          * svp;
                   3663: 
                   3664:        ASSERT (flag == KM_SLEEP || flag == KM_NOSLEEP);
                   3665: 
                   3666:        /*
                   3667:         * Allocate and initialise the data, possibly waiting for enough
                   3668:         * memory to become available.
                   3669:         */
                   3670: 
                   3671:        if ((svp = (sv_t *) _lock_malloc (sizeof (* svp),
                   3672:                                          flag)) != NULL) {
                   3673:                INIT_LNODE (& svp->sv_node, NULL, & synch_vars, flag);
                   3674:                PLIST_INIT (svp->sv_plist);
                   3675:        }
                   3676: 
                   3677:        return svp;
                   3678: }
                   3679: 
                   3680: 
                   3681: /*
                   3682:  *-STATUS:
                   3683:  *     DDI/DKI
                   3684:  *
                   3685:  *-NAME:
                   3686:  *     SV_BROADCAST () Wake up all processes sleeping on a synchronization
                   3687:  *                     variable.
                   3688:  *
                   3689:  *-SYNOPSIS:
                   3690:  *     #include <sys/ksynch.h>
                   3691:  *
                   3692:  *     void * SV_BROADCAST (sv_t * svp, int flags);
                   3693:  *
                   3694:  *-ARGUMENTS:
                   3695:  *     svp             Pointer to the synchronization variable to be
                   3696:  *                     broadcast signalled.
                   3697:  *
                   3698:  *     flags           Bit field for flags. No flags are defined for use in
                   3699:  *                     drivers and the "flags" argument must be set to zero.
                   3700:  *
                   3701:  *-DESCRIPTION:
                   3702:  *     If one or more processes are blocked on the synchronization variable
                   3703:  *     specified by "svp", SV_BROADCAST () wakes up all of the blocked
                   3704:  *     processes. Note that synchronization variables are stateless, and
                   3705:  *     therefore calls to SV_BROADCAST () only affect processes currently
                   3706:  *     blocked on the synchronization variable and have not effect on
                   3707:  *     processes that block on the synchronization variable at a later time.
                   3708:  *
                   3709:  *-RETURN VALUE:
                   3710:  *     None.
                   3711:  *
                   3712:  *-LEVEL:
                   3713:  *     Base or interrupt.
                   3714:  *
                   3715:  *-NOTES:
                   3716:  *     Does not sleep.
                   3717:  *
                   3718:  *     Driver-defined basic locks and read/write locks may be held across
                   3719:  *     calls to this function if "flag" is set to KM_NOSLEEP but may not be
                   3720:  *     held if "flag" is KM_SLEEP.
                   3721:  *
                   3722:  *     Driver-defined basic locks, read/write locks and sleep locks may be
                   3723:  *     held across calls to this function.
                   3724:  *
                   3725:  *-SEE_ALSO:
                   3726:  *     SV_ALLOC (), SV_DEALLOC (), SV_SIGNAL (), SV_WAIT (), SV_WAIT_SIG ()
                   3727:  */
                   3728: 
                   3729: #if    __USE_PROTO__
                   3730: void (SV_BROADCAST) (sv_t * svp, int flags)
                   3731: #else
                   3732: void
                   3733: SV_BROADCAST __ARGS ((svp, flags))
                   3734: sv_t         * svp;
                   3735: int            flags;
                   3736: #endif
                   3737: {
                   3738:        pl_t            prev_pl;
                   3739: 
                   3740:        ASSERT (flags == 0);
                   3741:        ASSERT (svp != NULL);
                   3742: 
                   3743:        /*
                   3744:         * Lock the list (required by WAKE_ALL ()), wake the sleepers, and
                   3745:         * unlock the list.
                   3746:         */
                   3747: 
                   3748:        prev_pl = PLIST_LOCK (svp->sv_plist, "SV_BROADCAST");
                   3749: 
                   3750:        WAKE_ALL (svp->sv_plist);
                   3751: 
                   3752:        PLIST_UNLOCK (svp->sv_plist, prev_pl);
                   3753: }
                   3754: 
                   3755: 
                   3756: /*
                   3757:  *-STATUS:
                   3758:  *     DDI/DKI
                   3759:  *
                   3760:  *-NAME:
                   3761:  *     SV_DEALLOC ()   Deallocate an instance of a synchronization variable.
                   3762:  *
                   3763:  *-SYNOPSIS:
                   3764:  *     #include <sys/ksynch.h>
                   3765:  *
                   3766:  *     void SV_DEALLOC (sv_t * svp);
                   3767:  *
                   3768:  *-ARGUMENTS:
                   3769:  *     svp             Pointer to the synchronization variable to be
                   3770:  *                     deallocated.
                   3771:  *
                   3772:  *-DESCRIPTION:
                   3773:  *     SV_DEALLOC () deallocates the synchronization variable specified by
                   3774:  *     "svp".
                   3775:  *
                   3776:  *-RETURN VALUE:
                   3777:  *     None.
                   3778:  *
                   3779:  *-LEVEL:
                   3780:  *     Base or Interrupt.
                   3781:  *
                   3782:  *-NOTES:
                   3783:  *     Does not sleep.
                   3784:  *
                   3785:  *     Driver-defined basic locks, read/write locks, and sleep locks may be
                   3786:  *     held across calls to this function.
                   3787:  *
                   3788:  *-SEE_ALSO:
                   3789:  *     SV_ALLOC (), SV_BROADCAST (), SV_SIGNAL (), SV_WAIT (), SV_WAIT_SIG ()
                   3790:  */
                   3791: 
                   3792: #if    __USE_PROTO__
                   3793: void (SV_DEALLOC) (sv_t * svp)
                   3794: #else
                   3795: void
                   3796: SV_DEALLOC __ARGS ((svp))
                   3797: sv_t         * svp;
                   3798: #endif
                   3799: {
                   3800:        ASSERT (svp != NULL);
                   3801: 
                   3802:        /*
                   3803:         * Remove from the list of all synchronization variables and free any
                   3804:         * statistics buffer space before freeing the lock itself.
                   3805:         */
                   3806: 
                   3807:        PLIST_DESTROY (svp->sv_plist);
                   3808: 
                   3809:        FREE_LNODE (& svp->sv_node, & synch_vars);
                   3810: 
                   3811:        _lock_free (svp, sizeof (* svp));
                   3812: }
                   3813: 
                   3814: 
                   3815: /*
                   3816:  *-STATUS:
                   3817:  *     DDI/DKI
                   3818:  *
                   3819:  *-NAME:
                   3820:  *     SV_SIGNAL ()    Wake up one process sleeping on a synchronization
                   3821:  *                     variable.
                   3822:  *
                   3823:  *-SYNOPSIS:
                   3824:  *     #include <sys/ksynch.h>
                   3825:  *
                   3826:  *     void SV_SIGNAL (sv_t * svp, int flags);
                   3827:  *
                   3828:  *-ARGUMENTS:
                   3829:  *     svp             Pointer to the synchronization variable to be
                   3830:  *                     signalled.
                   3831:  *
                   3832:  *     flags           Bit field for flags. No flags are defined for use in
                   3833:  *                     drivers and the "flags" argument must be set to zero.
                   3834:  *
                   3835:  *-DESCRIPTION:
                   3836:  *     If one or more processes are blocked on the synchronization variable
                   3837:  *     specified by "svp", SV_SIGNAL () wakes up a single blocked process.
                   3838:  *     Note that synchronization variables are stateless, and therefore
                   3839:  *     calls to SV_SIGNAL only affect processes currently blocked on the
                   3840:  *     synchronization variable and have no effect on processes that block on
                   3841:  *     the synchronization variable at a later time.
                   3842:  *
                   3843:  *-RETURN VALUE:
                   3844:  *     None.
                   3845:  *
                   3846:  *-LEVEL:
                   3847:  *     Base or Interrupt.
                   3848:  *
                   3849:  *-NOTES:
                   3850:  *     Does not sleep.
                   3851:  *
                   3852:  *     Driver-defined basic locks, read/write locks, and sleep locks may be
                   3853:  *     held across calls to this function.
                   3854:  *
                   3855:  *-SEE_ALSO:
                   3856:  *     SV_ALLOC (), SV_BROADCAST (), SV_DEALLOC (), SV_WAIT (),
                   3857:  *     SV_WAIT_SIG ()
                   3858:  */
                   3859: 
                   3860: #if    __USE_PROTO__
                   3861: void (SV_SIGNAL) (sv_t * svp, int flags)
                   3862: #else
                   3863: void
                   3864: SV_SIGNAL __ARGS ((svp, flags))
                   3865: sv_t         * svp;
                   3866: int            flags;
                   3867: #endif
                   3868: {
                   3869:        pl_t            prev_pl;
                   3870: 
                   3871:        ASSERT (flags == 0);
                   3872:        ASSERT (svp != NULL);
                   3873: 
                   3874:        /*
                   3875:         * Lock the list (required by WAKE_ONE ()), wake a sleeper, and
                   3876:         * unlock the list.
                   3877:         */
                   3878: 
                   3879:        prev_pl = PLIST_LOCK (svp->sv_plist, "SV_SIGNAL");
                   3880: 
                   3881:        (void) WAKE_ONE (svp->sv_plist);
                   3882: 
                   3883:        PLIST_UNLOCK (svp->sv_plist, prev_pl);
                   3884: }
                   3885: 
                   3886: 
                   3887: /*
                   3888:  *-STATUS:
                   3889:  *     DDI/DKI
                   3890:  *
                   3891:  *-NAME:
                   3892:  *     SV_WAIT ()      Sleep on a synchronization variable.
                   3893:  *
                   3894:  *-SYNOPSIS:
                   3895:  *     #include <sys/types.h>
                   3896:  *     #include <sys/ksynch.h>
                   3897:  *
                   3898:  *     void SV_WAIT (sv_t * svp, int priority, lock_t * lkp);
                   3899:  *
                   3900:  *-ARGUMENTS:
                   3901:  *     svp             Pointer to the synchronization variable on which to
                   3902:  *                     sleep.
                   3903:  *
                   3904:  *     priority        A hint to the scheduling policy as to the relative
                   3905:  *                     priority the caller wishes to be assigned while
                   3906:  *                     running in the kernel after waking up. The valid
                   3907:  *                     values for this argument are as follows:
                   3908:  *
                   3909:  *                     pridisk     Priority appropriate for disk driver
                   3910:  *                     prinet      Priority appropriate for network driver.
                   3911:  *                     pritty      Priority appropriate for terminal driver.
                   3912:  *                     pritape     Priority appropriate for tape driver.
                   3913:  *                     prihi       High priority.
                   3914:  *                     primed      Medium priority.
                   3915:  *                     prilo       Low priority.
                   3916:  *
                   3917:  *                     Drivers may use these values to request a priority
                   3918:  *                     appropriate to a given type of device or to request a
                   3919:  *                     priority that is high, medium or low relative to other
                   3920:  *                     activities within the kernel.
                   3921:  *
                   3922:  *                     It is also permissible to specify positive or negative
                   3923:  *                     offsets from the values defined above. Positive
                   3924:  *                     offsets result in favourable priority. The maximum
                   3925:  *                     allowable offset in all cases is 3 (eg. pridisk+3
                   3926:  *                     and pridisk-3 are valid values by pridisk+4 and
                   3927:  *                     pridisk-4 are not valid). Offsets can be useful in
                   3928:  *                     defining the relative importance of different locks or
                   3929:  *                     resources that may be hald by a given driver. In
                   3930:  *                     general, a higher relative priority should be used
                   3931:  *                     when the caller is attempting to acquire a highly-
                   3932:  *                     contended lock or resource, or when the caller is
                   3933:  *                     already holding one or more locks or kernel resources
                   3934:  *                     upon entry to SV_WAIT ().
                   3935:  *
                   3936:  *                     The exact semantics of the "priority" argument is
                   3937:  *                     specific to the scheduling class of the caller, and
                   3938:  *                     some scheduling classes may choose to ignore the
                   3939:  *                     argument for the purposes of assigning a scheduling
                   3940:  *                     priority.
                   3941:  *
                   3942:  *     lkp             Pointer to a basic lock which must be locked when
                   3943:  *                     SV_WAIT () is called. The basic lock is released when
                   3944:  *                     the calling process goes to sleep, as described below.
                   3945:  *-DESCRIPTION:
                   3946:  *     SV_WAIT () causes the calling process to go to sleep (the caller's
                   3947:  *     execution is suspended and other processes may be scheduled) waiting
                   3948:  *     for a call to SV_SIGNAL () or SV_BROADCAST () for the synchronization
                   3949:  *     variable specified by "svp".
                   3950:  *
                   3951:  *     The basic lock specified by "lkp" must be held by the caller upon
                   3952:  *     entry. The lock is released and the interrupt priority level is set to
                   3953:  *     plbase after the process is queued on the synchronization variable but
                   3954:  *     prior to switching context switching to another process. When the
                   3955:  *     caller returns from SV_WAIT () the basic lock is not held and the
                   3956:  *     interrupt priority level is equal to plbase.
                   3957:  *
                   3958:  *     The caller will not be interrupted by signals while sleeping inside
                   3959:  *     SV_WAIT ().
                   3960:  *
                   3961:  *-RETURN VALUE:
                   3962:  *     None.
                   3963:  *
                   3964:  *-LEVEL:
                   3965:  *     Base level only.
                   3966:  *
                   3967:  *-NOTES:
                   3968:  *     May sleep.
                   3969:  *
                   3970:  *     Driver-defined basic locks and read/write locks may not be held across
                   3971:  *     calls to this function.
                   3972:  *
                   3973:  *     Driver-defined sleep locks may be held across calls to this function.
                   3974:  *
                   3975:  *-SEE_ALSO:
                   3976:  *     SV_ALLOC (), SV_BROADCAST (), SV_DEALLOC (), SV_SIGNAL (),
                   3977:  *     SV_WAIT_SIG ()
                   3978:  */
                   3979: 
                   3980: #if    __USE_PROTO__
                   3981: void (SV_WAIT) (sv_t * svp, int priority, lock_t * lkp)
                   3982: #else
                   3983: void
                   3984: SV_WAIT __ARGS ((svp, priority, lkp))
                   3985: sv_t         * svp;
                   3986: int            priority;
                   3987: lock_t       * lkp;
                   3988: #endif
                   3989: {
                   3990:        ASSERT (svp != NULL);
                   3991:        ASSERT (lkp != NULL);
                   3992:        ASSERT_BASE_LEVEL ();
                   3993: 
                   3994:        /*
                   3995:         * First off, we have to lock the process list. After this is done we
                   3996:         * can safely release the client's basic lock, since once we have our
                   3997:         * lock the rest of the wait operation will proceed atomically.
                   3998:         */
                   3999: 
                   4000:        (void) PLIST_LOCK (svp->sv_plist, "SV_WAIT");
                   4001: 
                   4002:        UNLOCK (lkp, plhi);
                   4003: 
                   4004:        (void) MAKE_SLEEPING (svp->sv_plist, priority, SLEEP_NO_SIGNALS);
                   4005: 
                   4006:        (void) splbase ();              /* let's make sure... */
                   4007: }
                   4008: 
                   4009: 
                   4010: /*
                   4011:  *-STATUS:
                   4012:  *     DDI/DKI
                   4013:  *
                   4014:  *-NAME:
                   4015:  *     SV_WAIT_SIG ()  Sleep on a synchronization variable.
                   4016:  *
                   4017:  *-SYNOPSIS:
                   4018:  *     #include <sys/types.h>
                   4019:  *     #include <sys/ksynch.h>
                   4020:  *
                   4021:  *     bool_t SV_WAIT_SIG (sv_t * svp, int priority, lock_t * lkp);
                   4022:  *
                   4023:  *-ARGUMENTS:
                   4024:  *     svp             Pointer to the synchronization variable on which to
                   4025:  *                     sleep.
                   4026:  *
                   4027:  *     priority        A hint to the scheduling policy as to the relative
                   4028:  *                     priority the caller wishes to be assigned while
                   4029:  *                     running in the kernel after waking up. The valid
                   4030:  *                     values for this argument are as follows:
                   4031:  *
                   4032:  *                     pridisk     Priority appropriate for disk driver
                   4033:  *                     prinet      Priority appropriate for network driver.
                   4034:  *                     pritty      Priority appropriate for terminal driver.
                   4035:  *                     pritape     Priority appropriate for tape driver.
                   4036:  *                     prihi       High priority.
                   4037:  *                     primed      Medium priority.
                   4038:  *                     prilo       Low priority.
                   4039:  *
                   4040:  *                     Drivers may use these values to request a priority
                   4041:  *                     appropriate to a given type of device or to request a
                   4042:  *                     priority that is high, medium or low relative to other
                   4043:  *                     activities within the kernel.
                   4044:  *
                   4045:  *                     It is also permissible to specify positive or negative
                   4046:  *                     offsets from the values defined above. Positive
                   4047:  *                     offsets result in favourable priority. The maximum
                   4048:  *                     allowable offset in all cases is 3 (eg. pridisk+3
                   4049:  *                     and pridisk-3 are valid values by pridisk+4 and
                   4050:  *                     pridisk-4 are not valid). Offsets can be useful in
                   4051:  *                     defining the relative importance of different locks or
                   4052:  *                     resources that may be hald by a given driver. In
                   4053:  *                     general, a higher relative priority should be used
                   4054:  *                     when the caller is attempting to acquire a highly-
                   4055:  *                     contended lock or resource, or when the caller is
                   4056:  *                     already holding one or more locks or kernel resources
                   4057:  *                     upon entry to SV_WAIT_SIG ().
                   4058:  *
                   4059:  *                     The exact semantics of the "priority" argument is
                   4060:  *                     specific to the scheduling class of the caller, and
                   4061:  *                     some scheduling classes may choose to ignore the
                   4062:  *                     argument for the purposes of assigning a scheduling
                   4063:  *                     priority.
                   4064:  *
                   4065:  *     lkp             Pointer to a basic lock which must be locked when
                   4066:  *                     SV_WAIT_SIG () is called. The basic lock is released
                   4067:  *                     when the calling process goes to sleep, as described
                   4068:  *                     below.
                   4069:  *
                   4070:  *-DESCRIPTION:
                   4071:  *     SV_WAIT_SIG () causes the calling process to go to sleep (the caller's
                   4072:  *     execution is suspended and other processes may be scheduled) waiting
                   4073:  *     for a call to SV_SIGNAL () or SV_BROADCAST () for the synchronization
                   4074:  *     variable specified by "svp".
                   4075:  *
                   4076:  *     The basic lock specified by "lkp" must be held by the caller upon
                   4077:  *     entry. The lock is released and the interrupt priority level is set to
                   4078:  *     plbase after the process is queued on the synchronization variable but
                   4079:  *     prior to switching context switching to another process. When the
                   4080:  *     caller returns from SV_WAIT_SIG () the basic lock is not held and the
                   4081:  *     interrupt priority level is equal to plbase.
                   4082:  *
                   4083:  *     SV_WAIT_SIG () may be interrupted by a signal, in which case it will
                   4084:  *     return early without waiting for a call to SV_SIGNAL () or
                   4085:  *     SV_BROADCAST ().
                   4086:  *
                   4087:  *     If the function is interrupted by a job control signal (eg SIGSTOP,
                   4088:  *     SIGTSTP, SIGTTIN, SIGTTOU) which results in the caller entering a
                   4089:  *     stopped state, when continued the SV_WAIT_SIG () function will return
                   4090:  *     TRUE as if the process had been awakened by a call to SV_SIGNAL () or
                   4091:  *     SV_BROADCAST ().
                   4092:  *
                   4093:  *     If the caller is interrupted by a signal other than a job control
                   4094:  *     signal, or by a job control signal that does not result in the caller
                   4095:  *     stopping (because the signal has a non-default disposition), the
                   4096:  *     SV_WAIT_SIG () call will return FALSE.
                   4097:  *
                   4098:  *-RETURN VALUE:
                   4099:  *     SV_WAIT_SIG () returns TRUE (a non-zero value) if the caller woke up
                   4100:  *     because of a call to SV_SIGNAL () or SV_BROADCAST (), or if the caller
                   4101:  *     was stopped and subsequently continued. SV_WAIT_SIG () returns FALSE
                   4102:  *     (zero) if the caller woke up and returned early because of a signal
                   4103:  *     other than a job control stop signal, or by a job control signal that
                   4104:  *     did not result in the caller stopping because the signal has a non-
                   4105:  *     default disposition.
                   4106:  *
                   4107:  *-LEVEL:
                   4108:  *     Base level only.
                   4109:  *
                   4110:  *-NOTES:
                   4111:  *     May sleep.
                   4112:  *
                   4113:  *     Driver-defined basic locks and read/write locks may not be held across
                   4114:  *     calls to this function.
                   4115:  *
                   4116:  *     Driver-defined sleep locks may be held across calls to this function.
                   4117:  *
                   4118:  *-SEE_ALSO:
                   4119:  *     SV_ALLOC (), SV_BROADCAST (), SV_DEALLOC (), SV_SIGNAL (), SV_WAIT ()
                   4120:  */
                   4121: 
                   4122: #if    __USE_PROTO__
                   4123: bool_t (SV_WAIT_SIG) (sv_t * svp, int priority, lock_t * lkp)
                   4124: #else
                   4125: bool_t
                   4126: SV_WAIT_SIG __ARGS ((svp, priority, lkp))
                   4127: sv_t         * svp;
                   4128: int            priority;
                   4129: lock_t       * lkp;
                   4130: #endif
                   4131: {
                   4132:        bool_t          not_signalled;
                   4133: 
                   4134:        ASSERT (svp != NULL);
                   4135:        ASSERT (lkp != NULL);
                   4136:        ASSERT_BASE_LEVEL ();
                   4137: 
                   4138:        /*
                   4139:         * First off, we have to lock the process list. After this is done we
                   4140:         * can safely release the client's basic lock, since once we have our
                   4141:         * lock the rest of the wait operation will proceed atomically.
                   4142:         */
                   4143: 
                   4144:        (void) PLIST_LOCK (svp->sv_plist, "SV_WAIT_SIG");
                   4145: 
                   4146:        UNLOCK (lkp, plhi);
                   4147: 
                   4148:        not_signalled = MAKE_SLEEPING (svp->sv_plist, priority,
                   4149:                                       SLEEP_INTERRUPTIBLE) != PROCESS_SIGNALLED;
                   4150: 
                   4151:        (void) splbase ();      /* let's make sure */
                   4152: 
                   4153:        return not_signalled;
                   4154: }
                   4155: 
                   4156: 
                   4157: /*
                   4158:  * This function exercises some of the most basic facilities of the locking
                   4159:  * system. It is difficult to assure that the code presented in this file
                   4160:  * will work correctly, because the nature of the service provided is a
                   4161:  * temporal guarantee that can't be verified without performing arbitrary
                   4162:  * fine-grained interleavings of at least two execution paths through each
                   4163:  * combination of interacting functions.
                   4164:  *
                   4165:  * So, the best we can do here in a portable fashion is to present some tests
                   4166:  * of the observable properties of the above code, and to (hopefully) exercise
                   4167:  * the ASSERT () statements in the above for some minimal self-checking.
                   4168:  *
                   4169:  * One problem with the use of ASSERT () tests is that it's difficult to
                   4170:  * build negative tests. The argument to this function indicates a negative
                   4171:  * tests that should be performed, presumably in conjunction with some test
                   4172:  * script capable of verifying an exception report against a previous run.
                   4173:  *
                   4174:  * Our tests use a lock interrupt level appropriate to the environment; in
                   4175:  * user-mode tests under Coherent, disabling interrupts is prohibited
                   4176:  */
                   4177: 
                   4178: #if    __COHERENT__
                   4179: # define       test_pl         plbase
                   4180: #else
                   4181: # define       test_pl         plhi
                   4182: #endif
                   4183: 
                   4184: #if    __USE_PROTO__
                   4185: int (LOCK_TESTS) (int negative)
                   4186: #else
                   4187: int
                   4188: LOCK_TESTS __ARGS ((negative))
                   4189: int            negative;
                   4190: #endif
                   4191: {
                   4192:        pl_t            prev_pl;
                   4193: 
                   4194:        lock_t        * basic_lock;
                   4195:        rwlock_t      * rw_lock;
                   4196:        sleep_t       * sleep_lock;
                   4197:        sv_t          * synch_var;
                   4198: 
                   4199:        static lkinfo_t basic_info = { "test basic lock" };
                   4200:        static lkinfo_t rw_info = { "test read/write lock" };
                   4201:        static lkinfo_t sleep_info = { "test sleep lock" };
                   4202: 
                   4203:        /*
                   4204:         * Allocate some locks that we can play with...
                   4205:         */
                   4206: 
                   4207:        basic_lock = LOCK_ALLOC (32, test_pl, & basic_info, KM_SLEEP);
                   4208:        rw_lock = RW_ALLOC (10, test_pl, & rw_info, KM_SLEEP);
                   4209:        sleep_lock = SLEEP_ALLOC (0, & sleep_info, KM_SLEEP);
                   4210:        synch_var = SV_ALLOC (KM_SLEEP);
                   4211: 
                   4212: 
                   4213:        /*
                   4214:         * Basic locks.
                   4215:         */
                   4216: 
                   4217:        if ((prev_pl = TRYLOCK (basic_lock, test_pl)) == invpl ||
                   4218:            TRYLOCK (basic_lock, test_pl) != invpl)
                   4219:                return -1;
                   4220: 
                   4221: 
                   4222:        UNLOCK (basic_lock, prev_pl);
                   4223: 
                   4224:        prev_pl = LOCK (basic_lock, test_pl);
                   4225: 
                   4226:        if (TRYLOCK (basic_lock, test_pl) != invpl)
                   4227:                return -1;
                   4228: 
                   4229:        UNLOCK (basic_lock, prev_pl);
                   4230: 
                   4231:        /*
                   4232:         * Read/write locks.
                   4233:         */
                   4234: 
                   4235:        if ((prev_pl = RW_TRYRDLOCK (rw_lock, test_pl)) == invpl ||
                   4236:            RW_TRYRDLOCK (rw_lock, test_pl) == invpl ||
                   4237:            RW_TRYWRLOCK (rw_lock, test_pl) != invpl)
                   4238:                return -1;
                   4239: 
                   4240:        (void) RW_RDLOCK (rw_lock, test_pl);
                   4241: 
                   4242:        if (RW_TRYWRLOCK (rw_lock, test_pl) != invpl)
                   4243:                return -1;
                   4244: 
                   4245:        RW_UNLOCK (rw_lock, prev_pl);
                   4246:        RW_UNLOCK (rw_lock, prev_pl);
                   4247:        RW_UNLOCK (rw_lock, prev_pl);
                   4248: 
                   4249: 
                   4250:        if ((prev_pl = RW_TRYWRLOCK (rw_lock, test_pl)) == invpl ||
                   4251:            RW_TRYWRLOCK (rw_lock, test_pl) != invpl ||
                   4252:            RW_TRYRDLOCK (rw_lock, test_pl) != invpl)
                   4253:                return -1;
                   4254: 
                   4255:        RW_UNLOCK (rw_lock, prev_pl);
                   4256: 
                   4257: 
                   4258:        prev_pl = RW_WRLOCK (rw_lock, test_pl);
                   4259: 
                   4260:        if (RW_TRYWRLOCK (rw_lock, test_pl) != invpl ||
                   4261:            RW_TRYRDLOCK (rw_lock, test_pl) != invpl)
                   4262:                return -1;
                   4263: 
                   4264:        RW_UNLOCK (rw_lock, prev_pl);
                   4265: 
                   4266: 
                   4267:        /*
                   4268:         * Sleep locks.
                   4269:         */
                   4270: 
                   4271:        if (SLEEP_LOCKOWNED (sleep_lock) == TRUE ||
                   4272:            SLEEP_LOCKAVAIL (sleep_lock) == FALSE ||
                   4273:            SLEEP_TRYLOCK (sleep_lock) == FALSE ||
                   4274:            SLEEP_LOCKOWNED (sleep_lock) == FALSE ||
                   4275:            SLEEP_LOCKAVAIL (sleep_lock) == TRUE ||
                   4276:            SLEEP_TRYLOCK (sleep_lock) == TRUE)
                   4277:                return -1;
                   4278: 
                   4279:        SLEEP_UNLOCK (sleep_lock);
                   4280: 
                   4281:        if (SLEEP_LOCKOWNED (sleep_lock) == TRUE ||
                   4282:            SLEEP_LOCKAVAIL (sleep_lock) == FALSE ||
                   4283:            SLEEP_LOCK_SIG (sleep_lock, prilo) == FALSE ||
                   4284:            SLEEP_LOCKOWNED (sleep_lock) == FALSE ||
                   4285:            SLEEP_LOCKAVAIL (sleep_lock) == TRUE ||
                   4286:            SLEEP_TRYLOCK (sleep_lock) == TRUE)
                   4287:                return -1;
                   4288: 
                   4289:        SLEEP_UNLOCK (sleep_lock);
                   4290: 
                   4291:        SLEEP_LOCK (sleep_lock, prilo);
                   4292: 
                   4293:        if (SLEEP_LOCKOWNED (sleep_lock) == FALSE ||
                   4294:            SLEEP_LOCKAVAIL (sleep_lock) == TRUE ||
                   4295:            SLEEP_TRYLOCK (sleep_lock) == TRUE)
                   4296:                return -1;
                   4297: 
                   4298:        SLEEP_UNLOCK (sleep_lock);
                   4299: 
                   4300: 
                   4301:        /*
                   4302:         * Synchronisation variables: this is impossible to test without
                   4303:         * access to timeout functions. Once DDI/DKI timeout functions are
                   4304:         * available, we can use those to at least begin to exercise the
                   4305:         * notion of synchronization.
                   4306:         */
                   4307: 
                   4308: 
                   4309:        /*
                   4310:         * Negative testing... need to add this!
                   4311:         */
                   4312: 
                   4313:        /*
                   4314:         * Clean up and bail out.
                   4315:         */
                   4316: 
                   4317:        LOCK_DEALLOC (basic_lock);
                   4318:        RW_DEALLOC (rw_lock);
                   4319:        SLEEP_DEALLOC (sleep_lock);
                   4320:        SV_DEALLOC (synch_var);
                   4321: 
                   4322:        return 0;
                   4323: }

unix.superglobalmegacorp.com

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