|
|
1.1 ! root 1: /* ! 2: * Copyright (c) 1999 Apple Computer, Inc. All rights reserved. ! 3: * ! 4: * @APPLE_LICENSE_HEADER_START@ ! 5: * ! 6: * Portions Copyright (c) 1999 Apple Computer, Inc. All Rights ! 7: * Reserved. This file contains Original Code and/or Modifications of ! 8: * Original Code as defined in and that are subject to the Apple Public ! 9: * Source License Version 1.1 (the "License"). You may not use this file ! 10: * except in compliance with the License. Please obtain a copy of the ! 11: * License at http://www.apple.com/publicsource and read it before using ! 12: * this file. ! 13: * ! 14: * The Original Code and all software distributed under the License are ! 15: * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER ! 16: * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, ! 17: * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, ! 18: * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the ! 19: * License for the specific language governing rights and limitations ! 20: * under the License. ! 21: * ! 22: * @APPLE_LICENSE_HEADER_END@ ! 23: */ ! 24: ! 25: /* ! 26: * Mach Operating System ! 27: * Copyright (c) 1993-1987 Carnegie Mellon University ! 28: * All Rights Reserved. ! 29: * ! 30: * Permission to use, copy, modify and distribute this software and its ! 31: * documentation is hereby granted, provided that both the copyright ! 32: * notice and this permission notice appear in all copies of the ! 33: * software, derivative works or modified versions, and any portions ! 34: * thereof, and that both notices appear in supporting documentation. ! 35: * ! 36: * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" ! 37: * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR ! 38: * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. ! 39: * ! 40: * Carnegie Mellon requests users of this software to return to ! 41: * ! 42: * Software Distribution Coordinator or [email protected] ! 43: * School of Computer Science ! 44: * Carnegie Mellon University ! 45: * Pittsburgh PA 15213-3890 ! 46: * ! 47: * any improvements or extensions that they make and grant Carnegie Mellon ! 48: * the rights to redistribute these changes. ! 49: */ ! 50: /* ! 51: * File: kern/lock.c ! 52: * Author: Avadis Tevanian, Jr., Michael Wayne Young ! 53: * Date: 1985 ! 54: * ! 55: * Locking primitives implementation ! 56: */ ! 57: ! 58: #include <cpus.h> ! 59: ! 60: #include <kern/lock.h> ! 61: #include <kern/thread.h> ! 62: #include <kern/sched_prim.h> ! 63: ! 64: ! 65: #if (DIAGNOSTIC && defined(__ppc__)) ! 66: void ! 67: simple_lock( ! 68: simple_lock_t slock) ! 69: { ! 70: real_simple_lock(slock); /* inline in mach/{ppc,i386}/simple_lock.h */ ! 71: slock->lock_data[1] = (int)(current_thread()); ! 72: } ! 73: #endif /* DIAGNOSTIC */ ! 74: ! 75: #if NCPUS > 1 ! 76: ! 77: /* ! 78: * Module: lock ! 79: * Function: ! 80: * Provide reader/writer sychronization. ! 81: * Implementation: ! 82: * Simple interlock on a bit. Readers first interlock, ! 83: * increment the reader count, then let go. Writers hold ! 84: * the interlock (thus preventing further readers), and ! 85: * wait for already-accepted readers to go away. ! 86: */ ! 87: ! 88: /* ! 89: * The simple-lock routines are the primitives out of which ! 90: * the lock package is built. The implementation is left ! 91: * to the machine-dependent code. ! 92: */ ! 93: ! 94: #ifdef notdef ! 95: /* ! 96: * A sample implementation of simple locks. ! 97: * assumes: ! 98: * boolean_t test_and_set(boolean_t *) ! 99: * indivisibly sets the boolean to TRUE ! 100: * and returns its old value ! 101: * and that setting a boolean to FALSE is indivisible. ! 102: */ ! 103: /* ! 104: * simple_lock_init initializes a simple lock. A simple lock ! 105: * may only be used for exclusive locks. ! 106: */ ! 107: ! 108: void simple_lock_init(simple_lock_t l) ! 109: { ! 110: *(boolean_t *)l = FALSE; ! 111: } ! 112: ! 113: void simple_lock(simple_lock_t l) ! 114: { ! 115: while (test_and_set((boolean_t *)l)) ! 116: continue; ! 117: } ! 118: ! 119: void simple_unlock(simple_lock_t l) ! 120: { ! 121: *(boolean_t *)l = FALSE; ! 122: } ! 123: ! 124: boolean_t simple_lock_try(simple_lock_t l) ! 125: { ! 126: return (!test_and_set((boolean_t *)l)); ! 127: } ! 128: #endif /* notdef */ ! 129: #endif /* NCPUS > 1 */ ! 130: ! 131: #if NCPUS > 1 ! 132: int lock_wait_time = 100; ! 133: #else /* NCPUS > 1 */ ! 134: ! 135: /* ! 136: * It is silly to spin on a uni-processor as if we ! 137: * thought something magical would happen to the ! 138: * want_write bit while we are executing. ! 139: */ ! 140: int lock_wait_time = 0; ! 141: #endif /* NCPUS > 1 */ ! 142: ! 143: simple_lock_t simple_lock_alloc(void) ! 144: { ! 145: #if MACH_SLOCKS ! 146: return (simple_lock_t)kalloc(sizeof(simple_lock_data_t)); ! 147: #else MACH_SLOCKS ! 148: return 0; ! 149: #endif MACH_SLOCKS ! 150: } ! 151: ! 152: void simple_lock_free( ! 153: simple_lock_t l) ! 154: { ! 155: #if MACH_SLOCKS ! 156: kfree(l, sizeof(*l)); ! 157: #endif MACH_SLOCKS ! 158: } ! 159: ! 160: /* ! 161: * Routine: lock_alloc ! 162: * Function: ! 163: * Allocate a lock_t data structure. Used by loadable ! 164: * servers that can't allocate a lock statically. ! 165: */ ! 166: lock_t lock_alloc(void) ! 167: { ! 168: return (lock_t)kalloc(sizeof(lock_data_t)); ! 169: } ! 170: ! 171: /* ! 172: * Routine: lock_free ! 173: * Function: ! 174: * Free a lock allocated by lock_alloc() ! 175: */ ! 176: void lock_free( ! 177: lock_t l) ! 178: { ! 179: kfree(l, sizeof(lock_data_t)); ! 180: } ! 181: ! 182: /* ! 183: * Routine: lock_init ! 184: * Function: ! 185: * Initialize a lock; required before use. ! 186: * Note that clients declare the "struct lock" ! 187: * variables and then initialize them, rather ! 188: * than getting a new one from this module. ! 189: */ ! 190: void lock_init( ! 191: lock_t l, ! 192: boolean_t can_sleep) ! 193: { ! 194: bzero((char *)l, sizeof(lock_data_t)); ! 195: simple_lock_init(&l->interlock); ! 196: l->want_write = FALSE; ! 197: l->want_upgrade = FALSE; ! 198: l->read_count = 0; ! 199: l->can_sleep = can_sleep; ! 200: l->thread = (struct thread *)-1; /* XXX */ ! 201: l->recursion_depth = 0; ! 202: } ! 203: ! 204: void lock_sleepable( ! 205: lock_t l, ! 206: boolean_t can_sleep) ! 207: { ! 208: simple_lock(&l->interlock); ! 209: l->can_sleep = can_sleep; ! 210: simple_unlock(&l->interlock); ! 211: } ! 212: ! 213: ! 214: /* ! 215: * Sleep locks. These use the same data structure and algorithm ! 216: * as the spin locks, but the process sleeps while it is waiting ! 217: * for the lock. These work on uniprocessor systems. ! 218: */ ! 219: ! 220: void lock_write( ! 221: register lock_t l) ! 222: { ! 223: register int i; ! 224: ! 225: simple_lock(&l->interlock); ! 226: ! 227: if (l->thread == current_thread()) { ! 228: /* ! 229: * Recursive lock. ! 230: */ ! 231: l->recursion_depth++; ! 232: simple_unlock(&l->interlock); ! 233: return; ! 234: } ! 235: ! 236: /* ! 237: * Try to acquire the want_write bit. ! 238: */ ! 239: while (l->want_write) { ! 240: if ((i = lock_wait_time) > 0) { ! 241: simple_unlock(&l->interlock); ! 242: while (--i > 0 && l->want_write) ! 243: continue; ! 244: simple_lock(&l->interlock); ! 245: } ! 246: ! 247: if (l->can_sleep && l->want_write) { ! 248: l->waiting = TRUE; ! 249: thread_sleep(l, ! 250: simple_lock_addr(l->interlock), FALSE); ! 251: simple_lock(&l->interlock); ! 252: } ! 253: } ! 254: l->want_write = TRUE; ! 255: ! 256: /* Wait for readers (and upgrades) to finish */ ! 257: ! 258: while ((l->read_count != 0) || l->want_upgrade) { ! 259: if ((i = lock_wait_time) > 0) { ! 260: simple_unlock(&l->interlock); ! 261: while (--i > 0 && (l->read_count != 0 || ! 262: l->want_upgrade)) ! 263: continue; ! 264: simple_lock(&l->interlock); ! 265: } ! 266: ! 267: if (l->can_sleep && (l->read_count != 0 || l->want_upgrade)) { ! 268: l->waiting = TRUE; ! 269: thread_sleep(l, ! 270: simple_lock_addr(l->interlock), FALSE); ! 271: simple_lock(&l->interlock); ! 272: } ! 273: } ! 274: simple_unlock(&l->interlock); ! 275: } ! 276: ! 277: void lock_done( ! 278: register lock_t l) ! 279: { ! 280: simple_lock(&l->interlock); ! 281: ! 282: if (l->read_count != 0) ! 283: l->read_count--; ! 284: else ! 285: if (l->recursion_depth != 0) ! 286: l->recursion_depth--; ! 287: else ! 288: if (l->want_upgrade) ! 289: l->want_upgrade = FALSE; ! 290: else ! 291: l->want_write = FALSE; ! 292: ! 293: /* ! 294: * There is no reason to wakeup a waiting thread ! 295: * if the read-count is non-zero. Consider: ! 296: * we must be dropping a read lock ! 297: * threads are waiting only if one wants a write lock ! 298: * if there are still readers, they can't proceed ! 299: */ ! 300: ! 301: if (l->waiting && (l->read_count == 0)) { ! 302: l->waiting = FALSE; ! 303: thread_wakeup(l); ! 304: } ! 305: ! 306: simple_unlock(&l->interlock); ! 307: } ! 308: ! 309: void lock_read( ! 310: register lock_t l) ! 311: { ! 312: register int i; ! 313: ! 314: simple_lock(&l->interlock); ! 315: ! 316: if (l->thread == current_thread()) { ! 317: /* ! 318: * Recursive lock. ! 319: */ ! 320: l->read_count++; ! 321: simple_unlock(&l->interlock); ! 322: return; ! 323: } ! 324: ! 325: while (l->want_write || l->want_upgrade) { ! 326: if ((i = lock_wait_time) > 0) { ! 327: simple_unlock(&l->interlock); ! 328: while (--i > 0 && (l->want_write || l->want_upgrade)) ! 329: continue; ! 330: simple_lock(&l->interlock); ! 331: } ! 332: ! 333: if (l->can_sleep && (l->want_write || l->want_upgrade)) { ! 334: l->waiting = TRUE; ! 335: thread_sleep(l, ! 336: simple_lock_addr(l->interlock), FALSE); ! 337: simple_lock(&l->interlock); ! 338: } ! 339: } ! 340: ! 341: l->read_count++; ! 342: simple_unlock(&l->interlock); ! 343: } ! 344: ! 345: /* ! 346: * Routine: lock_read_to_write ! 347: * Function: ! 348: * Improves a read-only lock to one with ! 349: * write permission. If another reader has ! 350: * already requested an upgrade to a write lock, ! 351: * no lock is held upon return. ! 352: * ! 353: * Returns TRUE if the upgrade *failed*. ! 354: */ ! 355: boolean_t lock_read_to_write( ! 356: register lock_t l) ! 357: { ! 358: register int i; ! 359: ! 360: simple_lock(&l->interlock); ! 361: ! 362: l->read_count--; ! 363: ! 364: if (l->thread == current_thread()) { ! 365: /* ! 366: * Recursive lock. ! 367: */ ! 368: l->recursion_depth++; ! 369: simple_unlock(&l->interlock); ! 370: return(FALSE); ! 371: } ! 372: ! 373: if (l->want_upgrade) { ! 374: /* ! 375: * Someone else has requested upgrade. ! 376: * Since we've released a read lock, wake ! 377: * him up. ! 378: */ ! 379: if (l->waiting && (l->read_count == 0)) { ! 380: l->waiting = FALSE; ! 381: thread_wakeup(l); ! 382: } ! 383: ! 384: simple_unlock(&l->interlock); ! 385: return TRUE; ! 386: } ! 387: ! 388: l->want_upgrade = TRUE; ! 389: ! 390: while (l->read_count != 0) { ! 391: if ((i = lock_wait_time) > 0) { ! 392: simple_unlock(&l->interlock); ! 393: while (--i > 0 && l->read_count != 0) ! 394: continue; ! 395: simple_lock(&l->interlock); ! 396: } ! 397: ! 398: if (l->can_sleep && l->read_count != 0) { ! 399: l->waiting = TRUE; ! 400: thread_sleep(l, ! 401: simple_lock_addr(l->interlock), FALSE); ! 402: simple_lock(&l->interlock); ! 403: } ! 404: } ! 405: ! 406: simple_unlock(&l->interlock); ! 407: return FALSE; ! 408: } ! 409: ! 410: void lock_write_to_read( ! 411: register lock_t l) ! 412: { ! 413: simple_lock(&l->interlock); ! 414: ! 415: l->read_count++; ! 416: if (l->recursion_depth != 0) ! 417: l->recursion_depth--; ! 418: else ! 419: if (l->want_upgrade) ! 420: l->want_upgrade = FALSE; ! 421: else ! 422: l->want_write = FALSE; ! 423: ! 424: if (l->waiting) { ! 425: l->waiting = FALSE; ! 426: thread_wakeup(l); ! 427: } ! 428: ! 429: simple_unlock(&l->interlock); ! 430: } ! 431: ! 432: ! 433: /* ! 434: * Routine: lock_try_write ! 435: * Function: ! 436: * Tries to get a write lock. ! 437: * ! 438: * Returns FALSE if the lock is not held on return. ! 439: */ ! 440: ! 441: boolean_t lock_try_write( ! 442: register lock_t l) ! 443: { ! 444: simple_lock(&l->interlock); ! 445: ! 446: if (l->thread == current_thread()) { ! 447: /* ! 448: * Recursive lock ! 449: */ ! 450: l->recursion_depth++; ! 451: simple_unlock(&l->interlock); ! 452: return TRUE; ! 453: } ! 454: ! 455: if (l->want_write || l->want_upgrade || l->read_count) { ! 456: /* ! 457: * Can't get lock. ! 458: */ ! 459: simple_unlock(&l->interlock); ! 460: return FALSE; ! 461: } ! 462: ! 463: /* ! 464: * Have lock. ! 465: */ ! 466: ! 467: l->want_write = TRUE; ! 468: simple_unlock(&l->interlock); ! 469: return TRUE; ! 470: } ! 471: ! 472: /* ! 473: * Routine: lock_try_read ! 474: * Function: ! 475: * Tries to get a read lock. ! 476: * ! 477: * Returns FALSE if the lock is not held on return. ! 478: */ ! 479: ! 480: boolean_t lock_try_read( ! 481: register lock_t l) ! 482: { ! 483: simple_lock(&l->interlock); ! 484: ! 485: if (l->thread == current_thread()) { ! 486: /* ! 487: * Recursive lock ! 488: */ ! 489: l->read_count++; ! 490: simple_unlock(&l->interlock); ! 491: return TRUE; ! 492: } ! 493: ! 494: if (l->want_write || l->want_upgrade) { ! 495: simple_unlock(&l->interlock); ! 496: return FALSE; ! 497: } ! 498: ! 499: l->read_count++; ! 500: simple_unlock(&l->interlock); ! 501: return TRUE; ! 502: } ! 503: ! 504: /* ! 505: * Routine: lock_try_read_to_write ! 506: * Function: ! 507: * Improves a read-only lock to one with ! 508: * write permission. If another reader has ! 509: * already requested an upgrade to a write lock, ! 510: * the read lock is still held upon return. ! 511: * ! 512: * Returns FALSE if the upgrade *failed*. ! 513: */ ! 514: boolean_t lock_try_read_to_write( ! 515: register lock_t l) ! 516: { ! 517: simple_lock(&l->interlock); ! 518: ! 519: if (l->thread == current_thread()) { ! 520: /* ! 521: * Recursive lock ! 522: */ ! 523: l->read_count--; ! 524: l->recursion_depth++; ! 525: simple_unlock(&l->interlock); ! 526: return TRUE; ! 527: } ! 528: ! 529: if (l->want_upgrade) { ! 530: simple_unlock(&l->interlock); ! 531: return FALSE; ! 532: } ! 533: l->want_upgrade = TRUE; ! 534: l->read_count--; ! 535: ! 536: while (l->read_count != 0) { ! 537: l->waiting = TRUE; ! 538: thread_sleep(l, ! 539: simple_lock_addr(l->interlock), FALSE); ! 540: simple_lock(&l->interlock); ! 541: } ! 542: ! 543: simple_unlock(&l->interlock); ! 544: return TRUE; ! 545: } ! 546: ! 547: /* ! 548: * Allow a process that has a lock for write to acquire it ! 549: * recursively (for read, write, or update). ! 550: */ ! 551: void lock_set_recursive( ! 552: lock_t l) ! 553: { ! 554: simple_lock(&l->interlock); ! 555: if (!l->want_write) { ! 556: panic("lock_set_recursive: don't have write lock"); ! 557: } ! 558: l->thread = current_thread(); ! 559: simple_unlock(&l->interlock); ! 560: } ! 561: ! 562: /* ! 563: * Prevent a lock from being re-acquired. ! 564: */ ! 565: void lock_clear_recursive( ! 566: lock_t l) ! 567: { ! 568: simple_lock(&l->interlock); ! 569: if (l->thread != current_thread()) { ! 570: panic("lock_clear_recursive: wrong thread"); ! 571: } ! 572: if (l->recursion_depth == 0) ! 573: l->thread = (struct thread *)-1; /* XXX */ ! 574: simple_unlock(&l->interlock); ! 575: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.