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