|
|
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++];
1.1.1.5 ! root 178: barrier();
1.1 root 179: info->l = l;
1.1.1.4 root 180: info->expr = expression;
181: info->loc = location;
1.1 root 182: }
183:
1.1.1.4 root 184: boolean_t _simple_lock_try(
185: simple_lock_t l,
186: const char *expression,
187: const char *location)
1.1 root 188: {
189: struct simple_locks_info *info;
190:
191: if (l->lock_data != 0)
192: return FALSE;
193:
194: l->lock_data = 1;
195:
196: info = &simple_locks_info[simple_locks_taken++];
1.1.1.5 ! root 197: barrier();
1.1 root 198: info->l = l;
1.1.1.4 root 199: info->expr = expression;
200: info->loc = location;
1.1 root 201:
202: return TRUE;
203: }
204:
205: void simple_unlock(
206: simple_lock_t l)
207: {
208: assert(l->lock_data != 0);
209:
210: l->lock_data = 0;
211:
212: if (simple_locks_info[simple_locks_taken-1].l != l) {
213: unsigned int i = simple_locks_taken;
214:
215: /* out-of-order unlocking */
216:
217: do
218: if (i == 0)
219: panic("simple_unlock");
220: while (simple_locks_info[--i].l != l);
221:
222: simple_locks_info[i] = simple_locks_info[simple_locks_taken-1];
223: }
1.1.1.5 ! root 224: barrier();
1.1 root 225: simple_locks_taken--;
1.1.1.4 root 226: simple_locks_info[simple_locks_taken] = (struct simple_locks_info) {0};
1.1 root 227: }
228:
229: #endif /* MACH_SLOCKS && NCPUS == 1 */
230:
231: /*
232: * Routine: lock_init
233: * Function:
234: * Initialize a lock; required before use.
235: * Note that clients declare the "struct lock"
236: * variables and then initialize them, rather
237: * than getting a new one from this module.
238: */
239: void lock_init(
240: lock_t l,
241: boolean_t can_sleep)
242: {
1.1.1.2 root 243: memset(l, 0, sizeof(lock_data_t));
1.1 root 244: simple_lock_init(&l->interlock);
245: l->want_write = FALSE;
246: l->want_upgrade = FALSE;
247: l->read_count = 0;
248: l->can_sleep = can_sleep;
249: l->thread = (struct thread *)-1; /* XXX */
250: l->recursion_depth = 0;
251: }
252:
253: void lock_sleepable(
254: lock_t l,
255: boolean_t can_sleep)
256: {
257: simple_lock(&l->interlock);
258: l->can_sleep = can_sleep;
259: simple_unlock(&l->interlock);
260: }
261:
262:
263: /*
264: * Sleep locks. These use the same data structure and algorithm
265: * as the spin locks, but the process sleeps while it is waiting
266: * for the lock. These work on uniprocessor systems.
267: */
268:
269: void lock_write(
1.1.1.3 root 270: lock_t l)
1.1 root 271: {
1.1.1.3 root 272: int i;
1.1 root 273:
274: check_simple_locks();
275: simple_lock(&l->interlock);
276:
277: if (l->thread == current_thread()) {
278: /*
279: * Recursive lock.
280: */
281: l->recursion_depth++;
282: simple_unlock(&l->interlock);
283: return;
284: }
285:
286: /*
287: * Try to acquire the want_write bit.
288: */
289: while (l->want_write) {
290: if ((i = lock_wait_time) > 0) {
291: simple_unlock(&l->interlock);
292: while (--i > 0 && l->want_write)
293: continue;
294: simple_lock(&l->interlock);
295: }
296:
297: if (l->can_sleep && l->want_write) {
298: l->waiting = TRUE;
299: thread_sleep(l,
300: simple_lock_addr(l->interlock), FALSE);
301: simple_lock(&l->interlock);
302: }
303: }
304: l->want_write = TRUE;
305:
306: /* Wait for readers (and upgrades) to finish */
307:
308: while ((l->read_count != 0) || l->want_upgrade) {
309: if ((i = lock_wait_time) > 0) {
310: simple_unlock(&l->interlock);
311: while (--i > 0 && (l->read_count != 0 ||
312: l->want_upgrade))
313: continue;
314: simple_lock(&l->interlock);
315: }
316:
317: if (l->can_sleep && (l->read_count != 0 || l->want_upgrade)) {
318: l->waiting = TRUE;
319: thread_sleep(l,
320: simple_lock_addr(l->interlock), FALSE);
321: simple_lock(&l->interlock);
322: }
323: }
1.1.1.4 root 324: #if MACH_LDEBUG
325: l->writer = current_thread();
326: #endif /* MACH_LDEBUG */
1.1 root 327: simple_unlock(&l->interlock);
328: }
329:
330: void lock_done(
1.1.1.3 root 331: lock_t l)
1.1 root 332: {
333: simple_lock(&l->interlock);
334:
335: if (l->read_count != 0)
336: l->read_count--;
337: else
338: if (l->recursion_depth != 0)
339: l->recursion_depth--;
340: else
341: if (l->want_upgrade)
342: l->want_upgrade = FALSE;
1.1.1.4 root 343: else {
1.1 root 344: l->want_write = FALSE;
1.1.1.4 root 345: #if MACH_LDEBUG
346: l->writer = THREAD_NULL;
347: #endif /* MACH_LDEBUG */
348: }
1.1 root 349:
350: /*
351: * There is no reason to wakeup a waiting thread
352: * if the read-count is non-zero. Consider:
353: * we must be dropping a read lock
354: * threads are waiting only if one wants a write lock
355: * if there are still readers, they can't proceed
356: */
357:
358: if (l->waiting && (l->read_count == 0)) {
359: l->waiting = FALSE;
360: thread_wakeup(l);
361: }
362:
363: simple_unlock(&l->interlock);
364: }
365:
366: void lock_read(
1.1.1.3 root 367: lock_t l)
1.1 root 368: {
1.1.1.3 root 369: int i;
1.1 root 370:
371: check_simple_locks();
372: simple_lock(&l->interlock);
373:
374: if (l->thread == current_thread()) {
375: /*
376: * Recursive lock.
377: */
378: l->read_count++;
379: simple_unlock(&l->interlock);
380: return;
381: }
382:
383: while (l->want_write || l->want_upgrade) {
384: if ((i = lock_wait_time) > 0) {
385: simple_unlock(&l->interlock);
386: while (--i > 0 && (l->want_write || l->want_upgrade))
387: continue;
388: simple_lock(&l->interlock);
389: }
390:
391: if (l->can_sleep && (l->want_write || l->want_upgrade)) {
392: l->waiting = TRUE;
393: thread_sleep(l,
394: simple_lock_addr(l->interlock), FALSE);
395: simple_lock(&l->interlock);
396: }
397: }
398:
399: l->read_count++;
400: simple_unlock(&l->interlock);
401: }
402:
403: /*
404: * Routine: lock_read_to_write
405: * Function:
406: * Improves a read-only lock to one with
407: * write permission. If another reader has
408: * already requested an upgrade to a write lock,
409: * no lock is held upon return.
410: *
411: * Returns TRUE if the upgrade *failed*.
412: */
413: boolean_t lock_read_to_write(
1.1.1.3 root 414: lock_t l)
1.1 root 415: {
1.1.1.3 root 416: int i;
1.1 root 417:
418: check_simple_locks();
419: simple_lock(&l->interlock);
420:
421: l->read_count--;
422:
423: if (l->thread == current_thread()) {
424: /*
425: * Recursive lock.
426: */
427: l->recursion_depth++;
428: simple_unlock(&l->interlock);
429: return(FALSE);
430: }
431:
432: if (l->want_upgrade) {
433: /*
434: * Someone else has requested upgrade.
435: * Since we've released a read lock, wake
436: * him up.
437: */
438: if (l->waiting && (l->read_count == 0)) {
439: l->waiting = FALSE;
440: thread_wakeup(l);
441: }
442:
443: simple_unlock(&l->interlock);
444: return TRUE;
445: }
446:
447: l->want_upgrade = TRUE;
448:
449: while (l->read_count != 0) {
450: if ((i = lock_wait_time) > 0) {
451: simple_unlock(&l->interlock);
452: while (--i > 0 && l->read_count != 0)
453: continue;
454: simple_lock(&l->interlock);
455: }
456:
457: if (l->can_sleep && l->read_count != 0) {
458: l->waiting = TRUE;
459: thread_sleep(l,
460: simple_lock_addr(l->interlock), FALSE);
461: simple_lock(&l->interlock);
462: }
463: }
464:
1.1.1.4 root 465: #if MACH_LDEBUG
466: l->writer = current_thread();
467: #endif /* MACH_LDEBUG */
1.1 root 468: simple_unlock(&l->interlock);
469: return FALSE;
470: }
471:
472: void lock_write_to_read(
1.1.1.3 root 473: lock_t l)
1.1 root 474: {
475: simple_lock(&l->interlock);
1.1.1.4 root 476: #if MACH_LDEBUG
477: assert(l->writer == current_thread());
478: #endif /* MACH_LDEBUG */
1.1 root 479:
480: l->read_count++;
481: if (l->recursion_depth != 0)
482: l->recursion_depth--;
483: else
484: if (l->want_upgrade)
485: l->want_upgrade = FALSE;
486: else
487: l->want_write = FALSE;
488:
489: if (l->waiting) {
490: l->waiting = FALSE;
491: thread_wakeup(l);
492: }
493:
1.1.1.4 root 494: #if MACH_LDEBUG
495: l->writer = THREAD_NULL;
496: #endif /* MACH_LDEBUG */
1.1 root 497: simple_unlock(&l->interlock);
498: }
499:
500:
501: /*
502: * Routine: lock_try_write
503: * Function:
504: * Tries to get a write lock.
505: *
506: * Returns FALSE if the lock is not held on return.
507: */
508:
509: boolean_t lock_try_write(
1.1.1.3 root 510: lock_t l)
1.1 root 511: {
512: simple_lock(&l->interlock);
513:
514: if (l->thread == current_thread()) {
515: /*
516: * Recursive lock
517: */
518: l->recursion_depth++;
519: simple_unlock(&l->interlock);
520: return TRUE;
521: }
522:
523: if (l->want_write || l->want_upgrade || l->read_count) {
524: /*
525: * Can't get lock.
526: */
527: simple_unlock(&l->interlock);
528: return FALSE;
529: }
530:
531: /*
532: * Have lock.
533: */
534:
535: l->want_write = TRUE;
1.1.1.4 root 536: #if MACH_LDEBUG
537: l->writer = current_thread();
538: #endif /* MACH_LDEBUG */
1.1 root 539: simple_unlock(&l->interlock);
540: return TRUE;
541: }
542:
543: /*
544: * Routine: lock_try_read
545: * Function:
546: * Tries to get a read lock.
547: *
548: * Returns FALSE if the lock is not held on return.
549: */
550:
551: boolean_t lock_try_read(
1.1.1.3 root 552: lock_t l)
1.1 root 553: {
554: simple_lock(&l->interlock);
555:
556: if (l->thread == current_thread()) {
557: /*
558: * Recursive lock
559: */
560: l->read_count++;
561: simple_unlock(&l->interlock);
562: return TRUE;
563: }
564:
565: if (l->want_write || l->want_upgrade) {
566: simple_unlock(&l->interlock);
567: return FALSE;
568: }
569:
570: l->read_count++;
571: simple_unlock(&l->interlock);
572: return TRUE;
573: }
574:
575: /*
576: * Routine: lock_try_read_to_write
577: * Function:
578: * Improves a read-only lock to one with
579: * write permission. If another reader has
580: * already requested an upgrade to a write lock,
581: * the read lock is still held upon return.
582: *
583: * Returns FALSE if the upgrade *failed*.
584: */
585: boolean_t lock_try_read_to_write(
1.1.1.3 root 586: lock_t l)
1.1 root 587: {
588: check_simple_locks();
589: simple_lock(&l->interlock);
590:
591: if (l->thread == current_thread()) {
592: /*
593: * Recursive lock
594: */
595: l->read_count--;
596: l->recursion_depth++;
597: simple_unlock(&l->interlock);
598: return TRUE;
599: }
600:
601: if (l->want_upgrade) {
602: simple_unlock(&l->interlock);
603: return FALSE;
604: }
605: l->want_upgrade = TRUE;
606: l->read_count--;
607:
608: while (l->read_count != 0) {
609: l->waiting = TRUE;
610: thread_sleep(l,
611: simple_lock_addr(l->interlock), FALSE);
612: simple_lock(&l->interlock);
613: }
614:
1.1.1.4 root 615: #if MACH_LDEBUG
616: l->writer = current_thread();
617: #endif /* MACH_LDEBUG */
1.1 root 618: simple_unlock(&l->interlock);
619: return TRUE;
620: }
621:
622: /*
623: * Allow a process that has a lock for write to acquire it
624: * recursively (for read, write, or update).
625: */
626: void lock_set_recursive(
627: lock_t l)
628: {
629: simple_lock(&l->interlock);
1.1.1.4 root 630: #if MACH_LDEBUG
631: assert(l->writer == current_thread());
632: #endif /* MACH_LDEBUG */
633:
1.1 root 634: if (!l->want_write) {
635: panic("lock_set_recursive: don't have write lock");
636: }
637: l->thread = current_thread();
638: simple_unlock(&l->interlock);
639: }
640:
641: /*
642: * Prevent a lock from being re-acquired.
643: */
644: void lock_clear_recursive(
645: lock_t l)
646: {
647: simple_lock(&l->interlock);
648: if (l->thread != current_thread()) {
649: panic("lock_clear_recursive: wrong thread");
650: }
651: if (l->recursion_depth == 0)
652: l->thread = (struct thread *)-1; /* XXX */
653: simple_unlock(&l->interlock);
654: }
655:
656: #if MACH_KDB
657: #if MACH_SLOCKS && NCPUS == 1
658: void db_show_all_slocks(void)
659: {
660: int i;
661: struct simple_locks_info *info;
662: simple_lock_t l;
663:
664: for (i = 0; i < simple_locks_taken; i++) {
665: info = &simple_locks_info[i];
1.1.1.4 root 666: db_printf("%d: %s (", i, info->expr);
1.1 root 667: db_printsym(info->l, DB_STGY_ANY);
1.1.1.4 root 668: db_printf(") locked by %s\n", info->loc);
1.1 root 669: }
670: }
671: #else /* MACH_SLOCKS && NCPUS == 1 */
672: void db_show_all_slocks(void)
673: {
674: db_printf("simple lock info not available\n");
675: }
676: #endif /* MACH_SLOCKS && NCPUS == 1 */
677: #endif /* MACH_KDB */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.