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

1.1     ! root        1: /*
        !             2:  * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
        !             3:  *
        !             4:  * @APPLE_LICENSE_HEADER_START@
        !             5:  * 
        !             6:  * The contents of this file constitute Original Code as defined in and
        !             7:  * are subject to the Apple Public Source License Version 1.1 (the
        !             8:  * "License").  You may not use this file except in compliance with the
        !             9:  * License.  Please obtain a copy of the License at
        !            10:  * http://www.apple.com/publicsource and read it before using this file.
        !            11:  * 
        !            12:  * This Original Code and all software distributed under the License are
        !            13:  * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
        !            14:  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
        !            15:  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
        !            16:  * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT.  Please see the
        !            17:  * License for the specific language governing rights and limitations
        !            18:  * under the License.
        !            19:  * 
        !            20:  * @APPLE_LICENSE_HEADER_END@
        !            21:  */
        !            22: /* 
        !            23:  * 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.