]>
git.saurik.com Git - apple/xnu.git/blob - bsd/kern/kern_lock.c
2 * Copyright (c) 2000-2001 Apple Computer, Inc. All rights reserved.
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
28 /* Copyright (c) 1995, 1997 Apple Computer, Inc. All Rights Reserved */
31 * The Regents of the University of California. All rights reserved.
33 * This code contains ideas from software contributed to Berkeley by
34 * Avadis Tevanian, Jr., Michael Wayne Young, and the Mach Operating
35 * System project at Carnegie-Mellon University.
37 * Redistribution and use in source and binary forms, with or without
38 * modification, are permitted provided that the following conditions
40 * 1. Redistributions of source code must retain the above copyright
41 * notice, this list of conditions and the following disclaimer.
42 * 2. Redistributions in binary form must reproduce the above copyright
43 * notice, this list of conditions and the following disclaimer in the
44 * documentation and/or other materials provided with the distribution.
45 * 3. All advertising materials mentioning features or use of this software
46 * must display the following acknowledgement:
47 * This product includes software developed by the University of
48 * California, Berkeley and its contributors.
49 * 4. Neither the name of the University nor the names of its contributors
50 * may be used to endorse or promote products derived from this software
51 * without specific prior written permission.
53 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
54 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
55 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
56 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
57 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
58 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
59 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
60 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
61 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
62 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
65 * @(#)kern_lock.c 8.18 (Berkeley) 5/21/95
68 #include <sys/param.h>
69 #include <sys/proc_internal.h>
71 #include <kern/cpu_number.h>
72 #include <kern/thread.h>
74 #include <mach/mach_types.h>
77 * Locking primitives implementation.
78 * Locks provide shared/exclusive sychronization.
82 #define COUNT(p, x) if (p) (p)->p_locks += (x)
90 * For multiprocessor system, try spin lock first.
92 * This should be inline expanded below, but we cannot have #if
93 * inside a multiline define.
95 int lock_wait_time
= 100;
96 #define PAUSE(lkp, wanted) \
97 if (lock_wait_time > 0) { \
100 for (i = lock_wait_time; i > 0; i--) \
107 #else /* NCPUS == 1 */
110 * It is an error to spin on a uniprocessor as nothing will ever cause
111 * the simple lock to clear while we are executing.
113 #define PAUSE(lkp, wanted)
115 #endif /* NCPUS == 1 */
118 * Acquire a resource.
120 #define ACQUIRE(lkp, error, extflags, wanted) \
121 PAUSE(lkp, wanted); \
122 for (error = 0; wanted; ) { \
123 (lkp)->lk_waitcount++; \
124 error = tsleep((void *)lkp, (lkp)->lk_prio, \
125 (lkp)->lk_wmesg, (lkp)->lk_timo); \
126 (lkp)->lk_waitcount--; \
129 if ((extflags) & LK_SLEEPFAIL) { \
136 * Initialize a lock; required before use.
139 lockinit(lkp
, prio
, wmesg
, timo
, flags
)
140 struct lock__bsd__
*lkp
;
147 bzero(lkp
, sizeof(struct lock__bsd__
));
148 lkp
->lk_flags
= flags
& LK_EXTFLG_MASK
;
151 lkp
->lk_wmesg
= wmesg
;
152 lkp
->lk_lockholder
= LK_NOPROC
;
153 lkp
->lk_lockthread
= 0;
157 * Determine the status of a lock.
161 struct lock__bsd__
*lkp
;
165 if (lkp
->lk_exclusivecount
!= 0)
166 lock_type
= LK_EXCLUSIVE
;
167 else if (lkp
->lk_sharecount
!= 0)
168 lock_type
= LK_SHARED
;
173 * Set, change, or release a lock.
175 * Shared requests increment the shared count. Exclusive requests set the
176 * LK_WANT_EXCL flag (preventing further shared locks), and wait for already
177 * accepted shared locks and shared-to-exclusive upgrades to go away.
180 lockmgr(lkp
, flags
, interlkp
, p
)
181 struct lock__bsd__
*lkp
;
191 error
= 0; self
= current_thread();
196 extflags
= (flags
| lkp
->lk_flags
) & LK_EXTFLG_MASK
;
199 * Once a lock has drained, the LK_DRAINING flag is set and an
200 * exclusive lock is returned. The only valid operation thereafter
201 * is a single release of that exclusive lock. This final release
202 * clears the LK_DRAINING flag and sets the LK_DRAINED flag. Any
203 * further requests of any sort will result in a panic. The bits
204 * selected for these two flags are chosen so that they will be set
205 * in memory that is freed (freed memory is filled with 0xdeadbeef).
206 * The final release is permitted to give a new lease on life to
207 * the lock by specifying LK_REENABLE.
209 if (lkp
->lk_flags
& (LK_DRAINING
|LK_DRAINED
)) {
210 if (lkp
->lk_flags
& LK_DRAINED
)
211 panic("lockmgr: using decommissioned lock");
212 if ((flags
& LK_TYPE_MASK
) != LK_RELEASE
||
213 (lkp
->lk_lockholder
!= pid
&& lkp
->lk_lockthread
!= self
)
214 panic("lockmgr: non-release on draining lock: %d\n",
215 flags
& LK_TYPE_MASK
);
216 lkp
->lk_flags
&= ~LK_DRAINING
;
217 if ((flags
& LK_REENABLE
) == 0)
218 lkp
->lk_flags
|= LK_DRAINED
;
222 switch (flags
& LK_TYPE_MASK
) {
225 if (lkp
->lk_lockholder
!= pid
|| lkp
->lk_lockthread
!= self
) {
227 * If just polling, check to see if we will block.
229 if ((extflags
& LK_NOWAIT
) && (lkp
->lk_flags
&
230 (LK_HAVE_EXCL
| LK_WANT_EXCL
| LK_WANT_UPGRADE
))) {
235 * Wait for exclusive locks and upgrades to clear.
237 ACQUIRE(lkp
, error
, extflags
, lkp
->lk_flags
&
238 (LK_HAVE_EXCL
| LK_WANT_EXCL
| LK_WANT_UPGRADE
));
241 lkp
->lk_sharecount
++;
246 * We hold an exclusive lock, so downgrade it to shared.
247 * An alternative would be to fail with EDEADLK.
249 lkp
->lk_sharecount
++;
251 /* fall into downgrade */
254 if (lkp
->lk_lockholder
!= pid
||
255 lkp
->lk_lockthread
!= self
||
256 lkp
->lk_exclusivecount
== 0)
257 panic("lockmgr: not holding exclusive lock");
258 lkp
->lk_sharecount
+= lkp
->lk_exclusivecount
;
259 lkp
->lk_exclusivecount
= 0;
260 lkp
->lk_flags
&= ~LK_HAVE_EXCL
;
261 lkp
->lk_lockholder
= LK_NOPROC
;
262 lkp
->lk_lockthread
= 0;
263 if (lkp
->lk_waitcount
)
269 * If another process is ahead of us to get an upgrade,
270 * then we want to fail rather than have an intervening
273 if (lkp
->lk_flags
& LK_WANT_UPGRADE
) {
274 lkp
->lk_sharecount
--;
279 /* fall into normal upgrade */
283 * Upgrade a shared lock to an exclusive one. If another
284 * shared lock has already requested an upgrade to an
285 * exclusive lock, our shared lock is released and an
286 * exclusive lock is requested (which will be granted
287 * after the upgrade). If we return an error, the file
288 * will always be unlocked.
290 if ((lkp
->lk_lockholder
== pid
&&
291 lkp
->lk_lockthread
== self
) ||
292 lkp
->lk_sharecount
<= 0)
293 panic("lockmgr: upgrade exclusive lock");
294 lkp
->lk_sharecount
--;
297 * If we are just polling, check to see if we will block.
299 if ((extflags
& LK_NOWAIT
) &&
300 ((lkp
->lk_flags
& LK_WANT_UPGRADE
) ||
301 lkp
->lk_sharecount
> 1)) {
305 if ((lkp
->lk_flags
& LK_WANT_UPGRADE
) == 0) {
307 * We are first shared lock to request an upgrade, so
308 * request upgrade and wait for the shared count to
309 * drop to zero, then take exclusive lock.
311 lkp
->lk_flags
|= LK_WANT_UPGRADE
;
312 ACQUIRE(lkp
, error
, extflags
, lkp
->lk_sharecount
);
313 lkp
->lk_flags
&= ~LK_WANT_UPGRADE
;
316 lkp
->lk_flags
|= LK_HAVE_EXCL
;
317 lkp
->lk_lockholder
= pid
;
318 lkp
->lk_lockthread
= self
;
319 if (lkp
->lk_exclusivecount
!= 0)
320 panic("lockmgr: non-zero exclusive count");
321 lkp
->lk_exclusivecount
= 1;
326 * Someone else has requested upgrade. Release our shared
327 * lock, awaken upgrade requestor if we are the last shared
328 * lock, then request an exclusive lock.
330 if (lkp
->lk_sharecount
== 0 && lkp
->lk_waitcount
)
332 /* fall into exclusive request */
335 if (lkp
->lk_lockholder
== pid
&& lkp
->lk_lockthread
== self
) {
339 if ((extflags
& LK_CANRECURSE
) == 0)
340 panic("lockmgr: locking against myself");
341 lkp
->lk_exclusivecount
++;
346 * If we are just polling, check to see if we will sleep.
348 if ((extflags
& LK_NOWAIT
) && ((lkp
->lk_flags
&
349 (LK_HAVE_EXCL
| LK_WANT_EXCL
| LK_WANT_UPGRADE
)) ||
350 lkp
->lk_sharecount
!= 0)) {
355 * Try to acquire the want_exclusive flag.
357 ACQUIRE(lkp
, error
, extflags
, lkp
->lk_flags
&
358 (LK_HAVE_EXCL
| LK_WANT_EXCL
));
361 lkp
->lk_flags
|= LK_WANT_EXCL
;
363 * Wait for shared locks and upgrades to finish.
365 ACQUIRE(lkp
, error
, extflags
, lkp
->lk_sharecount
!= 0 ||
366 (lkp
->lk_flags
& LK_WANT_UPGRADE
));
367 lkp
->lk_flags
&= ~LK_WANT_EXCL
;
370 lkp
->lk_flags
|= LK_HAVE_EXCL
;
371 lkp
->lk_lockholder
= pid
;
372 lkp
->lk_lockthread
= self
;
373 if (lkp
->lk_exclusivecount
!= 0)
374 panic("lockmgr: non-zero exclusive count");
375 lkp
->lk_exclusivecount
= 1;
380 if (lkp
->lk_exclusivecount
!= 0) {
381 if (pid
!= lkp
->lk_lockholder
||
382 lkp
->lk_lockthread
!= self
)
383 panic("lockmgr: pid %d, thread 0x%8x,"
384 " not exclusive lock holder pid %d"
385 " thread 0x%8x unlocking, exclusive count %d",
386 pid
, self
, lkp
->lk_lockholder
,
387 lkp
->lk_lockthread
, lkp
->lk_exclusivecount
);
388 lkp
->lk_exclusivecount
--;
390 if (lkp
->lk_exclusivecount
== 0) {
391 lkp
->lk_flags
&= ~LK_HAVE_EXCL
;
392 lkp
->lk_lockholder
= LK_NOPROC
;
393 lkp
->lk_lockthread
= 0;
395 } else if (lkp
->lk_sharecount
!= 0) {
396 lkp
->lk_sharecount
--;
399 if (lkp
->lk_waitcount
)
405 * Check that we do not already hold the lock, as it can
406 * never drain if we do. Unfortunately, we have no way to
407 * check for holding a shared lock, but at least we can
408 * check for an exclusive one.
410 if (lkp
->lk_lockholder
== pid
&& lkp
->lk_lockthread
== self
)
411 panic("lockmgr: draining against myself");
413 * If we are just polling, check to see if we will sleep.
415 if ((extflags
& LK_NOWAIT
) && ((lkp
->lk_flags
&
416 (LK_HAVE_EXCL
| LK_WANT_EXCL
| LK_WANT_UPGRADE
)) ||
417 lkp
->lk_sharecount
!= 0 || lkp
->lk_waitcount
!= 0)) {
421 PAUSE(lkp
, ((lkp
->lk_flags
&
422 (LK_HAVE_EXCL
| LK_WANT_EXCL
| LK_WANT_UPGRADE
)) ||
423 lkp
->lk_sharecount
!= 0 || lkp
->lk_waitcount
!= 0));
424 for (error
= 0; ((lkp
->lk_flags
&
425 (LK_HAVE_EXCL
| LK_WANT_EXCL
| LK_WANT_UPGRADE
)) ||
426 lkp
->lk_sharecount
!= 0 || lkp
->lk_waitcount
!= 0); ) {
427 lkp
->lk_flags
|= LK_WAITDRAIN
;
428 if (error
= tsleep((void *)&lkp
->lk_flags
, lkp
->lk_prio
,
429 lkp
->lk_wmesg
, lkp
->lk_timo
))
431 if ((extflags
) & LK_SLEEPFAIL
)
434 lkp
->lk_flags
|= LK_DRAINING
| LK_HAVE_EXCL
;
435 lkp
->lk_lockholder
= pid
;
436 lkp
->lk_lockthread
= self
;
437 lkp
->lk_exclusivecount
= 1;
442 panic("lockmgr: unknown locktype request %d",
443 flags
& LK_TYPE_MASK
);
446 if ((lkp
->lk_flags
& LK_WAITDRAIN
) && ((lkp
->lk_flags
&
447 (LK_HAVE_EXCL
| LK_WANT_EXCL
| LK_WANT_UPGRADE
)) == 0 &&
448 lkp
->lk_sharecount
== 0 && lkp
->lk_waitcount
== 0)) {
449 lkp
->lk_flags
&= ~LK_WAITDRAIN
;
450 wakeup((void *)&lkp
->lk_flags
);
456 * Print out information about state of a lock. Used by VOP_PRINT
457 * routines to display ststus about contained locks.
460 lockmgr_printinfo(lkp
)
461 struct lock__bsd__
*lkp
;
464 if (lkp
->lk_sharecount
)
465 printf(" lock type %s: SHARED (count %d)", lkp
->lk_wmesg
,
467 else if (lkp
->lk_flags
& LK_HAVE_EXCL
)
468 printf(" lock type %s: EXCL (count %d) by pid %d",
469 lkp
->lk_wmesg
, lkp
->lk_exclusivecount
, lkp
->lk_lockholder
);
470 if (lkp
->lk_waitcount
> 0)
471 printf(" with %d pending", lkp
->lk_waitcount
);