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