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