|
|
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_*/
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.