|
|
1.1 root 1: /*
2: * Copyright (c) 1991 Regents of the University of California.
3: * All rights reserved.
4: *
5: * This code is derived from software contributed to Berkeley by
6: * The Mach Operating System project at Carnegie-Mellon University.
7: *
8: * Redistribution and use in source and binary forms, with or without
9: * modification, are permitted provided that the following conditions
10: * are met:
11: * 1. Redistributions of source code must retain the above copyright
12: * notice, this list of conditions and the following disclaimer.
13: * 2. Redistributions in binary form must reproduce the above copyright
14: * notice, this list of conditions and the following disclaimer in the
15: * documentation and/or other materials provided with the distribution.
16: * 3. All advertising materials mentioning features or use of this software
17: * must display the following acknowledgement:
18: * This product includes software developed by the University of
19: * California, Berkeley and its contributors.
20: * 4. Neither the name of the University nor the names of its contributors
21: * may be used to endorse or promote products derived from this software
22: * without specific prior written permission.
23: *
24: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34: * SUCH DAMAGE.
35: *
36: * @(#)kern_lock.c 7.4 (Berkeley) 4/21/91
37: *
38: *
39: * Copyright (c) 1987, 1990 Carnegie-Mellon University.
40: * All rights reserved.
41: *
42: * Authors: Avadis Tevanian, Jr., Michael Wayne Young
43: *
44: * Permission to use, copy, modify and distribute this software and
45: * its documentation is hereby granted, provided that both the copyright
46: * notice and this permission notice appear in all copies of the
47: * software, derivative works or modified versions, and any portions
48: * thereof, and that both notices appear in supporting documentation.
49: *
50: * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
51: * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND
52: * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
53: *
54: * Carnegie Mellon requests users of this software to return to
55: *
56: * Software Distribution Coordinator or [email protected]
57: * School of Computer Science
58: * Carnegie Mellon University
59: * Pittsburgh PA 15213-3890
60: *
61: * any improvements or extensions that they make and grant Carnegie the
62: * rights to redistribute these changes.
63: */
64:
65: /*
66: * Locking primitives implementation
67: */
68:
69: #include "param.h"
70: #include "vm_param.h"
71: #include "lock.h"
72:
73: /* XXX */
74: #include "proc.h"
75: typedef int *thread_t;
76: #define current_thread() ((thread_t)&curproc->p_thread)
77: /* XXX */
78:
79: #if NCPUS > 1
80:
81: /*
82: * Module: lock
83: * Function:
84: * Provide reader/writer sychronization.
85: * Implementation:
86: * Simple interlock on a bit. Readers first interlock
87: * increment the reader count, then let go. Writers hold
88: * the interlock (thus preventing further readers), and
89: * wait for already-accepted readers to go away.
90: */
91:
92: /*
93: * The simple-lock routines are the primitives out of which
94: * the lock package is built. The implementation is left
95: * to the machine-dependent code.
96: */
97:
98: #ifdef notdef
99: /*
100: * A sample implementation of simple locks.
101: * assumes:
102: * boolean_t test_and_set(boolean_t *)
103: * indivisibly sets the boolean to TRUE
104: * and returns its old value
105: * and that setting a boolean to FALSE is indivisible.
106: */
107: /*
108: * simple_lock_init initializes a simple lock. A simple lock
109: * may only be used for exclusive locks.
110: */
111:
112: void simple_lock_init(l)
113: simple_lock_t l;
114: {
115: *(boolean_t *)l = FALSE;
116: }
117:
118: void simple_lock(l)
119: simple_lock_t l;
120: {
121: while (test_and_set((boolean_t *)l))
122: continue;
123: }
124:
125: void simple_unlock(l)
126: simple_lock_t l;
127: {
128: *(boolean_t *)l = FALSE;
129: }
130:
131: boolean_t simple_lock_try(l)
132: simple_lock_t l;
133: {
134: return (!test_and_set((boolean_t *)l));
135: }
136: #endif notdef
137: #endif NCPUS > 1
138:
139: #if NCPUS > 1
140: int lock_wait_time = 100;
141: #else NCPUS > 1
142:
143: /*
144: * It is silly to spin on a uni-processor as if we
145: * thought something magical would happen to the
146: * want_write bit while we are executing.
147: */
148: int lock_wait_time = 0;
149: #endif NCPUS > 1
150:
151:
152: /*
153: * Routine: lock_init
154: * Function:
155: * Initialize a lock; required before use.
156: * Note that clients declare the "struct lock"
157: * variables and then initialize them, rather
158: * than getting a new one from this module.
159: */
160: void lock_init(l, can_sleep)
161: lock_t l;
162: boolean_t can_sleep;
163: {
164: bzero(l, sizeof(lock_data_t));
165: simple_lock_init(&l->interlock);
166: l->want_write = FALSE;
167: l->want_upgrade = FALSE;
168: l->read_count = 0;
169: l->can_sleep = can_sleep;
170: l->thread = (char *)-1; /* XXX */
171: l->recursion_depth = 0;
172: }
173:
174: void lock_sleepable(l, can_sleep)
175: lock_t l;
176: boolean_t can_sleep;
177: {
178: simple_lock(&l->interlock);
179: l->can_sleep = can_sleep;
180: simple_unlock(&l->interlock);
181: }
182:
183:
184: /*
185: * Sleep locks. These use the same data structure and algorithm
186: * as the spin locks, but the process sleeps while it is waiting
187: * for the lock. These work on uniprocessor systems.
188: */
189:
190: void lock_write(l)
191: register lock_t l;
192: {
193: register int i;
194:
195: simple_lock(&l->interlock);
196:
197: if (((thread_t)l->thread) == current_thread()) {
198: /*
199: * Recursive lock.
200: */
201: l->recursion_depth++;
202: simple_unlock(&l->interlock);
203: return;
204: }
205:
206: /*
207: * Try to acquire the want_write bit.
208: */
209: while (l->want_write) {
210: if ((i = lock_wait_time) > 0) {
211: simple_unlock(&l->interlock);
212: while (--i > 0 && l->want_write)
213: continue;
214: simple_lock(&l->interlock);
215: }
216:
217: if (l->can_sleep && l->want_write) {
218: l->waiting = TRUE;
219: thread_sleep((int) l, &l->interlock, FALSE);
220: simple_lock(&l->interlock);
221: }
222: }
223: l->want_write = TRUE;
224:
225: /* Wait for readers (and upgrades) to finish */
226:
227: while ((l->read_count != 0) || l->want_upgrade) {
228: if ((i = lock_wait_time) > 0) {
229: simple_unlock(&l->interlock);
230: while (--i > 0 && (l->read_count != 0 ||
231: l->want_upgrade))
232: continue;
233: simple_lock(&l->interlock);
234: }
235:
236: if (l->can_sleep && (l->read_count != 0 || l->want_upgrade)) {
237: l->waiting = TRUE;
238: thread_sleep((int) l, &l->interlock, FALSE);
239: simple_lock(&l->interlock);
240: }
241: }
242: simple_unlock(&l->interlock);
243: }
244:
245: void lock_done(l)
246: register lock_t l;
247: {
248: simple_lock(&l->interlock);
249:
250: if (l->read_count != 0)
251: l->read_count--;
252: else
253: if (l->recursion_depth != 0)
254: l->recursion_depth--;
255: else
256: if (l->want_upgrade)
257: l->want_upgrade = FALSE;
258: else
259: l->want_write = FALSE;
260:
261: if (l->waiting) {
262: l->waiting = FALSE;
263: thread_wakeup((int) l);
264: }
265: simple_unlock(&l->interlock);
266: }
267:
268: void lock_read(l)
269: register lock_t l;
270: {
271: register int i;
272:
273: simple_lock(&l->interlock);
274:
275: if (((thread_t)l->thread) == current_thread()) {
276: /*
277: * Recursive lock.
278: */
279: l->read_count++;
280: simple_unlock(&l->interlock);
281: return;
282: }
283:
284: while (l->want_write || l->want_upgrade) {
285: if ((i = lock_wait_time) > 0) {
286: simple_unlock(&l->interlock);
287: while (--i > 0 && (l->want_write || l->want_upgrade))
288: continue;
289: simple_lock(&l->interlock);
290: }
291:
292: if (l->can_sleep && (l->want_write || l->want_upgrade)) {
293: l->waiting = TRUE;
294: thread_sleep((int) l, &l->interlock, FALSE);
295: simple_lock(&l->interlock);
296: }
297: }
298:
299: l->read_count++;
300: simple_unlock(&l->interlock);
301: }
302:
303: /*
304: * Routine: lock_read_to_write
305: * Function:
306: * Improves a read-only lock to one with
307: * write permission. If another reader has
308: * already requested an upgrade to a write lock,
309: * no lock is held upon return.
310: *
311: * Returns TRUE if the upgrade *failed*.
312: */
313: boolean_t lock_read_to_write(l)
314: register lock_t l;
315: {
316: register int i;
317:
318: simple_lock(&l->interlock);
319:
320: l->read_count--;
321:
322: if (((thread_t)l->thread) == current_thread()) {
323: /*
324: * Recursive lock.
325: */
326: l->recursion_depth++;
327: simple_unlock(&l->interlock);
328: return(FALSE);
329: }
330:
331: if (l->want_upgrade) {
332: /*
333: * Someone else has requested upgrade.
334: * Since we've released a read lock, wake
335: * him up.
336: */
337: if (l->waiting) {
338: l->waiting = FALSE;
339: thread_wakeup((int) l);
340: }
341:
342: simple_unlock(&l->interlock);
343: return (TRUE);
344: }
345:
346: l->want_upgrade = TRUE;
347:
348: while (l->read_count != 0) {
349: if ((i = lock_wait_time) > 0) {
350: simple_unlock(&l->interlock);
351: while (--i > 0 && l->read_count != 0)
352: continue;
353: simple_lock(&l->interlock);
354: }
355:
356: if (l->can_sleep && l->read_count != 0) {
357: l->waiting = TRUE;
358: thread_sleep((int) l, &l->interlock, FALSE);
359: simple_lock(&l->interlock);
360: }
361: }
362:
363: simple_unlock(&l->interlock);
364: return (FALSE);
365: }
366:
367: void lock_write_to_read(l)
368: register lock_t l;
369: {
370: simple_lock(&l->interlock);
371:
372: l->read_count++;
373: if (l->recursion_depth != 0)
374: l->recursion_depth--;
375: else
376: if (l->want_upgrade)
377: l->want_upgrade = FALSE;
378: else
379: l->want_write = FALSE;
380:
381: if (l->waiting) {
382: l->waiting = FALSE;
383: thread_wakeup((int) l);
384: }
385:
386: simple_unlock(&l->interlock);
387: }
388:
389:
390: /*
391: * Routine: lock_try_write
392: * Function:
393: * Tries to get a write lock.
394: *
395: * Returns FALSE if the lock is not held on return.
396: */
397:
398: boolean_t lock_try_write(l)
399: register lock_t l;
400: {
401:
402: simple_lock(&l->interlock);
403:
404: if (((thread_t)l->thread) == current_thread()) {
405: /*
406: * Recursive lock
407: */
408: l->recursion_depth++;
409: simple_unlock(&l->interlock);
410: return(TRUE);
411: }
412:
413: if (l->want_write || l->want_upgrade || l->read_count) {
414: /*
415: * Can't get lock.
416: */
417: simple_unlock(&l->interlock);
418: return(FALSE);
419: }
420:
421: /*
422: * Have lock.
423: */
424:
425: l->want_write = TRUE;
426: simple_unlock(&l->interlock);
427: return(TRUE);
428: }
429:
430: /*
431: * Routine: lock_try_read
432: * Function:
433: * Tries to get a read lock.
434: *
435: * Returns FALSE if the lock is not held on return.
436: */
437:
438: boolean_t lock_try_read(l)
439: register lock_t l;
440: {
441: simple_lock(&l->interlock);
442:
443: if (((thread_t)l->thread) == current_thread()) {
444: /*
445: * Recursive lock
446: */
447: l->read_count++;
448: simple_unlock(&l->interlock);
449: return(TRUE);
450: }
451:
452: if (l->want_write || l->want_upgrade) {
453: simple_unlock(&l->interlock);
454: return(FALSE);
455: }
456:
457: l->read_count++;
458: simple_unlock(&l->interlock);
459: return(TRUE);
460: }
461:
462: /*
463: * Routine: lock_try_read_to_write
464: * Function:
465: * Improves a read-only lock to one with
466: * write permission. If another reader has
467: * already requested an upgrade to a write lock,
468: * the read lock is still held upon return.
469: *
470: * Returns FALSE if the upgrade *failed*.
471: */
472: boolean_t lock_try_read_to_write(l)
473: register lock_t l;
474: {
475:
476: simple_lock(&l->interlock);
477:
478: if (((thread_t)l->thread) == current_thread()) {
479: /*
480: * Recursive lock
481: */
482: l->read_count--;
483: l->recursion_depth++;
484: simple_unlock(&l->interlock);
485: return(TRUE);
486: }
487:
488: if (l->want_upgrade) {
489: simple_unlock(&l->interlock);
490: return(FALSE);
491: }
492: l->want_upgrade = TRUE;
493: l->read_count--;
494:
495: while (l->read_count != 0) {
496: l->waiting = TRUE;
497: thread_sleep((int) l, &l->interlock, FALSE);
498: simple_lock(&l->interlock);
499: }
500:
501: simple_unlock(&l->interlock);
502: return(TRUE);
503: }
504:
505: /*
506: * Allow a process that has a lock for write to acquire it
507: * recursively (for read, write, or update).
508: */
509: void lock_set_recursive(l)
510: lock_t l;
511: {
512: simple_lock(&l->interlock);
513: if (!l->want_write) {
514: panic("lock_set_recursive: don't have write lock");
515: }
516: l->thread = (char *) current_thread();
517: simple_unlock(&l->interlock);
518: }
519:
520: /*
521: * Prevent a lock from being re-acquired.
522: */
523: void lock_clear_recursive(l)
524: lock_t l;
525: {
526: simple_lock(&l->interlock);
527: if (((thread_t) l->thread) != current_thread()) {
528: panic("lock_clear_recursive: wrong thread");
529: }
530: if (l->recursion_depth == 0)
531: l->thread = (char *)-1; /* XXX */
532: simple_unlock(&l->interlock);
533: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.