|
|
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.