|
|
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.