FreeBSD/Linux Kernel Cross Reference
sys/vm/kern_lock.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 * from: @(#)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 * $FreeBSD: src/sys/vm/kern_lock.c,v 1.10.4.1 1999/09/05 08:24:16 peter Exp $
65 */
66
67 /*
68 * Locking primitives implementation
69 */
70
71 #include <sys/param.h>
72 #include <sys/systm.h>
73
74 /* XXX */
75 #include <sys/proc.h>
76
77 #include <vm/vm.h>
78 #include <vm/vm_param.h>
79 #include <vm/vm_prot.h>
80 #include <vm/lock.h>
81
82 /*
83 * Routine: lock_init
84 * Function:
85 * Initialize a lock; required before use.
86 * Note that clients declare the "struct lock"
87 * variables and then initialize them, rather
88 * than getting a new one from this module.
89 */
90 void
91 lock_init(l, can_sleep)
92 lock_t l;
93 boolean_t can_sleep;
94 {
95 l->want_write = 0;
96 l->want_upgrade = 0;
97 l->waiting = 0;
98 l->can_sleep = can_sleep;
99 l->read_count = 0;
100 l->proc = NULL;
101 l->recursion_depth = 0;
102 }
103
104 void
105 lock_sleepable(l, can_sleep)
106 lock_t l;
107 boolean_t can_sleep;
108 {
109 l->can_sleep = can_sleep;
110 }
111
112
113 /*
114 * Sleep locks. These use the same data structure and algorithm
115 * as the spin locks, but the process sleeps while it is waiting
116 * for the lock. These work on uniprocessor systems.
117 */
118
119 void
120 lock_write(l)
121 register lock_t l;
122 {
123 if (l->proc == curproc) {
124 /*
125 * Recursive lock.
126 */
127 l->recursion_depth++;
128 return;
129 }
130 /*
131 * Try to acquire the want_write bit.
132 */
133 while (l->want_write) {
134 if (l->can_sleep && l->want_write) {
135 l->waiting = TRUE;
136 tsleep(l, PVM, "lckwt1", 0);
137 }
138 }
139 l->want_write = TRUE;
140
141 /* Wait for readers (and upgrades) to finish */
142
143 while ((l->read_count != 0) || l->want_upgrade) {
144 if (l->can_sleep && (l->read_count != 0 || l->want_upgrade)) {
145 l->waiting = TRUE;
146 tsleep(l, PVM, "lckwt2", 0);
147 }
148 }
149 }
150
151 void
152 lock_done(l)
153 register lock_t l;
154 {
155 if (l->read_count != 0)
156 l->read_count--;
157 else if (l->recursion_depth != 0)
158 l->recursion_depth--;
159 else if (l->want_upgrade)
160 l->want_upgrade = FALSE;
161 else
162 l->want_write = FALSE;
163
164 if (l->waiting) {
165 l->waiting = FALSE;
166 wakeup(l);
167 }
168 }
169
170 void
171 lock_read(l)
172 register lock_t l;
173 {
174 if (l->proc == curproc) {
175 /*
176 * Recursive lock.
177 */
178 l->read_count++;
179 return;
180 }
181 while (l->want_write || l->want_upgrade) {
182 if (l->can_sleep && (l->want_write || l->want_upgrade)) {
183 l->waiting = TRUE;
184 tsleep(l, PVM, "lockrd", 0);
185 }
186 }
187
188 l->read_count++;
189 }
190
191 /*
192 * Routine: lock_read_to_write
193 * Function:
194 * Improves a read-only lock to one with
195 * write permission. If another reader has
196 * already requested an upgrade to a write lock,
197 * no lock is held upon return.
198 *
199 * Returns TRUE if the upgrade *failed*.
200 */
201 boolean_t
202 lock_read_to_write(l)
203 register lock_t l;
204 {
205 l->read_count--;
206
207 if (l->proc == curproc) {
208 /*
209 * Recursive lock.
210 */
211 l->recursion_depth++;
212 return (FALSE);
213 }
214 if (l->want_upgrade) {
215 /*
216 * Someone else has requested upgrade. Since we've released a
217 * read lock, wake him up.
218 */
219 if (l->waiting) {
220 l->waiting = FALSE;
221 wakeup(l);
222 }
223 return (TRUE);
224 }
225 l->want_upgrade = TRUE;
226
227 while (l->read_count != 0) {
228 if (l->can_sleep && l->read_count != 0) {
229 l->waiting = TRUE;
230 tsleep(l, PVM, "lckrw", 0);
231 }
232 }
233
234 return (FALSE);
235 }
236
237 void
238 lock_write_to_read(l)
239 register lock_t l;
240 {
241 l->read_count++;
242 if (l->recursion_depth != 0)
243 l->recursion_depth--;
244 else if (l->want_upgrade)
245 l->want_upgrade = FALSE;
246 else
247 l->want_write = FALSE;
248
249 if (l->waiting) {
250 l->waiting = FALSE;
251 wakeup(l);
252 }
253 }
254
255
256 /*
257 * Routine: lock_try_write
258 * Function:
259 * Tries to get a write lock.
260 *
261 * Returns FALSE if the lock is not held on return.
262 */
263
264 boolean_t
265 lock_try_write(l)
266 register lock_t l;
267 {
268 if (l->proc == curproc) {
269 /*
270 * Recursive lock
271 */
272 l->recursion_depth++;
273 return (TRUE);
274 }
275 if (l->want_write || l->want_upgrade || l->read_count) {
276 /*
277 * Can't get lock.
278 */
279 return (FALSE);
280 }
281 /*
282 * Have lock.
283 */
284
285 l->want_write = TRUE;
286 return (TRUE);
287 }
288
289 /*
290 * Routine: lock_try_read
291 * Function:
292 * Tries to get a read lock.
293 *
294 * Returns FALSE if the lock is not held on return.
295 */
296
297 boolean_t
298 lock_try_read(l)
299 register lock_t l;
300 {
301 if (l->proc == curproc) {
302 /*
303 * Recursive lock
304 */
305 l->read_count++;
306 return (TRUE);
307 }
308 if (l->want_write || l->want_upgrade) {
309 return (FALSE);
310 }
311 l->read_count++;
312 return (TRUE);
313 }
314
315 /*
316 * Routine: lock_try_read_to_write
317 * Function:
318 * Improves a read-only lock to one with
319 * write permission. If another reader has
320 * already requested an upgrade to a write lock,
321 * the read lock is still held upon return.
322 *
323 * Returns FALSE if the upgrade *failed*.
324 */
325 boolean_t
326 lock_try_read_to_write(l)
327 register lock_t l;
328 {
329 if (l->proc == curproc) {
330 /*
331 * Recursive lock
332 */
333 l->read_count--;
334 l->recursion_depth++;
335 return (TRUE);
336 }
337 if (l->want_upgrade) {
338 return (FALSE);
339 }
340 l->want_upgrade = TRUE;
341 l->read_count--;
342
343 while (l->read_count != 0) {
344 l->waiting = TRUE;
345 tsleep(l, PVM, "lcktrw", 0);
346 }
347
348 return (TRUE);
349 }
350
351 /*
352 * Allow a process that has a lock for write to acquire it
353 * recursively (for read, write, or update).
354 */
355 void
356 lock_set_recursive(l)
357 lock_t l;
358 {
359 if (!l->want_write) {
360 panic("lock_set_recursive: don't have write lock");
361 }
362 l->proc = curproc;
363 }
364
365 /*
366 * Prevent a lock from being re-acquired.
367 */
368 void
369 lock_clear_recursive(l)
370 lock_t l;
371 {
372 if (l->proc != curproc) {
373 panic("lock_clear_recursive: wrong proc");
374 }
375 if (l->recursion_depth == 0)
376 l->proc = NULL;
377 }
Cache object: a53259c2ddbfebcd7b53f3daa94a985f
|