|
|
1.1 ! root 1: /* ! 2: * Copyright (c) 1991 Regents of the University of California. ! 3: * 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 7.4 (Berkeley) 4/21/91 ! 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 [email protected] ! 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 "param.h" ! 70: #include "vm_param.h" ! 71: #include "lock.h" ! 72: ! 73: /* XXX */ ! 74: #include "proc.h" ! 75: typedef int *thread_t; ! 76: #define current_thread() ((thread_t)&curproc->p_thread) ! 77: /* XXX */ ! 78: ! 79: #if NCPUS > 1 ! 80: ! 81: /* ! 82: * Module: lock ! 83: * Function: ! 84: * Provide reader/writer sychronization. ! 85: * Implementation: ! 86: * Simple interlock on a bit. Readers first interlock ! 87: * increment the reader count, then let go. Writers hold ! 88: * the interlock (thus preventing further readers), and ! 89: * wait for already-accepted readers to go away. ! 90: */ ! 91: ! 92: /* ! 93: * The simple-lock routines are the primitives out of which ! 94: * the lock package is built. The implementation is left ! 95: * to the machine-dependent code. ! 96: */ ! 97: ! 98: #ifdef notdef ! 99: /* ! 100: * A sample implementation of simple locks. ! 101: * assumes: ! 102: * boolean_t test_and_set(boolean_t *) ! 103: * indivisibly sets the boolean to TRUE ! 104: * and returns its old value ! 105: * and that setting a boolean to FALSE is indivisible. ! 106: */ ! 107: /* ! 108: * simple_lock_init initializes a simple lock. A simple lock ! 109: * may only be used for exclusive locks. ! 110: */ ! 111: ! 112: void simple_lock_init(l) ! 113: simple_lock_t l; ! 114: { ! 115: *(boolean_t *)l = FALSE; ! 116: } ! 117: ! 118: void simple_lock(l) ! 119: simple_lock_t l; ! 120: { ! 121: while (test_and_set((boolean_t *)l)) ! 122: continue; ! 123: } ! 124: ! 125: void simple_unlock(l) ! 126: simple_lock_t l; ! 127: { ! 128: *(boolean_t *)l = FALSE; ! 129: } ! 130: ! 131: boolean_t simple_lock_try(l) ! 132: simple_lock_t l; ! 133: { ! 134: return (!test_and_set((boolean_t *)l)); ! 135: } ! 136: #endif notdef ! 137: #endif NCPUS > 1 ! 138: ! 139: #if NCPUS > 1 ! 140: int lock_wait_time = 100; ! 141: #else NCPUS > 1 ! 142: ! 143: /* ! 144: * It is silly to spin on a uni-processor as if we ! 145: * thought something magical would happen to the ! 146: * want_write bit while we are executing. ! 147: */ ! 148: int lock_wait_time = 0; ! 149: #endif NCPUS > 1 ! 150: ! 151: ! 152: /* ! 153: * Routine: lock_init ! 154: * Function: ! 155: * Initialize a lock; required before use. ! 156: * Note that clients declare the "struct lock" ! 157: * variables and then initialize them, rather ! 158: * than getting a new one from this module. ! 159: */ ! 160: void lock_init(l, can_sleep) ! 161: lock_t l; ! 162: boolean_t can_sleep; ! 163: { ! 164: bzero(l, sizeof(lock_data_t)); ! 165: simple_lock_init(&l->interlock); ! 166: l->want_write = FALSE; ! 167: l->want_upgrade = FALSE; ! 168: l->read_count = 0; ! 169: l->can_sleep = can_sleep; ! 170: l->thread = (char *)-1; /* XXX */ ! 171: l->recursion_depth = 0; ! 172: } ! 173: ! 174: void lock_sleepable(l, can_sleep) ! 175: lock_t l; ! 176: boolean_t can_sleep; ! 177: { ! 178: simple_lock(&l->interlock); ! 179: l->can_sleep = can_sleep; ! 180: simple_unlock(&l->interlock); ! 181: } ! 182: ! 183: ! 184: /* ! 185: * Sleep locks. These use the same data structure and algorithm ! 186: * as the spin locks, but the process sleeps while it is waiting ! 187: * for the lock. These work on uniprocessor systems. ! 188: */ ! 189: ! 190: void lock_write(l) ! 191: register lock_t l; ! 192: { ! 193: register int i; ! 194: ! 195: simple_lock(&l->interlock); ! 196: ! 197: if (((thread_t)l->thread) == current_thread()) { ! 198: /* ! 199: * Recursive lock. ! 200: */ ! 201: l->recursion_depth++; ! 202: simple_unlock(&l->interlock); ! 203: return; ! 204: } ! 205: ! 206: /* ! 207: * Try to acquire the want_write bit. ! 208: */ ! 209: while (l->want_write) { ! 210: if ((i = lock_wait_time) > 0) { ! 211: simple_unlock(&l->interlock); ! 212: while (--i > 0 && l->want_write) ! 213: continue; ! 214: simple_lock(&l->interlock); ! 215: } ! 216: ! 217: if (l->can_sleep && l->want_write) { ! 218: l->waiting = TRUE; ! 219: thread_sleep((int) l, &l->interlock, FALSE); ! 220: simple_lock(&l->interlock); ! 221: } ! 222: } ! 223: l->want_write = TRUE; ! 224: ! 225: /* Wait for readers (and upgrades) to finish */ ! 226: ! 227: while ((l->read_count != 0) || l->want_upgrade) { ! 228: if ((i = lock_wait_time) > 0) { ! 229: simple_unlock(&l->interlock); ! 230: while (--i > 0 && (l->read_count != 0 || ! 231: l->want_upgrade)) ! 232: continue; ! 233: simple_lock(&l->interlock); ! 234: } ! 235: ! 236: if (l->can_sleep && (l->read_count != 0 || l->want_upgrade)) { ! 237: l->waiting = TRUE; ! 238: thread_sleep((int) l, &l->interlock, FALSE); ! 239: simple_lock(&l->interlock); ! 240: } ! 241: } ! 242: simple_unlock(&l->interlock); ! 243: } ! 244: ! 245: void lock_done(l) ! 246: register lock_t l; ! 247: { ! 248: simple_lock(&l->interlock); ! 249: ! 250: if (l->read_count != 0) ! 251: l->read_count--; ! 252: else ! 253: if (l->recursion_depth != 0) ! 254: l->recursion_depth--; ! 255: else ! 256: if (l->want_upgrade) ! 257: l->want_upgrade = FALSE; ! 258: else ! 259: l->want_write = FALSE; ! 260: ! 261: if (l->waiting) { ! 262: l->waiting = FALSE; ! 263: thread_wakeup((int) l); ! 264: } ! 265: simple_unlock(&l->interlock); ! 266: } ! 267: ! 268: void lock_read(l) ! 269: register lock_t l; ! 270: { ! 271: register int i; ! 272: ! 273: simple_lock(&l->interlock); ! 274: ! 275: if (((thread_t)l->thread) == current_thread()) { ! 276: /* ! 277: * Recursive lock. ! 278: */ ! 279: l->read_count++; ! 280: simple_unlock(&l->interlock); ! 281: return; ! 282: } ! 283: ! 284: while (l->want_write || l->want_upgrade) { ! 285: if ((i = lock_wait_time) > 0) { ! 286: simple_unlock(&l->interlock); ! 287: while (--i > 0 && (l->want_write || l->want_upgrade)) ! 288: continue; ! 289: simple_lock(&l->interlock); ! 290: } ! 291: ! 292: if (l->can_sleep && (l->want_write || l->want_upgrade)) { ! 293: l->waiting = TRUE; ! 294: thread_sleep((int) l, &l->interlock, FALSE); ! 295: simple_lock(&l->interlock); ! 296: } ! 297: } ! 298: ! 299: l->read_count++; ! 300: simple_unlock(&l->interlock); ! 301: } ! 302: ! 303: /* ! 304: * Routine: lock_read_to_write ! 305: * Function: ! 306: * Improves a read-only lock to one with ! 307: * write permission. If another reader has ! 308: * already requested an upgrade to a write lock, ! 309: * no lock is held upon return. ! 310: * ! 311: * Returns TRUE if the upgrade *failed*. ! 312: */ ! 313: boolean_t lock_read_to_write(l) ! 314: register lock_t l; ! 315: { ! 316: register int i; ! 317: ! 318: simple_lock(&l->interlock); ! 319: ! 320: l->read_count--; ! 321: ! 322: if (((thread_t)l->thread) == current_thread()) { ! 323: /* ! 324: * Recursive lock. ! 325: */ ! 326: l->recursion_depth++; ! 327: simple_unlock(&l->interlock); ! 328: return(FALSE); ! 329: } ! 330: ! 331: if (l->want_upgrade) { ! 332: /* ! 333: * Someone else has requested upgrade. ! 334: * Since we've released a read lock, wake ! 335: * him up. ! 336: */ ! 337: if (l->waiting) { ! 338: l->waiting = FALSE; ! 339: thread_wakeup((int) l); ! 340: } ! 341: ! 342: simple_unlock(&l->interlock); ! 343: return (TRUE); ! 344: } ! 345: ! 346: l->want_upgrade = TRUE; ! 347: ! 348: while (l->read_count != 0) { ! 349: if ((i = lock_wait_time) > 0) { ! 350: simple_unlock(&l->interlock); ! 351: while (--i > 0 && l->read_count != 0) ! 352: continue; ! 353: simple_lock(&l->interlock); ! 354: } ! 355: ! 356: if (l->can_sleep && l->read_count != 0) { ! 357: l->waiting = TRUE; ! 358: thread_sleep((int) l, &l->interlock, FALSE); ! 359: simple_lock(&l->interlock); ! 360: } ! 361: } ! 362: ! 363: simple_unlock(&l->interlock); ! 364: return (FALSE); ! 365: } ! 366: ! 367: void lock_write_to_read(l) ! 368: register lock_t l; ! 369: { ! 370: simple_lock(&l->interlock); ! 371: ! 372: l->read_count++; ! 373: if (l->recursion_depth != 0) ! 374: l->recursion_depth--; ! 375: else ! 376: if (l->want_upgrade) ! 377: l->want_upgrade = FALSE; ! 378: else ! 379: l->want_write = FALSE; ! 380: ! 381: if (l->waiting) { ! 382: l->waiting = FALSE; ! 383: thread_wakeup((int) l); ! 384: } ! 385: ! 386: simple_unlock(&l->interlock); ! 387: } ! 388: ! 389: ! 390: /* ! 391: * Routine: lock_try_write ! 392: * Function: ! 393: * Tries to get a write lock. ! 394: * ! 395: * Returns FALSE if the lock is not held on return. ! 396: */ ! 397: ! 398: boolean_t lock_try_write(l) ! 399: register lock_t l; ! 400: { ! 401: ! 402: simple_lock(&l->interlock); ! 403: ! 404: if (((thread_t)l->thread) == current_thread()) { ! 405: /* ! 406: * Recursive lock ! 407: */ ! 408: l->recursion_depth++; ! 409: simple_unlock(&l->interlock); ! 410: return(TRUE); ! 411: } ! 412: ! 413: if (l->want_write || l->want_upgrade || l->read_count) { ! 414: /* ! 415: * Can't get lock. ! 416: */ ! 417: simple_unlock(&l->interlock); ! 418: return(FALSE); ! 419: } ! 420: ! 421: /* ! 422: * Have lock. ! 423: */ ! 424: ! 425: l->want_write = TRUE; ! 426: simple_unlock(&l->interlock); ! 427: return(TRUE); ! 428: } ! 429: ! 430: /* ! 431: * Routine: lock_try_read ! 432: * Function: ! 433: * Tries to get a read lock. ! 434: * ! 435: * Returns FALSE if the lock is not held on return. ! 436: */ ! 437: ! 438: boolean_t lock_try_read(l) ! 439: register lock_t l; ! 440: { ! 441: simple_lock(&l->interlock); ! 442: ! 443: if (((thread_t)l->thread) == current_thread()) { ! 444: /* ! 445: * Recursive lock ! 446: */ ! 447: l->read_count++; ! 448: simple_unlock(&l->interlock); ! 449: return(TRUE); ! 450: } ! 451: ! 452: if (l->want_write || l->want_upgrade) { ! 453: simple_unlock(&l->interlock); ! 454: return(FALSE); ! 455: } ! 456: ! 457: l->read_count++; ! 458: simple_unlock(&l->interlock); ! 459: return(TRUE); ! 460: } ! 461: ! 462: /* ! 463: * Routine: lock_try_read_to_write ! 464: * Function: ! 465: * Improves a read-only lock to one with ! 466: * write permission. If another reader has ! 467: * already requested an upgrade to a write lock, ! 468: * the read lock is still held upon return. ! 469: * ! 470: * Returns FALSE if the upgrade *failed*. ! 471: */ ! 472: boolean_t lock_try_read_to_write(l) ! 473: register lock_t l; ! 474: { ! 475: ! 476: simple_lock(&l->interlock); ! 477: ! 478: if (((thread_t)l->thread) == current_thread()) { ! 479: /* ! 480: * Recursive lock ! 481: */ ! 482: l->read_count--; ! 483: l->recursion_depth++; ! 484: simple_unlock(&l->interlock); ! 485: return(TRUE); ! 486: } ! 487: ! 488: if (l->want_upgrade) { ! 489: simple_unlock(&l->interlock); ! 490: return(FALSE); ! 491: } ! 492: l->want_upgrade = TRUE; ! 493: l->read_count--; ! 494: ! 495: while (l->read_count != 0) { ! 496: l->waiting = TRUE; ! 497: thread_sleep((int) l, &l->interlock, FALSE); ! 498: simple_lock(&l->interlock); ! 499: } ! 500: ! 501: simple_unlock(&l->interlock); ! 502: return(TRUE); ! 503: } ! 504: ! 505: /* ! 506: * Allow a process that has a lock for write to acquire it ! 507: * recursively (for read, write, or update). ! 508: */ ! 509: void lock_set_recursive(l) ! 510: lock_t l; ! 511: { ! 512: simple_lock(&l->interlock); ! 513: if (!l->want_write) { ! 514: panic("lock_set_recursive: don't have write lock"); ! 515: } ! 516: l->thread = (char *) current_thread(); ! 517: simple_unlock(&l->interlock); ! 518: } ! 519: ! 520: /* ! 521: * Prevent a lock from being re-acquired. ! 522: */ ! 523: void lock_clear_recursive(l) ! 524: lock_t l; ! 525: { ! 526: simple_lock(&l->interlock); ! 527: if (((thread_t) l->thread) != current_thread()) { ! 528: panic("lock_clear_recursive: wrong thread"); ! 529: } ! 530: if (l->recursion_depth == 0) ! 531: l->thread = (char *)-1; /* XXX */ ! 532: simple_unlock(&l->interlock); ! 533: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.