Annotation of XNU/osfmk/kern/simple_lock.h, revision 1.1.1.1

1.1       root        1: /*
                      2:  * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
                      3:  *
                      4:  * @APPLE_LICENSE_HEADER_START@
                      5:  * 
                      6:  * The contents of this file constitute Original Code as defined in and
                      7:  * are subject to the Apple Public Source License Version 1.1 (the
                      8:  * "License").  You may not use this file except in compliance with the
                      9:  * License.  Please obtain a copy of the License at
                     10:  * http://www.apple.com/publicsource and read it before using this file.
                     11:  * 
                     12:  * This Original Code and all software distributed under the License are
                     13:  * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
                     14:  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
                     15:  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
                     16:  * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT.  Please see the
                     17:  * License for the specific language governing rights and limitations
                     18:  * under the License.
                     19:  * 
                     20:  * @APPLE_LICENSE_HEADER_END@
                     21:  */
                     22: /* 
                     23:  * Copyright (C) 1998 Apple Computer
                     24:  * All Rights Reserved
                     25:  */
                     26: /*
                     27:  * @OSF_COPYRIGHT@
                     28:  */
                     29: /*
                     30:  * Mach Operating System
                     31:  * Copyright (c) 1991,1990,1989,1988,1987 Carnegie Mellon University
                     32:  * All Rights Reserved.
                     33:  * 
                     34:  * Permission to use, copy, modify and distribute this software and its
                     35:  * documentation is hereby granted, provided that both the copyright
                     36:  * notice and this permission notice appear in all copies of the
                     37:  * software, derivative works or modified versions, and any portions
                     38:  * thereof, and that both notices appear in supporting documentation.
                     39:  * 
                     40:  * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
                     41:  * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
                     42:  * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
                     43:  * 
                     44:  * Carnegie Mellon requests users of this software to return to
                     45:  * 
                     46:  *  Software Distribution Coordinator  or  [email protected]
                     47:  *  School of Computer Science
                     48:  *  Carnegie Mellon University
                     49:  *  Pittsburgh PA 15213-3890
                     50:  * 
                     51:  * any improvements or extensions that they make and grant Carnegie Mellon
                     52:  * the rights to redistribute these changes.
                     53:  */
                     54: /*
                     55:  *     File:   kern/simple_lock.h (derived from kern/lock.h)
                     56:  *     Author: Avadis Tevanian, Jr., Michael Wayne Young
                     57:  *     Date:   1985
                     58:  *
                     59:  *     Simple Locking primitives definitions
                     60:  */
                     61: 
                     62: #ifndef        _SIMPLE_LOCK_H_
                     63: #define        _SIMPLE_LOCK_H_
                     64: 
                     65: /*
                     66:  * Configuration variables:
                     67:  *
                     68:  *
                     69:  *     MACH_LDEBUG:    record pc and thread of callers, turn on
                     70:  *                     all lock debugging.
                     71:  *
                     72:  *
                     73:  *     ETAP:           The Event Trace Analysis Package (ETAP) monitors
                     74:  *                     and records micro-kernel lock behavior and general
                     75:  *                     kernel events.  ETAP supports two levels of
                     76:  *                     tracing for locks:
                     77:  *                             - cumulative (ETAP_LOCK_ACCUMULATE)
                     78:  *                             - monitored  (ETAP_LOCK_MONITOR)
                     79:  *
                     80:  *                     Note: If either level of tracing is configured then
                     81:  *                           ETAP_LOCK_TRACE is automatically defined to 
                     82:  *                           equal one.
                     83:  *
                     84:  *                     Several macros are added throughout the lock code to
                     85:  *                      allow for convenient configuration.
                     86:  */
                     87: 
                     88: #include <mach/boolean.h>
                     89: #include <kern/kern_types.h>
                     90: 
                     91: #include <kern/simple_lock_types.h>
                     92: #include <mach/etap_events.h>
                     93: #include <mach/etap.h>
                     94: 
                     95: /*
                     96:  *     The Mach lock package exports the following simple lock abstractions:
                     97:  *
                     98:  *     Lock Type  Properties
                     99:  *     hw_lock    lowest level hardware abstraction; atomic,
                    100:  *                non-blocking, mutual exclusion; supports pre-emption
                    101:  *     usimple    non-blocking spinning lock, available in all
                    102:  *                kernel configurations; may be used from thread
                    103:  *                and interrupt contexts; supports debugging,
                    104:  *                statistics and pre-emption
                    105:  *     simple     non-blocking spinning lock, intended for SMP
                    106:  *                synchronization (vanishes on a uniprocessor);
                    107:  *                supports debugging, statistics and pre-emption
                    108:  *
                    109:  *     NOTES TO IMPLEMENTORS:  there are essentially two versions
                    110:  *     of the lock package.  One is portable, written in C, and
                    111:  *     supports all of the various flavors of debugging, statistics,
                    112:  *     uni- versus multi-processor, pre-emption, etc.  The "other"
                    113:  *     is whatever set of lock routines is provided by machine-dependent
                    114:  *     code.  Presumably, the machine-dependent package is heavily
                    115:  *     optimized and meant for production kernels.
                    116:  *
                    117:  *     We encourage implementors to focus on highly-efficient,
                    118:  *     production implementations of machine-dependent lock code,
                    119:  *     and use the portable lock package for everything else.
                    120:  */
                    121: 
                    122: #ifdef MACH_KERNEL_PRIVATE
                    123: /*
                    124:  *     Mach always initializes locks, even those statically
                    125:  *     allocated.
                    126:  *
                    127:  *     The conditional acquisition call, hw_lock_try,
                    128:  *     must return non-zero on success and zero on failure.
                    129:  *
                    130:  *     The hw_lock_held operation returns non-zero if the
                    131:  *     lock is set, zero if the lock is clear.  This operation
                    132:  *     should be implemented using an ordinary memory read,
                    133:  *     rather than a special atomic instruction, allowing
                    134:  *     a processor to spin in cache waiting for the lock to
                    135:  *     be released without chewing up bus cycles.
                    136:  */
                    137: extern void                    hw_lock_init(hw_lock_t);
                    138: extern void                    hw_lock_lock(hw_lock_t);
                    139: extern void                    hw_lock_unlock(hw_lock_t);
                    140: extern unsigned int            hw_lock_to(hw_lock_t, unsigned int);
                    141: extern unsigned int            hw_lock_try(hw_lock_t);
                    142: extern unsigned int            hw_lock_held(hw_lock_t);
                    143: #endif /* MACH_KERNEL_PRIVATE */
                    144: 
                    145: /*
                    146:  * Machine dependent atomic ops.  Probably should be in their own header.
                    147:  */
                    148: extern unsigned int            hw_lock_bit(unsigned int *, unsigned int, unsigned int);
                    149: extern unsigned int            hw_cpu_sync(unsigned int *, unsigned int);
                    150: extern unsigned int            hw_lock_mbits(unsigned int *, unsigned int, unsigned int,
                    151:        unsigned int, unsigned int);
                    152: void                           hw_unlock_bit(unsigned int *, unsigned int);
                    153: extern int                     hw_atomic_add(int *area, int inc);
                    154: extern int                     hw_atomic_sub(int *area, int dec);
                    155: extern unsigned int            hw_compare_and_store(unsigned int oldValue, unsigned int newValue, unsigned int *area);
                    156: extern void                    hw_queue_atomic(unsigned int *anchor, unsigned int *elem, unsigned int disp);
                    157: extern void                    hw_queue_atomic_list(unsigned int *anchor, unsigned int *first, unsigned int *last, unsigned int disp);
                    158: extern unsigned int            *hw_dequeue_atomic(unsigned int *anchor, unsigned int disp);
                    159: 
                    160: 
                    161: /*
                    162:  *     The remaining locking constructs may have two versions.
                    163:  *     One version is machine-independent, built in C on top of the
                    164:  *     hw_lock construct.  This version supports production, debugging
                    165:  *     and statistics configurations and is portable across architectures.
                    166:  *
                    167:  *     Any particular port may override some or all of the portable
                    168:  *     lock package for whatever reason -- usually efficiency.
                    169:  *
                    170:  *     The direct use of hw_locks by machine-independent Mach code
                    171:  *     should be rare; the preferred spinning lock is the simple_lock
                    172:  *     (see below).
                    173:  */
                    174: 
                    175: /*
                    176:  *     A "simple" spin lock, providing non-blocking mutual
                    177:  *     exclusion and conditional acquisition.
                    178:  *
                    179:  *     The usimple_lock exists even in uniprocessor configurations.
                    180:  *     A data structure is always allocated for it and the following
                    181:  *     operations are always defined:
                    182:  *
                    183:  *             usimple_lock_init       lock initialization (mandatory!)
                    184:  *             usimple_lock            lock acquisition
                    185:  *             usimple_unlock          lock release
                    186:  *             usimple_lock_try        conditional lock acquisition;
                    187:  *                                     non-zero means success
                    188:  *      Simple lock DEBUG interfaces
                    189:  *             usimple_lock_held       verify lock already held by me
                    190:  *             usimple_lock_none_held  verify no usimple locks are held
                    191:  *
                    192:  *     The usimple_lock may be used for synchronization between
                    193:  *     thread context and interrupt context, or between a uniprocessor
                    194:  *     and an intelligent device.  Obviously, it may also be used for
                    195:  *     multiprocessor synchronization.  Its use should be rare; the
                    196:  *     simple_lock is the preferred spinning lock (see below).
                    197:  *
                    198:  *     The usimple_lock supports optional lock debugging and statistics.
                    199:  *
                    200:  *     Normally, we expect the usimple_lock data structure to be
                    201:  *     defined here, with its operations implemented in an efficient,
                    202:  *     machine-dependent way.  However, any implementation may choose
                    203:  *     to rely on a C-based, portable  version of the usimple_lock for
                    204:  *     debugging, statistics, and/or tracing.  Three hooks are used in
                    205:  *     the portable lock package to allow the machine-dependent package
                    206:  *     to override some or all of the portable package's features.
                    207:  *
                    208:  *     The usimple_lock also handles pre-emption.  Lock acquisition
                    209:  *     implies disabling pre-emption, while lock release implies
                    210:  *     re-enabling pre-emption.  Conditional lock acquisition does
                    211:  *     not assume success:  on success, pre-emption is disabled
                    212:  *     but on failure the pre-emption state remains the same as
                    213:  *     the pre-emption state before the acquisition attempt.
                    214:  */
                    215: 
                    216: /*
                    217:  *     Each usimple_lock has a type, used for debugging and
                    218:  *     statistics.  This type may safely be ignored in a
                    219:  *     production configuration.
                    220:  *
                    221:  *     The conditional acquisition call, usimple_lock_try,
                    222:  *     must return non-zero on success and zero on failure.
                    223:  */
                    224: extern void            usimple_lock_init(usimple_lock_t,etap_event_t);
                    225: extern void            usimple_lock(usimple_lock_t);
                    226: extern void            usimple_unlock(usimple_lock_t);
                    227: extern unsigned int    usimple_lock_try(usimple_lock_t);
                    228: extern void            usimple_lock_held(usimple_lock_t);
                    229: extern void            usimple_lock_none_held(void);
                    230: 
                    231: 
                    232: /*
                    233:  *     Upon the usimple_lock we define the simple_lock, which
                    234:  *     exists for SMP configurations.  These locks aren't needed
                    235:  *     in a uniprocessor configuration, so compile-time tricks
                    236:  *     make them disappear when NCPUS==1.  (For debugging purposes,
                    237:  *     however, they can be enabled even on a uniprocessor.)  This
                    238:  *     should be the "most popular" spinning lock; the usimple_lock
                    239:  *     and hw_lock should only be used in rare cases.
                    240:  *
                    241:  *     IMPORTANT:  simple_locks that may be shared between interrupt
                    242:  *     and thread context must have their use coordinated with spl.
                    243:  *     The spl level must alway be the same when acquiring the lock.
                    244:  *     Otherwise, deadlock may result.
                    245:  */
                    246: 
                    247: #if MACH_KERNEL_PRIVATE
                    248: #include <cpus.h>
                    249: #include <mach_ldebug.h>
                    250: 
                    251: #if    NCPUS == 1 && !ETAP_LOCK_TRACE && !USLOCK_DEBUG
                    252: /*
                    253:  *     MACH_RT is a very special case:  in the case that the
                    254:  *     machine-dependent lock package hasn't taken responsibility
                    255:  *     but there is no other reason to turn on locks, if MACH_RT
                    256:  *     is turned on locks denote critical, non-preemptable points
                    257:  *     in the code.
                    258:  *
                    259:  *     Otherwise, simple_locks may be layered directly on top of
                    260:  *     usimple_locks.
                    261:  *
                    262:  *     N.B.  The reason that simple_lock_try may be assumed to
                    263:  *     succeed under MACH_RT is that the definition only is used
                    264:  *     when NCPUS==1 AND because simple_locks shared between thread
                    265:  *     and interrupt context are always acquired with elevated spl.
                    266:  *     Thus, it is never possible to be interrupted in a dangerous
                    267:  *     way while holding a simple_lock.
                    268:  */
                    269: /*
                    270:  *     for locks and there is no other apparent reason to turn them on.
                    271:  *     So make them disappear.
                    272:  */
                    273: #define simple_lock_init(l,t)
                    274: #define        simple_lock(l)          disable_preemption()
                    275: #define        simple_unlock(l)        enable_preemption()
                    276: #define simple_lock_try(l)     (disable_preemption(), 1)
                    277: #define simple_lock_addr(lock) ((simple_lock_t)0)
                    278: #define        __slock_held_func__(l)  preemption_is_disabled()
                    279: #endif /* NCPUS == 1 && !ETAP_LOCK_TRACE && !USLOCK_DEBUG */
                    280: 
                    281: #if    ETAP_LOCK_TRACE
                    282: extern void    simple_lock_no_trace(simple_lock_t l);
                    283: extern int     simple_lock_try_no_trace(simple_lock_t l);
                    284: extern void    simple_unlock_no_trace(simple_lock_t l);
                    285: #endif /* ETAP_LOCK_TRACE */
                    286: 
                    287: #endif /* MACH_KERNEL_PRIVATE */
                    288: 
                    289: /*
                    290:  * If we got to here and we still don't have simple_lock_init
                    291:  * defined, then we must either be outside the osfmk component,
                    292:  * running on a true SMP, or need debug.
                    293:  */
                    294: #if !defined(simple_lock_init)
                    295: #define simple_lock_init(l,t)  usimple_lock_init(l,t)
                    296: #define        simple_lock(l)          usimple_lock(l)
                    297: #define        simple_unlock(l)        usimple_unlock(l)
                    298: #define simple_lock_try(l)     usimple_lock_try(l)
                    299: #define simple_lock_addr(l)    (&(l))
                    300: #define        __slock_held_func__(l)  usimple_lock_held(l)
                    301: #endif / * !defined(simple_lock_init) */
                    302: 
                    303: #if    USLOCK_DEBUG
                    304: /*
                    305:  *     Debug-time only:
                    306:  *             + verify that usimple_lock is already held by caller
                    307:  *             + verify that usimple_lock is NOT held by caller
                    308:  *             + verify that current processor owns no usimple_locks
                    309:  *
                    310:  *     We do not provide a simple_lock_NOT_held function because
                    311:  *     it's impossible to verify when only MACH_RT is turned on.
                    312:  *     In that situation, only preemption is enabled/disabled
                    313:  *     around lock use, and it's impossible to tell which lock
                    314:  *     acquisition caused preemption to be disabled.  However,
                    315:  *     note that it's still valid to use check_simple_locks
                    316:  *     when only MACH_RT is turned on -- no locks should be
                    317:  *     held, hence preemption should be enabled.
                    318:  *     Actually, the above isn't strictly true, as explicit calls
                    319:  *     to disable_preemption() need to be accounted for.
                    320:  */
                    321: #define        simple_lock_held(l)     __slock_held_func__(l)
                    322: #define        check_simple_locks()    usimple_lock_none_held()
                    323: #else  /* USLOCK_DEBUG */
                    324: #define        simple_lock_held(l)
                    325: #define        check_simple_locks()
                    326: #endif /* USLOCK_DEBUG */
                    327: 
                    328: #endif /*!_SIMPLE_LOCK_H_*/

unix.superglobalmegacorp.com

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