|
|
1.1 root 1: /*
2: * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
3: *
4: * @APPLE_LICENSE_HEADER_START@
5: *
6: * The contents of this file constitute Original Code as defined in and
7: * are subject to the Apple Public Source License Version 1.1 (the
8: * "License"). You may not use this file except in compliance with the
9: * License. Please obtain a copy of the License at
10: * http://www.apple.com/publicsource and read it before using this file.
11: *
12: * This Original Code and all software distributed under the License are
13: * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14: * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15: * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16: * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17: * License for the specific language governing rights and limitations
18: * under the License.
19: *
20: * @APPLE_LICENSE_HEADER_END@
21: */
22: /* Copyright (c) 1995, 1997 Apple Computer, Inc. All Rights Reserved */
23: /*
24: * Copyright (c) 1995
25: * The Regents of the University of California. All rights reserved.
26: *
27: * This code contains ideas from software contributed to Berkeley by
28: * Avadis Tevanian, Jr., Michael Wayne Young, and the Mach Operating
29: * System project at Carnegie-Mellon University.
30: *
31: * Redistribution and use in source and binary forms, with or without
32: * modification, are permitted provided that the following conditions
33: * are met:
34: * 1. Redistributions of source code must retain the above copyright
35: * notice, this list of conditions and the following disclaimer.
36: * 2. Redistributions in binary form must reproduce the above copyright
37: * notice, this list of conditions and the following disclaimer in the
38: * documentation and/or other materials provided with the distribution.
39: * 3. All advertising materials mentioning features or use of this software
40: * must display the following acknowledgement:
41: * This product includes software developed by the University of
42: * California, Berkeley and its contributors.
43: * 4. Neither the name of the University nor the names of its contributors
44: * may be used to endorse or promote products derived from this software
45: * without specific prior written permission.
46: *
47: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
48: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
49: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
50: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
51: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
52: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
53: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
54: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
55: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
56: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
57: * SUCH DAMAGE.
58: *
59: * @(#)kern_lock.c 8.18 (Berkeley) 5/21/95
60: */
61:
62: #include <sys/param.h>
63: #include <sys/proc.h>
64: #include <sys/lock.h>
65: #include <kern/cpu_number.h>
66: #include <kern/thread.h>
67:
68: #include <mach/mach_types.h>
69:
70: /*
71: * Locking primitives implementation.
72: * Locks provide shared/exclusive sychronization.
73: */
74:
75: #if 0
76: #define COUNT(p, x) if (p) (p)->p_locks += (x)
77: #else
78: #define COUNT(p, x)
79: #endif
80:
81: #if NCPUS > 1
82:
83: /*
84: * For multiprocessor system, try spin lock first.
85: *
86: * This should be inline expanded below, but we cannot have #if
87: * inside a multiline define.
88: */
89: int lock_wait_time = 100;
90: #define PAUSE(lkp, wanted) \
91: if (lock_wait_time > 0) { \
92: int i; \
93: \
94: simple_unlock(&lkp->lk_interlock); \
95: for (i = lock_wait_time; i > 0; i--) \
96: if (!(wanted)) \
97: break; \
98: simple_lock(&lkp->lk_interlock); \
99: } \
100: if (!(wanted)) \
101: break;
102:
103: #else /* NCPUS == 1 */
104:
105: /*
106: * It is an error to spin on a uniprocessor as nothing will ever cause
107: * the simple lock to clear while we are executing.
108: */
109: #define PAUSE(lkp, wanted)
110:
111: #endif /* NCPUS == 1 */
112:
113: /*
114: * Acquire a resource.
115: */
116: #define ACQUIRE(lkp, error, extflags, wanted) \
117: PAUSE(lkp, wanted); \
118: for (error = 0; wanted; ) { \
119: (lkp)->lk_waitcount++; \
120: simple_unlock(&(lkp)->lk_interlock); \
121: error = tsleep((void *)lkp, (lkp)->lk_prio, \
122: (lkp)->lk_wmesg, (lkp)->lk_timo); \
123: simple_lock(&(lkp)->lk_interlock); \
124: (lkp)->lk_waitcount--; \
125: if (error) \
126: break; \
127: if ((extflags) & LK_SLEEPFAIL) { \
128: error = ENOLCK; \
129: break; \
130: } \
131: }
132:
133: /*
134: * Initialize a lock; required before use.
135: */
136: void
137: lockinit(lkp, prio, wmesg, timo, flags)
138: struct lock__bsd__ *lkp;
139: int prio;
140: char *wmesg;
141: int timo;
142: int flags;
143: {
144:
145: bzero(lkp, sizeof(struct lock__bsd__));
146: simple_lock_init(&lkp->lk_interlock);
147: lkp->lk_flags = flags & LK_EXTFLG_MASK;
148: lkp->lk_prio = prio;
149: lkp->lk_timo = timo;
150: lkp->lk_wmesg = wmesg;
151: lkp->lk_lockholder = LK_NOPROC;
152: lkp->lk_lockthread = 0;
153: }
154:
155: /*
156: * Determine the status of a lock.
157: */
158: int
159: lockstatus(lkp)
160: struct lock__bsd__ *lkp;
161: {
162: int lock_type = 0;
163:
164: simple_lock(&lkp->lk_interlock);
165: if (lkp->lk_exclusivecount != 0)
166: lock_type = LK_EXCLUSIVE;
167: else if (lkp->lk_sharecount != 0)
168: lock_type = LK_SHARED;
169: simple_unlock(&lkp->lk_interlock);
170: return (lock_type);
171: }
172:
173: /*
174: * Set, change, or release a lock.
175: *
176: * Shared requests increment the shared count. Exclusive requests set the
177: * LK_WANT_EXCL flag (preventing further shared locks), and wait for already
178: * accepted shared locks and shared-to-exclusive upgrades to go away.
179: */
180: int
181: lockmgr(lkp, flags, interlkp, p)
182: struct lock__bsd__ *lkp;
183: u_int flags;
184: simple_lock_t interlkp;
185: struct proc *p;
186: {
187: int error;
188: pid_t pid;
189: int extflags;
190: void *self;
191:
192: error = 0; self = current_thread();
193: if (p)
194: pid = p->p_pid;
195: else
196: pid = LK_KERNPROC;
197: simple_lock(&lkp->lk_interlock);
198: if (flags & LK_INTERLOCK)
199: simple_unlock(interlkp);
200: extflags = (flags | lkp->lk_flags) & LK_EXTFLG_MASK;
201: #if 0
202: /*
203: * Once a lock has drained, the LK_DRAINING flag is set and an
204: * exclusive lock is returned. The only valid operation thereafter
205: * is a single release of that exclusive lock. This final release
206: * clears the LK_DRAINING flag and sets the LK_DRAINED flag. Any
207: * further requests of any sort will result in a panic. The bits
208: * selected for these two flags are chosen so that they will be set
209: * in memory that is freed (freed memory is filled with 0xdeadbeef).
210: * The final release is permitted to give a new lease on life to
211: * the lock by specifying LK_REENABLE.
212: */
213: if (lkp->lk_flags & (LK_DRAINING|LK_DRAINED)) {
214: if (lkp->lk_flags & LK_DRAINED)
215: panic("lockmgr: using decommissioned lock");
216: if ((flags & LK_TYPE_MASK) != LK_RELEASE ||
217: (lkp->lk_lockholder != pid && lkp->lk_lockthread != self)
218: panic("lockmgr: non-release on draining lock: %d\n",
219: flags & LK_TYPE_MASK);
220: lkp->lk_flags &= ~LK_DRAINING;
221: if ((flags & LK_REENABLE) == 0)
222: lkp->lk_flags |= LK_DRAINED;
223: }
224: #endif
225:
226: switch (flags & LK_TYPE_MASK) {
227:
228: case LK_SHARED:
229: if (lkp->lk_lockholder != pid || lkp->lk_lockthread != self) {
230: /*
231: * If just polling, check to see if we will block.
232: */
233: if ((extflags & LK_NOWAIT) && (lkp->lk_flags &
234: (LK_HAVE_EXCL | LK_WANT_EXCL | LK_WANT_UPGRADE))) {
235: error = EBUSY;
236: break;
237: }
238: /*
239: * Wait for exclusive locks and upgrades to clear.
240: */
241: ACQUIRE(lkp, error, extflags, lkp->lk_flags &
242: (LK_HAVE_EXCL | LK_WANT_EXCL | LK_WANT_UPGRADE));
243: if (error)
244: break;
245: lkp->lk_sharecount++;
246: COUNT(p, 1);
247: break;
248: }
249: /*
250: * We hold an exclusive lock, so downgrade it to shared.
251: * An alternative would be to fail with EDEADLK.
252: */
253: lkp->lk_sharecount++;
254: COUNT(p, 1);
255: /* fall into downgrade */
256:
257: case LK_DOWNGRADE:
258: if (lkp->lk_lockholder != pid ||
259: lkp->lk_lockthread != self ||
260: lkp->lk_exclusivecount == 0)
261: panic("lockmgr: not holding exclusive lock");
262: lkp->lk_sharecount += lkp->lk_exclusivecount;
263: lkp->lk_exclusivecount = 0;
264: lkp->lk_flags &= ~LK_HAVE_EXCL;
265: lkp->lk_lockholder = LK_NOPROC;
266: lkp->lk_lockthread = 0;
267: if (lkp->lk_waitcount)
268: wakeup((void *)lkp);
269: break;
270:
271: case LK_EXCLUPGRADE:
272: /*
273: * If another process is ahead of us to get an upgrade,
274: * then we want to fail rather than have an intervening
275: * exclusive access.
276: */
277: if (lkp->lk_flags & LK_WANT_UPGRADE) {
278: lkp->lk_sharecount--;
279: COUNT(p, -1);
280: error = EBUSY;
281: break;
282: }
283: /* fall into normal upgrade */
284:
285: case LK_UPGRADE:
286: /*
287: * Upgrade a shared lock to an exclusive one. If another
288: * shared lock has already requested an upgrade to an
289: * exclusive lock, our shared lock is released and an
290: * exclusive lock is requested (which will be granted
291: * after the upgrade). If we return an error, the file
292: * will always be unlocked.
293: */
294: if ((lkp->lk_lockholder == pid &&
295: lkp->lk_lockthread == self) ||
296: lkp->lk_sharecount <= 0)
297: panic("lockmgr: upgrade exclusive lock");
298: lkp->lk_sharecount--;
299: COUNT(p, -1);
300: /*
301: * If we are just polling, check to see if we will block.
302: */
303: if ((extflags & LK_NOWAIT) &&
304: ((lkp->lk_flags & LK_WANT_UPGRADE) ||
305: lkp->lk_sharecount > 1)) {
306: error = EBUSY;
307: break;
308: }
309: if ((lkp->lk_flags & LK_WANT_UPGRADE) == 0) {
310: /*
311: * We are first shared lock to request an upgrade, so
312: * request upgrade and wait for the shared count to
313: * drop to zero, then take exclusive lock.
314: */
315: lkp->lk_flags |= LK_WANT_UPGRADE;
316: ACQUIRE(lkp, error, extflags, lkp->lk_sharecount);
317: lkp->lk_flags &= ~LK_WANT_UPGRADE;
318: if (error)
319: break;
320: lkp->lk_flags |= LK_HAVE_EXCL;
321: lkp->lk_lockholder = pid;
322: lkp->lk_lockthread = self;
323: if (lkp->lk_exclusivecount != 0)
324: panic("lockmgr: non-zero exclusive count");
325: lkp->lk_exclusivecount = 1;
326: COUNT(p, 1);
327: break;
328: }
329: /*
330: * Someone else has requested upgrade. Release our shared
331: * lock, awaken upgrade requestor if we are the last shared
332: * lock, then request an exclusive lock.
333: */
334: if (lkp->lk_sharecount == 0 && lkp->lk_waitcount)
335: wakeup((void *)lkp);
336: /* fall into exclusive request */
337:
338: case LK_EXCLUSIVE:
339: if (lkp->lk_lockholder == pid && lkp->lk_lockthread == self) {
340: /*
341: * Recursive lock.
342: */
343: if ((extflags & LK_CANRECURSE) == 0)
344: panic("lockmgr: locking against myself");
345: lkp->lk_exclusivecount++;
346: COUNT(p, 1);
347: break;
348: }
349: /*
350: * If we are just polling, check to see if we will sleep.
351: */
352: if ((extflags & LK_NOWAIT) && ((lkp->lk_flags &
353: (LK_HAVE_EXCL | LK_WANT_EXCL | LK_WANT_UPGRADE)) ||
354: lkp->lk_sharecount != 0)) {
355: error = EBUSY;
356: break;
357: }
358: /*
359: * Try to acquire the want_exclusive flag.
360: */
361: ACQUIRE(lkp, error, extflags, lkp->lk_flags &
362: (LK_HAVE_EXCL | LK_WANT_EXCL));
363: if (error)
364: break;
365: lkp->lk_flags |= LK_WANT_EXCL;
366: /*
367: * Wait for shared locks and upgrades to finish.
368: */
369: ACQUIRE(lkp, error, extflags, lkp->lk_sharecount != 0 ||
370: (lkp->lk_flags & LK_WANT_UPGRADE));
371: lkp->lk_flags &= ~LK_WANT_EXCL;
372: if (error)
373: break;
374: lkp->lk_flags |= LK_HAVE_EXCL;
375: lkp->lk_lockholder = pid;
376: lkp->lk_lockthread = self;
377: if (lkp->lk_exclusivecount != 0)
378: panic("lockmgr: non-zero exclusive count");
379: lkp->lk_exclusivecount = 1;
380: COUNT(p, 1);
381: break;
382:
383: case LK_RELEASE:
384: if (lkp->lk_exclusivecount != 0) {
385: if (pid != lkp->lk_lockholder ||
386: lkp->lk_lockthread != self)
387: panic("lockmgr: pid %d, not %s %d unlocking",
388: pid, "exclusive lock holder",
389: lkp->lk_lockholder);
390: lkp->lk_exclusivecount--;
391: COUNT(p, -1);
392: if (lkp->lk_exclusivecount == 0) {
393: lkp->lk_flags &= ~LK_HAVE_EXCL;
394: lkp->lk_lockholder = LK_NOPROC;
395: lkp->lk_lockthread = 0;
396: }
397: } else if (lkp->lk_sharecount != 0) {
398: lkp->lk_sharecount--;
399: COUNT(p, -1);
400: }
401: if (lkp->lk_waitcount)
402: wakeup((void *)lkp);
403: break;
404:
405: case LK_DRAIN:
406: /*
407: * Check that we do not already hold the lock, as it can
408: * never drain if we do. Unfortunately, we have no way to
409: * check for holding a shared lock, but at least we can
410: * check for an exclusive one.
411: */
412: if (lkp->lk_lockholder == pid && lkp->lk_lockthread == self)
413: panic("lockmgr: draining against myself");
414: /*
415: * If we are just polling, check to see if we will sleep.
416: */
417: if ((extflags & LK_NOWAIT) && ((lkp->lk_flags &
418: (LK_HAVE_EXCL | LK_WANT_EXCL | LK_WANT_UPGRADE)) ||
419: lkp->lk_sharecount != 0 || lkp->lk_waitcount != 0)) {
420: error = EBUSY;
421: break;
422: }
423: PAUSE(lkp, ((lkp->lk_flags &
424: (LK_HAVE_EXCL | LK_WANT_EXCL | LK_WANT_UPGRADE)) ||
425: lkp->lk_sharecount != 0 || lkp->lk_waitcount != 0));
426: for (error = 0; ((lkp->lk_flags &
427: (LK_HAVE_EXCL | LK_WANT_EXCL | LK_WANT_UPGRADE)) ||
428: lkp->lk_sharecount != 0 || lkp->lk_waitcount != 0); ) {
429: lkp->lk_flags |= LK_WAITDRAIN;
430: simple_unlock(&lkp->lk_interlock);
431: if (error = tsleep((void *)&lkp->lk_flags, lkp->lk_prio,
432: lkp->lk_wmesg, lkp->lk_timo))
433: return (error);
434: if ((extflags) & LK_SLEEPFAIL)
435: return (ENOLCK);
436: simple_lock(&lkp->lk_interlock);
437: }
438: lkp->lk_flags |= LK_DRAINING | LK_HAVE_EXCL;
439: lkp->lk_lockholder = pid;
440: lkp->lk_lockthread = self;
441: lkp->lk_exclusivecount = 1;
442: COUNT(p, 1);
443: break;
444:
445: default:
446: simple_unlock(&lkp->lk_interlock);
447: panic("lockmgr: unknown locktype request %d",
448: flags & LK_TYPE_MASK);
449: /* NOTREACHED */
450: }
451: if ((lkp->lk_flags & LK_WAITDRAIN) && ((lkp->lk_flags &
452: (LK_HAVE_EXCL | LK_WANT_EXCL | LK_WANT_UPGRADE)) == 0 &&
453: lkp->lk_sharecount == 0 && lkp->lk_waitcount == 0)) {
454: lkp->lk_flags &= ~LK_WAITDRAIN;
455: wakeup((void *)&lkp->lk_flags);
456: }
457: simple_unlock(&lkp->lk_interlock);
458: return (error);
459: }
460:
461: /*
462: * Print out information about state of a lock. Used by VOP_PRINT
463: * routines to display ststus about contained locks.
464: */
465: lockmgr_printinfo(lkp)
466: struct lock__bsd__ *lkp;
467: {
468:
469: if (lkp->lk_sharecount)
470: printf(" lock type %s: SHARED (count %d)", lkp->lk_wmesg,
471: lkp->lk_sharecount);
472: else if (lkp->lk_flags & LK_HAVE_EXCL)
473: printf(" lock type %s: EXCL (count %d) by pid %d",
474: lkp->lk_wmesg, lkp->lk_exclusivecount, lkp->lk_lockholder);
475: if (lkp->lk_waitcount > 0)
476: printf(" with %d pending", lkp->lk_waitcount);
477: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.