|
|
1.1 root 1: /*
2: * Mach Operating System
3: * Copyright (c) 1991,1990,1989,1988,1987 Carnegie Mellon University.
4: * Copyright (c) 1993,1994 The University of Utah and
5: * the Computer Systems Laboratory (CSL).
6: * All rights reserved.
7: *
8: * Permission to use, copy, modify and distribute this software and its
9: * documentation is hereby granted, provided that both the copyright
10: * notice and this permission notice appear in all copies of the
11: * software, derivative works or modified versions, and any portions
12: * thereof, and that both notices appear in supporting documentation.
13: *
14: * CARNEGIE MELLON, THE UNIVERSITY OF UTAH AND CSL ALLOW FREE USE OF
15: * THIS SOFTWARE IN ITS "AS IS" CONDITION, AND DISCLAIM ANY LIABILITY
16: * OF ANY KIND FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF
17: * THIS SOFTWARE.
18: *
19: * Carnegie Mellon requests users of this software to return to
20: *
21: * Software Distribution Coordinator or [email protected]
22: * School of Computer Science
23: * Carnegie Mellon University
24: * Pittsburgh PA 15213-3890
25: *
26: * any improvements or extensions that they make and grant Carnegie Mellon
27: * the rights to redistribute these changes.
28: */
29: /*
30: * File: kern/lock.c
31: * Author: Avadis Tevanian, Jr., Michael Wayne Young
32: * Date: 1985
33: *
34: * Locking primitives implementation
35: */
36:
1.1.1.2 root 37: #include <string.h>
1.1 root 38:
1.1.1.2 root 39: #include <kern/debug.h>
1.1 root 40: #include <kern/lock.h>
41: #include <kern/thread.h>
42: #include <kern/sched_prim.h>
43: #if MACH_KDB
44: #include <machine/db_machdep.h>
1.1.1.2 root 45: #include <ddb/db_output.h>
1.1 root 46: #include <ddb/db_sym.h>
47: #endif
48:
49:
50: #if NCPUS > 1
51:
52: /*
53: * Module: lock
54: * Function:
55: * Provide reader/writer sychronization.
56: * Implementation:
57: * Simple interlock on a bit. Readers first interlock,
58: * increment the reader count, then let go. Writers hold
59: * the interlock (thus preventing further readers), and
60: * wait for already-accepted readers to go away.
61: */
62:
63: /*
64: * The simple-lock routines are the primitives out of which
65: * the lock package is built. The implementation is left
66: * to the machine-dependent code.
67: */
68:
69: #ifdef notdef
70: /*
71: * A sample implementation of simple locks.
72: * assumes:
73: * boolean_t test_and_set(boolean_t *)
74: * indivisibly sets the boolean to TRUE
75: * and returns its old value
76: * and that setting a boolean to FALSE is indivisible.
77: */
78: /*
79: * simple_lock_init initializes a simple lock. A simple lock
80: * may only be used for exclusive locks.
81: */
82:
83: void simple_lock_init(simple_lock_t l)
84: {
85: *(boolean_t *)l = FALSE;
86: }
87:
88: void simple_lock(simple_lock_t l)
89: {
90: while (test_and_set((boolean_t *)l))
91: continue;
92: }
93:
94: void simple_unlock(simple_lock_t l)
95: {
96: *(boolean_t *)l = FALSE;
97: }
98:
99: boolean_t simple_lock_try(simple_lock_t l)
100: {
101: return (!test_and_set((boolean_t *)l));
102: }
103: #endif /* notdef */
104: #endif /* NCPUS > 1 */
105:
106: #if NCPUS > 1
1.1.1.2 root 107: static int lock_wait_time = 100;
1.1 root 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: */
1.1.1.2 root 115: static int lock_wait_time = 0;
1.1 root 116: #endif /* NCPUS > 1 */
117:
118: #if MACH_SLOCKS && NCPUS == 1
119: /*
120: * This code does not protect simple_locks_taken and simple_locks_info.
121: * It works despite the fact that interrupt code does use simple locks.
122: * This is because interrupts use locks in a stack-like manner.
123: * Each interrupt releases all the locks it acquires, so the data
124: * structures end up in the same state after the interrupt as before.
125: * The only precaution necessary is that simple_locks_taken be
126: * incremented first and decremented last, so that interrupt handlers
127: * don't over-write active slots in simple_locks_info.
128: */
129:
130: unsigned int simple_locks_taken = 0;
131:
132: #define NSLINFO 1000 /* maximum number of locks held */
133:
134: struct simple_locks_info {
135: simple_lock_t l;
1.1.1.4 ! root 136: const char *expr;
! 137: const char *loc;
1.1 root 138: } simple_locks_info[NSLINFO];
139:
1.1.1.4 ! root 140: int do_check_simple_locks = 1;
! 141:
1.1 root 142: void check_simple_locks(void)
143: {
1.1.1.4 ! root 144: assert(! do_check_simple_locks || simple_locks_taken == 0);
! 145: }
! 146:
! 147: void check_simple_locks_enable(void)
! 148: {
! 149: do_check_simple_locks = 1;
! 150: }
! 151:
! 152: void check_simple_locks_disable(void)
! 153: {
! 154: do_check_simple_locks = 0;
1.1 root 155: }
156:
157: /* Need simple lock sanity checking code if simple locks are being
158: compiled in, and we are compiling for a uniprocessor. */
159:
160: void simple_lock_init(
161: simple_lock_t l)
162: {
163: l->lock_data = 0;
164: }
165:
1.1.1.4 ! root 166: void _simple_lock(
! 167: simple_lock_t l,
! 168: const char *expression,
! 169: const char *location)
1.1 root 170: {
171: struct simple_locks_info *info;
172:
173: assert(l->lock_data == 0);
174:
175: l->lock_data = 1;
176:
177: info = &simple_locks_info[simple_locks_taken++];
178: info->l = l;
1.1.1.4 ! root 179: info->expr = expression;
! 180: info->loc = location;
1.1 root 181: }
182:
1.1.1.4 ! root 183: boolean_t _simple_lock_try(
! 184: simple_lock_t l,
! 185: const char *expression,
! 186: const char *location)
1.1 root 187: {
188: struct simple_locks_info *info;
189:
190: if (l->lock_data != 0)
191: return FALSE;
192:
193: l->lock_data = 1;
194:
195: info = &simple_locks_info[simple_locks_taken++];
196: info->l = l;
1.1.1.4 ! root 197: info->expr = expression;
! 198: info->loc = location;
1.1 root 199:
200: return TRUE;
201: }
202:
203: void simple_unlock(
204: simple_lock_t l)
205: {
206: assert(l->lock_data != 0);
207:
208: l->lock_data = 0;
209:
210: if (simple_locks_info[simple_locks_taken-1].l != l) {
211: unsigned int i = simple_locks_taken;
212:
213: /* out-of-order unlocking */
214:
215: do
216: if (i == 0)
217: panic("simple_unlock");
218: while (simple_locks_info[--i].l != l);
219:
220: simple_locks_info[i] = simple_locks_info[simple_locks_taken-1];
221: }
222: simple_locks_taken--;
1.1.1.4 ! root 223: simple_locks_info[simple_locks_taken] = (struct simple_locks_info) {0};
1.1 root 224: }
225:
226: #endif /* MACH_SLOCKS && NCPUS == 1 */
227:
228: /*
229: * Routine: lock_init
230: * Function:
231: * Initialize a lock; required before use.
232: * Note that clients declare the "struct lock"
233: * variables and then initialize them, rather
234: * than getting a new one from this module.
235: */
236: void lock_init(
237: lock_t l,
238: boolean_t can_sleep)
239: {
1.1.1.2 root 240: memset(l, 0, sizeof(lock_data_t));
1.1 root 241: simple_lock_init(&l->interlock);
242: l->want_write = FALSE;
243: l->want_upgrade = FALSE;
244: l->read_count = 0;
245: l->can_sleep = can_sleep;
246: l->thread = (struct thread *)-1; /* XXX */
247: l->recursion_depth = 0;
248: }
249:
250: void lock_sleepable(
251: lock_t l,
252: boolean_t can_sleep)
253: {
254: simple_lock(&l->interlock);
255: l->can_sleep = can_sleep;
256: simple_unlock(&l->interlock);
257: }
258:
259:
260: /*
261: * Sleep locks. These use the same data structure and algorithm
262: * as the spin locks, but the process sleeps while it is waiting
263: * for the lock. These work on uniprocessor systems.
264: */
265:
266: void lock_write(
1.1.1.3 root 267: lock_t l)
1.1 root 268: {
1.1.1.3 root 269: int i;
1.1 root 270:
271: check_simple_locks();
272: simple_lock(&l->interlock);
273:
274: if (l->thread == current_thread()) {
275: /*
276: * Recursive lock.
277: */
278: l->recursion_depth++;
279: simple_unlock(&l->interlock);
280: return;
281: }
282:
283: /*
284: * Try to acquire the want_write bit.
285: */
286: while (l->want_write) {
287: if ((i = lock_wait_time) > 0) {
288: simple_unlock(&l->interlock);
289: while (--i > 0 && l->want_write)
290: continue;
291: simple_lock(&l->interlock);
292: }
293:
294: if (l->can_sleep && l->want_write) {
295: l->waiting = TRUE;
296: thread_sleep(l,
297: simple_lock_addr(l->interlock), FALSE);
298: simple_lock(&l->interlock);
299: }
300: }
301: l->want_write = TRUE;
302:
303: /* Wait for readers (and upgrades) to finish */
304:
305: while ((l->read_count != 0) || l->want_upgrade) {
306: if ((i = lock_wait_time) > 0) {
307: simple_unlock(&l->interlock);
308: while (--i > 0 && (l->read_count != 0 ||
309: l->want_upgrade))
310: continue;
311: simple_lock(&l->interlock);
312: }
313:
314: if (l->can_sleep && (l->read_count != 0 || l->want_upgrade)) {
315: l->waiting = TRUE;
316: thread_sleep(l,
317: simple_lock_addr(l->interlock), FALSE);
318: simple_lock(&l->interlock);
319: }
320: }
1.1.1.4 ! root 321: #if MACH_LDEBUG
! 322: l->writer = current_thread();
! 323: #endif /* MACH_LDEBUG */
1.1 root 324: simple_unlock(&l->interlock);
325: }
326:
327: void lock_done(
1.1.1.3 root 328: lock_t l)
1.1 root 329: {
330: simple_lock(&l->interlock);
331:
332: if (l->read_count != 0)
333: l->read_count--;
334: else
335: if (l->recursion_depth != 0)
336: l->recursion_depth--;
337: else
338: if (l->want_upgrade)
339: l->want_upgrade = FALSE;
1.1.1.4 ! root 340: else {
1.1 root 341: l->want_write = FALSE;
1.1.1.4 ! root 342: #if MACH_LDEBUG
! 343: l->writer = THREAD_NULL;
! 344: #endif /* MACH_LDEBUG */
! 345: }
1.1 root 346:
347: /*
348: * There is no reason to wakeup a waiting thread
349: * if the read-count is non-zero. Consider:
350: * we must be dropping a read lock
351: * threads are waiting only if one wants a write lock
352: * if there are still readers, they can't proceed
353: */
354:
355: if (l->waiting && (l->read_count == 0)) {
356: l->waiting = FALSE;
357: thread_wakeup(l);
358: }
359:
360: simple_unlock(&l->interlock);
361: }
362:
363: void lock_read(
1.1.1.3 root 364: lock_t l)
1.1 root 365: {
1.1.1.3 root 366: int i;
1.1 root 367:
368: check_simple_locks();
369: simple_lock(&l->interlock);
370:
371: if (l->thread == current_thread()) {
372: /*
373: * Recursive lock.
374: */
375: l->read_count++;
376: simple_unlock(&l->interlock);
377: return;
378: }
379:
380: while (l->want_write || l->want_upgrade) {
381: if ((i = lock_wait_time) > 0) {
382: simple_unlock(&l->interlock);
383: while (--i > 0 && (l->want_write || l->want_upgrade))
384: continue;
385: simple_lock(&l->interlock);
386: }
387:
388: if (l->can_sleep && (l->want_write || l->want_upgrade)) {
389: l->waiting = TRUE;
390: thread_sleep(l,
391: simple_lock_addr(l->interlock), FALSE);
392: simple_lock(&l->interlock);
393: }
394: }
395:
396: l->read_count++;
397: simple_unlock(&l->interlock);
398: }
399:
400: /*
401: * Routine: lock_read_to_write
402: * Function:
403: * Improves a read-only lock to one with
404: * write permission. If another reader has
405: * already requested an upgrade to a write lock,
406: * no lock is held upon return.
407: *
408: * Returns TRUE if the upgrade *failed*.
409: */
410: boolean_t lock_read_to_write(
1.1.1.3 root 411: lock_t l)
1.1 root 412: {
1.1.1.3 root 413: int i;
1.1 root 414:
415: check_simple_locks();
416: simple_lock(&l->interlock);
417:
418: l->read_count--;
419:
420: if (l->thread == current_thread()) {
421: /*
422: * Recursive lock.
423: */
424: l->recursion_depth++;
425: simple_unlock(&l->interlock);
426: return(FALSE);
427: }
428:
429: if (l->want_upgrade) {
430: /*
431: * Someone else has requested upgrade.
432: * Since we've released a read lock, wake
433: * him up.
434: */
435: if (l->waiting && (l->read_count == 0)) {
436: l->waiting = FALSE;
437: thread_wakeup(l);
438: }
439:
440: simple_unlock(&l->interlock);
441: return TRUE;
442: }
443:
444: l->want_upgrade = TRUE;
445:
446: while (l->read_count != 0) {
447: if ((i = lock_wait_time) > 0) {
448: simple_unlock(&l->interlock);
449: while (--i > 0 && l->read_count != 0)
450: continue;
451: simple_lock(&l->interlock);
452: }
453:
454: if (l->can_sleep && l->read_count != 0) {
455: l->waiting = TRUE;
456: thread_sleep(l,
457: simple_lock_addr(l->interlock), FALSE);
458: simple_lock(&l->interlock);
459: }
460: }
461:
1.1.1.4 ! root 462: #if MACH_LDEBUG
! 463: l->writer = current_thread();
! 464: #endif /* MACH_LDEBUG */
1.1 root 465: simple_unlock(&l->interlock);
466: return FALSE;
467: }
468:
469: void lock_write_to_read(
1.1.1.3 root 470: lock_t l)
1.1 root 471: {
472: simple_lock(&l->interlock);
1.1.1.4 ! root 473: #if MACH_LDEBUG
! 474: assert(l->writer == current_thread());
! 475: #endif /* MACH_LDEBUG */
1.1 root 476:
477: l->read_count++;
478: if (l->recursion_depth != 0)
479: l->recursion_depth--;
480: else
481: if (l->want_upgrade)
482: l->want_upgrade = FALSE;
483: else
484: l->want_write = FALSE;
485:
486: if (l->waiting) {
487: l->waiting = FALSE;
488: thread_wakeup(l);
489: }
490:
1.1.1.4 ! root 491: #if MACH_LDEBUG
! 492: l->writer = THREAD_NULL;
! 493: #endif /* MACH_LDEBUG */
1.1 root 494: simple_unlock(&l->interlock);
495: }
496:
497:
498: /*
499: * Routine: lock_try_write
500: * Function:
501: * Tries to get a write lock.
502: *
503: * Returns FALSE if the lock is not held on return.
504: */
505:
506: boolean_t lock_try_write(
1.1.1.3 root 507: lock_t l)
1.1 root 508: {
509: simple_lock(&l->interlock);
510:
511: if (l->thread == current_thread()) {
512: /*
513: * Recursive lock
514: */
515: l->recursion_depth++;
516: simple_unlock(&l->interlock);
517: return TRUE;
518: }
519:
520: if (l->want_write || l->want_upgrade || l->read_count) {
521: /*
522: * Can't get lock.
523: */
524: simple_unlock(&l->interlock);
525: return FALSE;
526: }
527:
528: /*
529: * Have lock.
530: */
531:
532: l->want_write = TRUE;
1.1.1.4 ! root 533: #if MACH_LDEBUG
! 534: l->writer = current_thread();
! 535: #endif /* MACH_LDEBUG */
1.1 root 536: simple_unlock(&l->interlock);
537: return TRUE;
538: }
539:
540: /*
541: * Routine: lock_try_read
542: * Function:
543: * Tries to get a read lock.
544: *
545: * Returns FALSE if the lock is not held on return.
546: */
547:
548: boolean_t lock_try_read(
1.1.1.3 root 549: lock_t l)
1.1 root 550: {
551: simple_lock(&l->interlock);
552:
553: if (l->thread == current_thread()) {
554: /*
555: * Recursive lock
556: */
557: l->read_count++;
558: simple_unlock(&l->interlock);
559: return TRUE;
560: }
561:
562: if (l->want_write || l->want_upgrade) {
563: simple_unlock(&l->interlock);
564: return FALSE;
565: }
566:
567: l->read_count++;
568: simple_unlock(&l->interlock);
569: return TRUE;
570: }
571:
572: /*
573: * Routine: lock_try_read_to_write
574: * Function:
575: * Improves a read-only lock to one with
576: * write permission. If another reader has
577: * already requested an upgrade to a write lock,
578: * the read lock is still held upon return.
579: *
580: * Returns FALSE if the upgrade *failed*.
581: */
582: boolean_t lock_try_read_to_write(
1.1.1.3 root 583: lock_t l)
1.1 root 584: {
585: check_simple_locks();
586: simple_lock(&l->interlock);
587:
588: if (l->thread == current_thread()) {
589: /*
590: * Recursive lock
591: */
592: l->read_count--;
593: l->recursion_depth++;
594: simple_unlock(&l->interlock);
595: return TRUE;
596: }
597:
598: if (l->want_upgrade) {
599: simple_unlock(&l->interlock);
600: return FALSE;
601: }
602: l->want_upgrade = TRUE;
603: l->read_count--;
604:
605: while (l->read_count != 0) {
606: l->waiting = TRUE;
607: thread_sleep(l,
608: simple_lock_addr(l->interlock), FALSE);
609: simple_lock(&l->interlock);
610: }
611:
1.1.1.4 ! root 612: #if MACH_LDEBUG
! 613: l->writer = current_thread();
! 614: #endif /* MACH_LDEBUG */
1.1 root 615: simple_unlock(&l->interlock);
616: return TRUE;
617: }
618:
619: /*
620: * Allow a process that has a lock for write to acquire it
621: * recursively (for read, write, or update).
622: */
623: void lock_set_recursive(
624: lock_t l)
625: {
626: simple_lock(&l->interlock);
1.1.1.4 ! root 627: #if MACH_LDEBUG
! 628: assert(l->writer == current_thread());
! 629: #endif /* MACH_LDEBUG */
! 630:
1.1 root 631: if (!l->want_write) {
632: panic("lock_set_recursive: don't have write lock");
633: }
634: l->thread = current_thread();
635: simple_unlock(&l->interlock);
636: }
637:
638: /*
639: * Prevent a lock from being re-acquired.
640: */
641: void lock_clear_recursive(
642: lock_t l)
643: {
644: simple_lock(&l->interlock);
645: if (l->thread != current_thread()) {
646: panic("lock_clear_recursive: wrong thread");
647: }
648: if (l->recursion_depth == 0)
649: l->thread = (struct thread *)-1; /* XXX */
650: simple_unlock(&l->interlock);
651: }
652:
653: #if MACH_KDB
654: #if MACH_SLOCKS && NCPUS == 1
655: void db_show_all_slocks(void)
656: {
657: int i;
658: struct simple_locks_info *info;
659: simple_lock_t l;
660:
661: for (i = 0; i < simple_locks_taken; i++) {
662: info = &simple_locks_info[i];
1.1.1.4 ! root 663: db_printf("%d: %s (", i, info->expr);
1.1 root 664: db_printsym(info->l, DB_STGY_ANY);
1.1.1.4 ! root 665: db_printf(") locked by %s\n", info->loc);
1.1 root 666: }
667: }
668: #else /* MACH_SLOCKS && NCPUS == 1 */
669: void db_show_all_slocks(void)
670: {
671: db_printf("simple lock info not available\n");
672: }
673: #endif /* MACH_SLOCKS && NCPUS == 1 */
674: #endif /* MACH_KDB */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.