2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
8 * This file contains Original Code and/or Modifications of Original Code
9 * as defined in and that are subject to the Apple Public Source License
10 * Version 2.0 (the 'License'). You may not use this file except in
11 * compliance with the License. Please obtain a copy of the License at
12 * http://www.opensource.apple.com/apsl/ and read it before using this
15 * The Original Code and all software distributed under the License are
16 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
17 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
18 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
20 * Please see the License for the specific language governing rights and
21 * limitations under the License.
23 * @APPLE_LICENSE_HEADER_END@
29 * Mach Operating System
30 * Copyright (c) 1991,1990,1989,1988,1987 Carnegie Mellon University
31 * All Rights Reserved.
33 * Permission to use, copy, modify and distribute this software and its
34 * documentation is hereby granted, provided that both the copyright
35 * notice and this permission notice appear in all copies of the
36 * software, derivative works or modified versions, and any portions
37 * thereof, and that both notices appear in supporting documentation.
39 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
40 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
41 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
43 * Carnegie Mellon requests users of this software to return to
45 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
46 * School of Computer Science
47 * Carnegie Mellon University
48 * Pittsburgh PA 15213-3890
50 * any improvements or extensions that they make and grant Carnegie Mellon
51 * the rights to redistribute these changes.
55 * Author: Avadis Tevanian, Jr., Michael Wayne Young
58 * Locking primitives implementation
63 #include <mach_ldebug.h>
65 #include <kern/lock.h>
66 #include <kern/etap_macros.h>
67 #include <kern/misc_protos.h>
68 #include <kern/thread.h>
69 #include <kern/processor.h>
70 #include <kern/sched_prim.h>
72 #include <kern/debug.h>
76 #include <ddb/db_command.h>
77 #include <ddb/db_output.h>
78 #include <ddb/db_sym.h>
79 #include <ddb/db_print.h>
83 #include <ppc/Firmware.h>
86 #include <sys/kdebug.h>
88 #define ANY_LOCK_DEBUG (USLOCK_DEBUG || LOCK_DEBUG || MUTEX_DEBUG)
91 * Some portions of the lock debugging code must run with
92 * interrupts disabled. This can be machine-dependent,
93 * but we don't have any good hooks for that at the moment.
94 * If your architecture is different, add a machine-dependent
95 * ifdef here for these macros. XXX
98 #define DISABLE_INTERRUPTS(s) s = ml_set_interrupts_enabled(FALSE)
99 #define ENABLE_INTERRUPTS(s) (void)ml_set_interrupts_enabled(s)
102 /* Time we loop without holding the interlock.
103 * The former is for when we cannot sleep, the latter
104 * for when our thread can go to sleep (loop less)
105 * we shouldn't retake the interlock at all frequently
106 * if we cannot go to sleep, since it interferes with
107 * any other processors. In particular, 100 is too small
108 * a number for powerpc MP systems because of cache
109 * coherency issues and differing lock fetch times between
112 unsigned int lock_wait_time
[2] = { (unsigned int)-1, 100 } ;
113 #else /* NCPUS > 1 */
116 * It is silly to spin on a uni-processor as if we
117 * thought something magical would happen to the
118 * want_write bit while we are executing.
121 unsigned int lock_wait_time
[2] = { 0, 0 };
122 #endif /* NCPUS > 1 */
127 void db_print_simple_lock(
132 #endif /* MACH_KDB */
137 * Perform simple lock checks.
139 int uslock_check
= 1;
140 int max_lock_loops
= 100000000;
141 decl_simple_lock_data(extern , printf_lock
)
142 decl_simple_lock_data(extern , panic_lock
)
143 #if MACH_KDB && NCPUS > 1
144 decl_simple_lock_data(extern , kdb_lock
)
145 #endif /* MACH_KDB && NCPUS >1 */
146 #endif /* USLOCK_DEBUG */
150 * We often want to know the addresses of the callers
151 * of the various lock routines. However, this information
152 * is only used for debugging and statistics.
155 #define INVALID_PC ((void *) VM_MAX_KERNEL_ADDRESS)
156 #define INVALID_THREAD ((void *) VM_MAX_KERNEL_ADDRESS)
157 #if ANY_LOCK_DEBUG || ETAP_LOCK_TRACE
158 #define OBTAIN_PC(pc,l) ((pc) = (void *) GET_RETURN_PC(&(l)))
159 #else /* ANY_LOCK_DEBUG || ETAP_LOCK_TRACE */
162 * Eliminate lint complaints about unused local pc variables.
164 #define OBTAIN_PC(pc,l) ++pc
166 #define OBTAIN_PC(pc,l)
168 #endif /* USLOCK_DEBUG || ETAP_LOCK_TRACE */
171 /* #ifndef USIMPLE_LOCK_CALLS
172 * The i386 production version of usimple_locks isn't ready yet.
175 * Portable lock package implementation of usimple_locks.
179 #define ETAPCALL(stmt) stmt
180 void etap_simplelock_init(simple_lock_t
, etap_event_t
);
181 void etap_simplelock_unlock(simple_lock_t
);
182 void etap_simplelock_hold(simple_lock_t
, pc_t
, etap_time_t
);
183 etap_time_t
etap_simplelock_miss(simple_lock_t
);
185 void etap_mutex_init(mutex_t
*, etap_event_t
);
186 void etap_mutex_unlock(mutex_t
*);
187 void etap_mutex_hold(mutex_t
*, pc_t
, etap_time_t
);
188 etap_time_t
etap_mutex_miss(mutex_t
*);
189 #else /* ETAP_LOCK_TRACE */
190 #define ETAPCALL(stmt)
191 #endif /* ETAP_LOCK_TRACE */
194 #define USLDBG(stmt) stmt
195 void usld_lock_init(usimple_lock_t
, etap_event_t
);
196 void usld_lock_pre(usimple_lock_t
, pc_t
);
197 void usld_lock_post(usimple_lock_t
, pc_t
);
198 void usld_unlock(usimple_lock_t
, pc_t
);
199 void usld_lock_try_pre(usimple_lock_t
, pc_t
);
200 void usld_lock_try_post(usimple_lock_t
, pc_t
);
201 void usld_lock_held(usimple_lock_t
);
202 void usld_lock_none_held(void);
203 int usld_lock_common_checks(usimple_lock_t
, char *);
204 #else /* USLOCK_DEBUG */
206 #endif /* USLOCK_DEBUG */
209 * Initialize a usimple_lock.
211 * No change in preemption state.
218 #ifndef MACHINE_SIMPLE_LOCK
219 USLDBG(usld_lock_init(l
, event
));
220 ETAPCALL(etap_simplelock_init((l
),(event
)));
221 hw_lock_init(&l
->interlock
);
223 simple_lock_init((simple_lock_t
)l
,event
);
229 * Acquire a usimple_lock.
231 * Returns with preemption disabled. Note
232 * that the hw_lock routines are responsible for
233 * maintaining preemption state.
239 #ifndef MACHINE_SIMPLE_LOCK
243 etap_time_t start_wait_time
;
244 int no_miss_info
= 0;
245 #endif /* ETAP_LOCK_TRACE */
248 #endif /* USLOCK_DEBUG */
251 USLDBG(usld_lock_pre(l
, pc
));
253 ETAP_TIME_CLEAR(start_wait_time
);
254 #endif /* ETAP_LOCK_TRACE */
256 if(!hw_lock_to(&l
->interlock
, LockTimeOut
)) /* Try to get the lock with a timeout */
257 panic("simple lock deadlock detection - l=%08X, cpu=%d, ret=%08X", l
, cpu_number(), pc
);
259 ETAPCALL(etap_simplelock_hold(l
, pc
, start_wait_time
));
260 USLDBG(usld_lock_post(l
, pc
));
262 simple_lock((simple_lock_t
)l
);
268 * Release a usimple_lock.
270 * Returns with preemption enabled. Note
271 * that the hw_lock routines are responsible for
272 * maintaining preemption state.
278 #ifndef MACHINE_SIMPLE_LOCK
281 // checkNMI(); /* (TEST/DEBUG) */
284 USLDBG(usld_unlock(l
, pc
));
285 ETAPCALL(etap_simplelock_unlock(l
));
289 hw_lock_unlock(&l
->interlock
);
291 simple_unlock_rwmb((simple_lock_t
)l
);
297 * Conditionally acquire a usimple_lock.
299 * On success, returns with preemption disabled.
300 * On failure, returns with preemption in the same state
301 * as when first invoked. Note that the hw_lock routines
302 * are responsible for maintaining preemption state.
304 * XXX No stats are gathered on a miss; I preserved this
305 * behavior from the original assembly-language code, but
306 * doesn't it make sense to log misses? XXX
312 #ifndef MACHINE_SIMPLE_LOCK
314 unsigned int success
;
315 etap_time_t zero_time
;
318 USLDBG(usld_lock_try_pre(l
, pc
));
319 if (success
= hw_lock_try(&l
->interlock
)) {
320 USLDBG(usld_lock_try_post(l
, pc
));
321 ETAP_TIME_CLEAR(zero_time
);
322 ETAPCALL(etap_simplelock_hold(l
, pc
, zero_time
));
326 return(simple_lock_try((simple_lock_t
)l
));
332 simple_lock_no_trace(
338 USLDBG(usld_lock_pre(l
, pc
));
339 while (!hw_lock_try(&l
->interlock
)) {
340 while (hw_lock_held(&l
->interlock
)) {
342 * Spin watching the lock value in cache,
343 * without consuming external bus cycles.
344 * On most SMP architectures, the atomic
345 * instruction(s) used by hw_lock_try
346 * cost much, much more than an ordinary
351 USLDBG(usld_lock_post(l
, pc
));
355 simple_unlock_no_trace(
361 USLDBG(usld_unlock(l
, pc
));
362 hw_lock_unlock(&l
->interlock
);
366 simple_lock_try_no_trace(
370 unsigned int success
;
373 USLDBG(usld_lock_try_pre(l
, pc
));
374 if (success
= hw_lock_try(&l
->interlock
)) {
375 USLDBG(usld_lock_try_post(l
, pc
));
379 #endif /* ETAP_LOCK_TRACE */
384 * Verify that the lock is locked and owned by
385 * the current thread.
396 * Verify that no usimple_locks are held by
397 * this processor. Typically used in a
398 * trap handler when returning to user mode
399 * or in a path known to relinquish the processor.
402 usimple_lock_none_held(void)
404 usld_lock_none_held();
406 #endif /* USLOCK_DEBUG */
411 * States of a usimple_lock. The default when initializing
412 * a usimple_lock is setting it up for debug checking.
414 #define USLOCK_CHECKED 0x0001 /* lock is being checked */
415 #define USLOCK_TAKEN 0x0002 /* lock has been taken */
416 #define USLOCK_INIT 0xBAA0 /* lock has been initialized */
417 #define USLOCK_INITIALIZED (USLOCK_INIT|USLOCK_CHECKED)
418 #define USLOCK_CHECKING(l) (uslock_check && \
419 ((l)->debug.state & USLOCK_CHECKED))
422 * Maintain a per-cpu stack of acquired usimple_locks.
424 void usl_stack_push(usimple_lock_t
, int);
425 void usl_stack_pop(usimple_lock_t
, int);
428 * Trace activities of a particularly interesting lock.
430 void usl_trace(usimple_lock_t
, int, pc_t
, const char *);
434 * Initialize the debugging information contained
442 if (l
== USIMPLE_LOCK_NULL
)
443 panic("lock initialization: null lock pointer");
444 l
->lock_type
= USLOCK_TAG
;
445 l
->debug
.state
= uslock_check
? USLOCK_INITIALIZED
: 0;
446 l
->debug
.lock_cpu
= l
->debug
.unlock_cpu
= 0;
447 l
->debug
.lock_pc
= l
->debug
.unlock_pc
= INVALID_PC
;
448 l
->debug
.lock_thread
= l
->debug
.unlock_thread
= INVALID_THREAD
;
449 l
->debug
.duration
[0] = l
->debug
.duration
[1] = 0;
450 l
->debug
.unlock_cpu
= l
->debug
.unlock_cpu
= 0;
451 l
->debug
.unlock_pc
= l
->debug
.unlock_pc
= INVALID_PC
;
452 l
->debug
.unlock_thread
= l
->debug
.unlock_thread
= INVALID_THREAD
;
457 * These checks apply to all usimple_locks, not just
458 * those with USLOCK_CHECKED turned on.
461 usld_lock_common_checks(
465 if (l
== USIMPLE_LOCK_NULL
)
466 panic("%s: null lock pointer", caller
);
467 if (l
->lock_type
!= USLOCK_TAG
)
468 panic("%s: 0x%x is not a usimple lock", caller
, (integer_t
) l
);
469 if (!(l
->debug
.state
& USLOCK_INIT
))
470 panic("%s: 0x%x is not an initialized lock",
471 caller
, (integer_t
) l
);
472 return USLOCK_CHECKING(l
);
477 * Debug checks on a usimple_lock just before attempting
486 char *caller
= "usimple_lock";
490 printf("*** %08X %08X %04X %02X %08X %02X %08X - %s\n", /* (TEST/DEBUG) */
492 l
->debug
.lock_thread
,
495 l
->debug
.unlock_thread
,
501 if (!usld_lock_common_checks(l
, caller
))
505 * Note that we have a weird case where we are getting a lock when we are]
506 * in the process of putting the system to sleep. We are running with no
507 * current threads, therefore we can't tell if we are trying to retake a lock
508 * we have or someone on the other processor has it. Therefore we just
509 * ignore this test if the locking thread is 0.
512 if ((l
->debug
.state
& USLOCK_TAKEN
) && l
->debug
.lock_thread
&&
513 l
->debug
.lock_thread
== (void *) current_thread()) {
514 printf("%s: lock 0x%x already locked (at 0x%x) by",
515 caller
, (integer_t
) l
, l
->debug
.lock_pc
);
516 printf(" current thread 0x%x (new attempt at pc 0x%x)\n",
517 l
->debug
.lock_thread
, pc
);
520 mp_disable_preemption();
521 usl_trace(l
, cpu_number(), pc
, caller
);
522 mp_enable_preemption();
527 * Debug checks on a usimple_lock just after acquiring it.
529 * Pre-emption has been disabled at this point,
530 * so we are safe in using cpu_number.
538 char *caller
= "successful usimple_lock";
542 printf("*** %08X %08X %04X %02X %08X %02X %08X - %s\n", /* (TEST/DEBUG) */
544 l
->debug
.lock_thread
,
547 l
->debug
.unlock_thread
,
553 if (!usld_lock_common_checks(l
, caller
))
556 if (!((l
->debug
.state
& ~USLOCK_TAKEN
) == USLOCK_INITIALIZED
))
557 panic("%s: lock 0x%x became uninitialized",
558 caller
, (integer_t
) l
);
559 if ((l
->debug
.state
& USLOCK_TAKEN
))
560 panic("%s: lock 0x%x became TAKEN by someone else",
561 caller
, (integer_t
) l
);
563 mycpu
= cpu_number();
564 l
->debug
.lock_thread
= (void *)current_thread();
565 l
->debug
.state
|= USLOCK_TAKEN
;
566 l
->debug
.lock_pc
= pc
;
567 l
->debug
.lock_cpu
= mycpu
;
569 usl_stack_push(l
, mycpu
);
570 usl_trace(l
, mycpu
, pc
, caller
);
575 * Debug checks on a usimple_lock just before
576 * releasing it. Note that the caller has not
577 * yet released the hardware lock.
579 * Preemption is still disabled, so there's
580 * no problem using cpu_number.
588 char *caller
= "usimple_unlock";
592 printf("*** %08X %08X %04X %02X %08X %02X %08X - %s\n", /* (TEST/DEBUG) */
594 l
->debug
.lock_thread
,
597 l
->debug
.unlock_thread
,
603 if (!usld_lock_common_checks(l
, caller
))
606 mycpu
= cpu_number();
608 if (!(l
->debug
.state
& USLOCK_TAKEN
))
609 panic("%s: lock 0x%x hasn't been taken",
610 caller
, (integer_t
) l
);
611 if (l
->debug
.lock_thread
!= (void *) current_thread())
612 panic("%s: unlocking lock 0x%x, owned by thread 0x%x",
613 caller
, (integer_t
) l
, l
->debug
.lock_thread
);
614 if (l
->debug
.lock_cpu
!= mycpu
) {
615 printf("%s: unlocking lock 0x%x on cpu 0x%x",
616 caller
, (integer_t
) l
, mycpu
);
617 printf(" (acquired on cpu 0x%x)\n", l
->debug
.lock_cpu
);
620 usl_trace(l
, mycpu
, pc
, caller
);
621 usl_stack_pop(l
, mycpu
);
623 l
->debug
.unlock_thread
= l
->debug
.lock_thread
;
624 l
->debug
.lock_thread
= INVALID_PC
;
625 l
->debug
.state
&= ~USLOCK_TAKEN
;
626 l
->debug
.unlock_pc
= pc
;
627 l
->debug
.unlock_cpu
= mycpu
;
632 * Debug checks on a usimple_lock just before
633 * attempting to acquire it.
635 * Preemption isn't guaranteed to be disabled.
642 char *caller
= "usimple_lock_try";
644 if (!usld_lock_common_checks(l
, caller
))
646 mp_disable_preemption();
647 usl_trace(l
, cpu_number(), pc
, caller
);
648 mp_enable_preemption();
653 * Debug checks on a usimple_lock just after
654 * successfully attempting to acquire it.
656 * Preemption has been disabled by the
657 * lock acquisition attempt, so it's safe
666 char *caller
= "successful usimple_lock_try";
668 if (!usld_lock_common_checks(l
, caller
))
671 if (!((l
->debug
.state
& ~USLOCK_TAKEN
) == USLOCK_INITIALIZED
))
672 panic("%s: lock 0x%x became uninitialized",
673 caller
, (integer_t
) l
);
674 if ((l
->debug
.state
& USLOCK_TAKEN
))
675 panic("%s: lock 0x%x became TAKEN by someone else",
676 caller
, (integer_t
) l
);
678 mycpu
= cpu_number();
679 l
->debug
.lock_thread
= (void *) current_thread();
680 l
->debug
.state
|= USLOCK_TAKEN
;
681 l
->debug
.lock_pc
= pc
;
682 l
->debug
.lock_cpu
= mycpu
;
685 printf("*** %08X %08X %04X %02X %08X %02X %08X - %s\n", /* (TEST/DEBUG) */
687 l
->debug
.lock_thread
,
690 l
->debug
.unlock_thread
,
696 usl_stack_push(l
, mycpu
);
697 usl_trace(l
, mycpu
, pc
, caller
);
702 * Determine whether the lock in question is owned
703 * by the current thread.
709 char *caller
= "usimple_lock_held";
713 printf("*** %08X %08X %04X %02X %08X %02X %08X - %s\n", /* (TEST/DEBUG) */
715 l
->debug
.lock_thread
,
718 l
->debug
.unlock_thread
,
724 if (!usld_lock_common_checks(l
, caller
))
727 if (!(l
->debug
.state
& USLOCK_TAKEN
))
728 panic("%s: lock 0x%x hasn't been taken",
729 caller
, (integer_t
) l
);
730 if (l
->debug
.lock_thread
!= (void *) current_thread())
731 panic("%s: lock 0x%x is owned by thread 0x%x", caller
,
732 (integer_t
) l
, (integer_t
) l
->debug
.lock_thread
);
735 * The usimple_lock is active, so preemption
736 * is disabled and the current cpu should
737 * match the one recorded at lock acquisition time.
739 if (l
->debug
.lock_cpu
!= cpu_number())
740 panic("%s: current cpu 0x%x isn't acquiring cpu 0x%x",
741 caller
, cpu_number(), (integer_t
) l
->debug
.lock_cpu
);
746 * Per-cpu stack of currently active usimple_locks.
747 * Requires spl protection so that interrupt-level
748 * locks plug-n-play with their thread-context friends.
750 #define USLOCK_STACK_DEPTH 20
751 usimple_lock_t uslock_stack
[NCPUS
][USLOCK_STACK_DEPTH
];
752 unsigned int uslock_stack_index
[NCPUS
];
753 boolean_t uslock_stack_enabled
= FALSE
;
757 * Record a usimple_lock just acquired on
758 * the current processor.
760 * Preemption has been disabled by lock
761 * acquisition, so it's safe to use the cpu number
762 * specified by the caller.
771 if (uslock_stack_enabled
== FALSE
)
774 DISABLE_INTERRUPTS(s
);
775 assert(uslock_stack_index
[mycpu
] >= 0);
776 assert(uslock_stack_index
[mycpu
] < USLOCK_STACK_DEPTH
);
777 if (uslock_stack_index
[mycpu
] >= USLOCK_STACK_DEPTH
) {
778 printf("usl_stack_push (cpu 0x%x): too many locks (%d)",
779 mycpu
, uslock_stack_index
[mycpu
]);
780 printf(" disabling stacks\n");
781 uslock_stack_enabled
= FALSE
;
782 ENABLE_INTERRUPTS(s
);
785 uslock_stack
[mycpu
][uslock_stack_index
[mycpu
]] = l
;
786 uslock_stack_index
[mycpu
]++;
787 ENABLE_INTERRUPTS(s
);
792 * Eliminate the entry for a usimple_lock
793 * that had been active on the current processor.
795 * Preemption has been disabled by lock
796 * acquisition, and we haven't yet actually
797 * released the hardware lock associated with
798 * this usimple_lock, so it's safe to use the
799 * cpu number supplied by the caller.
806 unsigned int i
, index
;
809 if (uslock_stack_enabled
== FALSE
)
812 DISABLE_INTERRUPTS(s
);
813 assert(uslock_stack_index
[mycpu
] > 0);
814 assert(uslock_stack_index
[mycpu
] <= USLOCK_STACK_DEPTH
);
815 if (uslock_stack_index
[mycpu
] == 0) {
816 printf("usl_stack_pop (cpu 0x%x): not enough locks (%d)",
817 mycpu
, uslock_stack_index
[mycpu
]);
818 printf(" disabling stacks\n");
819 uslock_stack_enabled
= FALSE
;
820 ENABLE_INTERRUPTS(s
);
823 index
= --uslock_stack_index
[mycpu
];
824 for (i
= 0; i
<= index
; ++i
) {
825 if (uslock_stack
[mycpu
][i
] == l
) {
827 uslock_stack
[mycpu
][i
] =
828 uslock_stack
[mycpu
][index
];
829 ENABLE_INTERRUPTS(s
);
833 ENABLE_INTERRUPTS(s
);
834 panic("usl_stack_pop: can't find usimple_lock 0x%x", l
);
839 * Determine whether any usimple_locks are currently held.
841 * Caller's preemption state is uncertain. If
842 * preemption has been disabled, this check is accurate.
843 * Otherwise, this check is just a guess. We do the best
844 * we can by disabling scheduler interrupts, so at least
845 * the check is accurate w.r.t. whatever cpu we're running
846 * on while in this routine.
849 usld_lock_none_held()
853 unsigned int locks_held
;
854 char *caller
= "usimple_lock_none_held";
856 DISABLE_INTERRUPTS(s
);
857 mp_disable_preemption();
858 mycpu
= cpu_number();
859 locks_held
= uslock_stack_index
[mycpu
];
860 mp_enable_preemption();
861 ENABLE_INTERRUPTS(s
);
863 panic("%s: no locks should be held (0x%x locks held)",
864 caller
, (integer_t
) locks_held
);
869 * For very special cases, set traced_lock to point to a
870 * specific lock of interest. The result is a series of
871 * XPRs showing lock operations on that lock. The lock_seq
872 * value is used to show the order of those operations.
874 usimple_lock_t traced_lock
;
875 unsigned int lock_seq
;
882 const char * op_name
)
884 if (traced_lock
== l
) {
886 "seq %d, cpu %d, %s @ %x\n",
887 (integer_t
) lock_seq
, (integer_t
) mycpu
,
888 (integer_t
) op_name
, (integer_t
) pc
, 0);
896 #define printf kdbprintf
897 void db_show_all_slocks(void);
899 db_show_all_slocks(void)
901 unsigned int i
, index
;
902 int mycpu
= cpu_number();
905 if (uslock_stack_enabled
== FALSE
) {
906 printf("Lock stack not enabled\n");
911 if (!mach_slocks_init
)
912 iprintf("WARNING: simple locks stack may not be accurate\n");
914 assert(uslock_stack_index
[mycpu
] >= 0);
915 assert(uslock_stack_index
[mycpu
] <= USLOCK_STACK_DEPTH
);
916 index
= uslock_stack_index
[mycpu
];
917 for (i
= 0; i
< index
; ++i
) {
918 l
= uslock_stack
[mycpu
][i
];
920 db_printsym((vm_offset_t
)l
, DB_STGY_ANY
);
921 if (l
->debug
.lock_pc
!= INVALID_PC
) {
922 printf(" locked by ");
923 db_printsym((int)l
->debug
.lock_pc
, DB_STGY_PROC
);
928 #endif /* MACH_KDB */
930 #endif /* USLOCK_DEBUG */
932 /* #endif USIMPLE_LOCK_CALLS */
935 * Routine: lock_alloc
937 * Allocate a lock for external users who cannot
938 * hard-code the structure definition into their
940 * For now just use kalloc, but a zone is probably
947 etap_event_t i_event
)
951 if ((l
= (lock_t
*)kalloc(sizeof(lock_t
))) != 0)
952 lock_init(l
, can_sleep
, event
, i_event
);
959 * Free a lock allocated for external users.
960 * For now just use kfree, but a zone is probably
967 kfree((vm_offset_t
)l
, sizeof(lock_t
));
974 * Initialize a lock; required before use.
975 * Note that clients declare the "struct lock"
976 * variables and then initialize them, rather
977 * than getting a new one from this module.
984 etap_event_t i_event
)
986 (void) memset((void *) l
, 0, sizeof(lock_t
));
989 etap_event_table_assign(&l
->u
.event_table_chain
, event
);
990 l
->u
.s
.start_list
= SD_ENTRY_NULL
;
991 #endif /* ETAP_LOCK_TRACE */
993 simple_lock_init(&l
->interlock
, i_event
);
994 l
->want_write
= FALSE
;
995 l
->want_upgrade
= FALSE
;
997 l
->can_sleep
= can_sleep
;
999 #if ETAP_LOCK_ACCUMULATE
1000 l
->cbuff_write
= etap_cbuff_reserve(lock_event_table(l
));
1001 if (l
->cbuff_write
!= CBUFF_ENTRY_NULL
) {
1002 l
->cbuff_write
->event
= event
;
1003 l
->cbuff_write
->instance
= (unsigned long) l
;
1004 l
->cbuff_write
->kind
= WRITE_LOCK
;
1006 l
->cbuff_read
= CBUFF_ENTRY_NULL
;
1007 #endif /* ETAP_LOCK_ACCUMULATE */
1012 * Sleep locks. These use the same data structure and algorithm
1013 * as the spin locks, but the process sleeps while it is waiting
1014 * for the lock. These work on uniprocessor systems.
1017 #define DECREMENTER_TIMEOUT 1000000
1021 register lock_t
* l
)
1024 start_data_node_t entry
= {0};
1025 boolean_t lock_miss
= FALSE
;
1026 unsigned short dynamic
= 0;
1027 unsigned short trace
= 0;
1028 etap_time_t total_time
;
1029 etap_time_t stop_wait_time
;
1033 #endif /* MACH_LDEBUG */
1036 ETAP_STAMP(lock_event_table(l
), trace
, dynamic
);
1037 ETAP_CREATE_ENTRY(entry
, trace
);
1038 MON_ASSIGN_PC(entry
->start_pc
, pc
, trace
);
1040 simple_lock(&l
->interlock
);
1043 * Link the new start_list entry
1045 ETAP_LINK_ENTRY(l
, entry
, trace
);
1048 decrementer
= DECREMENTER_TIMEOUT
;
1049 #endif /* MACH_LDEBUG */
1052 * Try to acquire the want_write bit.
1054 while (l
->want_write
) {
1056 ETAP_CONTENTION_TIMESTAMP(entry
, trace
);
1060 i
= lock_wait_time
[l
->can_sleep
? 1 : 0];
1062 simple_unlock(&l
->interlock
);
1065 Debugger("timeout - want_write");
1066 #endif /* MACH_LDEBUG */
1067 while (--i
!= 0 && l
->want_write
)
1069 simple_lock(&l
->interlock
);
1072 if (l
->can_sleep
&& l
->want_write
) {
1074 ETAP_SET_REASON(current_thread(),
1075 BLOCKED_ON_COMPLEX_LOCK
);
1076 thread_sleep_simple_lock((event_t
) l
,
1077 simple_lock_addr(l
->interlock
),
1079 /* interlock relocked */
1082 l
->want_write
= TRUE
;
1084 /* Wait for readers (and upgrades) to finish */
1087 decrementer
= DECREMENTER_TIMEOUT
;
1088 #endif /* MACH_LDEBUG */
1089 while ((l
->read_count
!= 0) || l
->want_upgrade
) {
1091 ETAP_CONTENTION_TIMESTAMP(entry
,trace
);
1095 i
= lock_wait_time
[l
->can_sleep
? 1 : 0];
1097 simple_unlock(&l
->interlock
);
1100 Debugger("timeout - wait for readers");
1101 #endif /* MACH_LDEBUG */
1102 while (--i
!= 0 && (l
->read_count
!= 0 ||
1105 simple_lock(&l
->interlock
);
1108 if (l
->can_sleep
&& (l
->read_count
!= 0 || l
->want_upgrade
)) {
1110 ETAP_SET_REASON(current_thread(),
1111 BLOCKED_ON_COMPLEX_LOCK
);
1112 thread_sleep_simple_lock((event_t
) l
,
1113 simple_lock_addr(l
->interlock
),
1115 /* interlock relocked */
1120 * do not collect wait data if either the lock
1121 * was free or no wait traces are enabled.
1124 if (lock_miss
&& ETAP_CONTENTION_ENABLED(trace
)) {
1125 ETAP_TIMESTAMP(stop_wait_time
);
1126 ETAP_TOTAL_TIME(total_time
,
1128 entry
->start_wait_time
);
1129 CUM_WAIT_ACCUMULATE(l
->cbuff_write
, total_time
, dynamic
, trace
);
1138 simple_unlock(&l
->interlock
);
1141 * Set start hold time if some type of hold tracing is enabled.
1143 * Note: if the stop_wait_time was already stamped, use
1144 * it as the start_hold_time instead of doing an
1145 * expensive bus access.
1149 if (lock_miss
&& ETAP_CONTENTION_ENABLED(trace
))
1150 ETAP_COPY_START_HOLD_TIME(entry
, stop_wait_time
, trace
);
1152 ETAP_DURATION_TIMESTAMP(entry
, trace
);
1158 register lock_t
* l
)
1160 boolean_t do_wakeup
= FALSE
;
1161 start_data_node_t entry
;
1162 unsigned short dynamic
= 0;
1163 unsigned short trace
= 0;
1164 etap_time_t stop_hold_time
;
1165 etap_time_t total_time
;
1166 unsigned long lock_kind
;
1170 ETAP_STAMP(lock_event_table(l
), trace
, dynamic
);
1172 simple_lock(&l
->interlock
);
1174 if (l
->read_count
!= 0) {
1176 lock_kind
= READ_LOCK
;
1179 if (l
->want_upgrade
) {
1180 l
->want_upgrade
= FALSE
;
1181 lock_kind
= WRITE_LOCK
;
1184 l
->want_write
= FALSE
;
1185 lock_kind
= WRITE_LOCK
;
1189 * There is no reason to wakeup a waiting thread
1190 * if the read-count is non-zero. Consider:
1191 * we must be dropping a read lock
1192 * threads are waiting only if one wants a write lock
1193 * if there are still readers, they can't proceed
1196 if (l
->waiting
&& (l
->read_count
== 0)) {
1201 * Collect hold data if hold tracing is
1206 * NOTE: All complex locks whose tracing was on when the
1207 * lock was acquired will have an entry in the start_data
1211 ETAP_UNLINK_ENTRY(l
,entry
);
1212 if (ETAP_DURATION_ENABLED(trace
) && entry
!= SD_ENTRY_NULL
) {
1213 ETAP_TIMESTAMP (stop_hold_time
);
1214 ETAP_TOTAL_TIME (total_time
,
1216 entry
->start_hold_time
);
1218 if (lock_kind
& WRITE_LOCK
)
1219 CUM_HOLD_ACCUMULATE (l
->cbuff_write
,
1224 CUM_READ_ENTRY_RESERVE(l
,l
->cbuff_read
,trace
);
1225 CUM_HOLD_ACCUMULATE (l
->cbuff_read
,
1230 MON_ASSIGN_PC(entry
->end_pc
,pc
,trace
);
1231 MON_DATA_COLLECT(l
,entry
,
1238 simple_unlock(&l
->interlock
);
1240 ETAP_DESTROY_ENTRY(entry
);
1243 thread_wakeup((event_t
) l
);
1248 register lock_t
* l
)
1251 start_data_node_t entry
= {0};
1252 boolean_t lock_miss
= FALSE
;
1253 unsigned short dynamic
= 0;
1254 unsigned short trace
= 0;
1255 etap_time_t total_time
;
1256 etap_time_t stop_wait_time
;
1260 #endif /* MACH_LDEBUG */
1262 ETAP_STAMP(lock_event_table(l
), trace
, dynamic
);
1263 ETAP_CREATE_ENTRY(entry
, trace
);
1264 MON_ASSIGN_PC(entry
->start_pc
, pc
, trace
);
1266 simple_lock(&l
->interlock
);
1269 * Link the new start_list entry
1271 ETAP_LINK_ENTRY(l
,entry
,trace
);
1274 decrementer
= DECREMENTER_TIMEOUT
;
1275 #endif /* MACH_LDEBUG */
1276 while (l
->want_write
|| l
->want_upgrade
) {
1278 ETAP_CONTENTION_TIMESTAMP(entry
, trace
);
1282 i
= lock_wait_time
[l
->can_sleep
? 1 : 0];
1285 simple_unlock(&l
->interlock
);
1288 Debugger("timeout - wait no writers");
1289 #endif /* MACH_LDEBUG */
1290 while (--i
!= 0 && (l
->want_write
|| l
->want_upgrade
))
1292 simple_lock(&l
->interlock
);
1295 if (l
->can_sleep
&& (l
->want_write
|| l
->want_upgrade
)) {
1297 thread_sleep_simple_lock((event_t
) l
,
1298 simple_lock_addr(l
->interlock
),
1300 /* interlock relocked */
1307 * Do not collect wait data if the lock was free
1308 * or if no wait traces are enabled.
1311 if (lock_miss
&& ETAP_CONTENTION_ENABLED(trace
)) {
1312 ETAP_TIMESTAMP(stop_wait_time
);
1313 ETAP_TOTAL_TIME(total_time
,
1315 entry
->start_wait_time
);
1316 CUM_READ_ENTRY_RESERVE(l
, l
->cbuff_read
, trace
);
1317 CUM_WAIT_ACCUMULATE(l
->cbuff_read
, total_time
, dynamic
, trace
);
1325 simple_unlock(&l
->interlock
);
1328 * Set start hold time if some type of hold tracing is enabled.
1330 * Note: if the stop_wait_time was already stamped, use
1331 * it instead of doing an expensive bus access.
1335 if (lock_miss
&& ETAP_CONTENTION_ENABLED(trace
))
1336 ETAP_COPY_START_HOLD_TIME(entry
, stop_wait_time
, trace
);
1338 ETAP_DURATION_TIMESTAMP(entry
,trace
);
1343 * Routine: lock_read_to_write
1345 * Improves a read-only lock to one with
1346 * write permission. If another reader has
1347 * already requested an upgrade to a write lock,
1348 * no lock is held upon return.
1350 * Returns TRUE if the upgrade *failed*.
1355 register lock_t
* l
)
1358 boolean_t do_wakeup
= FALSE
;
1359 start_data_node_t entry
= {0};
1360 boolean_t lock_miss
= FALSE
;
1361 unsigned short dynamic
= 0;
1362 unsigned short trace
= 0;
1363 etap_time_t total_time
;
1364 etap_time_t stop_time
;
1368 #endif /* MACH_LDEBUG */
1371 ETAP_STAMP(lock_event_table(l
), trace
, dynamic
);
1373 simple_lock(&l
->interlock
);
1378 * Since the read lock is lost whether the write lock
1379 * is acquired or not, read hold data is collected here.
1380 * This, of course, is assuming some type of hold
1381 * tracing is enabled.
1383 * Note: trace is set to zero if the entry does not exist.
1386 ETAP_FIND_ENTRY(l
, entry
, trace
);
1388 if (ETAP_DURATION_ENABLED(trace
)) {
1389 ETAP_TIMESTAMP(stop_time
);
1390 ETAP_TOTAL_TIME(total_time
, stop_time
, entry
->start_hold_time
);
1391 CUM_HOLD_ACCUMULATE(l
->cbuff_read
, total_time
, dynamic
, trace
);
1392 MON_ASSIGN_PC(entry
->end_pc
, pc
, trace
);
1401 if (l
->want_upgrade
) {
1403 * Someone else has requested upgrade.
1404 * Since we've released a read lock, wake
1407 if (l
->waiting
&& (l
->read_count
== 0)) {
1412 ETAP_UNLINK_ENTRY(l
, entry
);
1413 simple_unlock(&l
->interlock
);
1414 ETAP_DESTROY_ENTRY(entry
);
1417 thread_wakeup((event_t
) l
);
1421 l
->want_upgrade
= TRUE
;
1423 MON_ASSIGN_PC(entry
->start_pc
, pc
, trace
);
1426 decrementer
= DECREMENTER_TIMEOUT
;
1427 #endif /* MACH_LDEBUG */
1428 while (l
->read_count
!= 0) {
1430 ETAP_CONTENTION_TIMESTAMP(entry
, trace
);
1434 i
= lock_wait_time
[l
->can_sleep
? 1 : 0];
1437 simple_unlock(&l
->interlock
);
1440 Debugger("timeout - read_count");
1441 #endif /* MACH_LDEBUG */
1442 while (--i
!= 0 && l
->read_count
!= 0)
1444 simple_lock(&l
->interlock
);
1447 if (l
->can_sleep
&& l
->read_count
!= 0) {
1449 thread_sleep_simple_lock((event_t
) l
,
1450 simple_lock_addr(l
->interlock
),
1452 /* interlock relocked */
1457 * do not collect wait data if the lock was free
1458 * or if no wait traces are enabled.
1461 if (lock_miss
&& ETAP_CONTENTION_ENABLED(trace
)) {
1462 ETAP_TIMESTAMP (stop_time
);
1463 ETAP_TOTAL_TIME(total_time
, stop_time
, entry
->start_wait_time
);
1464 CUM_WAIT_ACCUMULATE(l
->cbuff_write
, total_time
, dynamic
, trace
);
1473 simple_unlock(&l
->interlock
);
1476 * Set start hold time if some type of hold tracing is enabled
1478 * Note: if the stop_time was already stamped, use
1479 * it as the new start_hold_time instead of doing
1480 * an expensive VME access.
1484 if (lock_miss
&& ETAP_CONTENTION_ENABLED(trace
))
1485 ETAP_COPY_START_HOLD_TIME(entry
, stop_time
, trace
);
1487 ETAP_DURATION_TIMESTAMP(entry
, trace
);
1494 register lock_t
* l
)
1496 boolean_t do_wakeup
= FALSE
;
1497 start_data_node_t entry
= {0};
1498 unsigned short dynamic
= 0;
1499 unsigned short trace
= 0;
1500 etap_time_t stop_hold_time
;
1501 etap_time_t total_time
;
1504 ETAP_STAMP(lock_event_table(l
), trace
,dynamic
);
1506 simple_lock(&l
->interlock
);
1509 if (l
->want_upgrade
)
1510 l
->want_upgrade
= FALSE
;
1512 l
->want_write
= FALSE
;
1520 * Since we are switching from a write lock to a read lock,
1521 * the write lock data is stored and the read lock data
1522 * collection begins.
1524 * Note: trace is set to zero if the entry does not exist.
1527 ETAP_FIND_ENTRY(l
, entry
, trace
);
1529 if (ETAP_DURATION_ENABLED(trace
)) {
1530 ETAP_TIMESTAMP (stop_hold_time
);
1531 ETAP_TOTAL_TIME(total_time
, stop_hold_time
, entry
->start_hold_time
);
1532 CUM_HOLD_ACCUMULATE(l
->cbuff_write
, total_time
, dynamic
, trace
);
1533 MON_ASSIGN_PC(entry
->end_pc
, pc
, trace
);
1542 simple_unlock(&l
->interlock
);
1545 * Set start hold time if some type of hold tracing is enabled
1547 * Note: if the stop_hold_time was already stamped, use
1548 * it as the new start_hold_time instead of doing
1549 * an expensive bus access.
1553 if (ETAP_DURATION_ENABLED(trace
))
1554 ETAP_COPY_START_HOLD_TIME(entry
, stop_hold_time
, trace
);
1556 ETAP_DURATION_TIMESTAMP(entry
, trace
);
1558 MON_ASSIGN_PC(entry
->start_pc
, pc
, trace
);
1561 thread_wakeup((event_t
) l
);
1567 * Routine: lock_try_write
1569 * Tries to get a write lock.
1571 * Returns FALSE if the lock is not held on return.
1576 register lock_t
* l
)
1578 start_data_node_t entry
= {0};
1579 unsigned short trace
= 0;
1582 ETAP_STAMP(lock_event_table(l
), trace
, trace
);
1583 ETAP_CREATE_ENTRY(entry
, trace
);
1585 simple_lock(&l
->interlock
);
1587 if (l
->want_write
|| l
->want_upgrade
|| l
->read_count
) {
1591 simple_unlock(&l
->interlock
);
1592 ETAP_DESTROY_ENTRY(entry
);
1600 l
->want_write
= TRUE
;
1602 ETAP_LINK_ENTRY(l
, entry
, trace
);
1604 simple_unlock(&l
->interlock
);
1606 MON_ASSIGN_PC(entry
->start_pc
, pc
, trace
);
1607 ETAP_DURATION_TIMESTAMP(entry
, trace
);
1613 * Routine: lock_try_read
1615 * Tries to get a read lock.
1617 * Returns FALSE if the lock is not held on return.
1622 register lock_t
* l
)
1624 start_data_node_t entry
= {0};
1625 unsigned short trace
= 0;
1628 ETAP_STAMP(lock_event_table(l
), trace
, trace
);
1629 ETAP_CREATE_ENTRY(entry
, trace
);
1631 simple_lock(&l
->interlock
);
1633 if (l
->want_write
|| l
->want_upgrade
) {
1634 simple_unlock(&l
->interlock
);
1635 ETAP_DESTROY_ENTRY(entry
);
1641 ETAP_LINK_ENTRY(l
, entry
, trace
);
1643 simple_unlock(&l
->interlock
);
1645 MON_ASSIGN_PC(entry
->start_pc
, pc
, trace
);
1646 ETAP_DURATION_TIMESTAMP(entry
, trace
);
1654 void db_show_one_lock(lock_t
*);
1661 db_printf("Read_count = 0x%x, %swant_upgrade, %swant_write, ",
1663 lock
->want_upgrade
? "" : "!",
1664 lock
->want_write
? "" : "!");
1665 db_printf("%swaiting, %scan_sleep\n",
1666 lock
->waiting
? "" : "!", lock
->can_sleep
? "" : "!");
1667 db_printf("Interlock:\n");
1668 db_show_one_simple_lock((db_expr_t
)simple_lock_addr(lock
->interlock
),
1669 TRUE
, (db_expr_t
)0, (char *)0);
1671 #endif /* MACH_KDB */
1674 * The C portion of the mutex package. These routines are only invoked
1675 * if the optimized assembler routines can't do the work.
1679 * Routine: lock_alloc
1681 * Allocate a mutex for external users who cannot
1682 * hard-code the structure definition into their
1684 * For now just use kalloc, but a zone is probably
1693 if ((m
= (mutex_t
*)kalloc(sizeof(mutex_t
))) != 0)
1694 mutex_init(m
, event
);
1699 * Routine: mutex_free
1701 * Free a mutex allocated for external users.
1702 * For now just use kfree, but a zone is probably
1709 kfree((vm_offset_t
)m
, sizeof(mutex_t
));
1715 * Invoked in order to wait on contention.
1717 * Called with the interlock locked and
1718 * returns it unlocked.
1725 thread_t self
= current_thread();
1728 spl_t s
= splsched();
1730 priority
= self
->sched_pri
;
1731 if (priority
< self
->priority
)
1732 priority
= self
->priority
;
1733 if (priority
> MINPRI_KERNEL
)
1734 priority
= MINPRI_KERNEL
;
1736 if (priority
< BASEPRI_DEFAULT
)
1737 priority
= BASEPRI_DEFAULT
;
1739 assert(holder
->thread
== holder
); /* XXX */
1740 thread_lock(holder
);
1741 if (mutex
->promoted_pri
== 0)
1742 holder
->promotions
++;
1743 if (holder
->priority
< MINPRI_KERNEL
) {
1744 holder
->sched_mode
|= TH_MODE_PROMOTED
;
1745 if ( mutex
->promoted_pri
< priority
&&
1746 holder
->sched_pri
< priority
) {
1747 KERNEL_DEBUG_CONSTANT(
1748 MACHDBG_CODE(DBG_MACH_SCHED
,MACH_PROMOTE
) | DBG_FUNC_NONE
,
1749 holder
->sched_pri
, priority
, (int)holder
, (int)mutex
, 0);
1751 set_sched_pri(holder
, priority
);
1754 thread_unlock(holder
);
1757 if (mutex
->promoted_pri
< priority
)
1758 mutex
->promoted_pri
= priority
;
1761 if (self
->pending_promoter
[self
->pending_promoter_index
] == NULL
) {
1762 self
->pending_promoter
[self
->pending_promoter_index
] = mutex
;
1766 if (self
->pending_promoter
[self
->pending_promoter_index
] != mutex
) {
1767 self
->pending_promoter
[++self
->pending_promoter_index
] = mutex
;
1771 assert_wait(mutex
, THREAD_UNINT
);
1772 interlock_unlock(&mutex
->interlock
);
1774 thread_block(THREAD_CONTINUE_NULL
);
1778 * mutex_lock_acquire
1780 * Invoked on acquiring the mutex when there is
1783 * Returns the current number of waiters.
1785 * Called with the interlock locked.
1791 thread_t thread
= current_thread();
1793 if (thread
->pending_promoter
[thread
->pending_promoter_index
] == mutex
) {
1794 thread
->pending_promoter
[thread
->pending_promoter_index
] = NULL
;
1795 if (thread
->pending_promoter_index
> 0)
1796 thread
->pending_promoter_index
--;
1801 if (mutex
->waiters
> 0) {
1802 integer_t priority
= mutex
->promoted_pri
;
1803 spl_t s
= splsched();
1805 thread_lock(thread
);
1806 thread
->promotions
++;
1807 if (thread
->priority
< MINPRI_KERNEL
) {
1808 thread
->sched_mode
|= TH_MODE_PROMOTED
;
1809 if (thread
->sched_pri
< priority
) {
1810 KERNEL_DEBUG_CONSTANT(
1811 MACHDBG_CODE(DBG_MACH_SCHED
,MACH_PROMOTE
) | DBG_FUNC_NONE
,
1812 thread
->sched_pri
, priority
, 0, (int)mutex
, 0);
1814 set_sched_pri(thread
, priority
);
1817 thread_unlock(thread
);
1821 mutex
->promoted_pri
= 0;
1824 return (mutex
->waiters
);
1828 * mutex_unlock_wakeup
1830 * Invoked on unlock when there is contention.
1832 * Called with the interlock locked.
1835 mutex_unlock_wakeup (
1840 thread_t thread
= current_thread();
1842 if (thread
->top_act
!= holder
)
1843 panic("mutex_unlock_wakeup: mutex %x holder %x\n", mutex
, holder
);
1845 if (thread
->promotions
> 0) {
1846 spl_t s
= splsched();
1848 thread_lock(thread
);
1849 if ( --thread
->promotions
== 0 &&
1850 (thread
->sched_mode
& TH_MODE_PROMOTED
) ) {
1851 thread
->sched_mode
&= ~TH_MODE_PROMOTED
;
1852 if (thread
->sched_mode
& TH_MODE_ISDEPRESSED
) {
1853 KERNEL_DEBUG_CONSTANT(
1854 MACHDBG_CODE(DBG_MACH_SCHED
,MACH_DEMOTE
) | DBG_FUNC_NONE
,
1855 thread
->sched_pri
, DEPRESSPRI
, 0, (int)mutex
, 0);
1857 set_sched_pri(thread
, DEPRESSPRI
);
1860 if (thread
->priority
< thread
->sched_pri
) {
1861 KERNEL_DEBUG_CONSTANT(
1862 MACHDBG_CODE(DBG_MACH_SCHED
,MACH_DEMOTE
) |
1864 thread
->sched_pri
, thread
->priority
,
1868 compute_priority(thread
, FALSE
);
1871 thread_unlock(thread
);
1876 assert(mutex
->waiters
> 0);
1877 thread_wakeup_one(mutex
);
1881 mutex_preblock_wait(
1886 wait_result_t wresult
;
1890 assert(holder
== NULL
|| holder
->thread
== holder
);
1892 wq
= wait_event_wait_queue((event_t
)mutex
);
1893 if (!wait_queue_lock_try(wq
))
1896 if (holder
!= NULL
&& !thread_lock_try(holder
)) {
1897 wait_queue_unlock(wq
);
1901 wresult
= wait_queue_assert_wait64_locked(wq
, (uint32_t)mutex
,
1902 THREAD_UNINT
, thread
);
1903 wait_queue_unlock(wq
);
1904 assert(wresult
== THREAD_WAITING
);
1906 priority
= thread
->sched_pri
;
1907 if (priority
< thread
->priority
)
1908 priority
= thread
->priority
;
1909 if (priority
> MINPRI_KERNEL
)
1910 priority
= MINPRI_KERNEL
;
1912 if (priority
< BASEPRI_DEFAULT
)
1913 priority
= BASEPRI_DEFAULT
;
1915 if (holder
!= NULL
) {
1916 if (mutex
->promoted_pri
== 0)
1917 holder
->promotions
++;
1918 if (holder
->priority
< MINPRI_KERNEL
) {
1919 holder
->sched_mode
|= TH_MODE_PROMOTED
;
1920 if ( mutex
->promoted_pri
< priority
&&
1921 holder
->sched_pri
< priority
) {
1922 KERNEL_DEBUG_CONSTANT(
1923 MACHDBG_CODE(DBG_MACH_SCHED
,MACH_PROMOTE
) | DBG_FUNC_NONE
,
1924 holder
->sched_pri
, priority
,
1925 (int)holder
, (int)mutex
, 0);
1927 set_sched_pri(holder
, priority
);
1930 thread_unlock(holder
);
1933 if (mutex
->promoted_pri
< priority
)
1934 mutex
->promoted_pri
= priority
;
1936 if (thread
->pending_promoter
[thread
->pending_promoter_index
] == NULL
) {
1937 thread
->pending_promoter
[thread
->pending_promoter_index
] = mutex
;
1941 if (thread
->pending_promoter
[thread
->pending_promoter_index
] != mutex
) {
1942 thread
->pending_promoter
[++thread
->pending_promoter_index
] = mutex
;
1946 KERNEL_DEBUG_CONSTANT(
1947 MACHDBG_CODE(DBG_MACH_SCHED
,MACH_PREBLOCK_MUTEX
) | DBG_FUNC_NONE
,
1948 (int)thread
, thread
->sched_pri
, (int)mutex
, 0, 0);
1954 * mutex_pause: Called by former callers of simple_lock_pause().
1960 wait_result_t wait_result
;
1962 wait_result
= assert_wait_timeout( 1, THREAD_UNINT
);
1963 assert(wait_result
== THREAD_WAITING
);
1965 ETAP_SET_REASON(current_thread(), BLOCKED_ON_MUTEX_LOCK
);
1967 wait_result
= thread_block(THREAD_CONTINUE_NULL
);
1968 assert(wait_result
== THREAD_TIMED_OUT
);
1973 * Routines to print out simple_locks and mutexes in a nicely-formatted
1977 char *simple_lock_labels
= "ENTRY ILK THREAD DURATION CALLER";
1978 char *mutex_labels
= "ENTRY LOCKED WAITERS THREAD CALLER";
1981 db_show_one_simple_lock (
1983 boolean_t have_addr
,
1987 simple_lock_t saddr
= (simple_lock_t
)addr
;
1989 if (saddr
== (simple_lock_t
)0 || !have_addr
) {
1990 db_error ("No simple_lock\n");
1993 else if (saddr
->lock_type
!= USLOCK_TAG
)
1994 db_error ("Not a simple_lock\n");
1995 #endif /* USLOCK_DEBUG */
1997 db_printf ("%s\n", simple_lock_labels
);
1998 db_print_simple_lock (saddr
);
2002 db_print_simple_lock (
2006 db_printf ("%08x %3d", addr
, *hw_lock_addr(addr
->interlock
));
2008 db_printf (" %08x", addr
->debug
.lock_thread
);
2009 db_printf (" %08x ", addr
->debug
.duration
[1]);
2010 db_printsym ((int)addr
->debug
.lock_pc
, DB_STGY_ANY
);
2011 #endif /* USLOCK_DEBUG */
2018 boolean_t have_addr
,
2022 mutex_t
* maddr
= (mutex_t
*)addr
;
2024 if (maddr
== (mutex_t
*)0 || !have_addr
)
2025 db_error ("No mutex\n");
2027 else if (maddr
->type
!= MUTEX_TAG
)
2028 db_error ("Not a mutex\n");
2029 #endif /* MACH_LDEBUG */
2031 db_printf ("%s\n", mutex_labels
);
2032 db_print_mutex (maddr
);
2039 db_printf ("%08x %6d %7d",
2040 addr
, *hw_lock_addr(addr
->locked
), addr
->waiters
);
2042 db_printf (" %08x ", addr
->thread
);
2043 db_printsym (addr
->pc
, DB_STGY_ANY
);
2044 #endif /* MACH_LDEBUG */
2047 #endif /* MACH_KDB */
2050 extern void meter_simple_lock (
2052 extern void meter_simple_unlock (
2054 extern void cyctm05_stamp (
2055 unsigned long * start
);
2056 extern void cyctm05_diff (
2057 unsigned long * start
,
2058 unsigned long * end
,
2059 unsigned long * diff
);
2062 simple_lock_data_t loser
;
2070 cyctm05_stamp (lp
->duration
);
2074 int long_simple_lock_crash
;
2075 int long_simple_lock_time
= 0x600;
2077 * This is pretty gawd-awful. XXX
2079 decl_simple_lock_data(extern,kd_tty
)
2082 meter_simple_unlock(
2086 unsigned long stime
[2], etime
[2], delta
[2];
2088 if (lp
== &kd_tty
) /* XXX */
2091 stime
[0] = lp
->duration
[0];
2092 stime
[1] = lp
->duration
[1];
2094 cyctm05_stamp (etime
);
2096 if (etime
[1] < stime
[1]) /* XXX */
2099 cyctm05_diff (stime
, etime
, delta
);
2101 if (delta
[1] >= 0x10000) /* XXX */
2104 lp
->duration
[0] = delta
[0];
2105 lp
->duration
[1] = delta
[1];
2107 if (loser
.duration
[1] < lp
->duration
[1])
2110 assert (!long_simple_lock_crash
|| delta
[1] < long_simple_lock_time
);
2113 #endif /* MACH_LDEBUG */
2119 * ==============================================================
2120 * ETAP hook when initializing a usimple_lock. May be invoked
2121 * from the portable lock package or from an optimized machine-
2122 * dependent implementation.
2123 * ==============================================================
2127 etap_simplelock_init (
2131 ETAP_CLEAR_TRACE_DATA(l
);
2132 etap_event_table_assign(&l
->u
.event_table_chain
, event
);
2134 #if ETAP_LOCK_ACCUMULATE
2135 /* reserve an entry in the cumulative buffer */
2136 l
->cbuff_entry
= etap_cbuff_reserve(lock_event_table(l
));
2137 /* initialize the entry if one was returned */
2138 if (l
->cbuff_entry
!= CBUFF_ENTRY_NULL
) {
2139 l
->cbuff_entry
->event
= event
;
2140 l
->cbuff_entry
->instance
= (unsigned long) l
;
2141 l
->cbuff_entry
->kind
= SPIN_LOCK
;
2143 #endif /* ETAP_LOCK_ACCUMULATE */
2148 etap_simplelock_unlock(
2151 unsigned short dynamic
= 0;
2152 unsigned short trace
= 0;
2153 etap_time_t total_time
;
2154 etap_time_t stop_hold_time
;
2158 ETAP_STAMP(lock_event_table(l
), trace
, dynamic
);
2161 * Calculate & collect hold time data only if
2162 * the hold tracing was enabled throughout the
2163 * whole operation. This prevents collection of
2164 * bogus data caused by mid-operation trace changes.
2168 if (ETAP_DURATION_ENABLED(trace
) && ETAP_WHOLE_OP(l
)) {
2169 ETAP_TIMESTAMP (stop_hold_time
);
2170 ETAP_TOTAL_TIME(total_time
, stop_hold_time
,
2171 l
->u
.s
.start_hold_time
);
2172 CUM_HOLD_ACCUMULATE(l
->cbuff_entry
, total_time
, dynamic
, trace
);
2173 MON_ASSIGN_PC(l
->end_pc
, pc
, trace
);
2181 ETAP_CLEAR_TRACE_DATA(l
);
2184 /* ========================================================================
2185 * Since the the simple_lock() routine is machine dependant, it must always
2186 * be coded in assembly. The two hook routines below are used to collect
2188 * ========================================================================
2192 * ROUTINE: etap_simplelock_miss()
2194 * FUNCTION: This spin lock routine is called upon the first
2195 * spin (miss) of the lock.
2197 * A timestamp is taken at the beginning of the wait period,
2198 * if wait tracing is enabled.
2203 * - timestamp address.
2205 * RETURNS: Wait timestamp value. The timestamp value is later used
2206 * by etap_simplelock_hold().
2208 * NOTES: This routine is NOT ALWAYS called. The lock may be free
2209 * (never spinning). For this reason the pc is collected in
2210 * etap_simplelock_hold().
2214 etap_simplelock_miss (
2218 unsigned short trace
= 0;
2219 unsigned short dynamic
= 0;
2220 etap_time_t start_miss_time
;
2222 ETAP_STAMP(lock_event_table(l
), trace
, dynamic
);
2224 if (trace
& ETAP_CONTENTION
)
2225 ETAP_TIMESTAMP(start_miss_time
);
2227 return(start_miss_time
);
2231 * ROUTINE: etap_simplelock_hold()
2233 * FUNCTION: This spin lock routine is ALWAYS called once the lock
2234 * is acquired. Here, the contention time is calculated and
2235 * the start hold time is stamped.
2239 * - PC of the calling function.
2240 * - start wait timestamp.
2245 etap_simplelock_hold (
2248 etap_time_t start_hold_time
)
2250 unsigned short dynamic
= 0;
2251 unsigned short trace
= 0;
2252 etap_time_t total_time
;
2253 etap_time_t stop_hold_time
;
2255 ETAP_STAMP(lock_event_table(l
), trace
, dynamic
);
2257 MON_ASSIGN_PC(l
->start_pc
, pc
, trace
);
2259 /* do not collect wait data if lock was free */
2260 if (ETAP_TIME_IS_ZERO(start_hold_time
) && (trace
& ETAP_CONTENTION
)) {
2261 ETAP_TIMESTAMP(stop_hold_time
);
2262 ETAP_TOTAL_TIME(total_time
,
2265 CUM_WAIT_ACCUMULATE(l
->cbuff_entry
, total_time
, dynamic
, trace
);
2272 ETAP_COPY_START_HOLD_TIME(&l
->u
.s
, stop_hold_time
, trace
);
2275 ETAP_DURATION_TIMESTAMP(&l
->u
.s
, trace
);
2283 ETAP_CLEAR_TRACE_DATA(l
);
2284 etap_event_table_assign(&l
->u
.event_table_chain
, event
);
2286 #if ETAP_LOCK_ACCUMULATE
2287 /* reserve an entry in the cumulative buffer */
2288 l
->cbuff_entry
= etap_cbuff_reserve(lock_event_table(l
));
2289 /* initialize the entry if one was returned */
2290 if (l
->cbuff_entry
!= CBUFF_ENTRY_NULL
) {
2291 l
->cbuff_entry
->event
= event
;
2292 l
->cbuff_entry
->instance
= (unsigned long) l
;
2293 l
->cbuff_entry
->kind
= MUTEX_LOCK
;
2295 #endif /* ETAP_LOCK_ACCUMULATE */
2302 unsigned short trace
= 0;
2303 unsigned short dynamic
= 0;
2304 etap_time_t start_miss_time
;
2306 ETAP_STAMP(lock_event_table(l
), trace
, dynamic
);
2308 if (trace
& ETAP_CONTENTION
)
2309 ETAP_TIMESTAMP(start_miss_time
);
2311 ETAP_TIME_CLEAR(start_miss_time
);
2313 return(start_miss_time
);
2320 etap_time_t start_hold_time
)
2322 unsigned short dynamic
= 0;
2323 unsigned short trace
= 0;
2324 etap_time_t total_time
;
2325 etap_time_t stop_hold_time
;
2327 ETAP_STAMP(lock_event_table(l
), trace
, dynamic
);
2329 MON_ASSIGN_PC(l
->start_pc
, pc
, trace
);
2331 /* do not collect wait data if lock was free */
2332 if (!ETAP_TIME_IS_ZERO(start_hold_time
) && (trace
& ETAP_CONTENTION
)) {
2333 ETAP_TIMESTAMP(stop_hold_time
);
2334 ETAP_TOTAL_TIME(total_time
,
2337 CUM_WAIT_ACCUMULATE(l
->cbuff_entry
, total_time
, dynamic
, trace
);
2344 ETAP_COPY_START_HOLD_TIME(&l
->u
.s
, stop_hold_time
, trace
);
2347 ETAP_DURATION_TIMESTAMP(&l
->u
.s
, trace
);
2354 unsigned short dynamic
= 0;
2355 unsigned short trace
= 0;
2356 etap_time_t total_time
;
2357 etap_time_t stop_hold_time
;
2361 ETAP_STAMP(lock_event_table(l
), trace
, dynamic
);
2364 * Calculate & collect hold time data only if
2365 * the hold tracing was enabled throughout the
2366 * whole operation. This prevents collection of
2367 * bogus data caused by mid-operation trace changes.
2371 if (ETAP_DURATION_ENABLED(trace
) && ETAP_WHOLE_OP(l
)) {
2372 ETAP_TIMESTAMP(stop_hold_time
);
2373 ETAP_TOTAL_TIME(total_time
, stop_hold_time
,
2374 l
->u
.s
.start_hold_time
);
2375 CUM_HOLD_ACCUMULATE(l
->cbuff_entry
, total_time
, dynamic
, trace
);
2376 MON_ASSIGN_PC(l
->end_pc
, pc
, trace
);
2384 ETAP_CLEAR_TRACE_DATA(l
);
2387 #endif /* ETAP_LOCK_TRACE */