|
|
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: * Copyright (c) 1995, 1994, 1993, 1992, 1991, 1990 ! 27: * Open Software Foundation, Inc. ! 28: * ! 29: * Permission to use, copy, modify, and distribute this software and ! 30: * its documentation for any purpose and without fee is hereby granted, ! 31: * provided that the above copyright notice appears in all copies and ! 32: * that both the copyright notice and this permission notice appear in ! 33: * supporting documentation, and that the name of ("OSF") or Open Software ! 34: * Foundation not be used in advertising or publicity pertaining to ! 35: * distribution of the software without specific, written prior permission. ! 36: * ! 37: * OSF DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE ! 38: * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS ! 39: * FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL OSF BE LIABLE FOR ANY ! 40: * SPECIAL, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES ! 41: * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN ! 42: * ACTION OF CONTRACT, NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING ! 43: * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE ! 44: */ ! 45: /* ! 46: * OSF Research Institute MK6.1 (unencumbered) 1/31/1995 ! 47: */ ! 48: /* ! 49: * Mach Operating System ! 50: * Copyright (c) 1991,1990,1989 Carnegie Mellon University ! 51: * All Rights Reserved. ! 52: * ! 53: * Permission to use, copy, modify and distribute this software and its ! 54: * documentation is hereby granted, provided that both the copyright ! 55: * notice and this permission notice appear in all copies of the ! 56: * software, derivative works or modified versions, and any portions ! 57: * thereof, and that both notices appear in supporting documentation. ! 58: * ! 59: * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" ! 60: * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR ! 61: * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. ! 62: * ! 63: * Carnegie Mellon requests users of this software to return to ! 64: * ! 65: * Software Distribution Coordinator or [email protected] ! 66: * School of Computer Science ! 67: * Carnegie Mellon University ! 68: * Pittsburgh PA 15213-3890 ! 69: * ! 70: * any improvements or extensions that they make and grant Carnegie Mellon ! 71: * the rights to redistribute these changes. ! 72: */ ! 73: /* ! 74: * File: ipc/ipc_entry.c ! 75: * Author: Rich Draves ! 76: * Date: 1989 ! 77: * ! 78: * Primitive functions to manipulate translation entries. ! 79: */ ! 80: ! 81: #include <mach/kern_return.h> ! 82: #include <mach/port.h> ! 83: #include <kern/assert.h> ! 84: #include <kern/sched_prim.h> ! 85: #include <kern/zalloc.h> ! 86: #include <ipc/port.h> ! 87: #include <ipc/ipc_entry.h> ! 88: #include <ipc/ipc_space.h> ! 89: #include <ipc/ipc_splay.h> ! 90: #include <ipc/ipc_object.h> ! 91: #include <ipc/ipc_hash.h> ! 92: #include <ipc/ipc_table.h> ! 93: #include <ipc/ipc_port.h> ! 94: ! 95: zone_t ipc_tree_entry_zone; ! 96: ! 97: /* ! 98: * Forward declarations ! 99: */ ! 100: boolean_t ipc_entry_tree_collision( ! 101: ipc_space_t space, ! 102: mach_port_t name); ! 103: ! 104: /* ! 105: * Routine: ipc_entry_tree_collision ! 106: * Purpose: ! 107: * Checks if "name" collides with an allocated name ! 108: * in the space's tree. That is, returns TRUE ! 109: * if the splay tree contains a name with the same ! 110: * index as "name". ! 111: * Conditions: ! 112: * The space is locked (read or write) and active. ! 113: */ ! 114: ! 115: boolean_t ! 116: ipc_entry_tree_collision( ! 117: ipc_space_t space, ! 118: mach_port_t name) ! 119: { ! 120: mach_port_index_t index; ! 121: mach_port_t lower, upper; ! 122: ! 123: assert(space->is_active); ! 124: ! 125: /* ! 126: * Check if we collide with the next smaller name ! 127: * or the next larger name. ! 128: */ ! 129: ! 130: ipc_splay_tree_bounds(&space->is_tree, name, &lower, &upper); ! 131: ! 132: index = MACH_PORT_INDEX(name); ! 133: return (((lower != ~0) && (MACH_PORT_INDEX(lower) == index)) || ! 134: ((upper != 0) && (MACH_PORT_INDEX(upper) == index))); ! 135: } ! 136: ! 137: /* ! 138: * Routine: ipc_entry_lookup ! 139: * Purpose: ! 140: * Searches for an entry, given its name. ! 141: * Conditions: ! 142: * The space must be read or write locked throughout. ! 143: * The space must be active. ! 144: */ ! 145: ! 146: ipc_entry_t ! 147: ipc_entry_lookup( ! 148: ipc_space_t space, ! 149: mach_port_t name) ! 150: { ! 151: mach_port_index_t index; ! 152: ipc_entry_t entry; ! 153: ! 154: assert(space->is_active); ! 155: ! 156: index = MACH_PORT_INDEX(name); ! 157: if (index < space->is_table_size) { ! 158: entry = &space->is_table[index]; ! 159: if (IE_BITS_GEN(entry->ie_bits) != MACH_PORT_GEN(name)) ! 160: if (entry->ie_bits & IE_BITS_COLLISION) { ! 161: assert(space->is_tree_total > 0); ! 162: goto tree_lookup; ! 163: } else ! 164: entry = IE_NULL; ! 165: else if (IE_BITS_TYPE(entry->ie_bits) == MACH_PORT_TYPE_NONE) ! 166: entry = IE_NULL; ! 167: } else if (space->is_tree_total == 0) ! 168: entry = IE_NULL; ! 169: else ! 170: tree_lookup: ! 171: entry = (ipc_entry_t) ! 172: ipc_splay_tree_lookup(&space->is_tree, name); ! 173: ! 174: assert((entry == IE_NULL) || IE_BITS_TYPE(entry->ie_bits)); ! 175: return entry; ! 176: } ! 177: ! 178: /* ! 179: * Routine: ipc_entry_get ! 180: * Purpose: ! 181: * Tries to allocate an entry out of the space. ! 182: * Conditions: ! 183: * The space is write-locked and active throughout. ! 184: * An object may be locked. Will not allocate memory. ! 185: * Returns: ! 186: * KERN_SUCCESS A free entry was found. ! 187: * KERN_NO_SPACE No entry allocated. ! 188: */ ! 189: ! 190: kern_return_t ! 191: ipc_entry_get( ! 192: ipc_space_t space, ! 193: mach_port_t *namep, ! 194: ipc_entry_t *entryp) ! 195: { ! 196: ipc_entry_t table; ! 197: mach_port_index_t first_free; ! 198: ipc_entry_t free_entry; ! 199: ! 200: assert(space->is_active); ! 201: ! 202: { ! 203: table = space->is_table; ! 204: first_free = table->ie_next; ! 205: ! 206: if (first_free == 0) ! 207: return KERN_NO_SPACE; ! 208: ! 209: free_entry = &table[first_free]; ! 210: table->ie_next = free_entry->ie_next; ! 211: } ! 212: ! 213: /* ! 214: * Initialize the new entry. We need only ! 215: * increment the generation number and clear ie_request. ! 216: */ ! 217: ! 218: { ! 219: mach_port_t new_name; ! 220: mach_port_gen_t gen; ! 221: ! 222: assert((free_entry->ie_bits &~ IE_BITS_GEN_MASK) == 0); ! 223: gen = free_entry->ie_bits + IE_BITS_GEN_ONE; ! 224: free_entry->ie_bits = gen; ! 225: free_entry->ie_request = 0; ! 226: /* ! 227: * The new name can't be MACH_PORT_NULL because index ! 228: * is non-zero. It can't be MACH_PORT_DEAD because ! 229: * the table isn't allowed to grow big enough. ! 230: * (See comment in ipc/ipc_table.h.) ! 231: */ ! 232: new_name = MACH_PORT_MAKE(first_free, gen); ! 233: assert(MACH_PORT_VALID(new_name)); ! 234: *namep = new_name; ! 235: } ! 236: ! 237: assert(free_entry->ie_object == IO_NULL); ! 238: ! 239: *entryp = free_entry; ! 240: return KERN_SUCCESS; ! 241: } ! 242: ! 243: /* ! 244: * Routine: ipc_entry_alloc ! 245: * Purpose: ! 246: * Allocate an entry out of the space. ! 247: * Conditions: ! 248: * The space is not locked before, but it is write-locked after ! 249: * if the call is successful. May allocate memory. ! 250: * Returns: ! 251: * KERN_SUCCESS An entry was allocated. ! 252: * KERN_INVALID_TASK The space is dead. ! 253: * KERN_NO_SPACE No room for an entry in the space. ! 254: * KERN_RESOURCE_SHORTAGE Couldn't allocate memory for an entry. ! 255: */ ! 256: ! 257: kern_return_t ! 258: ipc_entry_alloc( ! 259: ipc_space_t space, ! 260: mach_port_t *namep, ! 261: ipc_entry_t *entryp) ! 262: { ! 263: kern_return_t kr; ! 264: ! 265: is_write_lock(space); ! 266: ! 267: for (;;) { ! 268: if (!space->is_active) { ! 269: is_write_unlock(space); ! 270: return KERN_INVALID_TASK; ! 271: } ! 272: ! 273: kr = ipc_entry_get(space, namep, entryp); ! 274: if (kr == KERN_SUCCESS) ! 275: return kr; ! 276: ! 277: kr = ipc_entry_grow_table(space, ITS_SIZE_NONE); ! 278: if (kr != KERN_SUCCESS) ! 279: return kr; /* space is unlocked */ ! 280: } ! 281: } ! 282: ! 283: /* ! 284: * Routine: ipc_entry_alloc_name ! 285: * Purpose: ! 286: * Allocates/finds an entry with a specific name. ! 287: * If an existing entry is returned, its type will be nonzero. ! 288: * Conditions: ! 289: * The space is not locked before, but it is write-locked after ! 290: * if the call is successful. May allocate memory. ! 291: * Returns: ! 292: * KERN_SUCCESS Found existing entry with same name. ! 293: * KERN_SUCCESS Allocated a new entry. ! 294: * KERN_INVALID_TASK The space is dead. ! 295: * KERN_RESOURCE_SHORTAGE Couldn't allocate memory. ! 296: */ ! 297: ! 298: kern_return_t ! 299: ipc_entry_alloc_name( ! 300: ipc_space_t space, ! 301: mach_port_t name, ! 302: ipc_entry_t *entryp) ! 303: { ! 304: mach_port_index_t index = MACH_PORT_INDEX(name); ! 305: mach_port_gen_t gen = MACH_PORT_GEN(name); ! 306: ipc_tree_entry_t tree_entry = ITE_NULL; ! 307: ! 308: assert(MACH_PORT_VALID(name)); ! 309: ! 310: is_write_lock(space); ! 311: ! 312: for (;;) { ! 313: ipc_entry_t entry; ! 314: ipc_tree_entry_t tentry; ! 315: ipc_table_size_t its; ! 316: ! 317: if (!space->is_active) { ! 318: is_write_unlock(space); ! 319: if (tree_entry) ite_free(tree_entry); ! 320: return KERN_INVALID_TASK; ! 321: } ! 322: ! 323: /* ! 324: * If we are under the table cutoff, ! 325: * there are three cases: ! 326: * 1) The entry is inuse, for the same name ! 327: * 2) The entry is inuse, for a different name ! 328: * 3) The entry is free ! 329: */ ! 330: ! 331: if ((0 < index) && (index < space->is_table_size)) { ! 332: ipc_entry_t table = space->is_table; ! 333: ! 334: entry = &table[index]; ! 335: ! 336: if (IE_BITS_TYPE(entry->ie_bits)) { ! 337: if (IE_BITS_GEN(entry->ie_bits) == gen) { ! 338: *entryp = entry; ! 339: if (tree_entry) ite_free(tree_entry); ! 340: return KERN_SUCCESS; ! 341: } ! 342: } else { ! 343: mach_port_index_t free_index, next_index; ! 344: ! 345: /* ! 346: * Rip the entry out of the free list. ! 347: */ ! 348: ! 349: for (free_index = 0; ! 350: (next_index = table[free_index].ie_next) ! 351: != index; ! 352: free_index = next_index) ! 353: continue; ! 354: ! 355: table[free_index].ie_next = ! 356: table[next_index].ie_next; ! 357: ! 358: entry->ie_bits = gen; ! 359: assert(entry->ie_object == IO_NULL); ! 360: entry->ie_request = 0; ! 361: ! 362: *entryp = entry; ! 363: if (tree_entry) ite_free(tree_entry); ! 364: return KERN_SUCCESS; ! 365: } ! 366: } ! 367: ! 368: /* ! 369: * Before trying to allocate any memory, ! 370: * check if the entry already exists in the tree. ! 371: * This avoids spurious resource errors. ! 372: * The splay tree makes a subsequent lookup/insert ! 373: * of the same name cheap, so this costs little. ! 374: */ ! 375: ! 376: if ((space->is_tree_total > 0) && ! 377: ((tentry = ipc_splay_tree_lookup(&space->is_tree, name)) ! 378: != ITE_NULL)) { ! 379: assert(tentry->ite_space == space); ! 380: assert(IE_BITS_TYPE(tentry->ite_bits)); ! 381: ! 382: *entryp = &tentry->ite_entry; ! 383: if (tree_entry) ite_free(tree_entry); ! 384: return KERN_SUCCESS; ! 385: } ! 386: ! 387: its = space->is_table_next; ! 388: ! 389: /* ! 390: * Check if the table should be grown. ! 391: * ! 392: * Note that if space->is_table_size == its->its_size, ! 393: * then we won't ever try to grow the table. ! 394: * ! 395: * Note that we are optimistically assuming that name ! 396: * doesn't collide with any existing names. (So if ! 397: * it were entered into the tree, is_tree_small would ! 398: * be incremented.) This is OK, because even in that ! 399: * case, we don't lose memory by growing the table. ! 400: */ ! 401: ! 402: if ((space->is_table_size <= index) && ! 403: (index < its->its_size) && ! 404: (((its->its_size - space->is_table_size) * ! 405: sizeof(struct ipc_entry)) < ! 406: ((space->is_tree_small + 1) * ! 407: sizeof(struct ipc_tree_entry)))) { ! 408: kern_return_t kr; ! 409: ! 410: /* ! 411: * Can save space by growing the table. ! 412: * Because the space will be unlocked, ! 413: * we must restart. ! 414: */ ! 415: ! 416: kr = ipc_entry_grow_table(space, ITS_SIZE_NONE); ! 417: assert(kr != KERN_NO_SPACE); ! 418: if (kr != KERN_SUCCESS) { ! 419: /* space is unlocked */ ! 420: if (tree_entry) ite_free(tree_entry); ! 421: return kr; ! 422: } ! 423: ! 424: continue; ! 425: } ! 426: ! 427: /* ! 428: * If a splay-tree entry was allocated previously, ! 429: * go ahead and insert it into the tree. ! 430: */ ! 431: ! 432: if (tree_entry != ITE_NULL) { ! 433: space->is_tree_total++; ! 434: ! 435: if (index < space->is_table_size) ! 436: space->is_table[index].ie_bits |= ! 437: IE_BITS_COLLISION; ! 438: else if ((index < its->its_size) && ! 439: !ipc_entry_tree_collision(space, name)) ! 440: space->is_tree_small++; ! 441: ! 442: ipc_splay_tree_insert(&space->is_tree, ! 443: name, tree_entry); ! 444: ! 445: tree_entry->ite_bits = 0; ! 446: tree_entry->ite_object = IO_NULL; ! 447: tree_entry->ite_request = 0; ! 448: tree_entry->ite_space = space; ! 449: *entryp = &tree_entry->ite_entry; ! 450: return KERN_SUCCESS; ! 451: } ! 452: ! 453: /* ! 454: * Allocate a tree entry and try again. ! 455: */ ! 456: ! 457: is_write_unlock(space); ! 458: tree_entry = ite_alloc(); ! 459: if (tree_entry == ITE_NULL) ! 460: return KERN_RESOURCE_SHORTAGE; ! 461: is_write_lock(space); ! 462: } ! 463: } ! 464: ! 465: /* ! 466: * Routine: ipc_entry_dealloc ! 467: * Purpose: ! 468: * Deallocates an entry from a space. ! 469: * Conditions: ! 470: * The space must be write-locked throughout. ! 471: * The space must be active. ! 472: */ ! 473: ! 474: void ! 475: ipc_entry_dealloc( ! 476: ipc_space_t space, ! 477: mach_port_t name, ! 478: ipc_entry_t entry) ! 479: { ! 480: ipc_entry_t table; ! 481: ipc_entry_num_t size; ! 482: mach_port_index_t index; ! 483: ! 484: assert(space->is_active); ! 485: assert(entry->ie_object == IO_NULL); ! 486: assert(entry->ie_request == 0); ! 487: ! 488: index = MACH_PORT_INDEX(name); ! 489: table = space->is_table; ! 490: size = space->is_table_size; ! 491: ! 492: if ((index < size) && (entry == &table[index])) { ! 493: assert(IE_BITS_GEN(entry->ie_bits) == MACH_PORT_GEN(name)); ! 494: ! 495: if (entry->ie_bits & IE_BITS_COLLISION) { ! 496: struct ipc_splay_tree small, collisions; ! 497: ipc_tree_entry_t tentry; ! 498: mach_port_t tname; ! 499: boolean_t pick; ! 500: ipc_entry_bits_t bits; ! 501: ipc_object_t obj; ! 502: ! 503: /* must move an entry from tree to table */ ! 504: ! 505: ipc_splay_tree_split(&space->is_tree, ! 506: MACH_PORT_MAKE(index+1, 0), ! 507: &collisions); ! 508: ipc_splay_tree_split(&collisions, ! 509: MACH_PORT_MAKE(index, 0), ! 510: &small); ! 511: ! 512: pick = ipc_splay_tree_pick(&collisions, ! 513: &tname, &tentry); ! 514: assert(pick); ! 515: assert(MACH_PORT_INDEX(tname) == index); ! 516: ! 517: bits = tentry->ite_bits; ! 518: entry->ie_bits = bits | MACH_PORT_GEN(tname); ! 519: entry->ie_object = obj = tentry->ite_object; ! 520: entry->ie_request = tentry->ite_request; ! 521: assert(tentry->ite_space == space); ! 522: ! 523: if (IE_BITS_TYPE(bits) == MACH_PORT_TYPE_SEND) { ! 524: ipc_hash_global_delete(space, obj, ! 525: tname, tentry); ! 526: ipc_hash_local_insert(space, obj, ! 527: index, entry); ! 528: } ! 529: ! 530: ipc_splay_tree_delete(&collisions, tname, tentry); ! 531: ! 532: assert(space->is_tree_total > 0); ! 533: space->is_tree_total--; ! 534: ! 535: /* check if collision bit should still be on */ ! 536: ! 537: pick = ipc_splay_tree_pick(&collisions, ! 538: &tname, &tentry); ! 539: if (pick) { ! 540: entry->ie_bits |= IE_BITS_COLLISION; ! 541: ipc_splay_tree_join(&space->is_tree, ! 542: &collisions); ! 543: } ! 544: ! 545: ipc_splay_tree_join(&space->is_tree, &small); ! 546: } else { ! 547: entry->ie_bits &= IE_BITS_GEN_MASK; ! 548: entry->ie_next = table->ie_next; ! 549: table->ie_next = index; ! 550: } ! 551: } else { ! 552: ipc_tree_entry_t tentry = (ipc_tree_entry_t) entry; ! 553: ! 554: assert(tentry->ite_space == space); ! 555: ! 556: ipc_splay_tree_delete(&space->is_tree, name, tentry); ! 557: ! 558: assert(space->is_tree_total > 0); ! 559: space->is_tree_total--; ! 560: ! 561: if (index < size) { ! 562: ipc_entry_t ientry = &table[index]; ! 563: ! 564: assert(ientry->ie_bits & IE_BITS_COLLISION); ! 565: ! 566: if (!ipc_entry_tree_collision(space, name)) ! 567: ientry->ie_bits &= ~IE_BITS_COLLISION; ! 568: } else if ((index < space->is_table_next->its_size) && ! 569: !ipc_entry_tree_collision(space, name)) { ! 570: assert(space->is_tree_small > 0); ! 571: space->is_tree_small--; ! 572: } ! 573: } ! 574: } ! 575: ! 576: /* ! 577: * Routine: ipc_entry_grow_table ! 578: * Purpose: ! 579: * Grows the table in a space. ! 580: * Conditions: ! 581: * The space must be write-locked and active before. ! 582: * If successful, it is also returned locked. ! 583: * Allocates memory. ! 584: * Returns: ! 585: * KERN_SUCCESS Grew the table. ! 586: * KERN_SUCCESS Somebody else grew the table. ! 587: * KERN_SUCCESS The space died. ! 588: * KERN_NO_SPACE Table has maximum size already. ! 589: * KERN_RESOURCE_SHORTAGE Couldn't allocate a new table. ! 590: */ ! 591: ! 592: kern_return_t ! 593: ipc_entry_grow_table( ! 594: ipc_space_t space, ! 595: int target_size) ! 596: { ! 597: ipc_entry_num_t osize, size, nsize, psize; ! 598: ! 599: do { ! 600: ipc_entry_t otable, table; ! 601: ipc_table_size_t oits, its, nits; ! 602: mach_port_index_t i, free_index; ! 603: ! 604: assert(space->is_active); ! 605: ! 606: if (space->is_growing) { ! 607: /* ! 608: * Somebody else is growing the table. ! 609: * We just wait for them to finish. ! 610: */ ! 611: ! 612: assert_wait((event_t) space, FALSE); ! 613: is_write_unlock(space); ! 614: thread_block_with_continuation((void (*)()) 0); ! 615: is_write_lock(space); ! 616: return KERN_SUCCESS; ! 617: } ! 618: ! 619: otable = space->is_table; ! 620: ! 621: its = space->is_table_next; ! 622: size = its->its_size; ! 623: ! 624: /* ! 625: * Since is_table_next points to the next natural size ! 626: * we can identify the current size entry. ! 627: */ ! 628: oits = its - 1; ! 629: osize = oits->its_size; ! 630: ! 631: /* ! 632: * If there is no target size, then the new size is simply ! 633: * specified by is_table_next. If there is a target ! 634: * size, then search for the next entry. ! 635: */ ! 636: if (target_size != ITS_SIZE_NONE) { ! 637: if (target_size <= osize) { ! 638: is_write_unlock(space); ! 639: return KERN_SUCCESS; ! 640: } ! 641: ! 642: psize = osize; ! 643: while ((psize != size) && (target_size > size)) { ! 644: psize = size; ! 645: its++; ! 646: size = its->its_size; ! 647: } ! 648: if (psize == size) { ! 649: is_write_unlock(space); ! 650: return KERN_NO_SPACE; ! 651: } ! 652: } ! 653: nits = its + 1; ! 654: nsize = nits->its_size; ! 655: ! 656: if (osize == size) { ! 657: is_write_unlock(space); ! 658: return KERN_NO_SPACE; ! 659: } ! 660: ! 661: assert((osize < size) && (size <= nsize)); ! 662: ! 663: /* ! 664: * OK, we'll attempt to grow the table. ! 665: * The realloc requires that the old table ! 666: * remain in existence. ! 667: */ ! 668: ! 669: space->is_growing = TRUE; ! 670: is_write_unlock(space); ! 671: if (it_entries_reallocable(oits)) ! 672: table = it_entries_realloc(oits, otable, its); ! 673: else ! 674: table = it_entries_alloc(its); ! 675: is_write_lock(space); ! 676: space->is_growing = FALSE; ! 677: ! 678: /* ! 679: * We need to do a wakeup on the space, ! 680: * to rouse waiting threads. We defer ! 681: * this until the space is unlocked, ! 682: * because we don't want them to spin. ! 683: */ ! 684: ! 685: if (table == IE_NULL) { ! 686: is_write_unlock(space); ! 687: thread_wakeup((event_t) space); ! 688: return KERN_RESOURCE_SHORTAGE; ! 689: } ! 690: ! 691: if (!space->is_active) { ! 692: /* ! 693: * The space died while it was unlocked. ! 694: */ ! 695: ! 696: is_write_unlock(space); ! 697: thread_wakeup((event_t) space); ! 698: it_entries_free(its, table); ! 699: is_write_lock(space); ! 700: return KERN_SUCCESS; ! 701: } ! 702: ! 703: assert(space->is_table == otable); ! 704: assert((space->is_table_next == its) || ! 705: (target_size != ITS_SIZE_NONE)); ! 706: assert(space->is_table_size == osize); ! 707: ! 708: space->is_table = table; ! 709: space->is_table_size = size; ! 710: space->is_table_next = nits; ! 711: ! 712: /* ! 713: * If we did a realloc, it remapped the data. ! 714: * Otherwise we copy by hand first. Then we have ! 715: * to clear the index fields in the old part and ! 716: * zero the new part. ! 717: */ ! 718: ! 719: if (!it_entries_reallocable(oits)) ! 720: bcopy((char *) otable, (char *) table, ! 721: osize * sizeof(struct ipc_entry)); ! 722: ! 723: for (i = 0; i < osize; i++) ! 724: table[i].ie_index = 0; ! 725: ! 726: bzero((char *) (table + osize), ! 727: (size - osize) * sizeof(struct ipc_entry)); ! 728: ! 729: /* ! 730: * Put old entries into the reverse hash table. ! 731: */ ! 732: ! 733: for (i = 0; i < osize; i++) { ! 734: ipc_entry_t entry = &table[i]; ! 735: ! 736: if (IE_BITS_TYPE(entry->ie_bits) == ! 737: MACH_PORT_TYPE_SEND) ! 738: ipc_hash_local_insert(space, entry->ie_object, ! 739: i, entry); ! 740: } ! 741: ! 742: /* ! 743: * If there are entries in the splay tree, ! 744: * then we have work to do: ! 745: * 1) transfer entries to the table ! 746: * 2) update is_tree_small ! 747: */ ! 748: ! 749: if (space->is_tree_total > 0) { ! 750: mach_port_index_t index; ! 751: boolean_t delete; ! 752: struct ipc_splay_tree ignore; ! 753: struct ipc_splay_tree move; ! 754: struct ipc_splay_tree small; ! 755: ipc_entry_num_t nosmall; ! 756: ipc_tree_entry_t tentry; ! 757: ! 758: /* ! 759: * The splay tree divides into four regions, ! 760: * based on the index of the entries: ! 761: * 1) 0 <= index < osize ! 762: * 2) osize <= index < size ! 763: * 3) size <= index < nsize ! 764: * 4) nsize <= index ! 765: * ! 766: * Entries in the first part are ignored. ! 767: * Entries in the second part, that don't ! 768: * collide, are moved into the table. ! 769: * Entries in the third part, that don't ! 770: * collide, are counted for is_tree_small. ! 771: * Entries in the fourth part are ignored. ! 772: */ ! 773: ! 774: ipc_splay_tree_split(&space->is_tree, ! 775: MACH_PORT_MAKE(nsize, 0), ! 776: &small); ! 777: ipc_splay_tree_split(&small, ! 778: MACH_PORT_MAKE(size, 0), ! 779: &move); ! 780: ipc_splay_tree_split(&move, ! 781: MACH_PORT_MAKE(osize, 0), ! 782: &ignore); ! 783: ! 784: /* move entries into the table */ ! 785: ! 786: for (tentry = ipc_splay_traverse_start(&move); ! 787: tentry != ITE_NULL; ! 788: tentry = ipc_splay_traverse_next(&move, delete)) { ! 789: mach_port_t name; ! 790: mach_port_gen_t gen; ! 791: mach_port_type_t type; ! 792: ipc_entry_bits_t bits; ! 793: ipc_object_t obj; ! 794: ipc_entry_t entry; ! 795: ! 796: name = tentry->ite_name; ! 797: gen = MACH_PORT_GEN(name); ! 798: index = MACH_PORT_INDEX(name); ! 799: ! 800: assert(tentry->ite_space == space); ! 801: assert((osize <= index) && (index < size)); ! 802: ! 803: entry = &table[index]; ! 804: ! 805: /* collision with previously moved entry? */ ! 806: ! 807: bits = entry->ie_bits; ! 808: if (bits != 0) { ! 809: assert(IE_BITS_TYPE(bits)); ! 810: assert(IE_BITS_GEN(bits) != gen); ! 811: ! 812: entry->ie_bits = ! 813: bits | IE_BITS_COLLISION; ! 814: delete = FALSE; ! 815: continue; ! 816: } ! 817: ! 818: bits = tentry->ite_bits; ! 819: type = IE_BITS_TYPE(bits); ! 820: assert(type != MACH_PORT_TYPE_NONE); ! 821: ! 822: entry->ie_bits = bits | gen; ! 823: entry->ie_object = obj = tentry->ite_object; ! 824: entry->ie_request = tentry->ite_request; ! 825: ! 826: if (type == MACH_PORT_TYPE_SEND) { ! 827: ipc_hash_global_delete(space, obj, ! 828: name, tentry); ! 829: ipc_hash_local_insert(space, obj, ! 830: index, entry); ! 831: } ! 832: ! 833: space->is_tree_total--; ! 834: delete = TRUE; ! 835: } ! 836: ipc_splay_traverse_finish(&move); ! 837: ! 838: /* count entries for is_tree_small */ ! 839: ! 840: nosmall = 0; index = 0; ! 841: for (tentry = ipc_splay_traverse_start(&small); ! 842: tentry != ITE_NULL; ! 843: tentry = ipc_splay_traverse_next(&small, FALSE)) { ! 844: mach_port_index_t nindex; ! 845: ! 846: nindex = MACH_PORT_INDEX(tentry->ite_name); ! 847: ! 848: if (nindex != index) { ! 849: nosmall++; ! 850: index = nindex; ! 851: } ! 852: } ! 853: ipc_splay_traverse_finish(&small); ! 854: ! 855: assert(nosmall <= (nsize - size)); ! 856: assert(nosmall <= space->is_tree_total); ! 857: space->is_tree_small = nosmall; ! 858: ! 859: /* put the splay tree back together */ ! 860: ! 861: ipc_splay_tree_join(&space->is_tree, &small); ! 862: ipc_splay_tree_join(&space->is_tree, &move); ! 863: ipc_splay_tree_join(&space->is_tree, &ignore); ! 864: } ! 865: ! 866: /* ! 867: * Add entries in the new part which still aren't used ! 868: * to the free list. Add them in reverse order, ! 869: * and set the generation number to -1, so that ! 870: * early allocations produce "natural" names. ! 871: */ ! 872: ! 873: free_index = table[0].ie_next; ! 874: for (i = size-1; i >= osize; --i) { ! 875: ipc_entry_t entry = &table[i]; ! 876: ! 877: if (entry->ie_bits == 0) { ! 878: entry->ie_bits = IE_BITS_GEN_MASK; ! 879: entry->ie_next = free_index; ! 880: free_index = i; ! 881: } ! 882: } ! 883: table[0].ie_next = free_index; ! 884: ! 885: /* ! 886: * Now we need to free the old table. ! 887: * If the space dies or grows while unlocked, ! 888: * then we can quit here. ! 889: */ ! 890: ! 891: is_write_unlock(space); ! 892: thread_wakeup((event_t) space); ! 893: it_entries_free(oits, otable); ! 894: is_write_lock(space); ! 895: if (!space->is_active || (space->is_table_next != nits)) ! 896: return KERN_SUCCESS; ! 897: ! 898: /* ! 899: * We might have moved enough entries from ! 900: * the splay tree into the table that ! 901: * the table can be profitably grown again. ! 902: * ! 903: * Note that if size == nsize, then ! 904: * space->is_tree_small == 0. ! 905: */ ! 906: } while ((space->is_tree_small > 0) && ! 907: (((nsize - size) * sizeof(struct ipc_entry)) < ! 908: (space->is_tree_small * sizeof(struct ipc_tree_entry)))); ! 909: ! 910: return KERN_SUCCESS; ! 911: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.