2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
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.
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
20 * @APPLE_LICENSE_HEADER_END@
26 * Mach Operating System
27 * Copyright (c) 1991,1990,1989,1988,1987 Carnegie Mellon University
28 * All Rights Reserved.
30 * Permission to use, copy, modify and distribute this software and its
31 * documentation is hereby granted, provided that both the copyright
32 * notice and this permission notice appear in all copies of the
33 * software, derivative works or modified versions, and any portions
34 * thereof, and that both notices appear in supporting documentation.
36 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
37 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
38 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
40 * Carnegie Mellon requests users of this software to return to
42 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
43 * School of Computer Science
44 * Carnegie Mellon University
45 * Pittsburgh PA 15213-3890
47 * any improvements or extensions that they make and grant Carnegie Mellon
48 * the rights to redistribute these changes.
52 * Author: Avadis Tevanian, Jr., Michael Wayne Young
55 * Locking primitives implementation
59 #include <mach_ldebug.h>
61 #include <kern/kalloc.h>
62 #include <kern/lock.h>
63 #include <kern/locks.h>
64 #include <kern/misc_protos.h>
65 #include <kern/thread.h>
66 #include <kern/processor.h>
67 #include <kern/sched_prim.h>
69 #include <kern/debug.h>
73 #include <ddb/db_command.h>
74 #include <ddb/db_output.h>
75 #include <ddb/db_sym.h>
76 #include <ddb/db_print.h>
80 #include <ppc/Firmware.h>
83 #include <sys/kdebug.h>
85 #define LCK_RW_LCK_EXCLUSIVE_CODE 0x100
86 #define LCK_RW_LCK_EXCLUSIVE1_CODE 0x101
87 #define LCK_RW_LCK_SHARED_CODE 0x102
88 #define LCK_RW_LCK_SH_TO_EX_CODE 0x103
89 #define LCK_RW_LCK_SH_TO_EX1_CODE 0x104
90 #define LCK_RW_LCK_EX_TO_SH_CODE 0x105
93 #define ANY_LOCK_DEBUG (USLOCK_DEBUG || LOCK_DEBUG || MUTEX_DEBUG)
95 unsigned int lock_wait_time
[2] = { (unsigned int)-1, 0 } ;
102 * Perform simple lock checks.
104 int uslock_check
= 1;
105 int max_lock_loops
= 100000000;
106 decl_simple_lock_data(extern , printf_lock
)
107 decl_simple_lock_data(extern , panic_lock
)
109 decl_simple_lock_data(extern , kdb_lock
)
110 #endif /* MACH_KDB */
111 #endif /* USLOCK_DEBUG */
115 * We often want to know the addresses of the callers
116 * of the various lock routines. However, this information
117 * is only used for debugging and statistics.
120 #define INVALID_PC ((void *) VM_MAX_KERNEL_ADDRESS)
121 #define INVALID_THREAD ((void *) VM_MAX_KERNEL_ADDRESS)
123 #define OBTAIN_PC(pc,l) ((pc) = (void *) GET_RETURN_PC(&(l)))
124 #else /* ANY_LOCK_DEBUG */
127 * Eliminate lint complaints about unused local pc variables.
129 #define OBTAIN_PC(pc,l) ++pc
131 #define OBTAIN_PC(pc,l)
133 #endif /* USLOCK_DEBUG */
137 * Portable lock package implementation of usimple_locks.
141 #define USLDBG(stmt) stmt
142 void usld_lock_init(usimple_lock_t
, unsigned short);
143 void usld_lock_pre(usimple_lock_t
, pc_t
);
144 void usld_lock_post(usimple_lock_t
, pc_t
);
145 void usld_unlock(usimple_lock_t
, pc_t
);
146 void usld_lock_try_pre(usimple_lock_t
, pc_t
);
147 void usld_lock_try_post(usimple_lock_t
, pc_t
);
148 int usld_lock_common_checks(usimple_lock_t
, char *);
149 #else /* USLOCK_DEBUG */
151 #endif /* USLOCK_DEBUG */
154 * Routine: lck_spin_alloc_init
162 if ((lck
= (lck_spin_t
*)kalloc(sizeof(lck_spin_t
))) != 0)
163 lck_spin_init(lck
, grp
, attr
);
169 * Routine: lck_spin_free
175 lck_spin_destroy(lck
, grp
);
176 kfree((void *)lck
, sizeof(lck_spin_t
));
180 * Routine: lck_spin_init
186 __unused lck_attr_t
*attr
) {
189 lck_grp_reference(grp
);
190 lck_grp_lckcnt_incr(grp
, LCK_TYPE_SPIN
);
194 * Routine: lck_spin_destroy
200 if (lck
->interlock
== LCK_SPIN_TAG_DESTROYED
)
202 lck
->interlock
= LCK_SPIN_TAG_DESTROYED
;
203 lck_grp_lckcnt_decr(grp
, LCK_TYPE_SPIN
);
204 lck_grp_deallocate(grp
);
208 * Initialize a usimple_lock.
210 * No change in preemption state.
217 #ifndef MACHINE_SIMPLE_LOCK
218 USLDBG(usld_lock_init(l
, tag
));
219 hw_lock_init(&l
->interlock
);
221 simple_lock_init((simple_lock_t
)l
,tag
);
227 * Acquire a usimple_lock.
229 * Returns with preemption disabled. Note
230 * that the hw_lock routines are responsible for
231 * maintaining preemption state.
237 #ifndef MACHINE_SIMPLE_LOCK
242 #endif /* USLOCK_DEBUG */
245 USLDBG(usld_lock_pre(l
, pc
));
247 if(!hw_lock_to(&l
->interlock
, LockTimeOut
)) /* Try to get the lock with a timeout */
248 panic("simple lock deadlock detection - l=0x%08X, cpu=%d, ret=0x%08X", l
, cpu_number(), pc
);
250 USLDBG(usld_lock_post(l
, pc
));
252 simple_lock((simple_lock_t
)l
);
258 * Release a usimple_lock.
260 * Returns with preemption enabled. Note
261 * that the hw_lock routines are responsible for
262 * maintaining preemption state.
268 #ifndef MACHINE_SIMPLE_LOCK
272 USLDBG(usld_unlock(l
, pc
));
274 hw_lock_unlock(&l
->interlock
);
276 simple_unlock_rwmb((simple_lock_t
)l
);
282 * Conditionally acquire a usimple_lock.
284 * On success, returns with preemption disabled.
285 * On failure, returns with preemption in the same state
286 * as when first invoked. Note that the hw_lock routines
287 * are responsible for maintaining preemption state.
289 * XXX No stats are gathered on a miss; I preserved this
290 * behavior from the original assembly-language code, but
291 * doesn't it make sense to log misses? XXX
297 #ifndef MACHINE_SIMPLE_LOCK
299 unsigned int success
;
302 USLDBG(usld_lock_try_pre(l
, pc
));
303 if (success
= hw_lock_try(&l
->interlock
)) {
304 USLDBG(usld_lock_try_post(l
, pc
));
308 return(simple_lock_try((simple_lock_t
)l
));
314 * States of a usimple_lock. The default when initializing
315 * a usimple_lock is setting it up for debug checking.
317 #define USLOCK_CHECKED 0x0001 /* lock is being checked */
318 #define USLOCK_TAKEN 0x0002 /* lock has been taken */
319 #define USLOCK_INIT 0xBAA0 /* lock has been initialized */
320 #define USLOCK_INITIALIZED (USLOCK_INIT|USLOCK_CHECKED)
321 #define USLOCK_CHECKING(l) (uslock_check && \
322 ((l)->debug.state & USLOCK_CHECKED))
325 * Trace activities of a particularly interesting lock.
327 void usl_trace(usimple_lock_t
, int, pc_t
, const char *);
331 * Initialize the debugging information contained
339 if (l
== USIMPLE_LOCK_NULL
)
340 panic("lock initialization: null lock pointer");
341 l
->lock_type
= USLOCK_TAG
;
342 l
->debug
.state
= uslock_check
? USLOCK_INITIALIZED
: 0;
343 l
->debug
.lock_cpu
= l
->debug
.unlock_cpu
= 0;
344 l
->debug
.lock_pc
= l
->debug
.unlock_pc
= INVALID_PC
;
345 l
->debug
.lock_thread
= l
->debug
.unlock_thread
= INVALID_THREAD
;
346 l
->debug
.duration
[0] = l
->debug
.duration
[1] = 0;
347 l
->debug
.unlock_cpu
= l
->debug
.unlock_cpu
= 0;
348 l
->debug
.unlock_pc
= l
->debug
.unlock_pc
= INVALID_PC
;
349 l
->debug
.unlock_thread
= l
->debug
.unlock_thread
= INVALID_THREAD
;
354 * These checks apply to all usimple_locks, not just
355 * those with USLOCK_CHECKED turned on.
358 usld_lock_common_checks(
362 if (l
== USIMPLE_LOCK_NULL
)
363 panic("%s: null lock pointer", caller
);
364 if (l
->lock_type
!= USLOCK_TAG
)
365 panic("%s: 0x%x is not a usimple lock", caller
, (integer_t
) l
);
366 if (!(l
->debug
.state
& USLOCK_INIT
))
367 panic("%s: 0x%x is not an initialized lock",
368 caller
, (integer_t
) l
);
369 return USLOCK_CHECKING(l
);
374 * Debug checks on a usimple_lock just before attempting
383 char *caller
= "usimple_lock";
386 if (!usld_lock_common_checks(l
, caller
))
390 * Note that we have a weird case where we are getting a lock when we are]
391 * in the process of putting the system to sleep. We are running with no
392 * current threads, therefore we can't tell if we are trying to retake a lock
393 * we have or someone on the other processor has it. Therefore we just
394 * ignore this test if the locking thread is 0.
397 if ((l
->debug
.state
& USLOCK_TAKEN
) && l
->debug
.lock_thread
&&
398 l
->debug
.lock_thread
== (void *) current_thread()) {
399 printf("%s: lock 0x%x already locked (at 0x%x) by",
400 caller
, (integer_t
) l
, l
->debug
.lock_pc
);
401 printf(" current thread 0x%x (new attempt at pc 0x%x)\n",
402 l
->debug
.lock_thread
, pc
);
405 mp_disable_preemption();
406 usl_trace(l
, cpu_number(), pc
, caller
);
407 mp_enable_preemption();
412 * Debug checks on a usimple_lock just after acquiring it.
414 * Pre-emption has been disabled at this point,
415 * so we are safe in using cpu_number.
423 char *caller
= "successful usimple_lock";
426 if (!usld_lock_common_checks(l
, caller
))
429 if (!((l
->debug
.state
& ~USLOCK_TAKEN
) == USLOCK_INITIALIZED
))
430 panic("%s: lock 0x%x became uninitialized",
431 caller
, (integer_t
) l
);
432 if ((l
->debug
.state
& USLOCK_TAKEN
))
433 panic("%s: lock 0x%x became TAKEN by someone else",
434 caller
, (integer_t
) l
);
436 mycpu
= cpu_number();
437 l
->debug
.lock_thread
= (void *)current_thread();
438 l
->debug
.state
|= USLOCK_TAKEN
;
439 l
->debug
.lock_pc
= pc
;
440 l
->debug
.lock_cpu
= mycpu
;
442 usl_trace(l
, mycpu
, pc
, caller
);
447 * Debug checks on a usimple_lock just before
448 * releasing it. Note that the caller has not
449 * yet released the hardware lock.
451 * Preemption is still disabled, so there's
452 * no problem using cpu_number.
460 char *caller
= "usimple_unlock";
463 if (!usld_lock_common_checks(l
, caller
))
466 mycpu
= cpu_number();
468 if (!(l
->debug
.state
& USLOCK_TAKEN
))
469 panic("%s: lock 0x%x hasn't been taken",
470 caller
, (integer_t
) l
);
471 if (l
->debug
.lock_thread
!= (void *) current_thread())
472 panic("%s: unlocking lock 0x%x, owned by thread 0x%x",
473 caller
, (integer_t
) l
, l
->debug
.lock_thread
);
474 if (l
->debug
.lock_cpu
!= mycpu
) {
475 printf("%s: unlocking lock 0x%x on cpu 0x%x",
476 caller
, (integer_t
) l
, mycpu
);
477 printf(" (acquired on cpu 0x%x)\n", l
->debug
.lock_cpu
);
480 usl_trace(l
, mycpu
, pc
, caller
);
482 l
->debug
.unlock_thread
= l
->debug
.lock_thread
;
483 l
->debug
.lock_thread
= INVALID_PC
;
484 l
->debug
.state
&= ~USLOCK_TAKEN
;
485 l
->debug
.unlock_pc
= pc
;
486 l
->debug
.unlock_cpu
= mycpu
;
491 * Debug checks on a usimple_lock just before
492 * attempting to acquire it.
494 * Preemption isn't guaranteed to be disabled.
501 char *caller
= "usimple_lock_try";
503 if (!usld_lock_common_checks(l
, caller
))
505 mp_disable_preemption();
506 usl_trace(l
, cpu_number(), pc
, caller
);
507 mp_enable_preemption();
512 * Debug checks on a usimple_lock just after
513 * successfully attempting to acquire it.
515 * Preemption has been disabled by the
516 * lock acquisition attempt, so it's safe
525 char *caller
= "successful usimple_lock_try";
527 if (!usld_lock_common_checks(l
, caller
))
530 if (!((l
->debug
.state
& ~USLOCK_TAKEN
) == USLOCK_INITIALIZED
))
531 panic("%s: lock 0x%x became uninitialized",
532 caller
, (integer_t
) l
);
533 if ((l
->debug
.state
& USLOCK_TAKEN
))
534 panic("%s: lock 0x%x became TAKEN by someone else",
535 caller
, (integer_t
) l
);
537 mycpu
= cpu_number();
538 l
->debug
.lock_thread
= (void *) current_thread();
539 l
->debug
.state
|= USLOCK_TAKEN
;
540 l
->debug
.lock_pc
= pc
;
541 l
->debug
.lock_cpu
= mycpu
;
543 usl_trace(l
, mycpu
, pc
, caller
);
548 * For very special cases, set traced_lock to point to a
549 * specific lock of interest. The result is a series of
550 * XPRs showing lock operations on that lock. The lock_seq
551 * value is used to show the order of those operations.
553 usimple_lock_t traced_lock
;
554 unsigned int lock_seq
;
561 const char * op_name
)
563 if (traced_lock
== l
) {
565 "seq %d, cpu %d, %s @ %x\n",
566 (integer_t
) lock_seq
, (integer_t
) mycpu
,
567 (integer_t
) op_name
, (integer_t
) pc
, 0);
573 #endif /* USLOCK_DEBUG */
576 * The C portion of the shared/exclusive locks package.
583 void lck_rw_lock_exclusive_gen(
586 lck_rw_type_t
lck_rw_done_gen(
590 lck_rw_lock_shared_gen(
594 lck_rw_lock_shared_to_exclusive_gen(
598 lck_rw_lock_exclusive_to_shared_gen(
602 lck_rw_try_lock_exclusive_gen(
606 lck_rw_try_lock_shared_gen(
609 void lck_rw_ext_init(
614 void lck_rw_ext_backtrace(
617 void lck_rw_lock_exclusive_ext(
621 lck_rw_type_t
lck_rw_done_ext(
626 lck_rw_lock_shared_ext(
631 lck_rw_lock_shared_to_exclusive_ext(
636 lck_rw_lock_exclusive_to_shared_ext(
641 lck_rw_try_lock_exclusive_ext(
646 lck_rw_try_lock_shared_ext(
664 * Routine: lock_alloc
666 * Allocate a lock for external users who cannot
667 * hard-code the structure definition into their
669 * For now just use kalloc, but a zone is probably
675 __unused
unsigned short tag
,
676 __unused
unsigned short tag1
)
680 if ((lck
= (lock_t
*)kalloc(sizeof(lock_t
))) != 0)
681 lock_init(lck
, can_sleep
, tag
, tag1
);
688 * Initialize a lock; required before use.
689 * Note that clients declare the "struct lock"
690 * variables and then initialize them, rather
691 * than getting a new one from this module.
697 __unused
unsigned short tag
,
698 __unused
unsigned short tag1
)
701 panic("lock_init: sleep mode must be set to TRUE\n");
703 (void) memset((void *) lck
, 0, sizeof(lock_t
));
705 lck
->lck_rw_deb
.type
= RW_TAG
;
706 lck
->lck_rw_attr
|= (LCK_RW_ATTR_DEBUG
|LCK_RW_ATTR_DIS_THREAD
|LCK_RW_ATTR_DIS_MYLOCK
);
707 lck
->lck_rw
.lck_rw_priv_excl
= TRUE
;
709 lck
->lck_rw_priv_excl
= TRUE
;
718 * Free a lock allocated for external users.
719 * For now just use kfree, but a zone is probably
726 kfree((void *)lck
, sizeof(lock_t
));
734 lck_rw_lock_exclusive_ext((lck_rw_ext_t
*)lck
, (lck_rw_t
*)lck
);
741 (void)lck_rw_done_ext((lck_rw_ext_t
*)lck
, (lck_rw_t
*)lck
);
748 lck_rw_lock_shared_ext((lck_rw_ext_t
*)lck
, (lck_rw_t
*)lck
);
755 return(lck_rw_lock_shared_to_exclusive_ext((lck_rw_ext_t
*)lck
, (lck_rw_t
*)lck
));
760 register lock_t
*lck
)
762 lck_rw_lock_exclusive_to_shared_ext((lck_rw_ext_t
*)lck
, (lck_rw_t
*)lck
);
767 * Routine: lck_rw_alloc_init
775 if ((lck
= (lck_rw_t
*)kalloc(sizeof(lck_rw_t
))) != 0)
776 lck_rw_init(lck
, grp
, attr
);
782 * Routine: lck_rw_free
788 lck_rw_destroy(lck
, grp
);
789 kfree((void *)lck
, sizeof(lck_rw_t
));
793 * Routine: lck_rw_init
800 lck_rw_ext_t
*lck_ext
;
801 lck_attr_t
*lck_attr
;
803 if (attr
!= LCK_ATTR_NULL
)
806 lck_attr
= &LockDefaultLckAttr
;
808 if ((lck_attr
->lck_attr_val
) & LCK_ATTR_DEBUG
) {
809 if ((lck_ext
= (lck_rw_ext_t
*)kalloc(sizeof(lck_rw_ext_t
))) != 0) {
810 lck_rw_ext_init(lck_ext
, grp
, lck_attr
);
811 lck
->lck_rw_tag
= LCK_RW_TAG_INDIRECT
;
812 lck
->lck_rw_ptr
= lck_ext
;
815 (void) memset((void *) lck
, 0, sizeof(lck_rw_t
));
816 if ((lck_attr
->lck_attr_val
) & LCK_ATTR_RW_SHARED_PRIORITY
)
817 lck
->lck_rw_priv_excl
= FALSE
;
819 lck
->lck_rw_priv_excl
= TRUE
;
822 lck_grp_reference(grp
);
823 lck_grp_lckcnt_incr(grp
, LCK_TYPE_RW
);
827 * Routine: lck_rw_ext_init
835 bzero((void *)lck
, sizeof(lck_rw_ext_t
));
836 if ((attr
->lck_attr_val
) & LCK_ATTR_RW_SHARED_PRIORITY
)
837 lck
->lck_rw
.lck_rw_priv_excl
= FALSE
;
839 lck
->lck_rw
.lck_rw_priv_excl
= TRUE
;
841 if ((attr
->lck_attr_val
) & LCK_ATTR_DEBUG
) {
842 lck
->lck_rw_deb
.type
= RW_TAG
;
843 lck
->lck_rw_attr
|= LCK_RW_ATTR_DEBUG
;
846 lck
->lck_rw_grp
= grp
;
848 if (grp
->lck_grp_attr
& LCK_GRP_ATTR_STAT
)
849 lck
->lck_rw_attr
|= LCK_RW_ATTR_STAT
;
853 * Routine: lck_rw_destroy
859 boolean_t lck_is_indirect
;
861 if (lck
->lck_rw_tag
== LCK_RW_TAG_DESTROYED
)
863 lck_is_indirect
= (lck
->lck_rw_tag
== LCK_RW_TAG_INDIRECT
);
864 lck
->lck_rw_tag
= LCK_RW_TAG_DESTROYED
;
866 kfree((void *)lck
->lck_rw_ptr
, sizeof(lck_rw_ext_t
));
868 lck_grp_lckcnt_decr(grp
, LCK_TYPE_RW
);
869 lck_grp_deallocate(grp
);
874 * Routine: lck_rw_lock
879 lck_rw_type_t lck_rw_type
)
881 if (lck_rw_type
== LCK_RW_TYPE_SHARED
)
882 lck_rw_lock_shared(lck
);
883 else if (lck_rw_type
== LCK_RW_TYPE_EXCLUSIVE
)
884 lck_rw_lock_exclusive(lck
);
886 panic("lck_rw_lock(): Invalid RW lock type: %d\n", lck_rw_type
);
891 * Routine: lck_rw_unlock
896 lck_rw_type_t lck_rw_type
)
898 if (lck_rw_type
== LCK_RW_TYPE_SHARED
)
899 lck_rw_unlock_shared(lck
);
900 else if (lck_rw_type
== LCK_RW_TYPE_EXCLUSIVE
)
901 lck_rw_unlock_exclusive(lck
);
903 panic("lck_rw_unlock(): Invalid RW lock type: %d\n", lck_rw_type
);
908 * Routine: lck_rw_unlock_shared
911 lck_rw_unlock_shared(
916 ret
= lck_rw_done(lck
);
918 if (ret
!= LCK_RW_TYPE_SHARED
)
919 panic("lck_rw_unlock(): lock held in mode: %d\n", ret
);
924 * Routine: lck_rw_unlock_exclusive
927 lck_rw_unlock_exclusive(
932 ret
= lck_rw_done(lck
);
934 if (ret
!= LCK_RW_TYPE_EXCLUSIVE
)
935 panic("lck_rw_unlock_exclusive(): lock held in mode: %d\n", ret
);
940 * Routine: lck_rw_try_lock
945 lck_rw_type_t lck_rw_type
)
947 if (lck_rw_type
== LCK_RW_TYPE_SHARED
)
948 return(lck_rw_try_lock_shared(lck
));
949 else if (lck_rw_type
== LCK_RW_TYPE_EXCLUSIVE
)
950 return(lck_rw_try_lock_exclusive(lck
));
952 panic("lck_rw_try_lock(): Invalid rw lock type: %x\n", lck_rw_type
);
959 * Routine: lck_rw_lock_exclusive_gen
962 lck_rw_lock_exclusive_gen(
966 boolean_t lock_miss
= FALSE
;
969 lck_rw_ilk_lock(lck
);
972 * Try to acquire the lck_rw_want_excl bit.
974 while (lck
->lck_rw_want_excl
) {
975 KERNEL_DEBUG(MACHDBG_CODE(DBG_MACH_LOCKS
, LCK_RW_LCK_EXCLUSIVE_CODE
) | DBG_FUNC_START
, (int)lck
, 0, 0, 0, 0);
981 i
= lock_wait_time
[1];
983 lck_rw_ilk_unlock(lck
);
984 while (--i
!= 0 && lck
->lck_rw_want_excl
)
986 lck_rw_ilk_lock(lck
);
989 if (lck
->lck_rw_want_excl
) {
990 lck
->lck_rw_waiting
= TRUE
;
991 res
= assert_wait((event_t
)(((unsigned int*)lck
)+((sizeof(lck_rw_t
)-1)/sizeof(unsigned int))), THREAD_UNINT
);
992 if (res
== THREAD_WAITING
) {
993 lck_rw_ilk_unlock(lck
);
994 res
= thread_block(THREAD_CONTINUE_NULL
);
995 lck_rw_ilk_lock(lck
);
998 KERNEL_DEBUG(MACHDBG_CODE(DBG_MACH_LOCKS
, LCK_RW_LCK_EXCLUSIVE_CODE
) | DBG_FUNC_END
, (int)lck
, res
, 0, 0, 0);
1000 lck
->lck_rw_want_excl
= TRUE
;
1002 /* Wait for readers (and upgrades) to finish */
1004 while ((lck
->lck_rw_shared_cnt
!= 0) || lck
->lck_rw_want_upgrade
) {
1009 i
= lock_wait_time
[1];
1011 KERNEL_DEBUG(MACHDBG_CODE(DBG_MACH_LOCKS
, LCK_RW_LCK_EXCLUSIVE1_CODE
) | DBG_FUNC_START
,
1012 (int)lck
, lck
->lck_rw_shared_cnt
, lck
->lck_rw_want_upgrade
, i
, 0);
1015 lck_rw_ilk_unlock(lck
);
1016 while (--i
!= 0 && (lck
->lck_rw_shared_cnt
!= 0 ||
1017 lck
->lck_rw_want_upgrade
))
1019 lck_rw_ilk_lock(lck
);
1022 if (lck
->lck_rw_shared_cnt
!= 0 || lck
->lck_rw_want_upgrade
) {
1023 lck
->lck_rw_waiting
= TRUE
;
1024 res
= assert_wait((event_t
)(((unsigned int*)lck
)+((sizeof(lck_rw_t
)-1)/sizeof(unsigned int))), THREAD_UNINT
);
1025 if (res
== THREAD_WAITING
) {
1026 lck_rw_ilk_unlock(lck
);
1027 res
= thread_block(THREAD_CONTINUE_NULL
);
1028 lck_rw_ilk_lock(lck
);
1031 KERNEL_DEBUG(MACHDBG_CODE(DBG_MACH_LOCKS
, LCK_RW_LCK_EXCLUSIVE1_CODE
) | DBG_FUNC_END
,
1032 (int)lck
, lck
->lck_rw_shared_cnt
, lck
->lck_rw_want_upgrade
, res
, 0);
1035 lck_rw_ilk_unlock(lck
);
1040 * Routine: lck_rw_done_gen
1046 boolean_t do_wakeup
= FALSE
;
1047 lck_rw_type_t lck_rw_type
;
1050 lck_rw_ilk_lock(lck
);
1052 if (lck
->lck_rw_shared_cnt
!= 0) {
1053 lck_rw_type
= LCK_RW_TYPE_SHARED
;
1054 lck
->lck_rw_shared_cnt
--;
1057 lck_rw_type
= LCK_RW_TYPE_EXCLUSIVE
;
1058 if (lck
->lck_rw_want_upgrade
)
1059 lck
->lck_rw_want_upgrade
= FALSE
;
1061 lck
->lck_rw_want_excl
= FALSE
;
1065 * There is no reason to wakeup a lck_rw_waiting thread
1066 * if the read-count is non-zero. Consider:
1067 * we must be dropping a read lock
1068 * threads are waiting only if one wants a write lock
1069 * if there are still readers, they can't proceed
1072 if (lck
->lck_rw_waiting
&& (lck
->lck_rw_shared_cnt
== 0)) {
1073 lck
->lck_rw_waiting
= FALSE
;
1077 lck_rw_ilk_unlock(lck
);
1080 thread_wakeup((event_t
)(((unsigned int*)lck
)+((sizeof(lck_rw_t
)-1)/sizeof(unsigned int))));
1081 return(lck_rw_type
);
1086 * Routine: lck_rw_lock_shared_gen
1089 lck_rw_lock_shared_gen(
1095 lck_rw_ilk_lock(lck
);
1097 while ((lck
->lck_rw_want_excl
|| lck
->lck_rw_want_upgrade
) &&
1098 ((lck
->lck_rw_shared_cnt
== 0) || (lck
->lck_rw_priv_excl
))) {
1099 i
= lock_wait_time
[1];
1101 KERNEL_DEBUG(MACHDBG_CODE(DBG_MACH_LOCKS
, LCK_RW_LCK_SHARED_CODE
) | DBG_FUNC_START
,
1102 (int)lck
, lck
->lck_rw_want_excl
, lck
->lck_rw_want_upgrade
, i
, 0);
1105 lck_rw_ilk_unlock(lck
);
1107 (lck
->lck_rw_want_excl
|| lck
->lck_rw_want_upgrade
) &&
1108 ((lck
->lck_rw_shared_cnt
== 0) || (lck
->lck_rw_priv_excl
)))
1110 lck_rw_ilk_lock(lck
);
1113 if ((lck
->lck_rw_want_excl
|| lck
->lck_rw_want_upgrade
) &&
1114 ((lck
->lck_rw_shared_cnt
== 0) || (lck
->lck_rw_priv_excl
))) {
1115 lck
->lck_rw_waiting
= TRUE
;
1116 res
= assert_wait((event_t
)(((unsigned int*)lck
)+((sizeof(lck_rw_t
)-1)/sizeof(unsigned int))), THREAD_UNINT
);
1117 if (res
== THREAD_WAITING
) {
1118 lck_rw_ilk_unlock(lck
);
1119 res
= thread_block(THREAD_CONTINUE_NULL
);
1120 lck_rw_ilk_lock(lck
);
1123 KERNEL_DEBUG(MACHDBG_CODE(DBG_MACH_LOCKS
, LCK_RW_LCK_SHARED_CODE
) | DBG_FUNC_END
,
1124 (int)lck
, lck
->lck_rw_want_excl
, lck
->lck_rw_want_upgrade
, res
, 0);
1127 lck
->lck_rw_shared_cnt
++;
1129 lck_rw_ilk_unlock(lck
);
1134 * Routine: lck_rw_lock_shared_to_exclusive_gen
1136 * Improves a read-only lock to one with
1137 * write permission. If another reader has
1138 * already requested an upgrade to a write lock,
1139 * no lock is held upon return.
1141 * Returns TRUE if the upgrade *failed*.
1145 lck_rw_lock_shared_to_exclusive_gen(
1149 boolean_t do_wakeup
= FALSE
;
1152 lck_rw_ilk_lock(lck
);
1154 lck
->lck_rw_shared_cnt
--;
1156 if (lck
->lck_rw_want_upgrade
) {
1157 KERNEL_DEBUG(MACHDBG_CODE(DBG_MACH_LOCKS
, LCK_RW_LCK_SH_TO_EX_CODE
) | DBG_FUNC_START
,
1158 (int)lck
, lck
->lck_rw_shared_cnt
, lck
->lck_rw_want_upgrade
, 0, 0);
1161 * Someone else has requested upgrade.
1162 * Since we've released a read lock, wake
1165 if (lck
->lck_rw_waiting
&& (lck
->lck_rw_shared_cnt
== 0)) {
1166 lck
->lck_rw_waiting
= FALSE
;
1170 lck_rw_ilk_unlock(lck
);
1173 thread_wakeup((event_t
)(((unsigned int*)lck
)+((sizeof(lck_rw_t
)-1)/sizeof(unsigned int))));
1175 KERNEL_DEBUG(MACHDBG_CODE(DBG_MACH_LOCKS
, LCK_RW_LCK_SH_TO_EX_CODE
) | DBG_FUNC_END
,
1176 (int)lck
, lck
->lck_rw_shared_cnt
, lck
->lck_rw_want_upgrade
, 0, 0);
1181 lck
->lck_rw_want_upgrade
= TRUE
;
1183 while (lck
->lck_rw_shared_cnt
!= 0) {
1184 i
= lock_wait_time
[1];
1186 KERNEL_DEBUG(MACHDBG_CODE(DBG_MACH_LOCKS
, LCK_RW_LCK_SH_TO_EX1_CODE
) | DBG_FUNC_START
,
1187 (int)lck
, lck
->lck_rw_shared_cnt
, i
, 0, 0);
1190 lck_rw_ilk_unlock(lck
);
1191 while (--i
!= 0 && lck
->lck_rw_shared_cnt
!= 0)
1193 lck_rw_ilk_lock(lck
);
1196 if (lck
->lck_rw_shared_cnt
!= 0) {
1197 lck
->lck_rw_waiting
= TRUE
;
1198 res
= assert_wait((event_t
)(((unsigned int*)lck
)+((sizeof(lck_rw_t
)-1)/sizeof(unsigned int))), THREAD_UNINT
);
1199 if (res
== THREAD_WAITING
) {
1200 lck_rw_ilk_unlock(lck
);
1201 res
= thread_block(THREAD_CONTINUE_NULL
);
1202 lck_rw_ilk_lock(lck
);
1205 KERNEL_DEBUG(MACHDBG_CODE(DBG_MACH_LOCKS
, LCK_RW_LCK_SH_TO_EX1_CODE
) | DBG_FUNC_END
,
1206 (int)lck
, lck
->lck_rw_shared_cnt
, 0, 0, 0);
1209 lck_rw_ilk_unlock(lck
);
1215 * Routine: lck_rw_lock_exclusive_to_shared_gen
1218 lck_rw_lock_exclusive_to_shared_gen(
1221 boolean_t do_wakeup
= FALSE
;
1223 lck_rw_ilk_lock(lck
);
1225 lck
->lck_rw_shared_cnt
++;
1226 if (lck
->lck_rw_want_upgrade
)
1227 lck
->lck_rw_want_upgrade
= FALSE
;
1229 lck
->lck_rw_want_excl
= FALSE
;
1231 if (lck
->lck_rw_waiting
) {
1232 lck
->lck_rw_waiting
= FALSE
;
1236 lck_rw_ilk_unlock(lck
);
1239 thread_wakeup((event_t
)(((unsigned int*)lck
)+((sizeof(lck_rw_t
)-1)/sizeof(unsigned int))));
1245 * Routine: lck_rw_try_lock_exclusive_gen
1247 * Tries to get a write lock.
1249 * Returns FALSE if the lock is not held on return.
1253 lck_rw_try_lock_exclusive_gen(
1256 lck_rw_ilk_lock(lck
);
1258 if (lck
->lck_rw_want_excl
|| lck
->lck_rw_want_upgrade
|| lck
->lck_rw_shared_cnt
) {
1262 lck_rw_ilk_unlock(lck
);
1270 lck
->lck_rw_want_excl
= TRUE
;
1272 lck_rw_ilk_unlock(lck
);
1278 * Routine: lck_rw_try_lock_shared_gen
1280 * Tries to get a read lock.
1282 * Returns FALSE if the lock is not held on return.
1286 lck_rw_try_lock_shared_gen(
1289 lck_rw_ilk_lock(lck
);
1291 if ((lck
->lck_rw_want_excl
|| lck
->lck_rw_want_upgrade
) &&
1292 ((lck
->lck_rw_shared_cnt
== 0) || (lck
->lck_rw_priv_excl
))) {
1293 lck_rw_ilk_unlock(lck
);
1297 lck
->lck_rw_shared_cnt
++;
1299 lck_rw_ilk_unlock(lck
);
1306 * Routine: lck_rw_ext_backtrace
1309 lck_rw_ext_backtrace(
1312 unsigned int *stackptr
, *stackptr_prev
;
1315 __asm__
volatile("mr %0,r1" : "=r" (stackptr
));
1317 while (frame
< LCK_FRAMES_MAX
) {
1318 stackptr_prev
= stackptr
;
1319 stackptr
= ( unsigned int *)*stackptr
;
1320 if ( (((unsigned int)stackptr_prev
) ^ ((unsigned int)stackptr
)) > 8192)
1322 lck
->lck_rw_deb
.stack
[frame
] = *(stackptr
+2);
1325 while (frame
< LCK_FRAMES_MAX
) {
1326 lck
->lck_rw_deb
.stack
[frame
] = 0;
1333 * Routine: lck_rw_lock_exclusive_ext
1336 lck_rw_lock_exclusive_ext(
1342 boolean_t lock_miss
= FALSE
;
1343 boolean_t lock_wait
= FALSE
;
1344 boolean_t lock_stat
;
1346 lck_rw_check_type(lck
, rlck
);
1348 if ( ((lck
->lck_rw_attr
& (LCK_RW_ATTR_DEBUG
|LCK_RW_ATTR_DIS_MYLOCK
)) == LCK_RW_ATTR_DEBUG
)
1349 && (lck
->lck_rw_deb
.thread
== current_thread()))
1350 panic("rw lock (0x%08X) recursive lock attempt\n", rlck
);
1352 lck_rw_ilk_lock(&lck
->lck_rw
);
1354 lock_stat
= (lck
->lck_rw_attr
& LCK_RW_ATTR_STAT
) ? TRUE
: FALSE
;
1357 lck
->lck_rw_grp
->lck_grp_stat
.lck_grp_rw_stat
.lck_grp_rw_util_cnt
++;
1360 * Try to acquire the lck_rw.lck_rw_want_excl bit.
1362 while (lck
->lck_rw
.lck_rw_want_excl
) {
1363 KERNEL_DEBUG(MACHDBG_CODE(DBG_MACH_LOCKS
, LCK_RW_LCK_EXCLUSIVE_CODE
) | DBG_FUNC_START
, (int)rlck
, 0, 0, 0, 0);
1365 if (lock_stat
&& !lock_miss
) {
1367 lck
->lck_rw_grp
->lck_grp_stat
.lck_grp_rw_stat
.lck_grp_rw_miss_cnt
++;
1370 i
= lock_wait_time
[1];
1372 lck_rw_ilk_unlock(&lck
->lck_rw
);
1373 while (--i
!= 0 && lck
->lck_rw
.lck_rw_want_excl
)
1375 lck_rw_ilk_lock(&lck
->lck_rw
);
1378 if (lck
->lck_rw
.lck_rw_want_excl
) {
1379 lck
->lck_rw
.lck_rw_waiting
= TRUE
;
1380 res
= assert_wait((event_t
)(((unsigned int*)rlck
)+((sizeof(lck_rw_t
)-1)/sizeof(unsigned int))), THREAD_UNINT
);
1381 if (res
== THREAD_WAITING
) {
1382 if (lock_stat
&& !lock_wait
) {
1384 lck
->lck_rw_grp
->lck_grp_stat
.lck_grp_rw_stat
.lck_grp_rw_wait_cnt
++;
1386 lck_rw_ilk_unlock(&lck
->lck_rw
);
1387 res
= thread_block(THREAD_CONTINUE_NULL
);
1388 lck_rw_ilk_lock(&lck
->lck_rw
);
1391 KERNEL_DEBUG(MACHDBG_CODE(DBG_MACH_LOCKS
, LCK_RW_LCK_EXCLUSIVE_CODE
) | DBG_FUNC_END
, (int)rlck
, res
, 0, 0, 0);
1393 lck
->lck_rw
.lck_rw_want_excl
= TRUE
;
1395 /* Wait for readers (and upgrades) to finish */
1397 while ((lck
->lck_rw
.lck_rw_shared_cnt
!= 0) || lck
->lck_rw
.lck_rw_want_upgrade
) {
1398 i
= lock_wait_time
[1];
1400 KERNEL_DEBUG(MACHDBG_CODE(DBG_MACH_LOCKS
, LCK_RW_LCK_EXCLUSIVE1_CODE
) | DBG_FUNC_START
,
1401 (int)rlck
, lck
->lck_rw
.lck_rw_shared_cnt
, lck
->lck_rw
.lck_rw_want_upgrade
, i
, 0);
1403 if (lock_stat
&& !lock_miss
) {
1405 lck
->lck_rw_grp
->lck_grp_stat
.lck_grp_rw_stat
.lck_grp_rw_miss_cnt
++;
1409 lck_rw_ilk_unlock(&lck
->lck_rw
);
1410 while (--i
!= 0 && (lck
->lck_rw
.lck_rw_shared_cnt
!= 0 ||
1411 lck
->lck_rw
.lck_rw_want_upgrade
))
1413 lck_rw_ilk_lock(&lck
->lck_rw
);
1416 if (lck
->lck_rw
.lck_rw_shared_cnt
!= 0 || lck
->lck_rw
.lck_rw_want_upgrade
) {
1417 lck
->lck_rw
.lck_rw_waiting
= TRUE
;
1418 res
= assert_wait((event_t
)(((unsigned int*)rlck
)+((sizeof(lck_rw_t
)-1)/sizeof(unsigned int))), THREAD_UNINT
);
1419 if (res
== THREAD_WAITING
) {
1420 if (lock_stat
&& !lock_wait
) {
1422 lck
->lck_rw_grp
->lck_grp_stat
.lck_grp_rw_stat
.lck_grp_rw_wait_cnt
++;
1424 lck_rw_ilk_unlock(&lck
->lck_rw
);
1425 res
= thread_block(THREAD_CONTINUE_NULL
);
1426 lck_rw_ilk_lock(&lck
->lck_rw
);
1429 KERNEL_DEBUG(MACHDBG_CODE(DBG_MACH_LOCKS
, LCK_RW_LCK_EXCLUSIVE1_CODE
) | DBG_FUNC_END
,
1430 (int)rlck
, lck
->lck_rw
.lck_rw_shared_cnt
, lck
->lck_rw
.lck_rw_want_upgrade
, res
, 0);
1433 lck
->lck_rw_deb
.pc_excl
= __builtin_return_address(0);
1434 if (LcksOpts
& enaLkExtStck
)
1435 lck_rw_ext_backtrace(lck
);
1436 lck
->lck_rw_deb
.thread
= current_thread();
1438 lck_rw_ilk_unlock(&lck
->lck_rw
);
1443 * Routine: lck_rw_done_ext
1450 boolean_t do_wakeup
= FALSE
;
1451 lck_rw_type_t lck_rw_type
;
1454 lck_rw_check_type(lck
, rlck
);
1456 lck_rw_ilk_lock(&lck
->lck_rw
);
1458 if (lck
->lck_rw
.lck_rw_shared_cnt
!= 0) {
1459 lck_rw_type
= LCK_RW_TYPE_SHARED
;
1460 lck
->lck_rw
.lck_rw_shared_cnt
--;
1463 lck_rw_type
= LCK_RW_TYPE_EXCLUSIVE
;
1464 if (lck
->lck_rw
.lck_rw_want_upgrade
)
1465 lck
->lck_rw
.lck_rw_want_upgrade
= FALSE
;
1466 else if (lck
->lck_rw
.lck_rw_want_excl
)
1467 lck
->lck_rw
.lck_rw_want_excl
= FALSE
;
1469 panic("rw lock (0x%08X) bad state (0x%08X) on attempt to release a shared or exlusive right\n",
1471 if (lck
->lck_rw_deb
.thread
== THREAD_NULL
)
1472 panic("rw lock (0x%08X) not held\n",
1474 else if ( ((lck
->lck_rw_attr
& (LCK_RW_ATTR_DEBUG
|LCK_RW_ATTR_DIS_THREAD
)) == LCK_RW_ATTR_DEBUG
)
1475 && (lck
->lck_rw_deb
.thread
!= current_thread()))
1476 panic("rw lock (0x%08X) unlocked by non-owner(0x%08X), current owner(0x%08X)\n",
1477 rlck
, current_thread(), lck
->lck_rw_deb
.thread
);
1478 lck
->lck_rw_deb
.thread
= THREAD_NULL
;
1481 if (lck
->lck_rw_attr
& LCK_RW_ATTR_DEBUG
)
1482 lck
->lck_rw_deb
.pc_done
= __builtin_return_address(0);
1485 * There is no reason to wakeup a waiting thread
1486 * if the read-count is non-zero. Consider:
1487 * we must be dropping a read lock
1488 * threads are waiting only if one wants a write lock
1489 * if there are still readers, they can't proceed
1492 if (lck
->lck_rw
.lck_rw_waiting
&& (lck
->lck_rw
.lck_rw_shared_cnt
== 0)) {
1493 lck
->lck_rw
.lck_rw_waiting
= FALSE
;
1497 lck_rw_ilk_unlock(&lck
->lck_rw
);
1500 thread_wakeup((event_t
)(((unsigned int*)rlck
)+((sizeof(lck_rw_t
)-1)/sizeof(unsigned int))));
1501 return(lck_rw_type
);
1506 * Routine: lck_rw_lock_shared_ext
1509 lck_rw_lock_shared_ext(
1515 boolean_t lock_miss
= FALSE
;
1516 boolean_t lock_wait
= FALSE
;
1517 boolean_t lock_stat
;
1519 lck_rw_check_type(lck
, rlck
);
1521 lck_rw_ilk_lock(&lck
->lck_rw
);
1523 lock_stat
= (lck
->lck_rw_attr
& LCK_RW_ATTR_STAT
) ? TRUE
: FALSE
;
1526 lck
->lck_rw_grp
->lck_grp_stat
.lck_grp_rw_stat
.lck_grp_rw_util_cnt
++;
1528 while ((lck
->lck_rw
.lck_rw_want_excl
|| lck
->lck_rw
.lck_rw_want_upgrade
) &&
1529 ((lck
->lck_rw
.lck_rw_shared_cnt
== 0) || (lck
->lck_rw
.lck_rw_priv_excl
))) {
1530 i
= lock_wait_time
[1];
1532 KERNEL_DEBUG(MACHDBG_CODE(DBG_MACH_LOCKS
, LCK_RW_LCK_SHARED_CODE
) | DBG_FUNC_START
,
1533 (int)rlck
, lck
->lck_rw
.lck_rw_want_excl
, lck
->lck_rw
.lck_rw_want_upgrade
, i
, 0);
1535 if (lock_stat
&& !lock_miss
) {
1537 lck
->lck_rw_grp
->lck_grp_stat
.lck_grp_rw_stat
.lck_grp_rw_miss_cnt
++;
1541 lck_rw_ilk_unlock(&lck
->lck_rw
);
1543 (lck
->lck_rw
.lck_rw_want_excl
|| lck
->lck_rw
.lck_rw_want_upgrade
) &&
1544 ((lck
->lck_rw
.lck_rw_shared_cnt
== 0) || (lck
->lck_rw
.lck_rw_priv_excl
)))
1546 lck_rw_ilk_lock(&lck
->lck_rw
);
1549 if ((lck
->lck_rw
.lck_rw_want_excl
|| lck
->lck_rw
.lck_rw_want_upgrade
) &&
1550 ((lck
->lck_rw
.lck_rw_shared_cnt
== 0) || (lck
->lck_rw
.lck_rw_priv_excl
))) {
1551 lck
->lck_rw
.lck_rw_waiting
= TRUE
;
1552 res
= assert_wait((event_t
)(((unsigned int*)rlck
)+((sizeof(lck_rw_t
)-1)/sizeof(unsigned int))), THREAD_UNINT
);
1553 if (res
== THREAD_WAITING
) {
1554 if (lock_stat
&& !lock_wait
) {
1556 lck
->lck_rw_grp
->lck_grp_stat
.lck_grp_rw_stat
.lck_grp_rw_wait_cnt
++;
1558 lck_rw_ilk_unlock(&lck
->lck_rw
);
1559 res
= thread_block(THREAD_CONTINUE_NULL
);
1560 lck_rw_ilk_lock(&lck
->lck_rw
);
1563 KERNEL_DEBUG(MACHDBG_CODE(DBG_MACH_LOCKS
, LCK_RW_LCK_SHARED_CODE
) | DBG_FUNC_END
,
1564 (int)rlck
, lck
->lck_rw
.lck_rw_want_excl
, lck
->lck_rw
.lck_rw_want_upgrade
, res
, 0);
1567 lck
->lck_rw
.lck_rw_shared_cnt
++;
1569 lck_rw_ilk_unlock(&lck
->lck_rw
);
1574 * Routine: lck_rw_lock_shared_to_exclusive_ext
1576 * Improves a read-only lock to one with
1577 * write permission. If another reader has
1578 * already requested an upgrade to a write lock,
1579 * no lock is held upon return.
1581 * Returns TRUE if the upgrade *failed*.
1585 lck_rw_lock_shared_to_exclusive_ext(
1590 boolean_t do_wakeup
= FALSE
;
1592 boolean_t lock_miss
= FALSE
;
1593 boolean_t lock_wait
= FALSE
;
1594 boolean_t lock_stat
;
1596 lck_rw_check_type(lck
, rlck
);
1598 if (lck
->lck_rw_deb
.thread
== current_thread())
1599 panic("rw lock (0x%08X) recursive lock attempt\n", rlck
);
1601 lck_rw_ilk_lock(&lck
->lck_rw
);
1603 lock_stat
= (lck
->lck_rw_attr
& LCK_RW_ATTR_STAT
) ? TRUE
: FALSE
;
1606 lck
->lck_rw_grp
->lck_grp_stat
.lck_grp_rw_stat
.lck_grp_rw_util_cnt
++;
1608 lck
->lck_rw
.lck_rw_shared_cnt
--;
1610 if (lck
->lck_rw
.lck_rw_want_upgrade
) {
1611 KERNEL_DEBUG(MACHDBG_CODE(DBG_MACH_LOCKS
, LCK_RW_LCK_SH_TO_EX_CODE
) | DBG_FUNC_START
,
1612 (int)rlck
, lck
->lck_rw
.lck_rw_shared_cnt
, lck
->lck_rw
.lck_rw_want_upgrade
, 0, 0);
1615 * Someone else has requested upgrade.
1616 * Since we've released a read lock, wake
1619 if (lck
->lck_rw
.lck_rw_waiting
&& (lck
->lck_rw
.lck_rw_shared_cnt
== 0)) {
1620 lck
->lck_rw
.lck_rw_waiting
= FALSE
;
1624 lck_rw_ilk_unlock(&lck
->lck_rw
);
1627 thread_wakeup((event_t
)(((unsigned int*)rlck
)+((sizeof(lck_rw_t
)-1)/sizeof(unsigned int))));
1629 KERNEL_DEBUG(MACHDBG_CODE(DBG_MACH_LOCKS
, LCK_RW_LCK_SH_TO_EX_CODE
) | DBG_FUNC_END
,
1630 (int)rlck
, lck
->lck_rw
.lck_rw_shared_cnt
, lck
->lck_rw
.lck_rw_want_upgrade
, 0, 0);
1635 lck
->lck_rw
.lck_rw_want_upgrade
= TRUE
;
1637 while (lck
->lck_rw
.lck_rw_shared_cnt
!= 0) {
1638 i
= lock_wait_time
[1];
1640 KERNEL_DEBUG(MACHDBG_CODE(DBG_MACH_LOCKS
, LCK_RW_LCK_SH_TO_EX1_CODE
) | DBG_FUNC_START
,
1641 (int)rlck
, lck
->lck_rw
.lck_rw_shared_cnt
, i
, 0, 0);
1643 if (lock_stat
&& !lock_miss
) {
1645 lck
->lck_rw_grp
->lck_grp_stat
.lck_grp_rw_stat
.lck_grp_rw_miss_cnt
++;
1649 lck_rw_ilk_unlock(&lck
->lck_rw
);
1650 while (--i
!= 0 && lck
->lck_rw
.lck_rw_shared_cnt
!= 0)
1652 lck_rw_ilk_lock(&lck
->lck_rw
);
1655 if (lck
->lck_rw
.lck_rw_shared_cnt
!= 0) {
1656 lck
->lck_rw
.lck_rw_waiting
= TRUE
;
1657 res
= assert_wait((event_t
)(((unsigned int*)rlck
)+((sizeof(lck_rw_t
)-1)/sizeof(unsigned int))), THREAD_UNINT
);
1658 if (res
== THREAD_WAITING
) {
1659 if (lock_stat
&& !lock_wait
) {
1661 lck
->lck_rw_grp
->lck_grp_stat
.lck_grp_rw_stat
.lck_grp_rw_wait_cnt
++;
1663 lck_rw_ilk_unlock(&lck
->lck_rw
);
1664 res
= thread_block(THREAD_CONTINUE_NULL
);
1665 lck_rw_ilk_lock(&lck
->lck_rw
);
1668 KERNEL_DEBUG(MACHDBG_CODE(DBG_MACH_LOCKS
, LCK_RW_LCK_SH_TO_EX1_CODE
) | DBG_FUNC_END
,
1669 (int)rlck
, lck
->lck_rw
.lck_rw_shared_cnt
, 0, 0, 0);
1672 lck
->lck_rw_deb
.pc_excl
= __builtin_return_address(0);
1673 if (LcksOpts
& enaLkExtStck
)
1674 lck_rw_ext_backtrace(lck
);
1675 lck
->lck_rw_deb
.thread
= current_thread();
1677 lck_rw_ilk_unlock(&lck
->lck_rw
);
1683 * Routine: lck_rw_lock_exclusive_to_shared_ext
1686 lck_rw_lock_exclusive_to_shared_ext(
1690 boolean_t do_wakeup
= FALSE
;
1692 lck_rw_check_type(lck
, rlck
);
1694 KERNEL_DEBUG(MACHDBG_CODE(DBG_MACH_LOCKS
, LCK_RW_LCK_EX_TO_SH_CODE
) | DBG_FUNC_START
,
1695 (int)rlck
, lck
->lck_rw
.lck_rw_want_excl
, lck
->lck_rw
.lck_rw_want_upgrade
, 0, 0);
1697 lck_rw_ilk_lock(&lck
->lck_rw
);
1699 lck
->lck_rw
.lck_rw_shared_cnt
++;
1700 if (lck
->lck_rw
.lck_rw_want_upgrade
)
1701 lck
->lck_rw
.lck_rw_want_upgrade
= FALSE
;
1702 else if (lck
->lck_rw
.lck_rw_want_excl
)
1703 lck
->lck_rw
.lck_rw_want_excl
= FALSE
;
1705 panic("rw lock (0x%08X) bad state (0x%08X) on attempt to release a shared or exlusive right\n",
1707 if (lck
->lck_rw_deb
.thread
== THREAD_NULL
)
1708 panic("rw lock (0x%08X) not held\n",
1710 else if ( ((lck
->lck_rw_attr
& (LCK_RW_ATTR_DEBUG
|LCK_RW_ATTR_DIS_THREAD
)) == LCK_RW_ATTR_DEBUG
)
1711 && (lck
->lck_rw_deb
.thread
!= current_thread()))
1712 panic("rw lock (0x%08X) unlocked by non-owner(0x%08X), current owner(0x%08X)\n",
1713 rlck
, current_thread(), lck
->lck_rw_deb
.thread
);
1715 lck
->lck_rw_deb
.thread
= THREAD_NULL
;
1717 if (lck
->lck_rw
.lck_rw_waiting
) {
1718 lck
->lck_rw
.lck_rw_waiting
= FALSE
;
1722 lck_rw_ilk_unlock(&lck
->lck_rw
);
1725 thread_wakeup((event_t
)(((unsigned int*)rlck
)+((sizeof(lck_rw_t
)-1)/sizeof(unsigned int))));
1727 KERNEL_DEBUG(MACHDBG_CODE(DBG_MACH_LOCKS
, LCK_RW_LCK_EX_TO_SH_CODE
) | DBG_FUNC_END
,
1728 (int)rlck
, lck
->lck_rw
.lck_rw_want_excl
, lck
->lck_rw
.lck_rw_want_upgrade
, lck
->lck_rw
.lck_rw_shared_cnt
, 0);
1734 * Routine: lck_rw_try_lock_exclusive_ext
1736 * Tries to get a write lock.
1738 * Returns FALSE if the lock is not held on return.
1742 lck_rw_try_lock_exclusive_ext(
1746 boolean_t lock_stat
;
1748 lck_rw_check_type(lck
, rlck
);
1750 lck_rw_ilk_lock(&lck
->lck_rw
);
1752 lock_stat
= (lck
->lck_rw_attr
& LCK_RW_ATTR_STAT
) ? TRUE
: FALSE
;
1755 lck
->lck_rw_grp
->lck_grp_stat
.lck_grp_rw_stat
.lck_grp_rw_util_cnt
++;
1757 if (lck
->lck_rw
.lck_rw_want_excl
|| lck
->lck_rw
.lck_rw_want_upgrade
|| lck
->lck_rw
.lck_rw_shared_cnt
) {
1762 lck
->lck_rw_grp
->lck_grp_stat
.lck_grp_rw_stat
.lck_grp_rw_miss_cnt
++;
1764 lck_rw_ilk_unlock(&lck
->lck_rw
);
1772 lck
->lck_rw
.lck_rw_want_excl
= TRUE
;
1773 lck
->lck_rw_deb
.pc_excl
= __builtin_return_address(0);
1774 if (LcksOpts
& enaLkExtStck
)
1775 lck_rw_ext_backtrace(lck
);
1776 lck
->lck_rw_deb
.thread
= current_thread();
1778 lck_rw_ilk_unlock(&lck
->lck_rw
);
1784 * Routine: lck_rw_try_lock_shared_ext
1786 * Tries to get a read lock.
1788 * Returns FALSE if the lock is not held on return.
1792 lck_rw_try_lock_shared_ext(
1796 boolean_t lock_stat
;
1798 lck_rw_check_type(lck
, rlck
);
1800 lck_rw_ilk_lock(&lck
->lck_rw
);
1802 lock_stat
= (lck
->lck_rw_attr
& LCK_RW_ATTR_STAT
) ? TRUE
: FALSE
;
1805 lck
->lck_rw_grp
->lck_grp_stat
.lck_grp_rw_stat
.lck_grp_rw_util_cnt
++;
1807 if ((lck
->lck_rw
.lck_rw_want_excl
|| lck
->lck_rw
.lck_rw_want_upgrade
) &&
1808 ((lck
->lck_rw
.lck_rw_shared_cnt
== 0) || (lck
->lck_rw
.lck_rw_priv_excl
))) {
1810 lck
->lck_rw_grp
->lck_grp_stat
.lck_grp_rw_stat
.lck_grp_rw_miss_cnt
++;
1812 lck_rw_ilk_unlock(&lck
->lck_rw
);
1816 lck
->lck_rw
.lck_rw_shared_cnt
++;
1818 lck_rw_ilk_unlock(&lck
->lck_rw
);
1828 if (lck
->lck_rw_deb
.type
!= RW_TAG
)
1829 panic("rw lock (0x%08X) not a rw lock type (0x%08X)\n",rlck
, lck
->lck_rw_deb
.type
);
1833 * The C portion of the mutex package. These routines are only invoked
1834 * if the optimized assembler routines can't do the work.
1838 * Forward definition
1841 void lck_mtx_ext_init(
1847 * Routine: mutex_alloc
1849 * Allocate a mutex for external users who cannot
1850 * hard-code the structure definition into their
1852 * For now just use kalloc, but a zone is probably
1861 if ((m
= (mutex_t
*)kalloc(sizeof(mutex_t
))) != 0)
1867 * Routine: mutex_free
1873 kfree((void *)m
, sizeof(mutex_t
));
1877 * Routine: lck_mtx_alloc_init
1885 if ((lck
= (lck_mtx_t
*)kalloc(sizeof(lck_mtx_t
))) != 0)
1886 lck_mtx_init(lck
, grp
, attr
);
1892 * Routine: lck_mtx_free
1898 lck_mtx_destroy(lck
, grp
);
1899 kfree((void *)lck
, sizeof(lck_mtx_t
));
1903 * Routine: lck_mtx_init
1910 lck_mtx_ext_t
*lck_ext
;
1911 lck_attr_t
*lck_attr
;
1913 if (attr
!= LCK_ATTR_NULL
)
1916 lck_attr
= &LockDefaultLckAttr
;
1918 if ((lck_attr
->lck_attr_val
) & LCK_ATTR_DEBUG
) {
1919 if ((lck_ext
= (lck_mtx_ext_t
*)kalloc(sizeof(lck_mtx_ext_t
))) != 0) {
1920 lck_mtx_ext_init(lck_ext
, grp
, lck_attr
);
1921 lck
->lck_mtx_tag
= LCK_MTX_TAG_INDIRECT
;
1922 lck
->lck_mtx_ptr
= lck_ext
;
1925 lck
->lck_mtx_data
= 0;
1926 lck
->lck_mtx_waiters
= 0;
1927 lck
->lck_mtx_pri
= 0;
1929 lck_grp_reference(grp
);
1930 lck_grp_lckcnt_incr(grp
, LCK_TYPE_MTX
);
1934 * Routine: lck_mtx_ext_init
1942 bzero((void *)lck
, sizeof(lck_mtx_ext_t
));
1944 if ((attr
->lck_attr_val
) & LCK_ATTR_DEBUG
) {
1945 lck
->lck_mtx_deb
.type
= MUTEX_TAG
;
1946 lck
->lck_mtx_attr
|= LCK_MTX_ATTR_DEBUG
;
1949 lck
->lck_mtx_grp
= grp
;
1951 if (grp
->lck_grp_attr
& LCK_GRP_ATTR_STAT
)
1952 lck
->lck_mtx_attr
|= LCK_MTX_ATTR_STAT
;
1956 * Routine: lck_mtx_destroy
1962 boolean_t lck_is_indirect
;
1964 if (lck
->lck_mtx_tag
== LCK_MTX_TAG_DESTROYED
)
1966 lck_is_indirect
= (lck
->lck_mtx_tag
== LCK_MTX_TAG_INDIRECT
);
1967 lck
->lck_mtx_tag
= LCK_MTX_TAG_DESTROYED
;
1968 if (lck_is_indirect
)
1969 kfree((void *)lck
->lck_mtx_ptr
, sizeof(lck_mtx_ext_t
));
1971 lck_grp_lckcnt_decr(grp
, LCK_TYPE_MTX
);
1972 lck_grp_deallocate(grp
);
1979 * Routines to print out simple_locks and mutexes in a nicely-formatted
1983 char *simple_lock_labels
= "ENTRY ILK THREAD DURATION CALLER";
1984 char *mutex_labels
= "ENTRY LOCKED WAITERS THREAD CALLER";
1986 void db_print_simple_lock(
1987 simple_lock_t addr
);
1989 void db_print_mutex(
1993 db_show_one_simple_lock (
1995 boolean_t have_addr
,
1999 simple_lock_t saddr
= (simple_lock_t
)addr
;
2001 if (saddr
== (simple_lock_t
)0 || !have_addr
) {
2002 db_error ("No simple_lock\n");
2005 else if (saddr
->lock_type
!= USLOCK_TAG
)
2006 db_error ("Not a simple_lock\n");
2007 #endif /* USLOCK_DEBUG */
2009 db_printf ("%s\n", simple_lock_labels
);
2010 db_print_simple_lock (saddr
);
2014 db_print_simple_lock (
2018 db_printf ("%08x %3d", addr
, *hw_lock_addr(addr
->interlock
));
2020 db_printf (" %08x", addr
->debug
.lock_thread
);
2021 db_printf (" %08x ", addr
->debug
.duration
[1]);
2022 db_printsym ((int)addr
->debug
.lock_pc
, DB_STGY_ANY
);
2023 #endif /* USLOCK_DEBUG */
2030 boolean_t have_addr
,
2034 mutex_t
* maddr
= (mutex_t
*)addr
;
2036 if (maddr
== (mutex_t
*)0 || !have_addr
)
2037 db_error ("No mutex\n");
2039 else if (maddr
->lck_mtx_deb
.type
!= MUTEX_TAG
)
2040 db_error ("Not a mutex\n");
2041 #endif /* MACH_LDEBUG */
2043 db_printf ("%s\n", mutex_labels
);
2044 db_print_mutex (maddr
);
2051 db_printf ("%08x %6d %7d",
2052 addr
, *addr
, addr
->lck_mtx
.lck_mtx_waiters
);
2054 db_printf (" %08x ", addr
->lck_mtx_deb
.thread
);
2055 db_printsym (addr
->lck_mtx_deb
.stack
[0], DB_STGY_ANY
);
2056 #endif /* MACH_LDEBUG */
2064 db_printf("shared_count = 0x%x, %swant_upgrade, %swant_exclusive, ",
2065 lock
->lck_rw
.lck_rw_shared_cnt
,
2066 lock
->lck_rw
.lck_rw_want_upgrade
? "" : "!",
2067 lock
->lck_rw
.lck_rw_want_excl
? "" : "!");
2068 db_printf("%swaiting\n",
2069 lock
->lck_rw
.lck_rw_waiting
? "" : "!");
2070 db_printf("%sInterlock\n",
2071 lock
->lck_rw
.lck_rw_interlock
? "" : "!");
2074 #endif /* MACH_KDB */