2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_OSREFERENCE_HEADER_START@
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
16 * Please obtain a copy of the License at
17 * http://www.opensource.apple.com/apsl/ and read it before using this
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.
28 * @APPLE_LICENSE_OSREFERENCE_HEADER_END@
34 * Mach Operating System
35 * Copyright (c) 1991,1990,1989,1988,1987 Carnegie Mellon University
36 * All Rights Reserved.
38 * Permission to use, copy, modify and distribute this software and its
39 * documentation is hereby granted, provided that both the copyright
40 * notice and this permission notice appear in all copies of the
41 * software, derivative works or modified versions, and any portions
42 * thereof, and that both notices appear in supporting documentation.
44 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
45 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
46 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
48 * Carnegie Mellon requests users of this software to return to
50 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
51 * School of Computer Science
52 * Carnegie Mellon University
53 * Pittsburgh PA 15213-3890
55 * any improvements or extensions that they make and grant Carnegie Mellon
56 * the rights to redistribute these changes.
60 * Author: Avadis Tevanian, Jr., Michael Wayne Young
63 * Locking primitives implementation
67 #include <mach_ldebug.h>
69 #include <kern/kalloc.h>
70 #include <kern/lock.h>
71 #include <kern/locks.h>
72 #include <kern/misc_protos.h>
73 #include <kern/thread.h>
74 #include <kern/processor.h>
75 #include <kern/sched_prim.h>
77 #include <kern/debug.h>
81 #include <ddb/db_command.h>
82 #include <ddb/db_output.h>
83 #include <ddb/db_sym.h>
84 #include <ddb/db_print.h>
88 #include <ppc/Firmware.h>
91 #include <sys/kdebug.h>
93 #define LCK_RW_LCK_EXCLUSIVE_CODE 0x100
94 #define LCK_RW_LCK_EXCLUSIVE1_CODE 0x101
95 #define LCK_RW_LCK_SHARED_CODE 0x102
96 #define LCK_RW_LCK_SH_TO_EX_CODE 0x103
97 #define LCK_RW_LCK_SH_TO_EX1_CODE 0x104
98 #define LCK_RW_LCK_EX_TO_SH_CODE 0x105
101 #define ANY_LOCK_DEBUG (USLOCK_DEBUG || LOCK_DEBUG || MUTEX_DEBUG)
103 unsigned int lock_wait_time
[2] = { (unsigned int)-1, 0 } ;
110 * Perform simple lock checks.
112 int uslock_check
= 1;
113 int max_lock_loops
= 100000000;
114 decl_simple_lock_data(extern , printf_lock
)
115 decl_simple_lock_data(extern , panic_lock
)
117 decl_simple_lock_data(extern , kdb_lock
)
118 #endif /* MACH_KDB */
119 #endif /* USLOCK_DEBUG */
123 * We often want to know the addresses of the callers
124 * of the various lock routines. However, this information
125 * is only used for debugging and statistics.
128 #define INVALID_PC ((void *) VM_MAX_KERNEL_ADDRESS)
129 #define INVALID_THREAD ((void *) VM_MAX_KERNEL_ADDRESS)
131 #define OBTAIN_PC(pc,l) ((pc) = (void *) GET_RETURN_PC(&(l)))
132 #else /* ANY_LOCK_DEBUG */
135 * Eliminate lint complaints about unused local pc variables.
137 #define OBTAIN_PC(pc,l) ++pc
139 #define OBTAIN_PC(pc,l)
141 #endif /* USLOCK_DEBUG */
145 * Portable lock package implementation of usimple_locks.
149 #define USLDBG(stmt) stmt
150 void usld_lock_init(usimple_lock_t
, unsigned short);
151 void usld_lock_pre(usimple_lock_t
, pc_t
);
152 void usld_lock_post(usimple_lock_t
, pc_t
);
153 void usld_unlock(usimple_lock_t
, pc_t
);
154 void usld_lock_try_pre(usimple_lock_t
, pc_t
);
155 void usld_lock_try_post(usimple_lock_t
, pc_t
);
156 int usld_lock_common_checks(usimple_lock_t
, char *);
157 #else /* USLOCK_DEBUG */
159 #endif /* USLOCK_DEBUG */
162 * Routine: lck_spin_alloc_init
170 if ((lck
= (lck_spin_t
*)kalloc(sizeof(lck_spin_t
))) != 0)
171 lck_spin_init(lck
, grp
, attr
);
177 * Routine: lck_spin_free
183 lck_spin_destroy(lck
, grp
);
184 kfree((void *)lck
, sizeof(lck_spin_t
));
188 * Routine: lck_spin_init
194 __unused lck_attr_t
*attr
) {
197 lck_grp_reference(grp
);
198 lck_grp_lckcnt_incr(grp
, LCK_TYPE_SPIN
);
202 * Routine: lck_spin_destroy
208 if (lck
->interlock
== LCK_SPIN_TAG_DESTROYED
)
210 lck
->interlock
= LCK_SPIN_TAG_DESTROYED
;
211 lck_grp_lckcnt_decr(grp
, LCK_TYPE_SPIN
);
212 lck_grp_deallocate(grp
);
216 * Initialize a usimple_lock.
218 * No change in preemption state.
225 #ifndef MACHINE_SIMPLE_LOCK
226 USLDBG(usld_lock_init(l
, tag
));
227 hw_lock_init(&l
->interlock
);
229 simple_lock_init((simple_lock_t
)l
,tag
);
235 * Acquire a usimple_lock.
237 * Returns with preemption disabled. Note
238 * that the hw_lock routines are responsible for
239 * maintaining preemption state.
245 #ifndef MACHINE_SIMPLE_LOCK
250 #endif /* USLOCK_DEBUG */
253 USLDBG(usld_lock_pre(l
, pc
));
255 if(!hw_lock_to(&l
->interlock
, LockTimeOut
)) /* Try to get the lock with a timeout */
256 panic("simple lock deadlock detection - l=0x%08X, cpu=%d, ret=0x%08X", l
, cpu_number(), pc
);
258 USLDBG(usld_lock_post(l
, pc
));
260 simple_lock((simple_lock_t
)l
);
266 * Release a usimple_lock.
268 * Returns with preemption enabled. Note
269 * that the hw_lock routines are responsible for
270 * maintaining preemption state.
276 #ifndef MACHINE_SIMPLE_LOCK
280 USLDBG(usld_unlock(l
, pc
));
282 hw_lock_unlock(&l
->interlock
);
284 simple_unlock_rwmb((simple_lock_t
)l
);
290 * Conditionally acquire a usimple_lock.
292 * On success, returns with preemption disabled.
293 * On failure, returns with preemption in the same state
294 * as when first invoked. Note that the hw_lock routines
295 * are responsible for maintaining preemption state.
297 * XXX No stats are gathered on a miss; I preserved this
298 * behavior from the original assembly-language code, but
299 * doesn't it make sense to log misses? XXX
305 #ifndef MACHINE_SIMPLE_LOCK
307 unsigned int success
;
310 USLDBG(usld_lock_try_pre(l
, pc
));
311 if (success
= hw_lock_try(&l
->interlock
)) {
312 USLDBG(usld_lock_try_post(l
, pc
));
316 return(simple_lock_try((simple_lock_t
)l
));
322 * States of a usimple_lock. The default when initializing
323 * a usimple_lock is setting it up for debug checking.
325 #define USLOCK_CHECKED 0x0001 /* lock is being checked */
326 #define USLOCK_TAKEN 0x0002 /* lock has been taken */
327 #define USLOCK_INIT 0xBAA0 /* lock has been initialized */
328 #define USLOCK_INITIALIZED (USLOCK_INIT|USLOCK_CHECKED)
329 #define USLOCK_CHECKING(l) (uslock_check && \
330 ((l)->debug.state & USLOCK_CHECKED))
333 * Trace activities of a particularly interesting lock.
335 void usl_trace(usimple_lock_t
, int, pc_t
, const char *);
339 * Initialize the debugging information contained
347 if (l
== USIMPLE_LOCK_NULL
)
348 panic("lock initialization: null lock pointer");
349 l
->lock_type
= USLOCK_TAG
;
350 l
->debug
.state
= uslock_check
? USLOCK_INITIALIZED
: 0;
351 l
->debug
.lock_cpu
= l
->debug
.unlock_cpu
= 0;
352 l
->debug
.lock_pc
= l
->debug
.unlock_pc
= INVALID_PC
;
353 l
->debug
.lock_thread
= l
->debug
.unlock_thread
= INVALID_THREAD
;
354 l
->debug
.duration
[0] = l
->debug
.duration
[1] = 0;
355 l
->debug
.unlock_cpu
= l
->debug
.unlock_cpu
= 0;
356 l
->debug
.unlock_pc
= l
->debug
.unlock_pc
= INVALID_PC
;
357 l
->debug
.unlock_thread
= l
->debug
.unlock_thread
= INVALID_THREAD
;
362 * These checks apply to all usimple_locks, not just
363 * those with USLOCK_CHECKED turned on.
366 usld_lock_common_checks(
370 if (l
== USIMPLE_LOCK_NULL
)
371 panic("%s: null lock pointer", caller
);
372 if (l
->lock_type
!= USLOCK_TAG
)
373 panic("%s: 0x%x is not a usimple lock", caller
, (integer_t
) l
);
374 if (!(l
->debug
.state
& USLOCK_INIT
))
375 panic("%s: 0x%x is not an initialized lock",
376 caller
, (integer_t
) l
);
377 return USLOCK_CHECKING(l
);
382 * Debug checks on a usimple_lock just before attempting
391 char *caller
= "usimple_lock";
394 if (!usld_lock_common_checks(l
, caller
))
398 * Note that we have a weird case where we are getting a lock when we are]
399 * in the process of putting the system to sleep. We are running with no
400 * current threads, therefore we can't tell if we are trying to retake a lock
401 * we have or someone on the other processor has it. Therefore we just
402 * ignore this test if the locking thread is 0.
405 if ((l
->debug
.state
& USLOCK_TAKEN
) && l
->debug
.lock_thread
&&
406 l
->debug
.lock_thread
== (void *) current_thread()) {
407 printf("%s: lock 0x%x already locked (at 0x%x) by",
408 caller
, (integer_t
) l
, l
->debug
.lock_pc
);
409 printf(" current thread 0x%x (new attempt at pc 0x%x)\n",
410 l
->debug
.lock_thread
, pc
);
413 mp_disable_preemption();
414 usl_trace(l
, cpu_number(), pc
, caller
);
415 mp_enable_preemption();
420 * Debug checks on a usimple_lock just after acquiring it.
422 * Pre-emption has been disabled at this point,
423 * so we are safe in using cpu_number.
431 char *caller
= "successful usimple_lock";
434 if (!usld_lock_common_checks(l
, caller
))
437 if (!((l
->debug
.state
& ~USLOCK_TAKEN
) == USLOCK_INITIALIZED
))
438 panic("%s: lock 0x%x became uninitialized",
439 caller
, (integer_t
) l
);
440 if ((l
->debug
.state
& USLOCK_TAKEN
))
441 panic("%s: lock 0x%x became TAKEN by someone else",
442 caller
, (integer_t
) l
);
444 mycpu
= cpu_number();
445 l
->debug
.lock_thread
= (void *)current_thread();
446 l
->debug
.state
|= USLOCK_TAKEN
;
447 l
->debug
.lock_pc
= pc
;
448 l
->debug
.lock_cpu
= mycpu
;
450 usl_trace(l
, mycpu
, pc
, caller
);
455 * Debug checks on a usimple_lock just before
456 * releasing it. Note that the caller has not
457 * yet released the hardware lock.
459 * Preemption is still disabled, so there's
460 * no problem using cpu_number.
468 char *caller
= "usimple_unlock";
471 if (!usld_lock_common_checks(l
, caller
))
474 mycpu
= cpu_number();
476 if (!(l
->debug
.state
& USLOCK_TAKEN
))
477 panic("%s: lock 0x%x hasn't been taken",
478 caller
, (integer_t
) l
);
479 if (l
->debug
.lock_thread
!= (void *) current_thread())
480 panic("%s: unlocking lock 0x%x, owned by thread 0x%x",
481 caller
, (integer_t
) l
, l
->debug
.lock_thread
);
482 if (l
->debug
.lock_cpu
!= mycpu
) {
483 printf("%s: unlocking lock 0x%x on cpu 0x%x",
484 caller
, (integer_t
) l
, mycpu
);
485 printf(" (acquired on cpu 0x%x)\n", l
->debug
.lock_cpu
);
488 usl_trace(l
, mycpu
, pc
, caller
);
490 l
->debug
.unlock_thread
= l
->debug
.lock_thread
;
491 l
->debug
.lock_thread
= INVALID_PC
;
492 l
->debug
.state
&= ~USLOCK_TAKEN
;
493 l
->debug
.unlock_pc
= pc
;
494 l
->debug
.unlock_cpu
= mycpu
;
499 * Debug checks on a usimple_lock just before
500 * attempting to acquire it.
502 * Preemption isn't guaranteed to be disabled.
509 char *caller
= "usimple_lock_try";
511 if (!usld_lock_common_checks(l
, caller
))
513 mp_disable_preemption();
514 usl_trace(l
, cpu_number(), pc
, caller
);
515 mp_enable_preemption();
520 * Debug checks on a usimple_lock just after
521 * successfully attempting to acquire it.
523 * Preemption has been disabled by the
524 * lock acquisition attempt, so it's safe
533 char *caller
= "successful usimple_lock_try";
535 if (!usld_lock_common_checks(l
, caller
))
538 if (!((l
->debug
.state
& ~USLOCK_TAKEN
) == USLOCK_INITIALIZED
))
539 panic("%s: lock 0x%x became uninitialized",
540 caller
, (integer_t
) l
);
541 if ((l
->debug
.state
& USLOCK_TAKEN
))
542 panic("%s: lock 0x%x became TAKEN by someone else",
543 caller
, (integer_t
) l
);
545 mycpu
= cpu_number();
546 l
->debug
.lock_thread
= (void *) current_thread();
547 l
->debug
.state
|= USLOCK_TAKEN
;
548 l
->debug
.lock_pc
= pc
;
549 l
->debug
.lock_cpu
= mycpu
;
551 usl_trace(l
, mycpu
, pc
, caller
);
556 * For very special cases, set traced_lock to point to a
557 * specific lock of interest. The result is a series of
558 * XPRs showing lock operations on that lock. The lock_seq
559 * value is used to show the order of those operations.
561 usimple_lock_t traced_lock
;
562 unsigned int lock_seq
;
569 const char * op_name
)
571 if (traced_lock
== l
) {
573 "seq %d, cpu %d, %s @ %x\n",
574 (integer_t
) lock_seq
, (integer_t
) mycpu
,
575 (integer_t
) op_name
, (integer_t
) pc
, 0);
581 #endif /* USLOCK_DEBUG */
584 * The C portion of the shared/exclusive locks package.
591 void lck_rw_lock_exclusive_gen(
594 lck_rw_type_t
lck_rw_done_gen(
598 lck_rw_lock_shared_gen(
602 lck_rw_lock_shared_to_exclusive_gen(
606 lck_rw_lock_exclusive_to_shared_gen(
610 lck_rw_try_lock_exclusive_gen(
614 lck_rw_try_lock_shared_gen(
617 void lck_rw_ext_init(
622 void lck_rw_ext_backtrace(
625 void lck_rw_lock_exclusive_ext(
629 lck_rw_type_t
lck_rw_done_ext(
634 lck_rw_lock_shared_ext(
639 lck_rw_lock_shared_to_exclusive_ext(
644 lck_rw_lock_exclusive_to_shared_ext(
649 lck_rw_try_lock_exclusive_ext(
654 lck_rw_try_lock_shared_ext(
672 * Routine: lock_alloc
674 * Allocate a lock for external users who cannot
675 * hard-code the structure definition into their
677 * For now just use kalloc, but a zone is probably
683 __unused
unsigned short tag
,
684 __unused
unsigned short tag1
)
688 if ((lck
= (lock_t
*)kalloc(sizeof(lock_t
))) != 0)
689 lock_init(lck
, can_sleep
, tag
, tag1
);
696 * Initialize a lock; required before use.
697 * Note that clients declare the "struct lock"
698 * variables and then initialize them, rather
699 * than getting a new one from this module.
705 __unused
unsigned short tag
,
706 __unused
unsigned short tag1
)
709 panic("lock_init: sleep mode must be set to TRUE\n");
711 (void) memset((void *) lck
, 0, sizeof(lock_t
));
713 lck
->lck_rw_deb
.type
= RW_TAG
;
714 lck
->lck_rw_attr
|= (LCK_RW_ATTR_DEBUG
|LCK_RW_ATTR_DIS_THREAD
|LCK_RW_ATTR_DIS_MYLOCK
);
723 * Free a lock allocated for external users.
724 * For now just use kfree, but a zone is probably
731 kfree((void *)lck
, sizeof(lock_t
));
739 lck_rw_lock_exclusive_ext((lck_rw_ext_t
*)lck
, (lck_rw_t
*)lck
);
746 (void)lck_rw_done_ext((lck_rw_ext_t
*)lck
, (lck_rw_t
*)lck
);
753 lck_rw_lock_shared_ext((lck_rw_ext_t
*)lck
, (lck_rw_t
*)lck
);
760 return(lck_rw_lock_shared_to_exclusive_ext((lck_rw_ext_t
*)lck
, (lck_rw_t
*)lck
));
765 register lock_t
*lck
)
767 lck_rw_lock_exclusive_to_shared_ext((lck_rw_ext_t
*)lck
, (lck_rw_t
*)lck
);
772 * Routine: lck_rw_alloc_init
780 if ((lck
= (lck_rw_t
*)kalloc(sizeof(lck_rw_t
))) != 0)
781 lck_rw_init(lck
, grp
, attr
);
787 * Routine: lck_rw_free
793 lck_rw_destroy(lck
, grp
);
794 kfree((void *)lck
, sizeof(lck_rw_t
));
798 * Routine: lck_rw_init
805 lck_rw_ext_t
*lck_ext
;
806 lck_attr_t
*lck_attr
;
808 if (attr
!= LCK_ATTR_NULL
)
811 lck_attr
= &LockDefaultLckAttr
;
813 if ((lck_attr
->lck_attr_val
) & LCK_ATTR_DEBUG
) {
814 if ((lck_ext
= (lck_rw_ext_t
*)kalloc(sizeof(lck_rw_ext_t
))) != 0) {
815 lck_rw_ext_init(lck_ext
, grp
, lck_attr
);
816 lck
->lck_rw_tag
= LCK_RW_TAG_INDIRECT
;
817 lck
->lck_rw_ptr
= lck_ext
;
820 (void) memset((void *) lck
, 0, sizeof(lck_rw_t
));
823 lck_grp_reference(grp
);
824 lck_grp_lckcnt_incr(grp
, LCK_TYPE_RW
);
828 * Routine: lck_rw_ext_init
836 bzero((void *)lck
, sizeof(lck_rw_ext_t
));
838 if ((attr
->lck_attr_val
) & LCK_ATTR_DEBUG
) {
839 lck
->lck_rw_deb
.type
= RW_TAG
;
840 lck
->lck_rw_attr
|= LCK_RW_ATTR_DEBUG
;
843 lck
->lck_rw_grp
= grp
;
845 if (grp
->lck_grp_attr
& LCK_GRP_ATTR_STAT
)
846 lck
->lck_rw_attr
|= LCK_RW_ATTR_STAT
;
850 * Routine: lck_rw_destroy
856 boolean_t lck_is_indirect
;
858 if (lck
->lck_rw_tag
== LCK_RW_TAG_DESTROYED
)
860 lck_is_indirect
= (lck
->lck_rw_tag
== LCK_RW_TAG_INDIRECT
);
861 lck
->lck_rw_tag
= LCK_RW_TAG_DESTROYED
;
863 kfree((void *)lck
->lck_rw_ptr
, sizeof(lck_rw_ext_t
));
865 lck_grp_lckcnt_decr(grp
, LCK_TYPE_RW
);
866 lck_grp_deallocate(grp
);
871 * Routine: lck_rw_lock
876 lck_rw_type_t lck_rw_type
)
878 if (lck_rw_type
== LCK_RW_TYPE_SHARED
)
879 lck_rw_lock_shared(lck
);
880 else if (lck_rw_type
== LCK_RW_TYPE_EXCLUSIVE
)
881 lck_rw_lock_exclusive(lck
);
883 panic("lck_rw_lock(): Invalid RW lock type: %d\n", lck_rw_type
);
888 * Routine: lck_rw_unlock
893 lck_rw_type_t lck_rw_type
)
895 if (lck_rw_type
== LCK_RW_TYPE_SHARED
)
896 lck_rw_unlock_shared(lck
);
897 else if (lck_rw_type
== LCK_RW_TYPE_EXCLUSIVE
)
898 lck_rw_unlock_exclusive(lck
);
900 panic("lck_rw_unlock(): Invalid RW lock type: %d\n", lck_rw_type
);
905 * Routine: lck_rw_unlock_shared
908 lck_rw_unlock_shared(
913 ret
= lck_rw_done(lck
);
915 if (ret
!= LCK_RW_TYPE_SHARED
)
916 panic("lck_rw_unlock(): lock held in mode: %d\n", ret
);
921 * Routine: lck_rw_unlock_exclusive
924 lck_rw_unlock_exclusive(
929 ret
= lck_rw_done(lck
);
931 if (ret
!= LCK_RW_TYPE_EXCLUSIVE
)
932 panic("lck_rw_unlock_exclusive(): lock held in mode: %d\n", ret
);
937 * Routine: lck_rw_try_lock
942 lck_rw_type_t lck_rw_type
)
944 if (lck_rw_type
== LCK_RW_TYPE_SHARED
)
945 return(lck_rw_try_lock_shared(lck
));
946 else if (lck_rw_type
== LCK_RW_TYPE_EXCLUSIVE
)
947 return(lck_rw_try_lock_exclusive(lck
));
949 panic("lck_rw_try_lock(): Invalid rw lock type: %x\n", lck_rw_type
);
956 * Routine: lck_rw_lock_exclusive_gen
959 lck_rw_lock_exclusive_gen(
963 boolean_t lock_miss
= FALSE
;
966 lck_rw_ilk_lock(lck
);
969 * Try to acquire the lck_rw_want_excl bit.
971 while (lck
->lck_rw_want_excl
) {
972 KERNEL_DEBUG(MACHDBG_CODE(DBG_MACH_LOCKS
, LCK_RW_LCK_EXCLUSIVE_CODE
) | DBG_FUNC_START
, (int)lck
, 0, 0, 0, 0);
978 i
= lock_wait_time
[1];
980 lck_rw_ilk_unlock(lck
);
981 while (--i
!= 0 && lck
->lck_rw_want_excl
)
983 lck_rw_ilk_lock(lck
);
986 if (lck
->lck_rw_want_excl
) {
987 lck
->lck_rw_waiting
= TRUE
;
988 res
= assert_wait((event_t
)(((unsigned int*)lck
)+((sizeof(lck_rw_t
)-1)/sizeof(unsigned int))), THREAD_UNINT
);
989 if (res
== THREAD_WAITING
) {
990 lck_rw_ilk_unlock(lck
);
991 res
= thread_block(THREAD_CONTINUE_NULL
);
992 lck_rw_ilk_lock(lck
);
995 KERNEL_DEBUG(MACHDBG_CODE(DBG_MACH_LOCKS
, LCK_RW_LCK_EXCLUSIVE_CODE
) | DBG_FUNC_END
, (int)lck
, res
, 0, 0, 0);
997 lck
->lck_rw_want_excl
= TRUE
;
999 /* Wait for readers (and upgrades) to finish */
1001 while ((lck
->lck_rw_shared_cnt
!= 0) || lck
->lck_rw_want_upgrade
) {
1006 i
= lock_wait_time
[1];
1008 KERNEL_DEBUG(MACHDBG_CODE(DBG_MACH_LOCKS
, LCK_RW_LCK_EXCLUSIVE1_CODE
) | DBG_FUNC_START
,
1009 (int)lck
, lck
->lck_rw_shared_cnt
, lck
->lck_rw_want_upgrade
, i
, 0);
1012 lck_rw_ilk_unlock(lck
);
1013 while (--i
!= 0 && (lck
->lck_rw_shared_cnt
!= 0 ||
1014 lck
->lck_rw_want_upgrade
))
1016 lck_rw_ilk_lock(lck
);
1019 if (lck
->lck_rw_shared_cnt
!= 0 || lck
->lck_rw_want_upgrade
) {
1020 lck
->lck_rw_waiting
= TRUE
;
1021 res
= assert_wait((event_t
)(((unsigned int*)lck
)+((sizeof(lck_rw_t
)-1)/sizeof(unsigned int))), THREAD_UNINT
);
1022 if (res
== THREAD_WAITING
) {
1023 lck_rw_ilk_unlock(lck
);
1024 res
= thread_block(THREAD_CONTINUE_NULL
);
1025 lck_rw_ilk_lock(lck
);
1028 KERNEL_DEBUG(MACHDBG_CODE(DBG_MACH_LOCKS
, LCK_RW_LCK_EXCLUSIVE1_CODE
) | DBG_FUNC_END
,
1029 (int)lck
, lck
->lck_rw_shared_cnt
, lck
->lck_rw_want_upgrade
, res
, 0);
1032 lck_rw_ilk_unlock(lck
);
1037 * Routine: lck_rw_done_gen
1043 boolean_t do_wakeup
= FALSE
;
1044 lck_rw_type_t lck_rw_type
;
1047 lck_rw_ilk_lock(lck
);
1049 if (lck
->lck_rw_shared_cnt
!= 0) {
1050 lck_rw_type
= LCK_RW_TYPE_SHARED
;
1051 lck
->lck_rw_shared_cnt
--;
1054 lck_rw_type
= LCK_RW_TYPE_EXCLUSIVE
;
1055 if (lck
->lck_rw_want_upgrade
)
1056 lck
->lck_rw_want_upgrade
= FALSE
;
1058 lck
->lck_rw_want_excl
= FALSE
;
1062 * There is no reason to wakeup a lck_rw_waiting thread
1063 * if the read-count is non-zero. Consider:
1064 * we must be dropping a read lock
1065 * threads are waiting only if one wants a write lock
1066 * if there are still readers, they can't proceed
1069 if (lck
->lck_rw_waiting
&& (lck
->lck_rw_shared_cnt
== 0)) {
1070 lck
->lck_rw_waiting
= FALSE
;
1074 lck_rw_ilk_unlock(lck
);
1077 thread_wakeup((event_t
)(((unsigned int*)lck
)+((sizeof(lck_rw_t
)-1)/sizeof(unsigned int))));
1078 return(lck_rw_type
);
1083 * Routine: lck_rw_lock_shared_gen
1086 lck_rw_lock_shared_gen(
1092 lck_rw_ilk_lock(lck
);
1094 while (lck
->lck_rw_want_excl
|| lck
->lck_rw_want_upgrade
) {
1095 i
= lock_wait_time
[1];
1097 KERNEL_DEBUG(MACHDBG_CODE(DBG_MACH_LOCKS
, LCK_RW_LCK_SHARED_CODE
) | DBG_FUNC_START
,
1098 (int)lck
, lck
->lck_rw_want_excl
, lck
->lck_rw_want_upgrade
, i
, 0);
1101 lck_rw_ilk_unlock(lck
);
1102 while (--i
!= 0 && (lck
->lck_rw_want_excl
|| lck
->lck_rw_want_upgrade
))
1104 lck_rw_ilk_lock(lck
);
1107 if (lck
->lck_rw_want_excl
|| lck
->lck_rw_want_upgrade
) {
1108 lck
->lck_rw_waiting
= TRUE
;
1109 res
= assert_wait((event_t
)(((unsigned int*)lck
)+((sizeof(lck_rw_t
)-1)/sizeof(unsigned int))), THREAD_UNINT
);
1110 if (res
== THREAD_WAITING
) {
1111 lck_rw_ilk_unlock(lck
);
1112 res
= thread_block(THREAD_CONTINUE_NULL
);
1113 lck_rw_ilk_lock(lck
);
1116 KERNEL_DEBUG(MACHDBG_CODE(DBG_MACH_LOCKS
, LCK_RW_LCK_SHARED_CODE
) | DBG_FUNC_END
,
1117 (int)lck
, lck
->lck_rw_want_excl
, lck
->lck_rw_want_upgrade
, res
, 0);
1120 lck
->lck_rw_shared_cnt
++;
1122 lck_rw_ilk_unlock(lck
);
1127 * Routine: lck_rw_lock_shared_to_exclusive_gen
1129 * Improves a read-only lock to one with
1130 * write permission. If another reader has
1131 * already requested an upgrade to a write lock,
1132 * no lock is held upon return.
1134 * Returns TRUE if the upgrade *failed*.
1138 lck_rw_lock_shared_to_exclusive_gen(
1142 boolean_t do_wakeup
= FALSE
;
1145 lck_rw_ilk_lock(lck
);
1147 lck
->lck_rw_shared_cnt
--;
1149 if (lck
->lck_rw_want_upgrade
) {
1150 KERNEL_DEBUG(MACHDBG_CODE(DBG_MACH_LOCKS
, LCK_RW_LCK_SH_TO_EX_CODE
) | DBG_FUNC_START
,
1151 (int)lck
, lck
->lck_rw_shared_cnt
, lck
->lck_rw_want_upgrade
, 0, 0);
1154 * Someone else has requested upgrade.
1155 * Since we've released a read lock, wake
1158 if (lck
->lck_rw_waiting
&& (lck
->lck_rw_shared_cnt
== 0)) {
1159 lck
->lck_rw_waiting
= FALSE
;
1163 lck_rw_ilk_unlock(lck
);
1166 thread_wakeup((event_t
)(((unsigned int*)lck
)+((sizeof(lck_rw_t
)-1)/sizeof(unsigned int))));
1168 KERNEL_DEBUG(MACHDBG_CODE(DBG_MACH_LOCKS
, LCK_RW_LCK_SH_TO_EX_CODE
) | DBG_FUNC_END
,
1169 (int)lck
, lck
->lck_rw_shared_cnt
, lck
->lck_rw_want_upgrade
, 0, 0);
1174 lck
->lck_rw_want_upgrade
= TRUE
;
1176 while (lck
->lck_rw_shared_cnt
!= 0) {
1177 i
= lock_wait_time
[1];
1179 KERNEL_DEBUG(MACHDBG_CODE(DBG_MACH_LOCKS
, LCK_RW_LCK_SH_TO_EX1_CODE
) | DBG_FUNC_START
,
1180 (int)lck
, lck
->lck_rw_shared_cnt
, i
, 0, 0);
1183 lck_rw_ilk_unlock(lck
);
1184 while (--i
!= 0 && lck
->lck_rw_shared_cnt
!= 0)
1186 lck_rw_ilk_lock(lck
);
1189 if (lck
->lck_rw_shared_cnt
!= 0) {
1190 lck
->lck_rw_waiting
= TRUE
;
1191 res
= assert_wait((event_t
)(((unsigned int*)lck
)+((sizeof(lck_rw_t
)-1)/sizeof(unsigned int))), THREAD_UNINT
);
1192 if (res
== THREAD_WAITING
) {
1193 lck_rw_ilk_unlock(lck
);
1194 res
= thread_block(THREAD_CONTINUE_NULL
);
1195 lck_rw_ilk_lock(lck
);
1198 KERNEL_DEBUG(MACHDBG_CODE(DBG_MACH_LOCKS
, LCK_RW_LCK_SH_TO_EX1_CODE
) | DBG_FUNC_END
,
1199 (int)lck
, lck
->lck_rw_shared_cnt
, 0, 0, 0);
1202 lck_rw_ilk_unlock(lck
);
1208 * Routine: lck_rw_lock_exclusive_to_shared_gen
1211 lck_rw_lock_exclusive_to_shared_gen(
1214 boolean_t do_wakeup
= FALSE
;
1216 lck_rw_ilk_lock(lck
);
1218 lck
->lck_rw_shared_cnt
++;
1219 if (lck
->lck_rw_want_upgrade
)
1220 lck
->lck_rw_want_upgrade
= FALSE
;
1222 lck
->lck_rw_want_excl
= FALSE
;
1224 if (lck
->lck_rw_waiting
) {
1225 lck
->lck_rw_waiting
= FALSE
;
1229 lck_rw_ilk_unlock(lck
);
1232 thread_wakeup((event_t
)(((unsigned int*)lck
)+((sizeof(lck_rw_t
)-1)/sizeof(unsigned int))));
1238 * Routine: lck_rw_try_lock_exclusive_gen
1240 * Tries to get a write lock.
1242 * Returns FALSE if the lock is not held on return.
1246 lck_rw_try_lock_exclusive_gen(
1249 lck_rw_ilk_lock(lck
);
1251 if (lck
->lck_rw_want_excl
|| lck
->lck_rw_want_upgrade
|| lck
->lck_rw_shared_cnt
) {
1255 lck_rw_ilk_unlock(lck
);
1263 lck
->lck_rw_want_excl
= TRUE
;
1265 lck_rw_ilk_unlock(lck
);
1271 * Routine: lck_rw_try_lock_shared_gen
1273 * Tries to get a read lock.
1275 * Returns FALSE if the lock is not held on return.
1279 lck_rw_try_lock_shared_gen(
1282 lck_rw_ilk_lock(lck
);
1284 if (lck
->lck_rw_want_excl
|| lck
->lck_rw_want_upgrade
) {
1285 lck_rw_ilk_unlock(lck
);
1289 lck
->lck_rw_shared_cnt
++;
1291 lck_rw_ilk_unlock(lck
);
1298 * Routine: lck_rw_ext_backtrace
1301 lck_rw_ext_backtrace(
1304 unsigned int *stackptr
, *stackptr_prev
;
1307 __asm__
volatile("mr %0,r1" : "=r" (stackptr
));
1309 while (frame
< LCK_FRAMES_MAX
) {
1310 stackptr_prev
= stackptr
;
1311 stackptr
= ( unsigned int *)*stackptr
;
1312 if ( (((unsigned int)stackptr_prev
) ^ ((unsigned int)stackptr
)) > 8192)
1314 lck
->lck_rw_deb
.stack
[frame
] = *(stackptr
+2);
1317 while (frame
< LCK_FRAMES_MAX
) {
1318 lck
->lck_rw_deb
.stack
[frame
] = 0;
1325 * Routine: lck_rw_lock_exclusive_ext
1328 lck_rw_lock_exclusive_ext(
1334 boolean_t lock_miss
= FALSE
;
1335 boolean_t lock_wait
= FALSE
;
1336 boolean_t lock_stat
;
1338 lck_rw_check_type(lck
, rlck
);
1340 if ( ((lck
->lck_rw_attr
& (LCK_RW_ATTR_DEBUG
|LCK_RW_ATTR_DIS_MYLOCK
)) == LCK_RW_ATTR_DEBUG
)
1341 && (lck
->lck_rw_deb
.thread
== current_thread()))
1342 panic("rw lock (0x%08X) recursive lock attempt\n", rlck
);
1344 lck_rw_ilk_lock(&lck
->lck_rw
);
1346 lock_stat
= (lck
->lck_rw_attr
& LCK_RW_ATTR_STAT
) ? TRUE
: FALSE
;
1349 lck
->lck_rw_grp
->lck_grp_stat
.lck_grp_rw_stat
.lck_grp_rw_util_cnt
++;
1352 * Try to acquire the lck_rw.lck_rw_want_excl bit.
1354 while (lck
->lck_rw
.lck_rw_want_excl
) {
1355 KERNEL_DEBUG(MACHDBG_CODE(DBG_MACH_LOCKS
, LCK_RW_LCK_EXCLUSIVE_CODE
) | DBG_FUNC_START
, (int)rlck
, 0, 0, 0, 0);
1357 if (lock_stat
&& !lock_miss
) {
1359 lck
->lck_rw_grp
->lck_grp_stat
.lck_grp_rw_stat
.lck_grp_rw_miss_cnt
++;
1362 i
= lock_wait_time
[1];
1364 lck_rw_ilk_unlock(&lck
->lck_rw
);
1365 while (--i
!= 0 && lck
->lck_rw
.lck_rw_want_excl
)
1367 lck_rw_ilk_lock(&lck
->lck_rw
);
1370 if (lck
->lck_rw
.lck_rw_want_excl
) {
1371 lck
->lck_rw
.lck_rw_waiting
= TRUE
;
1372 res
= assert_wait((event_t
)(((unsigned int*)rlck
)+((sizeof(lck_rw_t
)-1)/sizeof(unsigned int))), THREAD_UNINT
);
1373 if (res
== THREAD_WAITING
) {
1374 if (lock_stat
&& !lock_wait
) {
1376 lck
->lck_rw_grp
->lck_grp_stat
.lck_grp_rw_stat
.lck_grp_rw_wait_cnt
++;
1378 lck_rw_ilk_unlock(&lck
->lck_rw
);
1379 res
= thread_block(THREAD_CONTINUE_NULL
);
1380 lck_rw_ilk_lock(&lck
->lck_rw
);
1383 KERNEL_DEBUG(MACHDBG_CODE(DBG_MACH_LOCKS
, LCK_RW_LCK_EXCLUSIVE_CODE
) | DBG_FUNC_END
, (int)rlck
, res
, 0, 0, 0);
1385 lck
->lck_rw
.lck_rw_want_excl
= TRUE
;
1387 /* Wait for readers (and upgrades) to finish */
1389 while ((lck
->lck_rw
.lck_rw_shared_cnt
!= 0) || lck
->lck_rw
.lck_rw_want_upgrade
) {
1390 i
= lock_wait_time
[1];
1392 KERNEL_DEBUG(MACHDBG_CODE(DBG_MACH_LOCKS
, LCK_RW_LCK_EXCLUSIVE1_CODE
) | DBG_FUNC_START
,
1393 (int)rlck
, lck
->lck_rw
.lck_rw_shared_cnt
, lck
->lck_rw
.lck_rw_want_upgrade
, i
, 0);
1395 if (lock_stat
&& !lock_miss
) {
1397 lck
->lck_rw_grp
->lck_grp_stat
.lck_grp_rw_stat
.lck_grp_rw_miss_cnt
++;
1401 lck_rw_ilk_unlock(&lck
->lck_rw
);
1402 while (--i
!= 0 && (lck
->lck_rw
.lck_rw_shared_cnt
!= 0 ||
1403 lck
->lck_rw
.lck_rw_want_upgrade
))
1405 lck_rw_ilk_lock(&lck
->lck_rw
);
1408 if (lck
->lck_rw
.lck_rw_shared_cnt
!= 0 || lck
->lck_rw
.lck_rw_want_upgrade
) {
1409 lck
->lck_rw
.lck_rw_waiting
= TRUE
;
1410 res
= assert_wait((event_t
)(((unsigned int*)rlck
)+((sizeof(lck_rw_t
)-1)/sizeof(unsigned int))), THREAD_UNINT
);
1411 if (res
== THREAD_WAITING
) {
1412 if (lock_stat
&& !lock_wait
) {
1414 lck
->lck_rw_grp
->lck_grp_stat
.lck_grp_rw_stat
.lck_grp_rw_wait_cnt
++;
1416 lck_rw_ilk_unlock(&lck
->lck_rw
);
1417 res
= thread_block(THREAD_CONTINUE_NULL
);
1418 lck_rw_ilk_lock(&lck
->lck_rw
);
1421 KERNEL_DEBUG(MACHDBG_CODE(DBG_MACH_LOCKS
, LCK_RW_LCK_EXCLUSIVE1_CODE
) | DBG_FUNC_END
,
1422 (int)rlck
, lck
->lck_rw
.lck_rw_shared_cnt
, lck
->lck_rw
.lck_rw_want_upgrade
, res
, 0);
1425 lck
->lck_rw_deb
.pc_excl
= __builtin_return_address(0);
1426 if (LcksOpts
& enaLkExtStck
)
1427 lck_rw_ext_backtrace(lck
);
1428 lck
->lck_rw_deb
.thread
= current_thread();
1430 lck_rw_ilk_unlock(&lck
->lck_rw
);
1435 * Routine: lck_rw_done_ext
1442 boolean_t do_wakeup
= FALSE
;
1443 lck_rw_type_t lck_rw_type
;
1446 lck_rw_check_type(lck
, rlck
);
1448 lck_rw_ilk_lock(&lck
->lck_rw
);
1450 if (lck
->lck_rw
.lck_rw_shared_cnt
!= 0) {
1451 lck_rw_type
= LCK_RW_TYPE_SHARED
;
1452 lck
->lck_rw
.lck_rw_shared_cnt
--;
1455 lck_rw_type
= LCK_RW_TYPE_EXCLUSIVE
;
1456 if (lck
->lck_rw
.lck_rw_want_upgrade
)
1457 lck
->lck_rw
.lck_rw_want_upgrade
= FALSE
;
1458 else if (lck
->lck_rw
.lck_rw_want_excl
)
1459 lck
->lck_rw
.lck_rw_want_excl
= FALSE
;
1461 panic("rw lock (0x%08X) bad state (0x%08X) on attempt to release a shared or exlusive right\n",
1463 if (lck
->lck_rw_deb
.thread
== THREAD_NULL
)
1464 panic("rw lock (0x%08X) not held\n",
1466 else if ( ((lck
->lck_rw_attr
& (LCK_RW_ATTR_DEBUG
|LCK_RW_ATTR_DIS_THREAD
)) == LCK_RW_ATTR_DEBUG
)
1467 && (lck
->lck_rw_deb
.thread
!= current_thread()))
1468 panic("rw lock (0x%08X) unlocked by non-owner(0x%08X), current owner(0x%08X)\n",
1469 rlck
, current_thread(), lck
->lck_rw_deb
.thread
);
1470 lck
->lck_rw_deb
.thread
= THREAD_NULL
;
1473 if (lck
->lck_rw_attr
& LCK_RW_ATTR_DEBUG
)
1474 lck
->lck_rw_deb
.pc_done
= __builtin_return_address(0);
1477 * There is no reason to wakeup a waiting thread
1478 * if the read-count is non-zero. Consider:
1479 * we must be dropping a read lock
1480 * threads are waiting only if one wants a write lock
1481 * if there are still readers, they can't proceed
1484 if (lck
->lck_rw
.lck_rw_waiting
&& (lck
->lck_rw
.lck_rw_shared_cnt
== 0)) {
1485 lck
->lck_rw
.lck_rw_waiting
= FALSE
;
1489 lck_rw_ilk_unlock(&lck
->lck_rw
);
1492 thread_wakeup((event_t
)(((unsigned int*)rlck
)+((sizeof(lck_rw_t
)-1)/sizeof(unsigned int))));
1493 return(lck_rw_type
);
1498 * Routine: lck_rw_lock_shared_ext
1501 lck_rw_lock_shared_ext(
1507 boolean_t lock_miss
= FALSE
;
1508 boolean_t lock_wait
= FALSE
;
1509 boolean_t lock_stat
;
1511 lck_rw_check_type(lck
, rlck
);
1513 lck_rw_ilk_lock(&lck
->lck_rw
);
1515 lock_stat
= (lck
->lck_rw_attr
& LCK_RW_ATTR_STAT
) ? TRUE
: FALSE
;
1518 lck
->lck_rw_grp
->lck_grp_stat
.lck_grp_rw_stat
.lck_grp_rw_util_cnt
++;
1520 while (lck
->lck_rw
.lck_rw_want_excl
|| lck
->lck_rw
.lck_rw_want_upgrade
) {
1521 i
= lock_wait_time
[1];
1523 KERNEL_DEBUG(MACHDBG_CODE(DBG_MACH_LOCKS
, LCK_RW_LCK_SHARED_CODE
) | DBG_FUNC_START
,
1524 (int)rlck
, lck
->lck_rw
.lck_rw_want_excl
, lck
->lck_rw
.lck_rw_want_upgrade
, i
, 0);
1526 if (lock_stat
&& !lock_miss
) {
1528 lck
->lck_rw_grp
->lck_grp_stat
.lck_grp_rw_stat
.lck_grp_rw_miss_cnt
++;
1532 lck_rw_ilk_unlock(&lck
->lck_rw
);
1533 while (--i
!= 0 && (lck
->lck_rw
.lck_rw_want_excl
|| lck
->lck_rw
.lck_rw_want_upgrade
))
1535 lck_rw_ilk_lock(&lck
->lck_rw
);
1538 if (lck
->lck_rw
.lck_rw_want_excl
|| lck
->lck_rw
.lck_rw_want_upgrade
) {
1539 lck
->lck_rw
.lck_rw_waiting
= TRUE
;
1540 res
= assert_wait((event_t
)(((unsigned int*)rlck
)+((sizeof(lck_rw_t
)-1)/sizeof(unsigned int))), THREAD_UNINT
);
1541 if (res
== THREAD_WAITING
) {
1542 if (lock_stat
&& !lock_wait
) {
1544 lck
->lck_rw_grp
->lck_grp_stat
.lck_grp_rw_stat
.lck_grp_rw_wait_cnt
++;
1546 lck_rw_ilk_unlock(&lck
->lck_rw
);
1547 res
= thread_block(THREAD_CONTINUE_NULL
);
1548 lck_rw_ilk_lock(&lck
->lck_rw
);
1551 KERNEL_DEBUG(MACHDBG_CODE(DBG_MACH_LOCKS
, LCK_RW_LCK_SHARED_CODE
) | DBG_FUNC_END
,
1552 (int)rlck
, lck
->lck_rw
.lck_rw_want_excl
, lck
->lck_rw
.lck_rw_want_upgrade
, res
, 0);
1555 lck
->lck_rw
.lck_rw_shared_cnt
++;
1557 lck_rw_ilk_unlock(&lck
->lck_rw
);
1562 * Routine: lck_rw_lock_shared_to_exclusive_ext
1564 * Improves a read-only lock to one with
1565 * write permission. If another reader has
1566 * already requested an upgrade to a write lock,
1567 * no lock is held upon return.
1569 * Returns TRUE if the upgrade *failed*.
1573 lck_rw_lock_shared_to_exclusive_ext(
1578 boolean_t do_wakeup
= FALSE
;
1580 boolean_t lock_miss
= FALSE
;
1581 boolean_t lock_wait
= FALSE
;
1582 boolean_t lock_stat
;
1584 lck_rw_check_type(lck
, rlck
);
1586 if (lck
->lck_rw_deb
.thread
== current_thread())
1587 panic("rw lock (0x%08X) recursive lock attempt\n", rlck
);
1589 lck_rw_ilk_lock(&lck
->lck_rw
);
1591 lock_stat
= (lck
->lck_rw_attr
& LCK_RW_ATTR_STAT
) ? TRUE
: FALSE
;
1594 lck
->lck_rw_grp
->lck_grp_stat
.lck_grp_rw_stat
.lck_grp_rw_util_cnt
++;
1596 lck
->lck_rw
.lck_rw_shared_cnt
--;
1598 if (lck
->lck_rw
.lck_rw_want_upgrade
) {
1599 KERNEL_DEBUG(MACHDBG_CODE(DBG_MACH_LOCKS
, LCK_RW_LCK_SH_TO_EX_CODE
) | DBG_FUNC_START
,
1600 (int)rlck
, lck
->lck_rw
.lck_rw_shared_cnt
, lck
->lck_rw
.lck_rw_want_upgrade
, 0, 0);
1603 * Someone else has requested upgrade.
1604 * Since we've released a read lock, wake
1607 if (lck
->lck_rw
.lck_rw_waiting
&& (lck
->lck_rw
.lck_rw_shared_cnt
== 0)) {
1608 lck
->lck_rw
.lck_rw_waiting
= FALSE
;
1612 lck_rw_ilk_unlock(&lck
->lck_rw
);
1615 thread_wakeup((event_t
)(((unsigned int*)rlck
)+((sizeof(lck_rw_t
)-1)/sizeof(unsigned int))));
1617 KERNEL_DEBUG(MACHDBG_CODE(DBG_MACH_LOCKS
, LCK_RW_LCK_SH_TO_EX_CODE
) | DBG_FUNC_END
,
1618 (int)rlck
, lck
->lck_rw
.lck_rw_shared_cnt
, lck
->lck_rw
.lck_rw_want_upgrade
, 0, 0);
1623 lck
->lck_rw
.lck_rw_want_upgrade
= TRUE
;
1625 while (lck
->lck_rw
.lck_rw_shared_cnt
!= 0) {
1626 i
= lock_wait_time
[1];
1628 KERNEL_DEBUG(MACHDBG_CODE(DBG_MACH_LOCKS
, LCK_RW_LCK_SH_TO_EX1_CODE
) | DBG_FUNC_START
,
1629 (int)rlck
, lck
->lck_rw
.lck_rw_shared_cnt
, i
, 0, 0);
1631 if (lock_stat
&& !lock_miss
) {
1633 lck
->lck_rw_grp
->lck_grp_stat
.lck_grp_rw_stat
.lck_grp_rw_miss_cnt
++;
1637 lck_rw_ilk_unlock(&lck
->lck_rw
);
1638 while (--i
!= 0 && lck
->lck_rw
.lck_rw_shared_cnt
!= 0)
1640 lck_rw_ilk_lock(&lck
->lck_rw
);
1643 if (lck
->lck_rw
.lck_rw_shared_cnt
!= 0) {
1644 lck
->lck_rw
.lck_rw_waiting
= TRUE
;
1645 res
= assert_wait((event_t
)(((unsigned int*)rlck
)+((sizeof(lck_rw_t
)-1)/sizeof(unsigned int))), THREAD_UNINT
);
1646 if (res
== THREAD_WAITING
) {
1647 if (lock_stat
&& !lock_wait
) {
1649 lck
->lck_rw_grp
->lck_grp_stat
.lck_grp_rw_stat
.lck_grp_rw_wait_cnt
++;
1651 lck_rw_ilk_unlock(&lck
->lck_rw
);
1652 res
= thread_block(THREAD_CONTINUE_NULL
);
1653 lck_rw_ilk_lock(&lck
->lck_rw
);
1656 KERNEL_DEBUG(MACHDBG_CODE(DBG_MACH_LOCKS
, LCK_RW_LCK_SH_TO_EX1_CODE
) | DBG_FUNC_END
,
1657 (int)rlck
, lck
->lck_rw
.lck_rw_shared_cnt
, 0, 0, 0);
1660 lck
->lck_rw_deb
.pc_excl
= __builtin_return_address(0);
1661 if (LcksOpts
& enaLkExtStck
)
1662 lck_rw_ext_backtrace(lck
);
1663 lck
->lck_rw_deb
.thread
= current_thread();
1665 lck_rw_ilk_unlock(&lck
->lck_rw
);
1671 * Routine: lck_rw_lock_exclusive_to_shared_ext
1674 lck_rw_lock_exclusive_to_shared_ext(
1678 boolean_t do_wakeup
= FALSE
;
1680 lck_rw_check_type(lck
, rlck
);
1682 KERNEL_DEBUG(MACHDBG_CODE(DBG_MACH_LOCKS
, LCK_RW_LCK_EX_TO_SH_CODE
) | DBG_FUNC_START
,
1683 (int)rlck
, lck
->lck_rw
.lck_rw_want_excl
, lck
->lck_rw
.lck_rw_want_upgrade
, 0, 0);
1685 lck_rw_ilk_lock(&lck
->lck_rw
);
1687 lck
->lck_rw
.lck_rw_shared_cnt
++;
1688 if (lck
->lck_rw
.lck_rw_want_upgrade
)
1689 lck
->lck_rw
.lck_rw_want_upgrade
= FALSE
;
1690 else if (lck
->lck_rw
.lck_rw_want_excl
)
1691 lck
->lck_rw
.lck_rw_want_excl
= FALSE
;
1693 panic("rw lock (0x%08X) bad state (0x%08X) on attempt to release a shared or exlusive right\n",
1695 if (lck
->lck_rw_deb
.thread
== THREAD_NULL
)
1696 panic("rw lock (0x%08X) not held\n",
1698 else if ( ((lck
->lck_rw_attr
& (LCK_RW_ATTR_DEBUG
|LCK_RW_ATTR_DIS_THREAD
)) == LCK_RW_ATTR_DEBUG
)
1699 && (lck
->lck_rw_deb
.thread
!= current_thread()))
1700 panic("rw lock (0x%08X) unlocked by non-owner(0x%08X), current owner(0x%08X)\n",
1701 rlck
, current_thread(), lck
->lck_rw_deb
.thread
);
1703 lck
->lck_rw_deb
.thread
= THREAD_NULL
;
1705 if (lck
->lck_rw
.lck_rw_waiting
) {
1706 lck
->lck_rw
.lck_rw_waiting
= FALSE
;
1710 lck_rw_ilk_unlock(&lck
->lck_rw
);
1713 thread_wakeup((event_t
)(((unsigned int*)rlck
)+((sizeof(lck_rw_t
)-1)/sizeof(unsigned int))));
1715 KERNEL_DEBUG(MACHDBG_CODE(DBG_MACH_LOCKS
, LCK_RW_LCK_EX_TO_SH_CODE
) | DBG_FUNC_END
,
1716 (int)rlck
, lck
->lck_rw
.lck_rw_want_excl
, lck
->lck_rw
.lck_rw_want_upgrade
, lck
->lck_rw
.lck_rw_shared_cnt
, 0);
1722 * Routine: lck_rw_try_lock_exclusive_ext
1724 * Tries to get a write lock.
1726 * Returns FALSE if the lock is not held on return.
1730 lck_rw_try_lock_exclusive_ext(
1734 boolean_t lock_stat
;
1736 lck_rw_check_type(lck
, rlck
);
1738 lck_rw_ilk_lock(&lck
->lck_rw
);
1740 lock_stat
= (lck
->lck_rw_attr
& LCK_RW_ATTR_STAT
) ? TRUE
: FALSE
;
1743 lck
->lck_rw_grp
->lck_grp_stat
.lck_grp_rw_stat
.lck_grp_rw_util_cnt
++;
1745 if (lck
->lck_rw
.lck_rw_want_excl
|| lck
->lck_rw
.lck_rw_want_upgrade
|| lck
->lck_rw
.lck_rw_shared_cnt
) {
1750 lck
->lck_rw_grp
->lck_grp_stat
.lck_grp_rw_stat
.lck_grp_rw_miss_cnt
++;
1752 lck_rw_ilk_unlock(&lck
->lck_rw
);
1760 lck
->lck_rw
.lck_rw_want_excl
= TRUE
;
1761 lck
->lck_rw_deb
.pc_excl
= __builtin_return_address(0);
1762 if (LcksOpts
& enaLkExtStck
)
1763 lck_rw_ext_backtrace(lck
);
1764 lck
->lck_rw_deb
.thread
= current_thread();
1766 lck_rw_ilk_unlock(&lck
->lck_rw
);
1772 * Routine: lck_rw_try_lock_shared_ext
1774 * Tries to get a read lock.
1776 * Returns FALSE if the lock is not held on return.
1780 lck_rw_try_lock_shared_ext(
1784 boolean_t lock_stat
;
1786 lck_rw_check_type(lck
, rlck
);
1788 lck_rw_ilk_lock(&lck
->lck_rw
);
1790 lock_stat
= (lck
->lck_rw_attr
& LCK_RW_ATTR_STAT
) ? TRUE
: FALSE
;
1793 lck
->lck_rw_grp
->lck_grp_stat
.lck_grp_rw_stat
.lck_grp_rw_util_cnt
++;
1795 if (lck
->lck_rw
.lck_rw_want_excl
|| lck
->lck_rw
.lck_rw_want_upgrade
) {
1797 lck
->lck_rw_grp
->lck_grp_stat
.lck_grp_rw_stat
.lck_grp_rw_miss_cnt
++;
1799 lck_rw_ilk_unlock(&lck
->lck_rw
);
1803 lck
->lck_rw
.lck_rw_shared_cnt
++;
1805 lck_rw_ilk_unlock(&lck
->lck_rw
);
1815 if (lck
->lck_rw_deb
.type
!= RW_TAG
)
1816 panic("rw lock (0x%08X) not a rw lock type (0x%08X)\n",rlck
, lck
->lck_rw_deb
.type
);
1820 * The C portion of the mutex package. These routines are only invoked
1821 * if the optimized assembler routines can't do the work.
1825 * Forward definition
1828 void lck_mtx_ext_init(
1834 * Routine: mutex_alloc
1836 * Allocate a mutex for external users who cannot
1837 * hard-code the structure definition into their
1839 * For now just use kalloc, but a zone is probably
1848 if ((m
= (mutex_t
*)kalloc(sizeof(mutex_t
))) != 0)
1854 * Routine: mutex_free
1860 kfree((void *)m
, sizeof(mutex_t
));
1864 * Routine: lck_mtx_alloc_init
1872 if ((lck
= (lck_mtx_t
*)kalloc(sizeof(lck_mtx_t
))) != 0)
1873 lck_mtx_init(lck
, grp
, attr
);
1879 * Routine: lck_mtx_free
1885 lck_mtx_destroy(lck
, grp
);
1886 kfree((void *)lck
, sizeof(lck_mtx_t
));
1890 * Routine: lck_mtx_init
1897 lck_mtx_ext_t
*lck_ext
;
1898 lck_attr_t
*lck_attr
;
1900 if (attr
!= LCK_ATTR_NULL
)
1903 lck_attr
= &LockDefaultLckAttr
;
1905 if ((lck_attr
->lck_attr_val
) & LCK_ATTR_DEBUG
) {
1906 if ((lck_ext
= (lck_mtx_ext_t
*)kalloc(sizeof(lck_mtx_ext_t
))) != 0) {
1907 lck_mtx_ext_init(lck_ext
, grp
, lck_attr
);
1908 lck
->lck_mtx_tag
= LCK_MTX_TAG_INDIRECT
;
1909 lck
->lck_mtx_ptr
= lck_ext
;
1912 lck
->lck_mtx_data
= 0;
1913 lck
->lck_mtx_waiters
= 0;
1914 lck
->lck_mtx_pri
= 0;
1916 lck_grp_reference(grp
);
1917 lck_grp_lckcnt_incr(grp
, LCK_TYPE_MTX
);
1921 * Routine: lck_mtx_ext_init
1929 bzero((void *)lck
, sizeof(lck_mtx_ext_t
));
1931 if ((attr
->lck_attr_val
) & LCK_ATTR_DEBUG
) {
1932 lck
->lck_mtx_deb
.type
= MUTEX_TAG
;
1933 lck
->lck_mtx_attr
|= LCK_MTX_ATTR_DEBUG
;
1936 lck
->lck_mtx_grp
= grp
;
1938 if (grp
->lck_grp_attr
& LCK_GRP_ATTR_STAT
)
1939 lck
->lck_mtx_attr
|= LCK_MTX_ATTR_STAT
;
1943 * Routine: lck_mtx_destroy
1949 boolean_t lck_is_indirect
;
1951 if (lck
->lck_mtx_tag
== LCK_MTX_TAG_DESTROYED
)
1953 lck_is_indirect
= (lck
->lck_mtx_tag
== LCK_MTX_TAG_INDIRECT
);
1954 lck
->lck_mtx_tag
= LCK_MTX_TAG_DESTROYED
;
1955 if (lck_is_indirect
)
1956 kfree((void *)lck
->lck_mtx_ptr
, sizeof(lck_mtx_ext_t
));
1958 lck_grp_lckcnt_decr(grp
, LCK_TYPE_MTX
);
1959 lck_grp_deallocate(grp
);
1966 * Routines to print out simple_locks and mutexes in a nicely-formatted
1970 char *simple_lock_labels
= "ENTRY ILK THREAD DURATION CALLER";
1971 char *mutex_labels
= "ENTRY LOCKED WAITERS THREAD CALLER";
1973 void db_print_simple_lock(
1974 simple_lock_t addr
);
1976 void db_print_mutex(
1980 db_show_one_simple_lock (
1982 boolean_t have_addr
,
1986 simple_lock_t saddr
= (simple_lock_t
)addr
;
1988 if (saddr
== (simple_lock_t
)0 || !have_addr
) {
1989 db_error ("No simple_lock\n");
1992 else if (saddr
->lock_type
!= USLOCK_TAG
)
1993 db_error ("Not a simple_lock\n");
1994 #endif /* USLOCK_DEBUG */
1996 db_printf ("%s\n", simple_lock_labels
);
1997 db_print_simple_lock (saddr
);
2001 db_print_simple_lock (
2005 db_printf ("%08x %3d", addr
, *hw_lock_addr(addr
->interlock
));
2007 db_printf (" %08x", addr
->debug
.lock_thread
);
2008 db_printf (" %08x ", addr
->debug
.duration
[1]);
2009 db_printsym ((int)addr
->debug
.lock_pc
, DB_STGY_ANY
);
2010 #endif /* USLOCK_DEBUG */
2017 boolean_t have_addr
,
2021 mutex_t
* maddr
= (mutex_t
*)addr
;
2023 if (maddr
== (mutex_t
*)0 || !have_addr
)
2024 db_error ("No mutex\n");
2026 else if (maddr
->lck_mtx_deb
.type
!= MUTEX_TAG
)
2027 db_error ("Not a mutex\n");
2028 #endif /* MACH_LDEBUG */
2030 db_printf ("%s\n", mutex_labels
);
2031 db_print_mutex (maddr
);
2038 db_printf ("%08x %6d %7d",
2039 addr
, *addr
, addr
->lck_mtx
.lck_mtx_waiters
);
2041 db_printf (" %08x ", addr
->lck_mtx_deb
.thread
);
2042 db_printsym (addr
->lck_mtx_deb
.stack
[0], DB_STGY_ANY
);
2043 #endif /* MACH_LDEBUG */
2051 db_printf("shared_count = 0x%x, %swant_upgrade, %swant_exclusive, ",
2052 lock
->lck_rw
.lck_rw_shared_cnt
,
2053 lock
->lck_rw
.lck_rw_want_upgrade
? "" : "!",
2054 lock
->lck_rw
.lck_rw_want_excl
? "" : "!");
2055 db_printf("%swaiting\n",
2056 lock
->lck_rw
.lck_rw_waiting
? "" : "!");
2057 db_printf("%sInterlock\n",
2058 lock
->lck_rw
.lck_rw_interlock
? "" : "!");
2061 #endif /* MACH_KDB */