386BSD 0.1 development
[unix-history] / usr / src / sys.386bsd / vm / kern_lock.c
CommitLineData
b688fc87
WJ
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 Software.Distribution@CS.CMU.EDU
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"
75typedef 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
112void simple_lock_init(l)
113 simple_lock_t l;
114{
115 *(boolean_t *)l = FALSE;
116}
117
118void simple_lock(l)
119 simple_lock_t l;
120{
121 while (test_and_set((boolean_t *)l))
122 continue;
123}
124
125void simple_unlock(l)
126 simple_lock_t l;
127{
128 *(boolean_t *)l = FALSE;
129}
130
131boolean_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
140int 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 */
148int 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 */
160void 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
174void 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
190void 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
245void 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
268void 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 */
313boolean_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
367void 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
398boolean_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
438boolean_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 */
472boolean_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 */
509void 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 */
523void 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}