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