]> git.saurik.com Git - apple/xnu.git/blob - osfmk/kern/lock.c
xnu-517.12.7.tar.gz
[apple/xnu.git] / osfmk / kern / lock.c
1 /*
2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
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.
11 *
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
18 * under the License.
19 *
20 * @APPLE_LICENSE_HEADER_END@
21 */
22 /*
23 * @OSF_COPYRIGHT@
24 */
25 /*
26 * Mach Operating System
27 * Copyright (c) 1991,1990,1989,1988,1987 Carnegie Mellon University
28 * All Rights Reserved.
29 *
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.
35 *
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.
39 *
40 * Carnegie Mellon requests users of this software to return to
41 *
42 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
43 * School of Computer Science
44 * Carnegie Mellon University
45 * Pittsburgh PA 15213-3890
46 *
47 * any improvements or extensions that they make and grant Carnegie Mellon
48 * the rights to redistribute these changes.
49 */
50 /*
51 * File: kern/lock.c
52 * Author: Avadis Tevanian, Jr., Michael Wayne Young
53 * Date: 1985
54 *
55 * Locking primitives implementation
56 */
57
58 #include <cpus.h>
59 #include <mach_kdb.h>
60 #include <mach_ldebug.h>
61
62 #include <kern/lock.h>
63 #include <kern/etap_macros.h>
64 #include <kern/misc_protos.h>
65 #include <kern/thread.h>
66 #include <kern/processor.h>
67 #include <kern/sched_prim.h>
68 #include <kern/xpr.h>
69 #include <kern/debug.h>
70 #include <string.h>
71
72 #if MACH_KDB
73 #include <ddb/db_command.h>
74 #include <ddb/db_output.h>
75 #include <ddb/db_sym.h>
76 #include <ddb/db_print.h>
77 #endif /* MACH_KDB */
78
79 #ifdef __ppc__
80 #include <ppc/Firmware.h>
81 #endif
82
83 #include <sys/kdebug.h>
84
85 #define ANY_LOCK_DEBUG (USLOCK_DEBUG || LOCK_DEBUG || MUTEX_DEBUG)
86
87 /*
88 * Some portions of the lock debugging code must run with
89 * interrupts disabled. This can be machine-dependent,
90 * but we don't have any good hooks for that at the moment.
91 * If your architecture is different, add a machine-dependent
92 * ifdef here for these macros. XXX
93 */
94
95 #define DISABLE_INTERRUPTS(s) s = ml_set_interrupts_enabled(FALSE)
96 #define ENABLE_INTERRUPTS(s) (void)ml_set_interrupts_enabled(s)
97
98 #if NCPUS > 1
99 /* Time we loop without holding the interlock.
100 * The former is for when we cannot sleep, the latter
101 * for when our thread can go to sleep (loop less)
102 * we shouldn't retake the interlock at all frequently
103 * if we cannot go to sleep, since it interferes with
104 * any other processors. In particular, 100 is too small
105 * a number for powerpc MP systems because of cache
106 * coherency issues and differing lock fetch times between
107 * the processors
108 */
109 unsigned int lock_wait_time[2] = { (unsigned int)-1, 100 } ;
110 #else /* NCPUS > 1 */
111
112 /*
113 * It is silly to spin on a uni-processor as if we
114 * thought something magical would happen to the
115 * want_write bit while we are executing.
116 */
117
118 unsigned int lock_wait_time[2] = { 0, 0 };
119 #endif /* NCPUS > 1 */
120
121 /* Forwards */
122
123 #if MACH_KDB
124 void db_print_simple_lock(
125 simple_lock_t addr);
126
127 void db_print_mutex(
128 mutex_t * addr);
129 #endif /* MACH_KDB */
130
131
132 #if USLOCK_DEBUG
133 /*
134 * Perform simple lock checks.
135 */
136 int uslock_check = 1;
137 int max_lock_loops = 100000000;
138 decl_simple_lock_data(extern , printf_lock)
139 decl_simple_lock_data(extern , panic_lock)
140 #if MACH_KDB && NCPUS > 1
141 decl_simple_lock_data(extern , kdb_lock)
142 #endif /* MACH_KDB && NCPUS >1 */
143 #endif /* USLOCK_DEBUG */
144
145
146 /*
147 * We often want to know the addresses of the callers
148 * of the various lock routines. However, this information
149 * is only used for debugging and statistics.
150 */
151 typedef void *pc_t;
152 #define INVALID_PC ((void *) VM_MAX_KERNEL_ADDRESS)
153 #define INVALID_THREAD ((void *) VM_MAX_KERNEL_ADDRESS)
154 #if ANY_LOCK_DEBUG || ETAP_LOCK_TRACE
155 #define OBTAIN_PC(pc,l) ((pc) = (void *) GET_RETURN_PC(&(l)))
156 #else /* ANY_LOCK_DEBUG || ETAP_LOCK_TRACE */
157 #ifdef lint
158 /*
159 * Eliminate lint complaints about unused local pc variables.
160 */
161 #define OBTAIN_PC(pc,l) ++pc
162 #else /* lint */
163 #define OBTAIN_PC(pc,l)
164 #endif /* lint */
165 #endif /* USLOCK_DEBUG || ETAP_LOCK_TRACE */
166
167
168 /* #ifndef USIMPLE_LOCK_CALLS
169 * The i386 production version of usimple_locks isn't ready yet.
170 */
171 /*
172 * Portable lock package implementation of usimple_locks.
173 */
174
175 #if ETAP_LOCK_TRACE
176 #define ETAPCALL(stmt) stmt
177 void etap_simplelock_init(simple_lock_t, etap_event_t);
178 void etap_simplelock_unlock(simple_lock_t);
179 void etap_simplelock_hold(simple_lock_t, pc_t, etap_time_t);
180 etap_time_t etap_simplelock_miss(simple_lock_t);
181
182 void etap_mutex_init(mutex_t*, etap_event_t);
183 void etap_mutex_unlock(mutex_t*);
184 void etap_mutex_hold(mutex_t*, pc_t, etap_time_t);
185 etap_time_t etap_mutex_miss(mutex_t*);
186 #else /* ETAP_LOCK_TRACE */
187 #define ETAPCALL(stmt)
188 #endif /* ETAP_LOCK_TRACE */
189
190 #if USLOCK_DEBUG
191 #define USLDBG(stmt) stmt
192 void usld_lock_init(usimple_lock_t, etap_event_t);
193 void usld_lock_pre(usimple_lock_t, pc_t);
194 void usld_lock_post(usimple_lock_t, pc_t);
195 void usld_unlock(usimple_lock_t, pc_t);
196 void usld_lock_try_pre(usimple_lock_t, pc_t);
197 void usld_lock_try_post(usimple_lock_t, pc_t);
198 void usld_lock_held(usimple_lock_t);
199 void usld_lock_none_held(void);
200 int usld_lock_common_checks(usimple_lock_t, char *);
201 #else /* USLOCK_DEBUG */
202 #define USLDBG(stmt)
203 #endif /* USLOCK_DEBUG */
204
205 /*
206 * Initialize a usimple_lock.
207 *
208 * No change in preemption state.
209 */
210 void
211 usimple_lock_init(
212 usimple_lock_t l,
213 etap_event_t event)
214 {
215 #ifndef MACHINE_SIMPLE_LOCK
216 USLDBG(usld_lock_init(l, event));
217 ETAPCALL(etap_simplelock_init((l),(event)));
218 hw_lock_init(&l->interlock);
219 #else
220 simple_lock_init((simple_lock_t)l,event);
221 #endif
222 }
223
224
225 /*
226 * Acquire a usimple_lock.
227 *
228 * Returns with preemption disabled. Note
229 * that the hw_lock routines are responsible for
230 * maintaining preemption state.
231 */
232 void
233 usimple_lock(
234 usimple_lock_t l)
235 {
236 #ifndef MACHINE_SIMPLE_LOCK
237 int i;
238 pc_t pc;
239 #if ETAP_LOCK_TRACE
240 etap_time_t start_wait_time;
241 int no_miss_info = 0;
242 #endif /* ETAP_LOCK_TRACE */
243 #if USLOCK_DEBUG
244 int count = 0;
245 #endif /* USLOCK_DEBUG */
246
247 OBTAIN_PC(pc, l);
248 USLDBG(usld_lock_pre(l, pc));
249 #if ETAP_LOCK_TRACE
250 ETAP_TIME_CLEAR(start_wait_time);
251 #endif /* ETAP_LOCK_TRACE */
252
253 if(!hw_lock_to(&l->interlock, LockTimeOut)) /* Try to get the lock with a timeout */
254 panic("simple lock deadlock detection - l=%08X, cpu=%d, ret=%08X", l, cpu_number(), pc);
255
256 ETAPCALL(etap_simplelock_hold(l, pc, start_wait_time));
257 USLDBG(usld_lock_post(l, pc));
258 #else
259 simple_lock((simple_lock_t)l);
260 #endif
261 }
262
263
264 /*
265 * Release a usimple_lock.
266 *
267 * Returns with preemption enabled. Note
268 * that the hw_lock routines are responsible for
269 * maintaining preemption state.
270 */
271 void
272 usimple_unlock(
273 usimple_lock_t l)
274 {
275 #ifndef MACHINE_SIMPLE_LOCK
276 pc_t pc;
277
278 // checkNMI(); /* (TEST/DEBUG) */
279
280 OBTAIN_PC(pc, l);
281 USLDBG(usld_unlock(l, pc));
282 ETAPCALL(etap_simplelock_unlock(l));
283 #ifdef __ppc__
284 sync();
285 #endif
286 hw_lock_unlock(&l->interlock);
287 #else
288 simple_unlock_rwmb((simple_lock_t)l);
289 #endif
290 }
291
292
293 /*
294 * Conditionally acquire a usimple_lock.
295 *
296 * On success, returns with preemption disabled.
297 * On failure, returns with preemption in the same state
298 * as when first invoked. Note that the hw_lock routines
299 * are responsible for maintaining preemption state.
300 *
301 * XXX No stats are gathered on a miss; I preserved this
302 * behavior from the original assembly-language code, but
303 * doesn't it make sense to log misses? XXX
304 */
305 unsigned int
306 usimple_lock_try(
307 usimple_lock_t l)
308 {
309 #ifndef MACHINE_SIMPLE_LOCK
310 pc_t pc;
311 unsigned int success;
312 etap_time_t zero_time;
313
314 OBTAIN_PC(pc, l);
315 USLDBG(usld_lock_try_pre(l, pc));
316 if (success = hw_lock_try(&l->interlock)) {
317 USLDBG(usld_lock_try_post(l, pc));
318 ETAP_TIME_CLEAR(zero_time);
319 ETAPCALL(etap_simplelock_hold(l, pc, zero_time));
320 }
321 return success;
322 #else
323 return(simple_lock_try((simple_lock_t)l));
324 #endif
325 }
326
327 #if ETAP_LOCK_TRACE
328 void
329 simple_lock_no_trace(
330 simple_lock_t l)
331 {
332 pc_t pc;
333
334 OBTAIN_PC(pc, l);
335 USLDBG(usld_lock_pre(l, pc));
336 while (!hw_lock_try(&l->interlock)) {
337 while (hw_lock_held(&l->interlock)) {
338 /*
339 * Spin watching the lock value in cache,
340 * without consuming external bus cycles.
341 * On most SMP architectures, the atomic
342 * instruction(s) used by hw_lock_try
343 * cost much, much more than an ordinary
344 * memory read.
345 */
346 }
347 }
348 USLDBG(usld_lock_post(l, pc));
349 }
350
351 void
352 simple_unlock_no_trace(
353 simple_lock_t l)
354 {
355 pc_t pc;
356
357 OBTAIN_PC(pc, l);
358 USLDBG(usld_unlock(l, pc));
359 hw_lock_unlock(&l->interlock);
360 }
361
362 int
363 simple_lock_try_no_trace(
364 simple_lock_t l)
365 {
366 pc_t pc;
367 unsigned int success;
368
369 OBTAIN_PC(pc, l);
370 USLDBG(usld_lock_try_pre(l, pc));
371 if (success = hw_lock_try(&l->interlock)) {
372 USLDBG(usld_lock_try_post(l, pc));
373 }
374 return success;
375 }
376 #endif /* ETAP_LOCK_TRACE */
377
378
379 #if USLOCK_DEBUG
380 /*
381 * Verify that the lock is locked and owned by
382 * the current thread.
383 */
384 void
385 usimple_lock_held(
386 usimple_lock_t l)
387 {
388 usld_lock_held(l);
389 }
390
391
392 /*
393 * Verify that no usimple_locks are held by
394 * this processor. Typically used in a
395 * trap handler when returning to user mode
396 * or in a path known to relinquish the processor.
397 */
398 void
399 usimple_lock_none_held(void)
400 {
401 usld_lock_none_held();
402 }
403 #endif /* USLOCK_DEBUG */
404
405
406 #if USLOCK_DEBUG
407 /*
408 * States of a usimple_lock. The default when initializing
409 * a usimple_lock is setting it up for debug checking.
410 */
411 #define USLOCK_CHECKED 0x0001 /* lock is being checked */
412 #define USLOCK_TAKEN 0x0002 /* lock has been taken */
413 #define USLOCK_INIT 0xBAA0 /* lock has been initialized */
414 #define USLOCK_INITIALIZED (USLOCK_INIT|USLOCK_CHECKED)
415 #define USLOCK_CHECKING(l) (uslock_check && \
416 ((l)->debug.state & USLOCK_CHECKED))
417
418 /*
419 * Maintain a per-cpu stack of acquired usimple_locks.
420 */
421 void usl_stack_push(usimple_lock_t, int);
422 void usl_stack_pop(usimple_lock_t, int);
423
424 /*
425 * Trace activities of a particularly interesting lock.
426 */
427 void usl_trace(usimple_lock_t, int, pc_t, const char *);
428
429
430 /*
431 * Initialize the debugging information contained
432 * in a usimple_lock.
433 */
434 void
435 usld_lock_init(
436 usimple_lock_t l,
437 etap_event_t type)
438 {
439 if (l == USIMPLE_LOCK_NULL)
440 panic("lock initialization: null lock pointer");
441 l->lock_type = USLOCK_TAG;
442 l->debug.state = uslock_check ? USLOCK_INITIALIZED : 0;
443 l->debug.lock_cpu = l->debug.unlock_cpu = 0;
444 l->debug.lock_pc = l->debug.unlock_pc = INVALID_PC;
445 l->debug.lock_thread = l->debug.unlock_thread = INVALID_THREAD;
446 l->debug.duration[0] = l->debug.duration[1] = 0;
447 l->debug.unlock_cpu = l->debug.unlock_cpu = 0;
448 l->debug.unlock_pc = l->debug.unlock_pc = INVALID_PC;
449 l->debug.unlock_thread = l->debug.unlock_thread = INVALID_THREAD;
450 }
451
452
453 /*
454 * These checks apply to all usimple_locks, not just
455 * those with USLOCK_CHECKED turned on.
456 */
457 int
458 usld_lock_common_checks(
459 usimple_lock_t l,
460 char *caller)
461 {
462 if (l == USIMPLE_LOCK_NULL)
463 panic("%s: null lock pointer", caller);
464 if (l->lock_type != USLOCK_TAG)
465 panic("%s: 0x%x is not a usimple lock", caller, (integer_t) l);
466 if (!(l->debug.state & USLOCK_INIT))
467 panic("%s: 0x%x is not an initialized lock",
468 caller, (integer_t) l);
469 return USLOCK_CHECKING(l);
470 }
471
472
473 /*
474 * Debug checks on a usimple_lock just before attempting
475 * to acquire it.
476 */
477 /* ARGSUSED */
478 void
479 usld_lock_pre(
480 usimple_lock_t l,
481 pc_t pc)
482 {
483 char *caller = "usimple_lock";
484
485
486 #if 0
487 printf("*** %08X %08X %04X %02X %08X %02X %08X - %s\n", /* (TEST/DEBUG) */
488 l->debug.lock_pc,
489 l->debug.lock_thread,
490 l->debug.state,
491 l->debug.lock_cpu,
492 l->debug.unlock_thread,
493 l->debug.unlock_cpu,
494 l->debug.unlock_pc,
495 caller);
496 #endif
497
498 if (!usld_lock_common_checks(l, caller))
499 return;
500
501 /*
502 * Note that we have a weird case where we are getting a lock when we are]
503 * in the process of putting the system to sleep. We are running with no
504 * current threads, therefore we can't tell if we are trying to retake a lock
505 * we have or someone on the other processor has it. Therefore we just
506 * ignore this test if the locking thread is 0.
507 */
508
509 if ((l->debug.state & USLOCK_TAKEN) && l->debug.lock_thread &&
510 l->debug.lock_thread == (void *) current_thread()) {
511 printf("%s: lock 0x%x already locked (at 0x%x) by",
512 caller, (integer_t) l, l->debug.lock_pc);
513 printf(" current thread 0x%x (new attempt at pc 0x%x)\n",
514 l->debug.lock_thread, pc);
515 panic(caller);
516 }
517 mp_disable_preemption();
518 usl_trace(l, cpu_number(), pc, caller);
519 mp_enable_preemption();
520 }
521
522
523 /*
524 * Debug checks on a usimple_lock just after acquiring it.
525 *
526 * Pre-emption has been disabled at this point,
527 * so we are safe in using cpu_number.
528 */
529 void
530 usld_lock_post(
531 usimple_lock_t l,
532 pc_t pc)
533 {
534 register int mycpu;
535 char *caller = "successful usimple_lock";
536
537
538 #if 0
539 printf("*** %08X %08X %04X %02X %08X %02X %08X - %s\n", /* (TEST/DEBUG) */
540 l->debug.lock_pc,
541 l->debug.lock_thread,
542 l->debug.state,
543 l->debug.lock_cpu,
544 l->debug.unlock_thread,
545 l->debug.unlock_cpu,
546 l->debug.unlock_pc,
547 caller);
548 #endif
549
550 if (!usld_lock_common_checks(l, caller))
551 return;
552
553 if (!((l->debug.state & ~USLOCK_TAKEN) == USLOCK_INITIALIZED))
554 panic("%s: lock 0x%x became uninitialized",
555 caller, (integer_t) l);
556 if ((l->debug.state & USLOCK_TAKEN))
557 panic("%s: lock 0x%x became TAKEN by someone else",
558 caller, (integer_t) l);
559
560 mycpu = cpu_number();
561 l->debug.lock_thread = (void *)current_thread();
562 l->debug.state |= USLOCK_TAKEN;
563 l->debug.lock_pc = pc;
564 l->debug.lock_cpu = mycpu;
565
566 usl_stack_push(l, mycpu);
567 usl_trace(l, mycpu, pc, caller);
568 }
569
570
571 /*
572 * Debug checks on a usimple_lock just before
573 * releasing it. Note that the caller has not
574 * yet released the hardware lock.
575 *
576 * Preemption is still disabled, so there's
577 * no problem using cpu_number.
578 */
579 void
580 usld_unlock(
581 usimple_lock_t l,
582 pc_t pc)
583 {
584 register int mycpu;
585 char *caller = "usimple_unlock";
586
587
588 #if 0
589 printf("*** %08X %08X %04X %02X %08X %02X %08X - %s\n", /* (TEST/DEBUG) */
590 l->debug.lock_pc,
591 l->debug.lock_thread,
592 l->debug.state,
593 l->debug.lock_cpu,
594 l->debug.unlock_thread,
595 l->debug.unlock_cpu,
596 l->debug.unlock_pc,
597 caller);
598 #endif
599
600 if (!usld_lock_common_checks(l, caller))
601 return;
602
603 mycpu = cpu_number();
604
605 if (!(l->debug.state & USLOCK_TAKEN))
606 panic("%s: lock 0x%x hasn't been taken",
607 caller, (integer_t) l);
608 if (l->debug.lock_thread != (void *) current_thread())
609 panic("%s: unlocking lock 0x%x, owned by thread 0x%x",
610 caller, (integer_t) l, l->debug.lock_thread);
611 if (l->debug.lock_cpu != mycpu) {
612 printf("%s: unlocking lock 0x%x on cpu 0x%x",
613 caller, (integer_t) l, mycpu);
614 printf(" (acquired on cpu 0x%x)\n", l->debug.lock_cpu);
615 panic(caller);
616 }
617 usl_trace(l, mycpu, pc, caller);
618 usl_stack_pop(l, mycpu);
619
620 l->debug.unlock_thread = l->debug.lock_thread;
621 l->debug.lock_thread = INVALID_PC;
622 l->debug.state &= ~USLOCK_TAKEN;
623 l->debug.unlock_pc = pc;
624 l->debug.unlock_cpu = mycpu;
625 }
626
627
628 /*
629 * Debug checks on a usimple_lock just before
630 * attempting to acquire it.
631 *
632 * Preemption isn't guaranteed to be disabled.
633 */
634 void
635 usld_lock_try_pre(
636 usimple_lock_t l,
637 pc_t pc)
638 {
639 char *caller = "usimple_lock_try";
640
641 if (!usld_lock_common_checks(l, caller))
642 return;
643 mp_disable_preemption();
644 usl_trace(l, cpu_number(), pc, caller);
645 mp_enable_preemption();
646 }
647
648
649 /*
650 * Debug checks on a usimple_lock just after
651 * successfully attempting to acquire it.
652 *
653 * Preemption has been disabled by the
654 * lock acquisition attempt, so it's safe
655 * to use cpu_number.
656 */
657 void
658 usld_lock_try_post(
659 usimple_lock_t l,
660 pc_t pc)
661 {
662 register int mycpu;
663 char *caller = "successful usimple_lock_try";
664
665 if (!usld_lock_common_checks(l, caller))
666 return;
667
668 if (!((l->debug.state & ~USLOCK_TAKEN) == USLOCK_INITIALIZED))
669 panic("%s: lock 0x%x became uninitialized",
670 caller, (integer_t) l);
671 if ((l->debug.state & USLOCK_TAKEN))
672 panic("%s: lock 0x%x became TAKEN by someone else",
673 caller, (integer_t) l);
674
675 mycpu = cpu_number();
676 l->debug.lock_thread = (void *) current_thread();
677 l->debug.state |= USLOCK_TAKEN;
678 l->debug.lock_pc = pc;
679 l->debug.lock_cpu = mycpu;
680
681 #if 0
682 printf("*** %08X %08X %04X %02X %08X %02X %08X - %s\n", /* (TEST/DEBUG) */
683 l->debug.lock_pc,
684 l->debug.lock_thread,
685 l->debug.state,
686 l->debug.lock_cpu,
687 l->debug.unlock_thread,
688 l->debug.unlock_cpu,
689 l->debug.unlock_pc,
690 caller);
691 #endif
692
693 usl_stack_push(l, mycpu);
694 usl_trace(l, mycpu, pc, caller);
695 }
696
697
698 /*
699 * Determine whether the lock in question is owned
700 * by the current thread.
701 */
702 void
703 usld_lock_held(
704 usimple_lock_t l)
705 {
706 char *caller = "usimple_lock_held";
707
708
709 #if 0
710 printf("*** %08X %08X %04X %02X %08X %02X %08X - %s\n", /* (TEST/DEBUG) */
711 l->debug.lock_pc,
712 l->debug.lock_thread,
713 l->debug.state,
714 l->debug.lock_cpu,
715 l->debug.unlock_thread,
716 l->debug.unlock_cpu,
717 l->debug.unlock_pc,
718 caller);
719 #endif
720
721 if (!usld_lock_common_checks(l, caller))
722 return;
723
724 if (!(l->debug.state & USLOCK_TAKEN))
725 panic("%s: lock 0x%x hasn't been taken",
726 caller, (integer_t) l);
727 if (l->debug.lock_thread != (void *) current_thread())
728 panic("%s: lock 0x%x is owned by thread 0x%x", caller,
729 (integer_t) l, (integer_t) l->debug.lock_thread);
730
731 /*
732 * The usimple_lock is active, so preemption
733 * is disabled and the current cpu should
734 * match the one recorded at lock acquisition time.
735 */
736 if (l->debug.lock_cpu != cpu_number())
737 panic("%s: current cpu 0x%x isn't acquiring cpu 0x%x",
738 caller, cpu_number(), (integer_t) l->debug.lock_cpu);
739 }
740
741
742 /*
743 * Per-cpu stack of currently active usimple_locks.
744 * Requires spl protection so that interrupt-level
745 * locks plug-n-play with their thread-context friends.
746 */
747 #define USLOCK_STACK_DEPTH 20
748 usimple_lock_t uslock_stack[NCPUS][USLOCK_STACK_DEPTH];
749 unsigned int uslock_stack_index[NCPUS];
750 boolean_t uslock_stack_enabled = FALSE;
751
752
753 /*
754 * Record a usimple_lock just acquired on
755 * the current processor.
756 *
757 * Preemption has been disabled by lock
758 * acquisition, so it's safe to use the cpu number
759 * specified by the caller.
760 */
761 void
762 usl_stack_push(
763 usimple_lock_t l,
764 int mycpu)
765 {
766 boolean_t s;
767
768 if (uslock_stack_enabled == FALSE)
769 return;
770
771 DISABLE_INTERRUPTS(s);
772 assert(uslock_stack_index[mycpu] >= 0);
773 assert(uslock_stack_index[mycpu] < USLOCK_STACK_DEPTH);
774 if (uslock_stack_index[mycpu] >= USLOCK_STACK_DEPTH) {
775 printf("usl_stack_push (cpu 0x%x): too many locks (%d)",
776 mycpu, uslock_stack_index[mycpu]);
777 printf(" disabling stacks\n");
778 uslock_stack_enabled = FALSE;
779 ENABLE_INTERRUPTS(s);
780 return;
781 }
782 uslock_stack[mycpu][uslock_stack_index[mycpu]] = l;
783 uslock_stack_index[mycpu]++;
784 ENABLE_INTERRUPTS(s);
785 }
786
787
788 /*
789 * Eliminate the entry for a usimple_lock
790 * that had been active on the current processor.
791 *
792 * Preemption has been disabled by lock
793 * acquisition, and we haven't yet actually
794 * released the hardware lock associated with
795 * this usimple_lock, so it's safe to use the
796 * cpu number supplied by the caller.
797 */
798 void
799 usl_stack_pop(
800 usimple_lock_t l,
801 int mycpu)
802 {
803 unsigned int i, index;
804 boolean_t s;
805
806 if (uslock_stack_enabled == FALSE)
807 return;
808
809 DISABLE_INTERRUPTS(s);
810 assert(uslock_stack_index[mycpu] > 0);
811 assert(uslock_stack_index[mycpu] <= USLOCK_STACK_DEPTH);
812 if (uslock_stack_index[mycpu] == 0) {
813 printf("usl_stack_pop (cpu 0x%x): not enough locks (%d)",
814 mycpu, uslock_stack_index[mycpu]);
815 printf(" disabling stacks\n");
816 uslock_stack_enabled = FALSE;
817 ENABLE_INTERRUPTS(s);
818 return;
819 }
820 index = --uslock_stack_index[mycpu];
821 for (i = 0; i <= index; ++i) {
822 if (uslock_stack[mycpu][i] == l) {
823 if (i != index)
824 uslock_stack[mycpu][i] =
825 uslock_stack[mycpu][index];
826 ENABLE_INTERRUPTS(s);
827 return;
828 }
829 }
830 ENABLE_INTERRUPTS(s);
831 panic("usl_stack_pop: can't find usimple_lock 0x%x", l);
832 }
833
834
835 /*
836 * Determine whether any usimple_locks are currently held.
837 *
838 * Caller's preemption state is uncertain. If
839 * preemption has been disabled, this check is accurate.
840 * Otherwise, this check is just a guess. We do the best
841 * we can by disabling scheduler interrupts, so at least
842 * the check is accurate w.r.t. whatever cpu we're running
843 * on while in this routine.
844 */
845 void
846 usld_lock_none_held()
847 {
848 register int mycpu;
849 boolean_t s;
850 unsigned int locks_held;
851 char *caller = "usimple_lock_none_held";
852
853 DISABLE_INTERRUPTS(s);
854 mp_disable_preemption();
855 mycpu = cpu_number();
856 locks_held = uslock_stack_index[mycpu];
857 mp_enable_preemption();
858 ENABLE_INTERRUPTS(s);
859 if (locks_held > 0)
860 panic("%s: no locks should be held (0x%x locks held)",
861 caller, (integer_t) locks_held);
862 }
863
864
865 /*
866 * For very special cases, set traced_lock to point to a
867 * specific lock of interest. The result is a series of
868 * XPRs showing lock operations on that lock. The lock_seq
869 * value is used to show the order of those operations.
870 */
871 usimple_lock_t traced_lock;
872 unsigned int lock_seq;
873
874 void
875 usl_trace(
876 usimple_lock_t l,
877 int mycpu,
878 pc_t pc,
879 const char * op_name)
880 {
881 if (traced_lock == l) {
882 XPR(XPR_SLOCK,
883 "seq %d, cpu %d, %s @ %x\n",
884 (integer_t) lock_seq, (integer_t) mycpu,
885 (integer_t) op_name, (integer_t) pc, 0);
886 lock_seq++;
887 }
888 }
889
890
891
892 #if MACH_KDB
893 #define printf kdbprintf
894 void db_show_all_slocks(void);
895 void
896 db_show_all_slocks(void)
897 {
898 unsigned int i, index;
899 int mycpu = cpu_number();
900 usimple_lock_t l;
901
902 if (uslock_stack_enabled == FALSE) {
903 printf("Lock stack not enabled\n");
904 return;
905 }
906
907 #if 0
908 if (!mach_slocks_init)
909 iprintf("WARNING: simple locks stack may not be accurate\n");
910 #endif
911 assert(uslock_stack_index[mycpu] >= 0);
912 assert(uslock_stack_index[mycpu] <= USLOCK_STACK_DEPTH);
913 index = uslock_stack_index[mycpu];
914 for (i = 0; i < index; ++i) {
915 l = uslock_stack[mycpu][i];
916 iprintf("%d: ", i);
917 db_printsym((vm_offset_t)l, DB_STGY_ANY);
918 if (l->debug.lock_pc != INVALID_PC) {
919 printf(" locked by ");
920 db_printsym((int)l->debug.lock_pc, DB_STGY_PROC);
921 }
922 printf("\n");
923 }
924 }
925 #endif /* MACH_KDB */
926
927 #endif /* USLOCK_DEBUG */
928
929 /* #endif USIMPLE_LOCK_CALLS */
930
931 /*
932 * Routine: lock_alloc
933 * Function:
934 * Allocate a lock for external users who cannot
935 * hard-code the structure definition into their
936 * objects.
937 * For now just use kalloc, but a zone is probably
938 * warranted.
939 */
940 lock_t *
941 lock_alloc(
942 boolean_t can_sleep,
943 etap_event_t event,
944 etap_event_t i_event)
945 {
946 lock_t *l;
947
948 if ((l = (lock_t *)kalloc(sizeof(lock_t))) != 0)
949 lock_init(l, can_sleep, event, i_event);
950 return(l);
951 }
952
953 /*
954 * Routine: lock_free
955 * Function:
956 * Free a lock allocated for external users.
957 * For now just use kfree, but a zone is probably
958 * warranted.
959 */
960 void
961 lock_free(
962 lock_t *l)
963 {
964 kfree((vm_offset_t)l, sizeof(lock_t));
965 }
966
967
968 /*
969 * Routine: lock_init
970 * Function:
971 * Initialize a lock; required before use.
972 * Note that clients declare the "struct lock"
973 * variables and then initialize them, rather
974 * than getting a new one from this module.
975 */
976 void
977 lock_init(
978 lock_t *l,
979 boolean_t can_sleep,
980 etap_event_t event,
981 etap_event_t i_event)
982 {
983 (void) memset((void *) l, 0, sizeof(lock_t));
984
985 #if ETAP_LOCK_TRACE
986 etap_event_table_assign(&l->u.event_table_chain, event);
987 l->u.s.start_list = SD_ENTRY_NULL;
988 #endif /* ETAP_LOCK_TRACE */
989
990 simple_lock_init(&l->interlock, i_event);
991 l->want_write = FALSE;
992 l->want_upgrade = FALSE;
993 l->read_count = 0;
994 l->can_sleep = can_sleep;
995
996 #if ETAP_LOCK_ACCUMULATE
997 l->cbuff_write = etap_cbuff_reserve(lock_event_table(l));
998 if (l->cbuff_write != CBUFF_ENTRY_NULL) {
999 l->cbuff_write->event = event;
1000 l->cbuff_write->instance = (unsigned long) l;
1001 l->cbuff_write->kind = WRITE_LOCK;
1002 }
1003 l->cbuff_read = CBUFF_ENTRY_NULL;
1004 #endif /* ETAP_LOCK_ACCUMULATE */
1005 }
1006
1007
1008 /*
1009 * Sleep locks. These use the same data structure and algorithm
1010 * as the spin locks, but the process sleeps while it is waiting
1011 * for the lock. These work on uniprocessor systems.
1012 */
1013
1014 #define DECREMENTER_TIMEOUT 1000000
1015
1016 void
1017 lock_write(
1018 register lock_t * l)
1019 {
1020 register int i;
1021 start_data_node_t entry = {0};
1022 boolean_t lock_miss = FALSE;
1023 unsigned short dynamic = 0;
1024 unsigned short trace = 0;
1025 etap_time_t total_time;
1026 etap_time_t stop_wait_time;
1027 pc_t pc;
1028 #if MACH_LDEBUG
1029 int decrementer;
1030 #endif /* MACH_LDEBUG */
1031
1032
1033 ETAP_STAMP(lock_event_table(l), trace, dynamic);
1034 ETAP_CREATE_ENTRY(entry, trace);
1035 MON_ASSIGN_PC(entry->start_pc, pc, trace);
1036
1037 simple_lock(&l->interlock);
1038
1039 /*
1040 * Link the new start_list entry
1041 */
1042 ETAP_LINK_ENTRY(l, entry, trace);
1043
1044 #if MACH_LDEBUG
1045 decrementer = DECREMENTER_TIMEOUT;
1046 #endif /* MACH_LDEBUG */
1047
1048 /*
1049 * Try to acquire the want_write bit.
1050 */
1051 while (l->want_write) {
1052 if (!lock_miss) {
1053 ETAP_CONTENTION_TIMESTAMP(entry, trace);
1054 lock_miss = TRUE;
1055 }
1056
1057 i = lock_wait_time[l->can_sleep ? 1 : 0];
1058 if (i != 0) {
1059 simple_unlock(&l->interlock);
1060 #if MACH_LDEBUG
1061 if (!--decrementer)
1062 Debugger("timeout - want_write");
1063 #endif /* MACH_LDEBUG */
1064 while (--i != 0 && l->want_write)
1065 continue;
1066 simple_lock(&l->interlock);
1067 }
1068
1069 if (l->can_sleep && l->want_write) {
1070 l->waiting = TRUE;
1071 ETAP_SET_REASON(current_thread(),
1072 BLOCKED_ON_COMPLEX_LOCK);
1073 thread_sleep_simple_lock((event_t) l,
1074 simple_lock_addr(l->interlock),
1075 THREAD_UNINT);
1076 /* interlock relocked */
1077 }
1078 }
1079 l->want_write = TRUE;
1080
1081 /* Wait for readers (and upgrades) to finish */
1082
1083 #if MACH_LDEBUG
1084 decrementer = DECREMENTER_TIMEOUT;
1085 #endif /* MACH_LDEBUG */
1086 while ((l->read_count != 0) || l->want_upgrade) {
1087 if (!lock_miss) {
1088 ETAP_CONTENTION_TIMESTAMP(entry,trace);
1089 lock_miss = TRUE;
1090 }
1091
1092 i = lock_wait_time[l->can_sleep ? 1 : 0];
1093 if (i != 0) {
1094 simple_unlock(&l->interlock);
1095 #if MACH_LDEBUG
1096 if (!--decrementer)
1097 Debugger("timeout - wait for readers");
1098 #endif /* MACH_LDEBUG */
1099 while (--i != 0 && (l->read_count != 0 ||
1100 l->want_upgrade))
1101 continue;
1102 simple_lock(&l->interlock);
1103 }
1104
1105 if (l->can_sleep && (l->read_count != 0 || l->want_upgrade)) {
1106 l->waiting = TRUE;
1107 ETAP_SET_REASON(current_thread(),
1108 BLOCKED_ON_COMPLEX_LOCK);
1109 thread_sleep_simple_lock((event_t) l,
1110 simple_lock_addr(l->interlock),
1111 THREAD_UNINT);
1112 /* interlock relocked */
1113 }
1114 }
1115
1116 /*
1117 * do not collect wait data if either the lock
1118 * was free or no wait traces are enabled.
1119 */
1120
1121 if (lock_miss && ETAP_CONTENTION_ENABLED(trace)) {
1122 ETAP_TIMESTAMP(stop_wait_time);
1123 ETAP_TOTAL_TIME(total_time,
1124 stop_wait_time,
1125 entry->start_wait_time);
1126 CUM_WAIT_ACCUMULATE(l->cbuff_write, total_time, dynamic, trace);
1127 MON_DATA_COLLECT(l,
1128 entry,
1129 total_time,
1130 WRITE_LOCK,
1131 MON_CONTENTION,
1132 trace);
1133 }
1134
1135 simple_unlock(&l->interlock);
1136
1137 /*
1138 * Set start hold time if some type of hold tracing is enabled.
1139 *
1140 * Note: if the stop_wait_time was already stamped, use
1141 * it as the start_hold_time instead of doing an
1142 * expensive bus access.
1143 *
1144 */
1145
1146 if (lock_miss && ETAP_CONTENTION_ENABLED(trace))
1147 ETAP_COPY_START_HOLD_TIME(entry, stop_wait_time, trace);
1148 else
1149 ETAP_DURATION_TIMESTAMP(entry, trace);
1150
1151 }
1152
1153 void
1154 lock_done(
1155 register lock_t * l)
1156 {
1157 boolean_t do_wakeup = FALSE;
1158 start_data_node_t entry;
1159 unsigned short dynamic = 0;
1160 unsigned short trace = 0;
1161 etap_time_t stop_hold_time;
1162 etap_time_t total_time;
1163 unsigned long lock_kind;
1164 pc_t pc;
1165
1166
1167 ETAP_STAMP(lock_event_table(l), trace, dynamic);
1168
1169 simple_lock(&l->interlock);
1170
1171 if (l->read_count != 0) {
1172 l->read_count--;
1173 lock_kind = READ_LOCK;
1174 }
1175 else
1176 if (l->want_upgrade) {
1177 l->want_upgrade = FALSE;
1178 lock_kind = WRITE_LOCK;
1179 }
1180 else {
1181 l->want_write = FALSE;
1182 lock_kind = WRITE_LOCK;
1183 }
1184
1185 /*
1186 * There is no reason to wakeup a waiting thread
1187 * if the read-count is non-zero. Consider:
1188 * we must be dropping a read lock
1189 * threads are waiting only if one wants a write lock
1190 * if there are still readers, they can't proceed
1191 */
1192
1193 if (l->waiting && (l->read_count == 0)) {
1194 l->waiting = FALSE;
1195 do_wakeup = TRUE;
1196 }
1197 /*
1198 * Collect hold data if hold tracing is
1199 * enabled.
1200 */
1201
1202 /*
1203 * NOTE: All complex locks whose tracing was on when the
1204 * lock was acquired will have an entry in the start_data
1205 * list.
1206 */
1207
1208 ETAP_UNLINK_ENTRY(l,entry);
1209 if (ETAP_DURATION_ENABLED(trace) && entry != SD_ENTRY_NULL) {
1210 ETAP_TIMESTAMP (stop_hold_time);
1211 ETAP_TOTAL_TIME (total_time,
1212 stop_hold_time,
1213 entry->start_hold_time);
1214
1215 if (lock_kind & WRITE_LOCK)
1216 CUM_HOLD_ACCUMULATE (l->cbuff_write,
1217 total_time,
1218 dynamic,
1219 trace);
1220 else {
1221 CUM_READ_ENTRY_RESERVE(l,l->cbuff_read,trace);
1222 CUM_HOLD_ACCUMULATE (l->cbuff_read,
1223 total_time,
1224 dynamic,
1225 trace);
1226 }
1227 MON_ASSIGN_PC(entry->end_pc,pc,trace);
1228 MON_DATA_COLLECT(l,entry,
1229 total_time,
1230 lock_kind,
1231 MON_DURATION,
1232 trace);
1233 }
1234
1235 simple_unlock(&l->interlock);
1236
1237 ETAP_DESTROY_ENTRY(entry);
1238
1239 if (do_wakeup)
1240 thread_wakeup((event_t) l);
1241 }
1242
1243 void
1244 lock_read(
1245 register lock_t * l)
1246 {
1247 register int i;
1248 start_data_node_t entry = {0};
1249 boolean_t lock_miss = FALSE;
1250 unsigned short dynamic = 0;
1251 unsigned short trace = 0;
1252 etap_time_t total_time;
1253 etap_time_t stop_wait_time;
1254 pc_t pc;
1255 #if MACH_LDEBUG
1256 int decrementer;
1257 #endif /* MACH_LDEBUG */
1258
1259 ETAP_STAMP(lock_event_table(l), trace, dynamic);
1260 ETAP_CREATE_ENTRY(entry, trace);
1261 MON_ASSIGN_PC(entry->start_pc, pc, trace);
1262
1263 simple_lock(&l->interlock);
1264
1265 /*
1266 * Link the new start_list entry
1267 */
1268 ETAP_LINK_ENTRY(l,entry,trace);
1269
1270 #if MACH_LDEBUG
1271 decrementer = DECREMENTER_TIMEOUT;
1272 #endif /* MACH_LDEBUG */
1273 while (l->want_write || l->want_upgrade) {
1274 if (!lock_miss) {
1275 ETAP_CONTENTION_TIMESTAMP(entry, trace);
1276 lock_miss = TRUE;
1277 }
1278
1279 i = lock_wait_time[l->can_sleep ? 1 : 0];
1280
1281 if (i != 0) {
1282 simple_unlock(&l->interlock);
1283 #if MACH_LDEBUG
1284 if (!--decrementer)
1285 Debugger("timeout - wait no writers");
1286 #endif /* MACH_LDEBUG */
1287 while (--i != 0 && (l->want_write || l->want_upgrade))
1288 continue;
1289 simple_lock(&l->interlock);
1290 }
1291
1292 if (l->can_sleep && (l->want_write || l->want_upgrade)) {
1293 l->waiting = TRUE;
1294 thread_sleep_simple_lock((event_t) l,
1295 simple_lock_addr(l->interlock),
1296 THREAD_UNINT);
1297 /* interlock relocked */
1298 }
1299 }
1300
1301 l->read_count++;
1302
1303 /*
1304 * Do not collect wait data if the lock was free
1305 * or if no wait traces are enabled.
1306 */
1307
1308 if (lock_miss && ETAP_CONTENTION_ENABLED(trace)) {
1309 ETAP_TIMESTAMP(stop_wait_time);
1310 ETAP_TOTAL_TIME(total_time,
1311 stop_wait_time,
1312 entry->start_wait_time);
1313 CUM_READ_ENTRY_RESERVE(l, l->cbuff_read, trace);
1314 CUM_WAIT_ACCUMULATE(l->cbuff_read, total_time, dynamic, trace);
1315 MON_DATA_COLLECT(l,
1316 entry,
1317 total_time,
1318 READ_LOCK,
1319 MON_CONTENTION,
1320 trace);
1321 }
1322 simple_unlock(&l->interlock);
1323
1324 /*
1325 * Set start hold time if some type of hold tracing is enabled.
1326 *
1327 * Note: if the stop_wait_time was already stamped, use
1328 * it instead of doing an expensive bus access.
1329 *
1330 */
1331
1332 if (lock_miss && ETAP_CONTENTION_ENABLED(trace))
1333 ETAP_COPY_START_HOLD_TIME(entry, stop_wait_time, trace);
1334 else
1335 ETAP_DURATION_TIMESTAMP(entry,trace);
1336 }
1337
1338
1339 /*
1340 * Routine: lock_read_to_write
1341 * Function:
1342 * Improves a read-only lock to one with
1343 * write permission. If another reader has
1344 * already requested an upgrade to a write lock,
1345 * no lock is held upon return.
1346 *
1347 * Returns TRUE if the upgrade *failed*.
1348 */
1349
1350 boolean_t
1351 lock_read_to_write(
1352 register lock_t * l)
1353 {
1354 register int i;
1355 boolean_t do_wakeup = FALSE;
1356 start_data_node_t entry = {0};
1357 boolean_t lock_miss = FALSE;
1358 unsigned short dynamic = 0;
1359 unsigned short trace = 0;
1360 etap_time_t total_time;
1361 etap_time_t stop_time;
1362 pc_t pc;
1363 #if MACH_LDEBUG
1364 int decrementer;
1365 #endif /* MACH_LDEBUG */
1366
1367
1368 ETAP_STAMP(lock_event_table(l), trace, dynamic);
1369
1370 simple_lock(&l->interlock);
1371
1372 l->read_count--;
1373
1374 /*
1375 * Since the read lock is lost whether the write lock
1376 * is acquired or not, read hold data is collected here.
1377 * This, of course, is assuming some type of hold
1378 * tracing is enabled.
1379 *
1380 * Note: trace is set to zero if the entry does not exist.
1381 */
1382
1383 ETAP_FIND_ENTRY(l, entry, trace);
1384
1385 if (ETAP_DURATION_ENABLED(trace)) {
1386 ETAP_TIMESTAMP(stop_time);
1387 ETAP_TOTAL_TIME(total_time, stop_time, entry->start_hold_time);
1388 CUM_HOLD_ACCUMULATE(l->cbuff_read, total_time, dynamic, trace);
1389 MON_ASSIGN_PC(entry->end_pc, pc, trace);
1390 MON_DATA_COLLECT(l,
1391 entry,
1392 total_time,
1393 READ_LOCK,
1394 MON_DURATION,
1395 trace);
1396 }
1397
1398 if (l->want_upgrade) {
1399 /*
1400 * Someone else has requested upgrade.
1401 * Since we've released a read lock, wake
1402 * him up.
1403 */
1404 if (l->waiting && (l->read_count == 0)) {
1405 l->waiting = FALSE;
1406 do_wakeup = TRUE;
1407 }
1408
1409 ETAP_UNLINK_ENTRY(l, entry);
1410 simple_unlock(&l->interlock);
1411 ETAP_DESTROY_ENTRY(entry);
1412
1413 if (do_wakeup)
1414 thread_wakeup((event_t) l);
1415 return (TRUE);
1416 }
1417
1418 l->want_upgrade = TRUE;
1419
1420 MON_ASSIGN_PC(entry->start_pc, pc, trace);
1421
1422 #if MACH_LDEBUG
1423 decrementer = DECREMENTER_TIMEOUT;
1424 #endif /* MACH_LDEBUG */
1425 while (l->read_count != 0) {
1426 if (!lock_miss) {
1427 ETAP_CONTENTION_TIMESTAMP(entry, trace);
1428 lock_miss = TRUE;
1429 }
1430
1431 i = lock_wait_time[l->can_sleep ? 1 : 0];
1432
1433 if (i != 0) {
1434 simple_unlock(&l->interlock);
1435 #if MACH_LDEBUG
1436 if (!--decrementer)
1437 Debugger("timeout - read_count");
1438 #endif /* MACH_LDEBUG */
1439 while (--i != 0 && l->read_count != 0)
1440 continue;
1441 simple_lock(&l->interlock);
1442 }
1443
1444 if (l->can_sleep && l->read_count != 0) {
1445 l->waiting = TRUE;
1446 thread_sleep_simple_lock((event_t) l,
1447 simple_lock_addr(l->interlock),
1448 THREAD_UNINT);
1449 /* interlock relocked */
1450 }
1451 }
1452
1453 /*
1454 * do not collect wait data if the lock was free
1455 * or if no wait traces are enabled.
1456 */
1457
1458 if (lock_miss && ETAP_CONTENTION_ENABLED(trace)) {
1459 ETAP_TIMESTAMP (stop_time);
1460 ETAP_TOTAL_TIME(total_time, stop_time, entry->start_wait_time);
1461 CUM_WAIT_ACCUMULATE(l->cbuff_write, total_time, dynamic, trace);
1462 MON_DATA_COLLECT(l,
1463 entry,
1464 total_time,
1465 WRITE_LOCK,
1466 MON_CONTENTION,
1467 trace);
1468 }
1469
1470 simple_unlock(&l->interlock);
1471
1472 /*
1473 * Set start hold time if some type of hold tracing is enabled
1474 *
1475 * Note: if the stop_time was already stamped, use
1476 * it as the new start_hold_time instead of doing
1477 * an expensive VME access.
1478 *
1479 */
1480
1481 if (lock_miss && ETAP_CONTENTION_ENABLED(trace))
1482 ETAP_COPY_START_HOLD_TIME(entry, stop_time, trace);
1483 else
1484 ETAP_DURATION_TIMESTAMP(entry, trace);
1485
1486 return (FALSE);
1487 }
1488
1489 void
1490 lock_write_to_read(
1491 register lock_t * l)
1492 {
1493 boolean_t do_wakeup = FALSE;
1494 start_data_node_t entry = {0};
1495 unsigned short dynamic = 0;
1496 unsigned short trace = 0;
1497 etap_time_t stop_hold_time;
1498 etap_time_t total_time;
1499 pc_t pc;
1500
1501 ETAP_STAMP(lock_event_table(l), trace,dynamic);
1502
1503 simple_lock(&l->interlock);
1504
1505 l->read_count++;
1506 if (l->want_upgrade)
1507 l->want_upgrade = FALSE;
1508 else
1509 l->want_write = FALSE;
1510
1511 if (l->waiting) {
1512 l->waiting = FALSE;
1513 do_wakeup = TRUE;
1514 }
1515
1516 /*
1517 * Since we are switching from a write lock to a read lock,
1518 * the write lock data is stored and the read lock data
1519 * collection begins.
1520 *
1521 * Note: trace is set to zero if the entry does not exist.
1522 */
1523
1524 ETAP_FIND_ENTRY(l, entry, trace);
1525
1526 if (ETAP_DURATION_ENABLED(trace)) {
1527 ETAP_TIMESTAMP (stop_hold_time);
1528 ETAP_TOTAL_TIME(total_time, stop_hold_time, entry->start_hold_time);
1529 CUM_HOLD_ACCUMULATE(l->cbuff_write, total_time, dynamic, trace);
1530 MON_ASSIGN_PC(entry->end_pc, pc, trace);
1531 MON_DATA_COLLECT(l,
1532 entry,
1533 total_time,
1534 WRITE_LOCK,
1535 MON_DURATION,
1536 trace);
1537 }
1538
1539 simple_unlock(&l->interlock);
1540
1541 /*
1542 * Set start hold time if some type of hold tracing is enabled
1543 *
1544 * Note: if the stop_hold_time was already stamped, use
1545 * it as the new start_hold_time instead of doing
1546 * an expensive bus access.
1547 *
1548 */
1549
1550 if (ETAP_DURATION_ENABLED(trace))
1551 ETAP_COPY_START_HOLD_TIME(entry, stop_hold_time, trace);
1552 else
1553 ETAP_DURATION_TIMESTAMP(entry, trace);
1554
1555 MON_ASSIGN_PC(entry->start_pc, pc, trace);
1556
1557 if (do_wakeup)
1558 thread_wakeup((event_t) l);
1559 }
1560
1561
1562 #if 0 /* Unused */
1563 /*
1564 * Routine: lock_try_write
1565 * Function:
1566 * Tries to get a write lock.
1567 *
1568 * Returns FALSE if the lock is not held on return.
1569 */
1570
1571 boolean_t
1572 lock_try_write(
1573 register lock_t * l)
1574 {
1575 start_data_node_t entry = {0};
1576 unsigned short trace = 0;
1577 pc_t pc;
1578
1579 ETAP_STAMP(lock_event_table(l), trace, trace);
1580 ETAP_CREATE_ENTRY(entry, trace);
1581
1582 simple_lock(&l->interlock);
1583
1584 if (l->want_write || l->want_upgrade || l->read_count) {
1585 /*
1586 * Can't get lock.
1587 */
1588 simple_unlock(&l->interlock);
1589 ETAP_DESTROY_ENTRY(entry);
1590 return(FALSE);
1591 }
1592
1593 /*
1594 * Have lock.
1595 */
1596
1597 l->want_write = TRUE;
1598
1599 ETAP_LINK_ENTRY(l, entry, trace);
1600
1601 simple_unlock(&l->interlock);
1602
1603 MON_ASSIGN_PC(entry->start_pc, pc, trace);
1604 ETAP_DURATION_TIMESTAMP(entry, trace);
1605
1606 return(TRUE);
1607 }
1608
1609 /*
1610 * Routine: lock_try_read
1611 * Function:
1612 * Tries to get a read lock.
1613 *
1614 * Returns FALSE if the lock is not held on return.
1615 */
1616
1617 boolean_t
1618 lock_try_read(
1619 register lock_t * l)
1620 {
1621 start_data_node_t entry = {0};
1622 unsigned short trace = 0;
1623 pc_t pc;
1624
1625 ETAP_STAMP(lock_event_table(l), trace, trace);
1626 ETAP_CREATE_ENTRY(entry, trace);
1627
1628 simple_lock(&l->interlock);
1629
1630 if (l->want_write || l->want_upgrade) {
1631 simple_unlock(&l->interlock);
1632 ETAP_DESTROY_ENTRY(entry);
1633 return(FALSE);
1634 }
1635
1636 l->read_count++;
1637
1638 ETAP_LINK_ENTRY(l, entry, trace);
1639
1640 simple_unlock(&l->interlock);
1641
1642 MON_ASSIGN_PC(entry->start_pc, pc, trace);
1643 ETAP_DURATION_TIMESTAMP(entry, trace);
1644
1645 return(TRUE);
1646 }
1647 #endif /* Unused */
1648
1649 #if MACH_KDB
1650
1651 void db_show_one_lock(lock_t *);
1652
1653
1654 void
1655 db_show_one_lock(
1656 lock_t *lock)
1657 {
1658 db_printf("Read_count = 0x%x, %swant_upgrade, %swant_write, ",
1659 lock->read_count,
1660 lock->want_upgrade ? "" : "!",
1661 lock->want_write ? "" : "!");
1662 db_printf("%swaiting, %scan_sleep\n",
1663 lock->waiting ? "" : "!", lock->can_sleep ? "" : "!");
1664 db_printf("Interlock:\n");
1665 db_show_one_simple_lock((db_expr_t)simple_lock_addr(lock->interlock),
1666 TRUE, (db_expr_t)0, (char *)0);
1667 }
1668 #endif /* MACH_KDB */
1669
1670 /*
1671 * The C portion of the mutex package. These routines are only invoked
1672 * if the optimized assembler routines can't do the work.
1673 */
1674
1675 /*
1676 * Routine: lock_alloc
1677 * Function:
1678 * Allocate a mutex for external users who cannot
1679 * hard-code the structure definition into their
1680 * objects.
1681 * For now just use kalloc, but a zone is probably
1682 * warranted.
1683 */
1684 mutex_t *
1685 mutex_alloc(
1686 etap_event_t event)
1687 {
1688 mutex_t *m;
1689
1690 if ((m = (mutex_t *)kalloc(sizeof(mutex_t))) != 0)
1691 mutex_init(m, event);
1692 return(m);
1693 }
1694
1695 /*
1696 * Routine: mutex_free
1697 * Function:
1698 * Free a mutex allocated for external users.
1699 * For now just use kfree, but a zone is probably
1700 * warranted.
1701 */
1702 void
1703 mutex_free(
1704 mutex_t *m)
1705 {
1706 kfree((vm_offset_t)m, sizeof(mutex_t));
1707 }
1708
1709 /*
1710 * mutex_lock_wait
1711 *
1712 * Invoked in order to wait on contention.
1713 *
1714 * Called with the interlock locked and
1715 * returns it unlocked.
1716 */
1717 void
1718 mutex_lock_wait (
1719 mutex_t *mutex,
1720 thread_t holder)
1721 {
1722 thread_t self = current_thread();
1723 #if !defined(i386)
1724 integer_t priority;
1725 spl_t s = splsched();
1726
1727 priority = self->sched_pri;
1728 if (priority < self->priority)
1729 priority = self->priority;
1730 if (priority > MINPRI_KERNEL)
1731 priority = MINPRI_KERNEL;
1732 else
1733 if (priority < BASEPRI_DEFAULT)
1734 priority = BASEPRI_DEFAULT;
1735
1736 assert(holder->thread == holder); /* XXX */
1737 thread_lock(holder);
1738 if (mutex->promoted_pri == 0)
1739 holder->promotions++;
1740 if (holder->priority < MINPRI_KERNEL) {
1741 holder->sched_mode |= TH_MODE_PROMOTED;
1742 if ( mutex->promoted_pri < priority &&
1743 holder->sched_pri < priority ) {
1744 KERNEL_DEBUG_CONSTANT(
1745 MACHDBG_CODE(DBG_MACH_SCHED,MACH_PROMOTE) | DBG_FUNC_NONE,
1746 holder->sched_pri, priority, (int)holder, (int)mutex, 0);
1747
1748 set_sched_pri(holder, priority);
1749 }
1750 }
1751 thread_unlock(holder);
1752 splx(s);
1753
1754 if (mutex->promoted_pri < priority)
1755 mutex->promoted_pri = priority;
1756 #endif
1757
1758 if (self->pending_promoter[self->pending_promoter_index] == NULL) {
1759 self->pending_promoter[self->pending_promoter_index] = mutex;
1760 mutex->waiters++;
1761 }
1762 else
1763 if (self->pending_promoter[self->pending_promoter_index] != mutex) {
1764 self->pending_promoter[++self->pending_promoter_index] = mutex;
1765 mutex->waiters++;
1766 }
1767
1768 assert_wait(mutex, THREAD_UNINT);
1769 interlock_unlock(&mutex->interlock);
1770
1771 thread_block(THREAD_CONTINUE_NULL);
1772 }
1773
1774 /*
1775 * mutex_lock_acquire
1776 *
1777 * Invoked on acquiring the mutex when there is
1778 * contention.
1779 *
1780 * Returns the current number of waiters.
1781 *
1782 * Called with the interlock locked.
1783 */
1784 int
1785 mutex_lock_acquire(
1786 mutex_t *mutex)
1787 {
1788 thread_t thread = current_thread();
1789
1790 if (thread->pending_promoter[thread->pending_promoter_index] == mutex) {
1791 thread->pending_promoter[thread->pending_promoter_index] = NULL;
1792 if (thread->pending_promoter_index > 0)
1793 thread->pending_promoter_index--;
1794 mutex->waiters--;
1795 }
1796
1797 #if !defined(i386)
1798 if (mutex->waiters > 0) {
1799 integer_t priority = mutex->promoted_pri;
1800 spl_t s = splsched();
1801
1802 thread_lock(thread);
1803 thread->promotions++;
1804 if (thread->priority < MINPRI_KERNEL) {
1805 thread->sched_mode |= TH_MODE_PROMOTED;
1806 if (thread->sched_pri < priority) {
1807 KERNEL_DEBUG_CONSTANT(
1808 MACHDBG_CODE(DBG_MACH_SCHED,MACH_PROMOTE) | DBG_FUNC_NONE,
1809 thread->sched_pri, priority, 0, (int)mutex, 0);
1810
1811 set_sched_pri(thread, priority);
1812 }
1813 }
1814 thread_unlock(thread);
1815 splx(s);
1816 }
1817 else
1818 mutex->promoted_pri = 0;
1819 #endif
1820
1821 return (mutex->waiters);
1822 }
1823
1824 /*
1825 * mutex_unlock_wakeup
1826 *
1827 * Invoked on unlock when there is contention.
1828 *
1829 * Called with the interlock locked.
1830 */
1831 void
1832 mutex_unlock_wakeup (
1833 mutex_t *mutex,
1834 thread_t holder)
1835 {
1836 #if !defined(i386)
1837 thread_t thread = current_thread();
1838
1839 if (thread->top_act != holder)
1840 panic("mutex_unlock_wakeup: mutex %x holder %x\n", mutex, holder);
1841
1842 if (thread->promotions > 0) {
1843 spl_t s = splsched();
1844
1845 thread_lock(thread);
1846 if ( --thread->promotions == 0 &&
1847 (thread->sched_mode & TH_MODE_PROMOTED) ) {
1848 thread->sched_mode &= ~TH_MODE_PROMOTED;
1849 if (thread->sched_mode & TH_MODE_ISDEPRESSED) {
1850 KERNEL_DEBUG_CONSTANT(
1851 MACHDBG_CODE(DBG_MACH_SCHED,MACH_DEMOTE) | DBG_FUNC_NONE,
1852 thread->sched_pri, DEPRESSPRI, 0, (int)mutex, 0);
1853
1854 set_sched_pri(thread, DEPRESSPRI);
1855 }
1856 else {
1857 if (thread->priority < thread->sched_pri) {
1858 KERNEL_DEBUG_CONSTANT(
1859 MACHDBG_CODE(DBG_MACH_SCHED,MACH_DEMOTE) |
1860 DBG_FUNC_NONE,
1861 thread->sched_pri, thread->priority,
1862 0, (int)mutex, 0);
1863 }
1864
1865 compute_priority(thread, FALSE);
1866 }
1867 }
1868 thread_unlock(thread);
1869 splx(s);
1870 }
1871 #endif
1872
1873 assert(mutex->waiters > 0);
1874 thread_wakeup_one(mutex);
1875 }
1876
1877 boolean_t
1878 mutex_preblock_wait(
1879 mutex_t *mutex,
1880 thread_t thread,
1881 thread_t holder)
1882 {
1883 wait_result_t wresult;
1884 integer_t priority;
1885 wait_queue_t wq;
1886
1887 assert(holder == NULL || holder->thread == holder);
1888
1889 wq = wait_event_wait_queue((event_t)mutex);
1890 if (!wait_queue_lock_try(wq))
1891 return (FALSE);
1892
1893 if (holder != NULL && !thread_lock_try(holder)) {
1894 wait_queue_unlock(wq);
1895 return (FALSE);
1896 }
1897
1898 wresult = wait_queue_assert_wait64_locked(wq, (uint32_t)mutex,
1899 THREAD_UNINT, thread);
1900 wait_queue_unlock(wq);
1901 assert(wresult == THREAD_WAITING);
1902
1903 priority = thread->sched_pri;
1904 if (priority < thread->priority)
1905 priority = thread->priority;
1906 if (priority > MINPRI_KERNEL)
1907 priority = MINPRI_KERNEL;
1908 else
1909 if (priority < BASEPRI_DEFAULT)
1910 priority = BASEPRI_DEFAULT;
1911
1912 if (holder != NULL) {
1913 if (mutex->promoted_pri == 0)
1914 holder->promotions++;
1915 if (holder->priority < MINPRI_KERNEL) {
1916 holder->sched_mode |= TH_MODE_PROMOTED;
1917 if ( mutex->promoted_pri < priority &&
1918 holder->sched_pri < priority ) {
1919 KERNEL_DEBUG_CONSTANT(
1920 MACHDBG_CODE(DBG_MACH_SCHED,MACH_PROMOTE) | DBG_FUNC_NONE,
1921 holder->sched_pri, priority,
1922 (int)holder, (int)mutex, 0);
1923
1924 set_sched_pri(holder, priority);
1925 }
1926 }
1927 thread_unlock(holder);
1928 }
1929
1930 if (mutex->promoted_pri < priority)
1931 mutex->promoted_pri = priority;
1932
1933 if (thread->pending_promoter[thread->pending_promoter_index] == NULL) {
1934 thread->pending_promoter[thread->pending_promoter_index] = mutex;
1935 mutex->waiters++;
1936 }
1937 else
1938 if (thread->pending_promoter[thread->pending_promoter_index] != mutex) {
1939 thread->pending_promoter[++thread->pending_promoter_index] = mutex;
1940 mutex->waiters++;
1941 }
1942
1943 KERNEL_DEBUG_CONSTANT(
1944 MACHDBG_CODE(DBG_MACH_SCHED,MACH_PREBLOCK_MUTEX) | DBG_FUNC_NONE,
1945 (int)thread, thread->sched_pri, (int)mutex, 0, 0);
1946
1947 return (TRUE);
1948 }
1949
1950 /*
1951 * mutex_pause: Called by former callers of simple_lock_pause().
1952 */
1953
1954 void
1955 mutex_pause(void)
1956 {
1957 wait_result_t wait_result;
1958
1959 wait_result = assert_wait_timeout( 1, THREAD_UNINT);
1960 assert(wait_result == THREAD_WAITING);
1961
1962 ETAP_SET_REASON(current_thread(), BLOCKED_ON_MUTEX_LOCK);
1963
1964 wait_result = thread_block(THREAD_CONTINUE_NULL);
1965 assert(wait_result == THREAD_TIMED_OUT);
1966 }
1967
1968 #if MACH_KDB
1969 /*
1970 * Routines to print out simple_locks and mutexes in a nicely-formatted
1971 * fashion.
1972 */
1973
1974 char *simple_lock_labels = "ENTRY ILK THREAD DURATION CALLER";
1975 char *mutex_labels = "ENTRY LOCKED WAITERS THREAD CALLER";
1976
1977 void
1978 db_show_one_simple_lock (
1979 db_expr_t addr,
1980 boolean_t have_addr,
1981 db_expr_t count,
1982 char * modif)
1983 {
1984 simple_lock_t saddr = (simple_lock_t)addr;
1985
1986 if (saddr == (simple_lock_t)0 || !have_addr) {
1987 db_error ("No simple_lock\n");
1988 }
1989 #if USLOCK_DEBUG
1990 else if (saddr->lock_type != USLOCK_TAG)
1991 db_error ("Not a simple_lock\n");
1992 #endif /* USLOCK_DEBUG */
1993
1994 db_printf ("%s\n", simple_lock_labels);
1995 db_print_simple_lock (saddr);
1996 }
1997
1998 void
1999 db_print_simple_lock (
2000 simple_lock_t addr)
2001 {
2002
2003 db_printf ("%08x %3d", addr, *hw_lock_addr(addr->interlock));
2004 #if USLOCK_DEBUG
2005 db_printf (" %08x", addr->debug.lock_thread);
2006 db_printf (" %08x ", addr->debug.duration[1]);
2007 db_printsym ((int)addr->debug.lock_pc, DB_STGY_ANY);
2008 #endif /* USLOCK_DEBUG */
2009 db_printf ("\n");
2010 }
2011
2012 void
2013 db_show_one_mutex (
2014 db_expr_t addr,
2015 boolean_t have_addr,
2016 db_expr_t count,
2017 char * modif)
2018 {
2019 mutex_t * maddr = (mutex_t *)addr;
2020
2021 if (maddr == (mutex_t *)0 || !have_addr)
2022 db_error ("No mutex\n");
2023 #if MACH_LDEBUG
2024 else if (maddr->type != MUTEX_TAG)
2025 db_error ("Not a mutex\n");
2026 #endif /* MACH_LDEBUG */
2027
2028 db_printf ("%s\n", mutex_labels);
2029 db_print_mutex (maddr);
2030 }
2031
2032 void
2033 db_print_mutex (
2034 mutex_t * addr)
2035 {
2036 db_printf ("%08x %6d %7d",
2037 addr, *hw_lock_addr(addr->locked), addr->waiters);
2038 #if MACH_LDEBUG
2039 db_printf (" %08x ", addr->thread);
2040 db_printsym (addr->pc, DB_STGY_ANY);
2041 #endif /* MACH_LDEBUG */
2042 db_printf ("\n");
2043 }
2044 #endif /* MACH_KDB */
2045
2046 #if MACH_LDEBUG
2047 extern void meter_simple_lock (
2048 simple_lock_t l);
2049 extern void meter_simple_unlock (
2050 simple_lock_t l);
2051 extern void cyctm05_stamp (
2052 unsigned long * start);
2053 extern void cyctm05_diff (
2054 unsigned long * start,
2055 unsigned long * end,
2056 unsigned long * diff);
2057
2058 #if 0
2059 simple_lock_data_t loser;
2060 #endif
2061
2062 void
2063 meter_simple_lock(
2064 simple_lock_t lp)
2065 {
2066 #if 0
2067 cyctm05_stamp (lp->duration);
2068 #endif
2069 }
2070
2071 int long_simple_lock_crash;
2072 int long_simple_lock_time = 0x600;
2073 /*
2074 * This is pretty gawd-awful. XXX
2075 */
2076 decl_simple_lock_data(extern,kd_tty)
2077
2078 void
2079 meter_simple_unlock(
2080 simple_lock_t lp)
2081 {
2082 #if 0
2083 unsigned long stime[2], etime[2], delta[2];
2084
2085 if (lp == &kd_tty) /* XXX */
2086 return; /* XXX */
2087
2088 stime[0] = lp->duration[0];
2089 stime[1] = lp->duration[1];
2090
2091 cyctm05_stamp (etime);
2092
2093 if (etime[1] < stime[1]) /* XXX */
2094 return; /* XXX */
2095
2096 cyctm05_diff (stime, etime, delta);
2097
2098 if (delta[1] >= 0x10000) /* XXX */
2099 return; /* XXX */
2100
2101 lp->duration[0] = delta[0];
2102 lp->duration[1] = delta[1];
2103
2104 if (loser.duration[1] < lp->duration[1])
2105 loser = *lp;
2106
2107 assert (!long_simple_lock_crash || delta[1] < long_simple_lock_time);
2108 #endif
2109 }
2110 #endif /* MACH_LDEBUG */
2111
2112
2113 #if ETAP_LOCK_TRACE
2114
2115 /*
2116 * ==============================================================
2117 * ETAP hook when initializing a usimple_lock. May be invoked
2118 * from the portable lock package or from an optimized machine-
2119 * dependent implementation.
2120 * ==============================================================
2121 */
2122
2123 void
2124 etap_simplelock_init (
2125 simple_lock_t l,
2126 etap_event_t event)
2127 {
2128 ETAP_CLEAR_TRACE_DATA(l);
2129 etap_event_table_assign(&l->u.event_table_chain, event);
2130
2131 #if ETAP_LOCK_ACCUMULATE
2132 /* reserve an entry in the cumulative buffer */
2133 l->cbuff_entry = etap_cbuff_reserve(lock_event_table(l));
2134 /* initialize the entry if one was returned */
2135 if (l->cbuff_entry != CBUFF_ENTRY_NULL) {
2136 l->cbuff_entry->event = event;
2137 l->cbuff_entry->instance = (unsigned long) l;
2138 l->cbuff_entry->kind = SPIN_LOCK;
2139 }
2140 #endif /* ETAP_LOCK_ACCUMULATE */
2141 }
2142
2143
2144 void
2145 etap_simplelock_unlock(
2146 simple_lock_t l)
2147 {
2148 unsigned short dynamic = 0;
2149 unsigned short trace = 0;
2150 etap_time_t total_time;
2151 etap_time_t stop_hold_time;
2152 pc_t pc;
2153
2154 OBTAIN_PC(pc, l);
2155 ETAP_STAMP(lock_event_table(l), trace, dynamic);
2156
2157 /*
2158 * Calculate & collect hold time data only if
2159 * the hold tracing was enabled throughout the
2160 * whole operation. This prevents collection of
2161 * bogus data caused by mid-operation trace changes.
2162 *
2163 */
2164
2165 if (ETAP_DURATION_ENABLED(trace) && ETAP_WHOLE_OP(l)) {
2166 ETAP_TIMESTAMP (stop_hold_time);
2167 ETAP_TOTAL_TIME(total_time, stop_hold_time,
2168 l->u.s.start_hold_time);
2169 CUM_HOLD_ACCUMULATE(l->cbuff_entry, total_time, dynamic, trace);
2170 MON_ASSIGN_PC(l->end_pc, pc, trace);
2171 MON_DATA_COLLECT(l,
2172 l,
2173 total_time,
2174 SPIN_LOCK,
2175 MON_DURATION,
2176 trace);
2177 }
2178 ETAP_CLEAR_TRACE_DATA(l);
2179 }
2180
2181 /* ========================================================================
2182 * Since the the simple_lock() routine is machine dependant, it must always
2183 * be coded in assembly. The two hook routines below are used to collect
2184 * lock_stat data.
2185 * ========================================================================
2186 */
2187
2188 /*
2189 * ROUTINE: etap_simplelock_miss()
2190 *
2191 * FUNCTION: This spin lock routine is called upon the first
2192 * spin (miss) of the lock.
2193 *
2194 * A timestamp is taken at the beginning of the wait period,
2195 * if wait tracing is enabled.
2196 *
2197 *
2198 * PARAMETERS:
2199 * - lock address.
2200 * - timestamp address.
2201 *
2202 * RETURNS: Wait timestamp value. The timestamp value is later used
2203 * by etap_simplelock_hold().
2204 *
2205 * NOTES: This routine is NOT ALWAYS called. The lock may be free
2206 * (never spinning). For this reason the pc is collected in
2207 * etap_simplelock_hold().
2208 *
2209 */
2210 etap_time_t
2211 etap_simplelock_miss (
2212 simple_lock_t l)
2213
2214 {
2215 unsigned short trace = 0;
2216 unsigned short dynamic = 0;
2217 etap_time_t start_miss_time;
2218
2219 ETAP_STAMP(lock_event_table(l), trace, dynamic);
2220
2221 if (trace & ETAP_CONTENTION)
2222 ETAP_TIMESTAMP(start_miss_time);
2223
2224 return(start_miss_time);
2225 }
2226
2227 /*
2228 * ROUTINE: etap_simplelock_hold()
2229 *
2230 * FUNCTION: This spin lock routine is ALWAYS called once the lock
2231 * is acquired. Here, the contention time is calculated and
2232 * the start hold time is stamped.
2233 *
2234 * PARAMETERS:
2235 * - lock address.
2236 * - PC of the calling function.
2237 * - start wait timestamp.
2238 *
2239 */
2240
2241 void
2242 etap_simplelock_hold (
2243 simple_lock_t l,
2244 pc_t pc,
2245 etap_time_t start_hold_time)
2246 {
2247 unsigned short dynamic = 0;
2248 unsigned short trace = 0;
2249 etap_time_t total_time;
2250 etap_time_t stop_hold_time;
2251
2252 ETAP_STAMP(lock_event_table(l), trace, dynamic);
2253
2254 MON_ASSIGN_PC(l->start_pc, pc, trace);
2255
2256 /* do not collect wait data if lock was free */
2257 if (ETAP_TIME_IS_ZERO(start_hold_time) && (trace & ETAP_CONTENTION)) {
2258 ETAP_TIMESTAMP(stop_hold_time);
2259 ETAP_TOTAL_TIME(total_time,
2260 stop_hold_time,
2261 start_hold_time);
2262 CUM_WAIT_ACCUMULATE(l->cbuff_entry, total_time, dynamic, trace);
2263 MON_DATA_COLLECT(l,
2264 l,
2265 total_time,
2266 SPIN_LOCK,
2267 MON_CONTENTION,
2268 trace);
2269 ETAP_COPY_START_HOLD_TIME(&l->u.s, stop_hold_time, trace);
2270 }
2271 else
2272 ETAP_DURATION_TIMESTAMP(&l->u.s, trace);
2273 }
2274
2275 void
2276 etap_mutex_init (
2277 mutex_t *l,
2278 etap_event_t event)
2279 {
2280 ETAP_CLEAR_TRACE_DATA(l);
2281 etap_event_table_assign(&l->u.event_table_chain, event);
2282
2283 #if ETAP_LOCK_ACCUMULATE
2284 /* reserve an entry in the cumulative buffer */
2285 l->cbuff_entry = etap_cbuff_reserve(lock_event_table(l));
2286 /* initialize the entry if one was returned */
2287 if (l->cbuff_entry != CBUFF_ENTRY_NULL) {
2288 l->cbuff_entry->event = event;
2289 l->cbuff_entry->instance = (unsigned long) l;
2290 l->cbuff_entry->kind = MUTEX_LOCK;
2291 }
2292 #endif /* ETAP_LOCK_ACCUMULATE */
2293 }
2294
2295 etap_time_t
2296 etap_mutex_miss (
2297 mutex_t *l)
2298 {
2299 unsigned short trace = 0;
2300 unsigned short dynamic = 0;
2301 etap_time_t start_miss_time;
2302
2303 ETAP_STAMP(lock_event_table(l), trace, dynamic);
2304
2305 if (trace & ETAP_CONTENTION)
2306 ETAP_TIMESTAMP(start_miss_time);
2307 else
2308 ETAP_TIME_CLEAR(start_miss_time);
2309
2310 return(start_miss_time);
2311 }
2312
2313 void
2314 etap_mutex_hold (
2315 mutex_t *l,
2316 pc_t pc,
2317 etap_time_t start_hold_time)
2318 {
2319 unsigned short dynamic = 0;
2320 unsigned short trace = 0;
2321 etap_time_t total_time;
2322 etap_time_t stop_hold_time;
2323
2324 ETAP_STAMP(lock_event_table(l), trace, dynamic);
2325
2326 MON_ASSIGN_PC(l->start_pc, pc, trace);
2327
2328 /* do not collect wait data if lock was free */
2329 if (!ETAP_TIME_IS_ZERO(start_hold_time) && (trace & ETAP_CONTENTION)) {
2330 ETAP_TIMESTAMP(stop_hold_time);
2331 ETAP_TOTAL_TIME(total_time,
2332 stop_hold_time,
2333 start_hold_time);
2334 CUM_WAIT_ACCUMULATE(l->cbuff_entry, total_time, dynamic, trace);
2335 MON_DATA_COLLECT(l,
2336 l,
2337 total_time,
2338 MUTEX_LOCK,
2339 MON_CONTENTION,
2340 trace);
2341 ETAP_COPY_START_HOLD_TIME(&l->u.s, stop_hold_time, trace);
2342 }
2343 else
2344 ETAP_DURATION_TIMESTAMP(&l->u.s, trace);
2345 }
2346
2347 void
2348 etap_mutex_unlock(
2349 mutex_t *l)
2350 {
2351 unsigned short dynamic = 0;
2352 unsigned short trace = 0;
2353 etap_time_t total_time;
2354 etap_time_t stop_hold_time;
2355 pc_t pc;
2356
2357 OBTAIN_PC(pc, l);
2358 ETAP_STAMP(lock_event_table(l), trace, dynamic);
2359
2360 /*
2361 * Calculate & collect hold time data only if
2362 * the hold tracing was enabled throughout the
2363 * whole operation. This prevents collection of
2364 * bogus data caused by mid-operation trace changes.
2365 *
2366 */
2367
2368 if (ETAP_DURATION_ENABLED(trace) && ETAP_WHOLE_OP(l)) {
2369 ETAP_TIMESTAMP(stop_hold_time);
2370 ETAP_TOTAL_TIME(total_time, stop_hold_time,
2371 l->u.s.start_hold_time);
2372 CUM_HOLD_ACCUMULATE(l->cbuff_entry, total_time, dynamic, trace);
2373 MON_ASSIGN_PC(l->end_pc, pc, trace);
2374 MON_DATA_COLLECT(l,
2375 l,
2376 total_time,
2377 MUTEX_LOCK,
2378 MON_DURATION,
2379 trace);
2380 }
2381 ETAP_CLEAR_TRACE_DATA(l);
2382 }
2383
2384 #endif /* ETAP_LOCK_TRACE */