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