]>
Commit | Line | Data |
---|---|---|
1c79356b A |
1 | /* |
2 | * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. | |
3 | * | |
8ad349bb | 4 | * @APPLE_LICENSE_OSREFERENCE_HEADER_START@ |
1c79356b | 5 | * |
8ad349bb A |
6 | * This file contains Original Code and/or Modifications of Original Code |
7 | * as defined in and that are subject to the Apple Public Source License | |
8 | * Version 2.0 (the 'License'). You may not use this file except in | |
9 | * compliance with the License. The rights granted to you under the | |
10 | * License may not be used to create, or enable the creation or | |
11 | * redistribution of, unlawful or unlicensed copies of an Apple operating | |
12 | * system, or to circumvent, violate, or enable the circumvention or | |
13 | * violation of, any terms of an Apple operating system software license | |
14 | * agreement. | |
15 | * | |
16 | * Please obtain a copy of the License at | |
17 | * http://www.opensource.apple.com/apsl/ and read it before using this | |
18 | * file. | |
19 | * | |
20 | * The Original Code and all software distributed under the License are | |
21 | * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER | |
22 | * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, | |
23 | * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, | |
24 | * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. | |
25 | * Please see the License for the specific language governing rights and | |
26 | * limitations under the License. | |
27 | * | |
28 | * @APPLE_LICENSE_OSREFERENCE_HEADER_END@ | |
1c79356b A |
29 | */ |
30 | /* | |
31 | * @OSF_COPYRIGHT@ | |
32 | */ | |
33 | /* | |
34 | * Mach Operating System | |
35 | * Copyright (c) 1989 Carnegie-Mellon University | |
36 | * All rights reserved. The CMU software License Agreement specifies | |
37 | * the terms and conditions for use and redistribution. | |
38 | */ | |
39 | ||
1c79356b A |
40 | #include <mach_rt.h> |
41 | #include <platforms.h> | |
42 | #include <mach_ldebug.h> | |
43 | #include <i386/asm.h> | |
1c79356b | 44 | |
9bccf70c | 45 | #include "assym.s" |
1c79356b | 46 | |
91447636 A |
47 | #define PAUSE rep; nop |
48 | ||
1c79356b A |
49 | /* |
50 | * When performance isn't the only concern, it's | |
51 | * nice to build stack frames... | |
52 | */ | |
91447636 A |
53 | #define BUILD_STACK_FRAMES (GPROF || \ |
54 | ((MACH_LDEBUG || ETAP_LOCK_TRACE) && MACH_KDB)) | |
1c79356b A |
55 | |
56 | #if BUILD_STACK_FRAMES | |
57 | ||
91447636 A |
58 | /* STack-frame-relative: */ |
59 | #define L_PC B_PC | |
60 | #define L_ARG0 B_ARG0 | |
61 | #define L_ARG1 B_ARG1 | |
62 | ||
63 | #define LEAF_ENTRY(name) \ | |
64 | Entry(name); \ | |
65 | FRAME; \ | |
66 | MCOUNT | |
67 | ||
68 | #define LEAF_ENTRY2(n1,n2) \ | |
69 | Entry(n1); \ | |
70 | Entry(n2); \ | |
71 | FRAME; \ | |
72 | MCOUNT | |
73 | ||
74 | #define LEAF_RET \ | |
75 | EMARF; \ | |
76 | ret | |
1c79356b | 77 | |
91447636 | 78 | #else /* BUILD_STACK_FRAMES */ |
1c79356b | 79 | |
91447636 A |
80 | /* Stack-pointer-relative: */ |
81 | #define L_PC S_PC | |
82 | #define L_ARG0 S_ARG0 | |
83 | #define L_ARG1 S_ARG1 | |
84 | ||
85 | #define LEAF_ENTRY(name) \ | |
86 | Entry(name) | |
87 | ||
88 | #define LEAF_ENTRY2(n1,n2) \ | |
89 | Entry(n1); \ | |
90 | Entry(n2) | |
91 | ||
92 | #define LEAF_RET \ | |
93 | ret | |
1c79356b | 94 | |
91447636 | 95 | #endif /* BUILD_STACK_FRAMES */ |
1c79356b | 96 | |
91447636 A |
97 | |
98 | /* Non-leaf routines always have a stack frame: */ | |
99 | ||
100 | #define NONLEAF_ENTRY(name) \ | |
101 | Entry(name); \ | |
102 | FRAME; \ | |
103 | MCOUNT | |
104 | ||
105 | #define NONLEAF_ENTRY2(n1,n2) \ | |
106 | Entry(n1); \ | |
107 | Entry(n2); \ | |
108 | FRAME; \ | |
109 | MCOUNT | |
110 | ||
111 | #define NONLEAF_RET \ | |
112 | EMARF; \ | |
113 | ret | |
1c79356b A |
114 | |
115 | ||
55e303ae A |
116 | #define M_ILK (%edx) |
117 | #define M_LOCKED MUTEX_LOCKED(%edx) | |
118 | #define M_WAITERS MUTEX_WAITERS(%edx) | |
119 | #define M_PROMOTED_PRI MUTEX_PROMOTED_PRI(%edx) | |
91447636 A |
120 | #define M_ITAG MUTEX_ITAG(%edx) |
121 | #define M_PTR MUTEX_PTR(%edx) | |
1c79356b | 122 | #if MACH_LDEBUG |
55e303ae A |
123 | #define M_TYPE MUTEX_TYPE(%edx) |
124 | #define M_PC MUTEX_PC(%edx) | |
125 | #define M_THREAD MUTEX_THREAD(%edx) | |
1c79356b A |
126 | #endif /* MACH_LDEBUG */ |
127 | ||
55e303ae | 128 | #include <i386/mp.h> |
1c79356b | 129 | #define CX(addr,reg) addr(,reg,4) |
1c79356b A |
130 | |
131 | #if MACH_LDEBUG | |
132 | /* | |
133 | * Routines for general lock debugging. | |
134 | */ | |
8ad349bb A |
135 | #define S_TYPE SLOCK_TYPE(%edx) |
136 | #define S_PC SLOCK_PC(%edx) | |
137 | #define S_THREAD SLOCK_THREAD(%edx) | |
138 | #define S_DURATIONH SLOCK_DURATIONH(%edx) | |
139 | #define S_DURATIONL SLOCK_DURATIONL(%edx) | |
1c79356b A |
140 | |
141 | /* | |
142 | * Checks for expected lock types and calls "panic" on | |
143 | * mismatch. Detects calls to Mutex functions with | |
144 | * type simplelock and vice versa. | |
145 | */ | |
146 | #define CHECK_MUTEX_TYPE() \ | |
9bccf70c | 147 | cmpl $ MUTEX_TAG,M_TYPE ; \ |
1c79356b A |
148 | je 1f ; \ |
149 | pushl $2f ; \ | |
150 | call EXT(panic) ; \ | |
151 | hlt ; \ | |
152 | .data ; \ | |
153 | 2: String "not a mutex!" ; \ | |
154 | .text ; \ | |
155 | 1: | |
156 | ||
8ad349bb A |
157 | #define CHECK_SIMPLE_LOCK_TYPE() \ |
158 | cmpl $ USLOCK_TAG,S_TYPE ; \ | |
159 | je 1f ; \ | |
160 | pushl $2f ; \ | |
161 | call EXT(panic) ; \ | |
162 | hlt ; \ | |
163 | .data ; \ | |
164 | 2: String "not a simple lock!" ; \ | |
165 | .text ; \ | |
166 | 1: | |
167 | ||
1c79356b A |
168 | /* |
169 | * If one or more simplelocks are currently held by a thread, | |
170 | * an attempt to acquire a mutex will cause this check to fail | |
171 | * (since a mutex lock may context switch, holding a simplelock | |
172 | * is not a good thing). | |
173 | */ | |
91447636 | 174 | #if MACH_RT |
1c79356b | 175 | #define CHECK_PREEMPTION_LEVEL() \ |
91447636 | 176 | cmpl $0,%gs:CPU_PREEMPTION_LEVEL ; \ |
1c79356b A |
177 | je 1f ; \ |
178 | pushl $2f ; \ | |
179 | call EXT(panic) ; \ | |
180 | hlt ; \ | |
181 | .data ; \ | |
182 | 2: String "preemption_level != 0!" ; \ | |
183 | .text ; \ | |
184 | 1: | |
185 | #else /* MACH_RT */ | |
186 | #define CHECK_PREEMPTION_LEVEL() | |
187 | #endif /* MACH_RT */ | |
188 | ||
189 | #define CHECK_NO_SIMPLELOCKS() \ | |
91447636 | 190 | cmpl $0,%gs:CPU_SIMPLE_LOCK_COUNT ; \ |
1c79356b A |
191 | je 1f ; \ |
192 | pushl $2f ; \ | |
193 | call EXT(panic) ; \ | |
194 | hlt ; \ | |
195 | .data ; \ | |
196 | 2: String "simple_locks_held!" ; \ | |
197 | .text ; \ | |
198 | 1: | |
199 | ||
200 | /* | |
201 | * Verifies return to the correct thread in "unlock" situations. | |
202 | */ | |
203 | #define CHECK_THREAD(thd) \ | |
91447636 | 204 | movl %gs:CPU_ACTIVE_THREAD,%ecx ; \ |
1c79356b A |
205 | testl %ecx,%ecx ; \ |
206 | je 1f ; \ | |
207 | cmpl %ecx,thd ; \ | |
208 | je 1f ; \ | |
209 | pushl $2f ; \ | |
210 | call EXT(panic) ; \ | |
211 | hlt ; \ | |
212 | .data ; \ | |
213 | 2: String "wrong thread!" ; \ | |
214 | .text ; \ | |
215 | 1: | |
216 | ||
217 | #define CHECK_MYLOCK(thd) \ | |
91447636 | 218 | movl %gs:CPU_ACTIVE_THREAD,%ecx ; \ |
1c79356b A |
219 | testl %ecx,%ecx ; \ |
220 | je 1f ; \ | |
221 | cmpl %ecx,thd ; \ | |
222 | jne 1f ; \ | |
223 | pushl $2f ; \ | |
224 | call EXT(panic) ; \ | |
225 | hlt ; \ | |
226 | .data ; \ | |
227 | 2: String "mylock attempt!" ; \ | |
228 | .text ; \ | |
229 | 1: | |
230 | ||
231 | #define METER_SIMPLE_LOCK_LOCK(reg) \ | |
232 | pushl reg ; \ | |
233 | call EXT(meter_simple_lock) ; \ | |
234 | popl reg | |
235 | ||
236 | #define METER_SIMPLE_LOCK_UNLOCK(reg) \ | |
237 | pushl reg ; \ | |
238 | call EXT(meter_simple_unlock) ; \ | |
239 | popl reg | |
240 | ||
241 | #else /* MACH_LDEBUG */ | |
242 | #define CHECK_MUTEX_TYPE() | |
243 | #define CHECK_SIMPLE_LOCK_TYPE | |
244 | #define CHECK_THREAD(thd) | |
245 | #define CHECK_PREEMPTION_LEVEL() | |
246 | #define CHECK_NO_SIMPLELOCKS() | |
247 | #define CHECK_MYLOCK(thd) | |
248 | #define METER_SIMPLE_LOCK_LOCK(reg) | |
249 | #define METER_SIMPLE_LOCK_UNLOCK(reg) | |
250 | #endif /* MACH_LDEBUG */ | |
251 | ||
252 | ||
253 | /* | |
254 | * void hw_lock_init(hw_lock_t) | |
255 | * | |
256 | * Initialize a hardware lock. | |
257 | */ | |
91447636 | 258 | LEAF_ENTRY(hw_lock_init) |
1c79356b | 259 | movl L_ARG0,%edx /* fetch lock pointer */ |
91447636 A |
260 | movl $0,0(%edx) /* clear the lock */ |
261 | LEAF_RET | |
1c79356b A |
262 | |
263 | /* | |
264 | * void hw_lock_lock(hw_lock_t) | |
265 | * | |
266 | * Acquire lock, spinning until it becomes available. | |
267 | * MACH_RT: also return with preemption disabled. | |
268 | */ | |
91447636 | 269 | LEAF_ENTRY(hw_lock_lock) |
1c79356b A |
270 | movl L_ARG0,%edx /* fetch lock pointer */ |
271 | ||
8ad349bb A |
272 | movl L_PC,%ecx |
273 | 1: DISABLE_PREEMPTION | |
91447636 A |
274 | movl 0(%edx), %eax |
275 | testl %eax,%eax /* lock locked? */ | |
276 | jne 3f /* branch if so */ | |
277 | lock; cmpxchgl %ecx,0(%edx) /* try to acquire the HW lock */ | |
1c79356b | 278 | jne 3f |
9bccf70c | 279 | movl $1,%eax /* In case this was a timeout call */ |
91447636 | 280 | LEAF_RET /* if yes, then nothing left to do */ |
8ad349bb A |
281 | |
282 | 3: ENABLE_PREEMPTION /* no reason we can't be preemptable */ | |
91447636 A |
283 | PAUSE /* pause for hyper-threading */ |
284 | jmp 1b /* try again */ | |
1c79356b | 285 | |
55e303ae A |
286 | /* |
287 | * unsigned int hw_lock_to(hw_lock_t, unsigned int) | |
288 | * | |
289 | * Acquire lock, spinning until it becomes available or timeout. | |
290 | * MACH_RT: also return with preemption disabled. | |
291 | */ | |
91447636 | 292 | LEAF_ENTRY(hw_lock_to) |
55e303ae | 293 | 1: |
91447636 | 294 | movl L_ARG0,%edx /* fetch lock pointer */ |
8ad349bb | 295 | movl L_PC,%ecx |
55e303ae A |
296 | /* |
297 | * Attempt to grab the lock immediately | |
298 | * - fastpath without timeout nonsense. | |
299 | */ | |
91447636 A |
300 | DISABLE_PREEMPTION |
301 | movl 0(%edx), %eax | |
302 | testl %eax,%eax /* lock locked? */ | |
303 | jne 2f /* branch if so */ | |
304 | lock; cmpxchgl %ecx,0(%edx) /* try to acquire the HW lock */ | |
305 | jne 2f /* branch on failure */ | |
55e303ae | 306 | movl $1,%eax |
91447636 | 307 | LEAF_RET |
55e303ae A |
308 | |
309 | 2: | |
310 | #define INNER_LOOP_COUNT 1000 | |
311 | /* | |
312 | * Failed to get the lock so set the timeout | |
313 | * and then spin re-checking the lock but pausing | |
314 | * every so many (INNER_LOOP_COUNT) spins to check for timeout. | |
315 | */ | |
316 | movl L_ARG1,%ecx /* fetch timeout */ | |
317 | push %edi | |
318 | push %ebx | |
319 | mov %edx,%edi | |
320 | ||
321 | rdtsc /* read cyclecount into %edx:%eax */ | |
322 | addl %ecx,%eax /* fetch and timeout */ | |
323 | adcl $0,%edx /* add carry */ | |
324 | mov %edx,%ecx | |
325 | mov %eax,%ebx /* %ecx:%ebx is the timeout expiry */ | |
8ad349bb A |
326 | 3: |
327 | ENABLE_PREEMPTION /* no reason not to be preempted now */ | |
55e303ae A |
328 | 4: |
329 | /* | |
330 | * The inner-loop spin to look for the lock being freed. | |
331 | */ | |
55e303ae A |
332 | mov $(INNER_LOOP_COUNT),%edx |
333 | 5: | |
91447636 A |
334 | PAUSE /* pause for hyper-threading */ |
335 | movl 0(%edi),%eax /* spin checking lock value in cache */ | |
336 | testl %eax,%eax | |
55e303ae A |
337 | je 6f /* zero => unlocked, try to grab it */ |
338 | decl %edx /* decrement inner loop count */ | |
339 | jnz 5b /* time to check for timeout? */ | |
340 | ||
341 | /* | |
342 | * Here after spinning INNER_LOOP_COUNT times, check for timeout | |
343 | */ | |
344 | rdtsc /* cyclecount into %edx:%eax */ | |
345 | cmpl %ecx,%edx /* compare high-order 32-bits */ | |
346 | jb 4b /* continue spinning if less, or */ | |
347 | cmpl %ebx,%eax /* compare low-order 32-bits */ | |
8ad349bb | 348 | jb 5b /* continue if less, else bail */ |
55e303ae A |
349 | xor %eax,%eax /* with 0 return value */ |
350 | pop %ebx | |
351 | pop %edi | |
91447636 | 352 | LEAF_RET |
55e303ae A |
353 | |
354 | 6: | |
355 | /* | |
356 | * Here to try to grab the lock that now appears to be free | |
357 | * after contention. | |
358 | */ | |
8ad349bb A |
359 | movl 8+L_PC,%edx /* calling pc (8+ for pushed regs) */ |
360 | DISABLE_PREEMPTION | |
91447636 | 361 | lock; cmpxchgl %edx,0(%edi) /* try to acquire the HW lock */ |
8ad349bb | 362 | jne 3b /* no - spin again */ |
55e303ae A |
363 | movl $1,%eax /* yes */ |
364 | pop %ebx | |
365 | pop %edi | |
91447636 | 366 | LEAF_RET |
55e303ae | 367 | |
1c79356b A |
368 | /* |
369 | * void hw_lock_unlock(hw_lock_t) | |
370 | * | |
371 | * Unconditionally release lock. | |
372 | * MACH_RT: release preemption level. | |
373 | */ | |
91447636 | 374 | LEAF_ENTRY(hw_lock_unlock) |
1c79356b | 375 | movl L_ARG0,%edx /* fetch lock pointer */ |
91447636 A |
376 | movl $0,0(%edx) /* clear the lock */ |
377 | ENABLE_PREEMPTION | |
378 | LEAF_RET | |
1c79356b A |
379 | |
380 | /* | |
381 | * unsigned int hw_lock_try(hw_lock_t) | |
382 | * MACH_RT: returns with preemption disabled on success. | |
383 | */ | |
91447636 | 384 | LEAF_ENTRY(hw_lock_try) |
1c79356b A |
385 | movl L_ARG0,%edx /* fetch lock pointer */ |
386 | ||
8ad349bb | 387 | movl L_PC,%ecx |
91447636 A |
388 | DISABLE_PREEMPTION |
389 | movl 0(%edx),%eax | |
390 | testl %eax,%eax | |
391 | jne 1f | |
392 | lock; cmpxchgl %ecx,0(%edx) /* try to acquire the HW lock */ | |
393 | jne 1f | |
1c79356b A |
394 | |
395 | movl $1,%eax /* success */ | |
91447636 | 396 | LEAF_RET |
1c79356b | 397 | |
8ad349bb | 398 | 1: ENABLE_PREEMPTION /* failure: release preemption... */ |
1c79356b | 399 | xorl %eax,%eax /* ...and return failure */ |
91447636 | 400 | LEAF_RET |
1c79356b A |
401 | |
402 | /* | |
403 | * unsigned int hw_lock_held(hw_lock_t) | |
404 | * MACH_RT: doesn't change preemption state. | |
405 | * N.B. Racy, of course. | |
406 | */ | |
91447636 | 407 | LEAF_ENTRY(hw_lock_held) |
1c79356b A |
408 | movl L_ARG0,%edx /* fetch lock pointer */ |
409 | ||
91447636 A |
410 | movl 0(%edx),%eax /* check lock value */ |
411 | testl %eax,%eax | |
55e303ae | 412 | movl $1,%ecx |
91447636 A |
413 | cmovne %ecx,%eax /* 0 => unlocked, 1 => locked */ |
414 | LEAF_RET | |
1c79356b | 415 | |
91447636 A |
416 | LEAF_ENTRY(mutex_init) |
417 | movl L_ARG0,%edx /* fetch lock pointer */ | |
418 | xorl %eax,%eax | |
419 | movl %eax,M_ILK /* clear interlock */ | |
420 | movl %eax,M_LOCKED /* clear locked flag */ | |
421 | movw %ax,M_WAITERS /* init waiter count */ | |
422 | movw %ax,M_PROMOTED_PRI | |
1c79356b | 423 | |
91447636 A |
424 | #if MACH_LDEBUG |
425 | movl $ MUTEX_TAG,M_TYPE /* set lock type */ | |
426 | movl %eax,M_PC /* init caller pc */ | |
427 | movl %eax,M_THREAD /* and owning thread */ | |
428 | #endif | |
1c79356b | 429 | |
91447636 | 430 | LEAF_RET |
1c79356b | 431 | |
91447636 | 432 | NONLEAF_ENTRY2(mutex_lock,_mutex_lock) |
1c79356b | 433 | |
91447636 | 434 | movl B_ARG0,%edx /* fetch lock pointer */ |
1c79356b | 435 | |
91447636 A |
436 | CHECK_MUTEX_TYPE() |
437 | CHECK_NO_SIMPLELOCKS() | |
438 | CHECK_PREEMPTION_LEVEL() | |
1c79356b | 439 | |
91447636 A |
440 | pushf /* save interrupt state */ |
441 | cli /* disable interrupts */ | |
1c79356b | 442 | |
8ad349bb A |
443 | ml_retry: |
444 | movl B_PC,%ecx | |
445 | ||
446 | ml_get_hw: | |
91447636 A |
447 | movl M_ILK,%eax /* read interlock */ |
448 | testl %eax,%eax /* unlocked? */ | |
8ad349bb A |
449 | je 1f /* yes - attempt to lock it */ |
450 | PAUSE /* no - pause */ | |
451 | jmp ml_get_hw /* try again */ | |
452 | 1: | |
91447636 | 453 | lock; cmpxchgl %ecx,M_ILK /* atomic compare and exchange */ |
8ad349bb | 454 | jne ml_get_hw /* branch on failure to retry */ |
91447636 A |
455 | |
456 | movl M_LOCKED,%ecx /* get lock owner */ | |
457 | testl %ecx,%ecx /* is the mutex locked? */ | |
8ad349bb | 458 | jne ml_fail /* yes, we lose */ |
91447636 A |
459 | movl %gs:CPU_ACTIVE_THREAD,%ecx |
460 | movl %ecx,M_LOCKED | |
1c79356b A |
461 | |
462 | #if MACH_LDEBUG | |
91447636 A |
463 | movl %ecx,M_THREAD |
464 | movl B_PC,%ecx | |
465 | movl %ecx,M_PC | |
1c79356b | 466 | #endif |
1c79356b | 467 | |
91447636 A |
468 | pushl %edx /* save mutex address */ |
469 | pushl %edx | |
470 | call EXT(lck_mtx_lock_acquire) | |
471 | addl $4,%esp | |
472 | popl %edx /* restore mutex address */ | |
1c79356b | 473 | |
91447636 | 474 | xorl %eax,%eax |
8ad349bb | 475 | movl %eax,M_ILK |
1c79356b | 476 | |
8ad349bb | 477 | popf /* restore interrupt state */ |
c0fea474 | 478 | |
8ad349bb | 479 | NONLEAF_RET |
c0fea474 | 480 | |
8ad349bb A |
481 | ml_fail: |
482 | ml_block: | |
91447636 A |
483 | CHECK_MYLOCK(M_THREAD) |
484 | pushl M_LOCKED | |
485 | pushl %edx /* push mutex address */ | |
486 | call EXT(lck_mtx_lock_wait) /* wait for the lock */ | |
487 | addl $8,%esp | |
488 | movl B_ARG0,%edx /* refetch mutex address */ | |
8ad349bb | 489 | jmp ml_retry /* and try again */ |
1c79356b | 490 | |
91447636 | 491 | NONLEAF_ENTRY2(mutex_try,_mutex_try) |
1c79356b | 492 | |
91447636 | 493 | movl B_ARG0,%edx /* fetch lock pointer */ |
1c79356b | 494 | |
91447636 A |
495 | CHECK_MUTEX_TYPE() |
496 | CHECK_NO_SIMPLELOCKS() | |
1c79356b | 497 | |
8ad349bb A |
498 | movl B_PC,%ecx |
499 | ||
91447636 A |
500 | pushf /* save interrupt state */ |
501 | cli /* disable interrupts */ | |
1c79356b | 502 | |
8ad349bb | 503 | mt_get_hw: |
91447636 A |
504 | movl M_ILK,%eax /* read interlock */ |
505 | testl %eax,%eax /* unlocked? */ | |
8ad349bb A |
506 | je 1f /* yes - attempt to lock it */ |
507 | PAUSE /* no - pause */ | |
508 | jmp mt_get_hw /* try again */ | |
509 | 1: | |
91447636 | 510 | lock; cmpxchgl %ecx,M_ILK /* atomic compare and exchange */ |
8ad349bb | 511 | jne mt_get_hw /* branch on failure to retry */ |
1c79356b | 512 | |
91447636 A |
513 | movl M_LOCKED,%ecx /* get lock owner */ |
514 | testl %ecx,%ecx /* is the mutex locked? */ | |
8ad349bb | 515 | jne mt_fail /* yes, we lose */ |
91447636 A |
516 | movl %gs:CPU_ACTIVE_THREAD,%ecx |
517 | movl %ecx,M_LOCKED | |
1c79356b A |
518 | |
519 | #if MACH_LDEBUG | |
91447636 A |
520 | movl %ecx,M_THREAD |
521 | movl B_PC,%ecx | |
522 | movl %ecx,M_PC | |
1c79356b | 523 | #endif |
1c79356b | 524 | |
8ad349bb A |
525 | pushl %edx /* save mutex address */ |
526 | pushl %edx | |
527 | call EXT(lck_mtx_lock_acquire) | |
528 | addl $4,%esp | |
529 | popl %edx /* restore mutex address */ | |
530 | ||
91447636 A |
531 | xorl %eax,%eax |
532 | movl %eax,M_ILK | |
8ad349bb | 533 | |
91447636 | 534 | popf /* restore interrupt state */ |
1c79356b | 535 | |
91447636 | 536 | movl $1,%eax |
1c79356b | 537 | |
91447636 | 538 | NONLEAF_RET |
1c79356b | 539 | |
8ad349bb | 540 | mt_fail: |
1c79356b | 541 | xorl %eax,%eax |
91447636 | 542 | movl %eax,M_ILK |
1c79356b | 543 | |
91447636 | 544 | popf /* restore interrupt state */ |
1c79356b | 545 | |
91447636 | 546 | xorl %eax,%eax |
1c79356b | 547 | |
91447636 | 548 | NONLEAF_RET |
1c79356b | 549 | |
91447636 A |
550 | NONLEAF_ENTRY(mutex_unlock) |
551 | movl B_ARG0,%edx /* fetch lock pointer */ | |
1c79356b A |
552 | |
553 | CHECK_MUTEX_TYPE() | |
91447636 | 554 | CHECK_THREAD(M_THREAD) |
1c79356b | 555 | |
8ad349bb A |
556 | movl B_PC,%ecx |
557 | ||
91447636 A |
558 | pushf /* save interrupt state */ |
559 | cli /* disable interrupts */ | |
1c79356b | 560 | |
8ad349bb | 561 | mu_get_hw: |
91447636 A |
562 | movl M_ILK,%eax /* read interlock */ |
563 | testl %eax,%eax /* unlocked? */ | |
8ad349bb A |
564 | je 1f /* yes - attempt to lock it */ |
565 | PAUSE /* no - pause */ | |
566 | jmp mu_get_hw /* try again */ | |
567 | 1: | |
91447636 | 568 | lock; cmpxchgl %ecx,M_ILK /* atomic compare and exchange */ |
8ad349bb | 569 | jne mu_get_hw /* branch on failure to retry */ |
1c79356b | 570 | |
91447636 | 571 | cmpw $0,M_WAITERS /* are there any waiters? */ |
8ad349bb | 572 | jne mu_wakeup /* yes, more work to do */ |
91447636 | 573 | |
8ad349bb | 574 | mu_doit: |
9bccf70c | 575 | |
1c79356b | 576 | #if MACH_LDEBUG |
91447636 | 577 | movl $0,M_THREAD /* disown thread */ |
1c79356b A |
578 | #endif |
579 | ||
55e303ae | 580 | xorl %ecx,%ecx |
91447636 | 581 | movl %ecx,M_LOCKED /* unlock the mutex */ |
1c79356b | 582 | |
91447636 | 583 | movl %ecx,M_ILK |
1c79356b | 584 | |
91447636 | 585 | popf /* restore interrupt state */ |
1c79356b | 586 | |
91447636 | 587 | NONLEAF_RET |
1c79356b | 588 | |
8ad349bb | 589 | mu_wakeup: |
91447636 | 590 | pushl M_LOCKED |
1c79356b | 591 | pushl %edx /* push mutex address */ |
91447636 | 592 | call EXT(lck_mtx_unlock_wakeup)/* yes, wake a thread */ |
9bccf70c | 593 | addl $8,%esp |
91447636 | 594 | movl B_ARG0,%edx /* restore lock pointer */ |
8ad349bb | 595 | jmp mu_doit |
1c79356b | 596 | |
91447636 A |
597 | /* |
598 | * lck_mtx_lock() | |
599 | * lck_mtx_try_lock() | |
600 | * lck_mutex_unlock() | |
601 | * | |
602 | * These are variants of mutex_lock(), mutex_try() and mutex_unlock() without | |
603 | * DEBUG checks (which require fields not present in lck_mtx_t's). | |
604 | */ | |
605 | NONLEAF_ENTRY(lck_mtx_lock) | |
1c79356b | 606 | |
91447636 A |
607 | movl B_ARG0,%edx /* fetch lock pointer */ |
608 | cmpl $(MUTEX_IND),M_ITAG /* is this indirect? */ | |
609 | cmove M_PTR,%edx /* yes - take indirection */ | |
1c79356b | 610 | |
1c79356b | 611 | CHECK_NO_SIMPLELOCKS() |
91447636 | 612 | CHECK_PREEMPTION_LEVEL() |
1c79356b | 613 | |
91447636 A |
614 | pushf /* save interrupt state */ |
615 | cli /* disable interrupts */ | |
9bccf70c | 616 | |
8ad349bb A |
617 | lml_retry: |
618 | movl B_PC,%ecx | |
619 | ||
620 | lml_get_hw: | |
91447636 A |
621 | movl M_ILK,%eax /* read interlock */ |
622 | testl %eax,%eax /* unlocked? */ | |
8ad349bb A |
623 | je 1f /* yes - attempt to lock it */ |
624 | PAUSE /* no - pause */ | |
625 | jmp lml_get_hw /* try again */ | |
626 | 1: | |
91447636 | 627 | lock; cmpxchgl %ecx,M_ILK /* atomic compare and exchange */ |
8ad349bb | 628 | jne lml_get_hw /* branch on failure to retry */ |
91447636 A |
629 | |
630 | movl M_LOCKED,%ecx /* get lock owner */ | |
631 | testl %ecx,%ecx /* is the mutex locked? */ | |
8ad349bb | 632 | jne lml_fail /* yes, we lose */ |
91447636 A |
633 | movl %gs:CPU_ACTIVE_THREAD,%ecx |
634 | movl %ecx,M_LOCKED | |
9bccf70c | 635 | |
91447636 | 636 | pushl %edx /* save mutex address */ |
9bccf70c | 637 | pushl %edx |
91447636 | 638 | call EXT(lck_mtx_lock_acquire) |
9bccf70c | 639 | addl $4,%esp |
91447636 | 640 | popl %edx /* restore mutex address */ |
9bccf70c | 641 | |
91447636 | 642 | xorl %eax,%eax |
8ad349bb | 643 | movl %eax,M_ILK |
9bccf70c | 644 | |
8ad349bb | 645 | popf /* restore interrupt state */ |
c0fea474 | 646 | |
8ad349bb | 647 | NONLEAF_RET |
c0fea474 | 648 | |
8ad349bb | 649 | lml_fail: |
91447636 A |
650 | CHECK_MYLOCK(M_THREAD) |
651 | pushl %edx /* save mutex address */ | |
652 | pushl M_LOCKED | |
9bccf70c | 653 | pushl %edx /* push mutex address */ |
91447636 A |
654 | call EXT(lck_mtx_lock_wait) /* wait for the lock */ |
655 | addl $8,%esp | |
656 | popl %edx /* restore mutex address */ | |
8ad349bb | 657 | jmp lml_retry /* and try again */ |
9bccf70c | 658 | |
91447636 | 659 | NONLEAF_ENTRY(lck_mtx_try_lock) |
1c79356b | 660 | |
91447636 A |
661 | movl B_ARG0,%edx /* fetch lock pointer */ |
662 | cmpl $(MUTEX_IND),M_ITAG /* is this indirect? */ | |
663 | cmove M_PTR,%edx /* yes - take indirection */ | |
9bccf70c | 664 | |
91447636 A |
665 | CHECK_NO_SIMPLELOCKS() |
666 | CHECK_PREEMPTION_LEVEL() | |
1c79356b | 667 | |
8ad349bb A |
668 | movl B_PC,%ecx |
669 | ||
91447636 A |
670 | pushf /* save interrupt state */ |
671 | cli /* disable interrupts */ | |
9bccf70c | 672 | |
8ad349bb | 673 | lmt_get_hw: |
91447636 A |
674 | movl M_ILK,%eax /* read interlock */ |
675 | testl %eax,%eax /* unlocked? */ | |
8ad349bb A |
676 | je 1f /* yes - attempt to lock it */ |
677 | PAUSE /* no - pause */ | |
678 | jmp lmt_get_hw /* try again */ | |
679 | 1: | |
91447636 | 680 | lock; cmpxchgl %ecx,M_ILK /* atomic compare and exchange */ |
8ad349bb | 681 | jne lmt_get_hw /* branch on failure to retry */ |
91447636 A |
682 | |
683 | movl M_LOCKED,%ecx /* get lock owner */ | |
684 | testl %ecx,%ecx /* is the mutex locked? */ | |
8ad349bb | 685 | jne lmt_fail /* yes, we lose */ |
91447636 A |
686 | movl %gs:CPU_ACTIVE_THREAD,%ecx |
687 | movl %ecx,M_LOCKED | |
688 | ||
8ad349bb A |
689 | pushl %edx /* save mutex address */ |
690 | pushl %edx | |
691 | call EXT(lck_mtx_lock_acquire) | |
692 | addl $4,%esp | |
693 | popl %edx /* restore mutex address */ | |
694 | ||
9bccf70c | 695 | xorl %eax,%eax |
91447636 | 696 | movl %eax,M_ILK |
9bccf70c | 697 | |
91447636 | 698 | popf /* restore interrupt state */ |
1c79356b | 699 | |
91447636 A |
700 | movl $1,%eax /* return success */ |
701 | NONLEAF_RET | |
1c79356b | 702 | |
8ad349bb | 703 | lmt_fail: |
91447636 A |
704 | xorl %eax,%eax |
705 | movl %eax,M_ILK | |
1c79356b | 706 | |
91447636 | 707 | popf /* restore interrupt state */ |
1c79356b | 708 | |
91447636 A |
709 | xorl %eax,%eax /* return failure */ |
710 | NONLEAF_RET | |
1c79356b | 711 | |
91447636 | 712 | NONLEAF_ENTRY(lck_mtx_unlock) |
1c79356b | 713 | |
91447636 A |
714 | movl B_ARG0,%edx /* fetch lock pointer */ |
715 | cmpl $(MUTEX_IND),M_ITAG /* is this indirect? */ | |
716 | cmove M_PTR,%edx /* yes - take indirection */ | |
1c79356b | 717 | |
8ad349bb A |
718 | movl B_PC,%ecx |
719 | ||
91447636 A |
720 | pushf /* save interrupt state */ |
721 | cli /* disable interrupts */ | |
1c79356b | 722 | |
8ad349bb | 723 | lmu_get_hw: |
91447636 A |
724 | movl M_ILK,%eax /* read interlock */ |
725 | testl %eax,%eax /* unlocked? */ | |
8ad349bb A |
726 | je 1f /* yes - attempt to lock it */ |
727 | PAUSE /* no - pause */ | |
728 | jmp lmu_get_hw /* try again */ | |
729 | 1: | |
91447636 | 730 | lock; cmpxchgl %ecx,M_ILK /* atomic compare and exchange */ |
8ad349bb | 731 | jne lmu_get_hw /* branch on failure to retry */ |
1c79356b | 732 | |
91447636 | 733 | cmpw $0,M_WAITERS /* are there any waiters? */ |
8ad349bb | 734 | jne lmu_wakeup /* yes, more work to do */ |
91447636 | 735 | |
8ad349bb | 736 | lmu_doit: |
55e303ae | 737 | xorl %ecx,%ecx |
91447636 | 738 | movl %ecx,M_LOCKED /* unlock the mutex */ |
1c79356b | 739 | |
91447636 | 740 | movl %ecx,M_ILK |
1c79356b | 741 | |
91447636 | 742 | popf /* restore interrupt state */ |
1c79356b | 743 | |
91447636 A |
744 | NONLEAF_RET |
745 | ||
8ad349bb | 746 | lmu_wakeup: |
91447636 A |
747 | pushl %edx /* save mutex address */ |
748 | pushl M_LOCKED | |
1c79356b | 749 | pushl %edx /* push mutex address */ |
91447636 | 750 | call EXT(lck_mtx_unlock_wakeup)/* yes, wake a thread */ |
9bccf70c | 751 | addl $8,%esp |
91447636 | 752 | popl %edx /* restore mutex pointer */ |
8ad349bb | 753 | jmp lmu_doit |
1c79356b | 754 | |
91447636 A |
755 | LEAF_ENTRY(lck_mtx_ilk_unlock) |
756 | movl L_ARG0,%edx /* no indirection here */ | |
1c79356b | 757 | |
91447636 A |
758 | xorl %eax,%eax |
759 | movl %eax,M_ILK | |
1c79356b | 760 | |
91447636 | 761 | LEAF_RET |
1c79356b | 762 | |
91447636 | 763 | LEAF_ENTRY(_disable_preemption) |
1c79356b | 764 | #if MACH_RT |
91447636 | 765 | _DISABLE_PREEMPTION |
1c79356b | 766 | #endif /* MACH_RT */ |
91447636 | 767 | LEAF_RET |
1c79356b | 768 | |
91447636 | 769 | LEAF_ENTRY(_enable_preemption) |
1c79356b A |
770 | #if MACH_RT |
771 | #if MACH_ASSERT | |
91447636 | 772 | cmpl $0,%gs:CPU_PREEMPTION_LEVEL |
1c79356b | 773 | jg 1f |
91447636 | 774 | pushl %gs:CPU_PREEMPTION_LEVEL |
1c79356b A |
775 | pushl $2f |
776 | call EXT(panic) | |
777 | hlt | |
778 | .data | |
779 | 2: String "_enable_preemption: preemption_level(%d) < 0!" | |
780 | .text | |
781 | 1: | |
782 | #endif /* MACH_ASSERT */ | |
91447636 | 783 | _ENABLE_PREEMPTION |
1c79356b | 784 | #endif /* MACH_RT */ |
91447636 | 785 | LEAF_RET |
1c79356b | 786 | |
91447636 | 787 | LEAF_ENTRY(_enable_preemption_no_check) |
1c79356b A |
788 | #if MACH_RT |
789 | #if MACH_ASSERT | |
91447636 | 790 | cmpl $0,%gs:CPU_PREEMPTION_LEVEL |
1c79356b A |
791 | jg 1f |
792 | pushl $2f | |
793 | call EXT(panic) | |
794 | hlt | |
795 | .data | |
796 | 2: String "_enable_preemption_no_check: preemption_level <= 0!" | |
797 | .text | |
798 | 1: | |
799 | #endif /* MACH_ASSERT */ | |
91447636 | 800 | _ENABLE_PREEMPTION_NO_CHECK |
1c79356b | 801 | #endif /* MACH_RT */ |
91447636 | 802 | LEAF_RET |
1c79356b A |
803 | |
804 | ||
91447636 A |
805 | LEAF_ENTRY(_mp_disable_preemption) |
806 | #if MACH_RT | |
807 | _DISABLE_PREEMPTION | |
808 | #endif /* MACH_RT */ | |
809 | LEAF_RET | |
1c79356b | 810 | |
91447636 A |
811 | LEAF_ENTRY(_mp_enable_preemption) |
812 | #if MACH_RT | |
1c79356b | 813 | #if MACH_ASSERT |
91447636 | 814 | cmpl $0,%gs:CPU_PREEMPTION_LEVEL |
1c79356b | 815 | jg 1f |
91447636 | 816 | pushl %gs:CPU_PREEMPTION_LEVEL |
1c79356b A |
817 | pushl $2f |
818 | call EXT(panic) | |
819 | hlt | |
820 | .data | |
821 | 2: String "_mp_enable_preemption: preemption_level (%d) <= 0!" | |
822 | .text | |
823 | 1: | |
824 | #endif /* MACH_ASSERT */ | |
91447636 A |
825 | _ENABLE_PREEMPTION |
826 | #endif /* MACH_RT */ | |
827 | LEAF_RET | |
1c79356b | 828 | |
91447636 A |
829 | LEAF_ENTRY(_mp_enable_preemption_no_check) |
830 | #if MACH_RT | |
1c79356b | 831 | #if MACH_ASSERT |
91447636 | 832 | cmpl $0,%gs:CPU_PREEMPTION_LEVEL |
1c79356b A |
833 | jg 1f |
834 | pushl $2f | |
835 | call EXT(panic) | |
836 | hlt | |
837 | .data | |
838 | 2: String "_mp_enable_preemption_no_check: preemption_level <= 0!" | |
839 | .text | |
840 | 1: | |
841 | #endif /* MACH_ASSERT */ | |
91447636 A |
842 | _ENABLE_PREEMPTION_NO_CHECK |
843 | #endif /* MACH_RT */ | |
844 | LEAF_RET | |
1c79356b A |
845 | |
846 | ||
91447636 A |
847 | LEAF_ENTRY(i_bit_set) |
848 | movl L_ARG0,%edx | |
849 | movl L_ARG1,%eax | |
1c79356b | 850 | lock |
c0fea474 | 851 | bts %edx,(%eax) |
91447636 | 852 | LEAF_RET |
1c79356b | 853 | |
91447636 A |
854 | LEAF_ENTRY(i_bit_clear) |
855 | movl L_ARG0,%edx | |
856 | movl L_ARG1,%eax | |
1c79356b | 857 | lock |
c0fea474 | 858 | btr %edx,(%eax) |
91447636 | 859 | LEAF_RET |
1c79356b | 860 | |
91447636 A |
861 | LEAF_ENTRY(bit_lock) |
862 | movl L_ARG0,%ecx | |
863 | movl L_ARG1,%eax | |
1c79356b A |
864 | 1: |
865 | lock | |
866 | bts %ecx,(%eax) | |
867 | jb 1b | |
91447636 | 868 | LEAF_RET |
1c79356b | 869 | |
91447636 A |
870 | LEAF_ENTRY(bit_lock_try) |
871 | movl L_ARG0,%ecx | |
872 | movl L_ARG1,%eax | |
1c79356b A |
873 | lock |
874 | bts %ecx,(%eax) | |
875 | jb bit_lock_failed | |
91447636 | 876 | LEAF_RET /* %eax better not be null ! */ |
1c79356b A |
877 | bit_lock_failed: |
878 | xorl %eax,%eax | |
91447636 | 879 | LEAF_RET |
1c79356b | 880 | |
91447636 A |
881 | LEAF_ENTRY(bit_unlock) |
882 | movl L_ARG0,%ecx | |
883 | movl L_ARG1,%eax | |
1c79356b A |
884 | lock |
885 | btr %ecx,(%eax) | |
91447636 | 886 | LEAF_RET |