BSD 4_4_Lite2 development
[unix-history] / .ref-BSD-4_4_Lite1 / usr / src / sys / vm / kern_lock.c
CommitLineData
ad787160
C
1/*
2 * Copyright (c) 1991, 1993
3 * The Regents of the University of California. 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 8.1 (Berkeley) 6/11/93
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 <sys/param.h>
70#include <sys/systm.h>
71
72#include <vm/vm.h>
73
74/* XXX */
75#include <sys/proc.h>
76typedef 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
113void simple_lock_init(l)
114 simple_lock_t l;
115{
116 *(boolean_t *)l = FALSE;
117}
118
119void simple_lock(l)
120 simple_lock_t l;
121{
122 while (test_and_set((boolean_t *)l))
123 continue;
124}
125
126void simple_unlock(l)
127 simple_lock_t l;
128{
129 *(boolean_t *)l = FALSE;
130}
131
132boolean_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
141int 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 */
149int 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 */
161void 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
175void 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
191void 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
246void 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
269void 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 */
314boolean_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
368void 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
399boolean_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
439boolean_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 */
473boolean_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 */
510void 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 */
524void 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}