|
|
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_hash.c ! 54: * Author: Rich Draves ! 55: * Date: 1989 ! 56: * ! 57: * Entry hash table operations. ! 58: */ ! 59: ! 60: #include <mach/boolean.h> ! 61: #include <mach/port.h> ! 62: #include <kern/lock.h> ! 63: #include <kern/kalloc.h> ! 64: #include <ipc/port.h> ! 65: #include <ipc/ipc_space.h> ! 66: #include <ipc/ipc_object.h> ! 67: #include <ipc/ipc_entry.h> ! 68: #include <ipc/ipc_hash.h> ! 69: #include <ipc/ipc_init.h> ! 70: ! 71: #include <mach_ipc_debug.h> ! 72: ! 73: #if MACH_IPC_DEBUG ! 74: #include <mach/kern_return.h> ! 75: #include <mach_debug/hash_info.h> ! 76: #include <vm/vm_map.h> ! 77: #include <vm/vm_kern.h> ! 78: #include <vm/vm_user.h> ! 79: #endif /* MACH_IPC_DEBUG */ ! 80: ! 81: /* ! 82: * Forward declarations ! 83: */ ! 84: ! 85: /* Lookup (space, obj) in global hash table */ ! 86: boolean_t ipc_hash_global_lookup( ! 87: ipc_space_t space, ! 88: ipc_object_t obj, ! 89: mach_port_name_t *namep, ! 90: ipc_tree_entry_t *entryp); ! 91: ! 92: /* Insert an entry into the global reverse hash table */ ! 93: void ipc_hash_global_insert( ! 94: ipc_space_t space, ! 95: ipc_object_t obj, ! 96: mach_port_name_t name, ! 97: ipc_tree_entry_t entry); ! 98: ! 99: /* Delete an entry from the local reverse hash table */ ! 100: void ipc_hash_local_delete( ! 101: ipc_space_t space, ! 102: ipc_object_t obj, ! 103: mach_port_index_t index, ! 104: ipc_entry_t entry); ! 105: ! 106: /* ! 107: * Routine: ipc_hash_lookup ! 108: * Purpose: ! 109: * Converts (space, obj) -> (name, entry). ! 110: * Returns TRUE if an entry was found. ! 111: * Conditions: ! 112: * The space must be locked (read or write) throughout. ! 113: */ ! 114: ! 115: boolean_t ! 116: ipc_hash_lookup( ! 117: ipc_space_t space, ! 118: ipc_object_t obj, ! 119: mach_port_name_t *namep, ! 120: ipc_entry_t *entryp) ! 121: { ! 122: boolean_t rv; ! 123: ! 124: rv = ipc_hash_local_lookup(space, obj, namep, entryp); ! 125: if (!rv) { ! 126: assert(!is_fast_space(space) || space->is_tree_hash == 0); ! 127: if (space->is_tree_hash > 0) ! 128: rv = ipc_hash_global_lookup(space, obj, namep, ! 129: (ipc_tree_entry_t *) entryp); ! 130: } ! 131: return (rv); ! 132: } ! 133: ! 134: /* ! 135: * Routine: ipc_hash_insert ! 136: * Purpose: ! 137: * Inserts an entry into the appropriate reverse hash table, ! 138: * so that ipc_hash_lookup will find it. ! 139: * Conditions: ! 140: * The space must be write-locked. ! 141: */ ! 142: ! 143: void ! 144: ipc_hash_insert( ! 145: ipc_space_t space, ! 146: ipc_object_t obj, ! 147: mach_port_name_t name, ! 148: ipc_entry_t entry) ! 149: { ! 150: mach_port_index_t index; ! 151: ! 152: index = MACH_PORT_INDEX(name); ! 153: if ((index < space->is_table_size) && ! 154: (entry == &space->is_table[index])) ! 155: ipc_hash_local_insert(space, obj, index, entry); ! 156: else { ! 157: assert(!is_fast_space(space)); ! 158: ipc_hash_global_insert(space, obj, name, ! 159: (ipc_tree_entry_t) entry); ! 160: } ! 161: } ! 162: ! 163: /* ! 164: * Routine: ipc_hash_delete ! 165: * Purpose: ! 166: * Deletes an entry from the appropriate reverse hash table. ! 167: * Conditions: ! 168: * The space must be write-locked. ! 169: */ ! 170: ! 171: void ! 172: ipc_hash_delete( ! 173: ipc_space_t space, ! 174: ipc_object_t obj, ! 175: mach_port_name_t name, ! 176: ipc_entry_t entry) ! 177: { ! 178: mach_port_index_t index; ! 179: ! 180: index = MACH_PORT_INDEX(name); ! 181: if ((index < space->is_table_size) && ! 182: (entry == &space->is_table[index])) ! 183: ipc_hash_local_delete(space, obj, index, entry); ! 184: else { ! 185: assert(!is_fast_space(space)); ! 186: ipc_hash_global_delete(space, obj, name, ! 187: (ipc_tree_entry_t) entry); ! 188: } ! 189: } ! 190: ! 191: /* ! 192: * The global reverse hash table holds splay tree entries. ! 193: * It is a simple open-chaining hash table with singly-linked buckets. ! 194: * Each bucket is locked separately, with an exclusive lock. ! 195: * Within each bucket, move-to-front is used. ! 196: */ ! 197: ! 198: typedef natural_t ipc_hash_index_t; ! 199: ! 200: ipc_hash_index_t ipc_hash_global_size; ! 201: ipc_hash_index_t ipc_hash_global_mask; ! 202: ! 203: #define IH_GLOBAL_HASH(space, obj) \ ! 204: (((((ipc_hash_index_t) ((vm_offset_t)space)) >> 4) + \ ! 205: (((ipc_hash_index_t) ((vm_offset_t)obj)) >> 6)) & \ ! 206: ipc_hash_global_mask) ! 207: ! 208: typedef struct ipc_hash_global_bucket { ! 209: decl_mutex_data(, ihgb_lock_data) ! 210: ipc_tree_entry_t ihgb_head; ! 211: } *ipc_hash_global_bucket_t; ! 212: ! 213: #define IHGB_NULL ((ipc_hash_global_bucket_t) 0) ! 214: ! 215: #define ihgb_lock_init(ihgb) mutex_init(&(ihgb)->ihgb_lock_data, \ ! 216: ETAP_IPC_IHGB) ! 217: #define ihgb_lock(ihgb) mutex_lock(&(ihgb)->ihgb_lock_data) ! 218: #define ihgb_unlock(ihgb) mutex_unlock(&(ihgb)->ihgb_lock_data) ! 219: ! 220: ipc_hash_global_bucket_t ipc_hash_global_table; ! 221: ! 222: /* ! 223: * Routine: ipc_hash_global_lookup ! 224: * Purpose: ! 225: * Converts (space, obj) -> (name, entry). ! 226: * Looks in the global table, for splay tree entries. ! 227: * Returns TRUE if an entry was found. ! 228: * Conditions: ! 229: * The space must be locked (read or write) throughout. ! 230: */ ! 231: ! 232: boolean_t ! 233: ipc_hash_global_lookup( ! 234: ipc_space_t space, ! 235: ipc_object_t obj, ! 236: mach_port_name_t *namep, ! 237: ipc_tree_entry_t *entryp) ! 238: { ! 239: ipc_hash_global_bucket_t bucket; ! 240: ipc_tree_entry_t this, *last; ! 241: ! 242: assert(space != IS_NULL); ! 243: assert(obj != IO_NULL); ! 244: ! 245: assert(!is_fast_space(space)); ! 246: bucket = &ipc_hash_global_table[IH_GLOBAL_HASH(space, obj)]; ! 247: ihgb_lock(bucket); ! 248: ! 249: if ((this = bucket->ihgb_head) != ITE_NULL) { ! 250: if ((this->ite_object == obj) && ! 251: (this->ite_space == space)) { ! 252: /* found it at front; no need to move */ ! 253: ! 254: *namep = this->ite_name; ! 255: *entryp = this; ! 256: } else for (last = &this->ite_next; ! 257: (this = *last) != ITE_NULL; ! 258: last = &this->ite_next) { ! 259: if ((this->ite_object == obj) && ! 260: (this->ite_space == space)) { ! 261: /* found it; move to front */ ! 262: ! 263: *last = this->ite_next; ! 264: this->ite_next = bucket->ihgb_head; ! 265: bucket->ihgb_head = this; ! 266: ! 267: *namep = this->ite_name; ! 268: *entryp = this; ! 269: break; ! 270: } ! 271: } ! 272: } ! 273: ! 274: ihgb_unlock(bucket); ! 275: return this != ITE_NULL; ! 276: } ! 277: ! 278: /* ! 279: * Routine: ipc_hash_global_insert ! 280: * Purpose: ! 281: * Inserts an entry into the global reverse hash table. ! 282: * Conditions: ! 283: * The space must be write-locked. ! 284: */ ! 285: ! 286: void ! 287: ipc_hash_global_insert( ! 288: ipc_space_t space, ! 289: ipc_object_t obj, ! 290: mach_port_name_t name, ! 291: ipc_tree_entry_t entry) ! 292: { ! 293: ipc_hash_global_bucket_t bucket; ! 294: ! 295: ! 296: assert(!is_fast_space(space)); ! 297: ! 298: ! 299: assert(entry->ite_name == name); ! 300: assert(space != IS_NULL); ! 301: assert(entry->ite_space == space); ! 302: assert(obj != IO_NULL); ! 303: assert(entry->ite_object == obj); ! 304: ! 305: space->is_tree_hash++; ! 306: assert(space->is_tree_hash <= space->is_tree_total); ! 307: ! 308: bucket = &ipc_hash_global_table[IH_GLOBAL_HASH(space, obj)]; ! 309: ihgb_lock(bucket); ! 310: ! 311: /* insert at front of bucket */ ! 312: ! 313: entry->ite_next = bucket->ihgb_head; ! 314: bucket->ihgb_head = entry; ! 315: ! 316: ihgb_unlock(bucket); ! 317: } ! 318: ! 319: /* ! 320: * Routine: ipc_hash_global_delete ! 321: * Purpose: ! 322: * Deletes an entry from the global reverse hash table. ! 323: * Conditions: ! 324: * The space must be write-locked. ! 325: */ ! 326: ! 327: void ! 328: ipc_hash_global_delete( ! 329: ipc_space_t space, ! 330: ipc_object_t obj, ! 331: mach_port_name_t name, ! 332: ipc_tree_entry_t entry) ! 333: { ! 334: ipc_hash_global_bucket_t bucket; ! 335: ipc_tree_entry_t this, *last; ! 336: ! 337: assert(!is_fast_space(space)); ! 338: ! 339: assert(entry->ite_name == name); ! 340: assert(space != IS_NULL); ! 341: assert(entry->ite_space == space); ! 342: assert(obj != IO_NULL); ! 343: assert(entry->ite_object == obj); ! 344: ! 345: assert(space->is_tree_hash > 0); ! 346: space->is_tree_hash--; ! 347: ! 348: bucket = &ipc_hash_global_table[IH_GLOBAL_HASH(space, obj)]; ! 349: ihgb_lock(bucket); ! 350: ! 351: for (last = &bucket->ihgb_head; ! 352: (this = *last) != ITE_NULL; ! 353: last = &this->ite_next) { ! 354: if (this == entry) { ! 355: /* found it; remove from bucket */ ! 356: ! 357: *last = this->ite_next; ! 358: break; ! 359: } ! 360: } ! 361: assert(this != ITE_NULL); ! 362: ! 363: ihgb_unlock(bucket); ! 364: } ! 365: ! 366: /* ! 367: * Each space has a local reverse hash table, which holds ! 368: * entries from the space's table. In fact, the hash table ! 369: * just uses a field (ie_index) in the table itself. ! 370: * ! 371: * The local hash table is an open-addressing hash table, ! 372: * which means that when a collision occurs, instead of ! 373: * throwing the entry into a bucket, the entry is rehashed ! 374: * to another position in the table. In this case the rehash ! 375: * is very simple: linear probing (ie, just increment the position). ! 376: * This simple rehash makes deletions tractable (they're still a pain), ! 377: * but it means that collisions tend to build up into clumps. ! 378: * ! 379: * Because at least one entry in the table (index 0) is always unused, ! 380: * there will always be room in the reverse hash table. If a table ! 381: * with n slots gets completely full, the reverse hash table will ! 382: * have one giant clump of n-1 slots and one free slot somewhere. ! 383: * Because entries are only entered into the reverse table if they ! 384: * are pure send rights (not receive, send-once, port-set, ! 385: * or dead-name rights), and free entries of course aren't entered, ! 386: * I expect the reverse hash table won't get unreasonably full. ! 387: * ! 388: * Ordered hash tables (Amble & Knuth, Computer Journal, v. 17, no. 2, ! 389: * pp. 135-142.) may be desirable here. They can dramatically help ! 390: * unsuccessful lookups. But unsuccessful lookups are almost always ! 391: * followed by insertions, and those slow down somewhat. They ! 392: * also can help deletions somewhat. Successful lookups aren't affected. ! 393: * So possibly a small win; probably nothing significant. ! 394: */ ! 395: ! 396: #define IH_LOCAL_HASH(obj, size) \ ! 397: ((((mach_port_index_t) (obj)) >> 6) % (size)) ! 398: ! 399: /* ! 400: * Routine: ipc_hash_local_lookup ! 401: * Purpose: ! 402: * Converts (space, obj) -> (name, entry). ! 403: * Looks in the space's local table, for table entries. ! 404: * Returns TRUE if an entry was found. ! 405: * Conditions: ! 406: * The space must be locked (read or write) throughout. ! 407: */ ! 408: ! 409: boolean_t ! 410: ipc_hash_local_lookup( ! 411: ipc_space_t space, ! 412: ipc_object_t obj, ! 413: mach_port_name_t *namep, ! 414: ipc_entry_t *entryp) ! 415: { ! 416: ipc_entry_t table; ! 417: ipc_entry_num_t size; ! 418: mach_port_index_t hindex, index; ! 419: ! 420: assert(space != IS_NULL); ! 421: assert(obj != IO_NULL); ! 422: ! 423: table = space->is_table; ! 424: size = space->is_table_size; ! 425: hindex = IH_LOCAL_HASH(obj, size); ! 426: ! 427: /* ! 428: * Ideally, table[hindex].ie_index is the name we want. ! 429: * However, must check ie_object to verify this, ! 430: * because collisions can happen. In case of a collision, ! 431: * search farther along in the clump. ! 432: */ ! 433: ! 434: while ((index = table[hindex].ie_index) != 0) { ! 435: ipc_entry_t entry = &table[index]; ! 436: ! 437: if (entry->ie_object == obj) { ! 438: *entryp = entry; ! 439: *namep = MACH_PORT_MAKE(index, ! 440: IE_BITS_GEN(entry->ie_bits)); ! 441: return TRUE; ! 442: } ! 443: ! 444: if (++hindex == size) ! 445: hindex = 0; ! 446: } ! 447: ! 448: return FALSE; ! 449: } ! 450: ! 451: /* ! 452: * Routine: ipc_hash_local_insert ! 453: * Purpose: ! 454: * Inserts an entry into the space's reverse hash table. ! 455: * Conditions: ! 456: * The space must be write-locked. ! 457: */ ! 458: ! 459: void ! 460: ipc_hash_local_insert( ! 461: ipc_space_t space, ! 462: ipc_object_t obj, ! 463: mach_port_index_t index, ! 464: ipc_entry_t entry) ! 465: { ! 466: ipc_entry_t table; ! 467: ipc_entry_num_t size; ! 468: mach_port_index_t hindex; ! 469: ! 470: assert(index != 0); ! 471: assert(space != IS_NULL); ! 472: assert(obj != IO_NULL); ! 473: ! 474: table = space->is_table; ! 475: size = space->is_table_size; ! 476: hindex = IH_LOCAL_HASH(obj, size); ! 477: ! 478: assert(entry == &table[index]); ! 479: assert(entry->ie_object == obj); ! 480: ! 481: /* ! 482: * We want to insert at hindex, but there may be collisions. ! 483: * If a collision occurs, search for the end of the clump ! 484: * and insert there. ! 485: */ ! 486: ! 487: while (table[hindex].ie_index != 0) { ! 488: if (++hindex == size) ! 489: hindex = 0; ! 490: } ! 491: ! 492: table[hindex].ie_index = index; ! 493: } ! 494: ! 495: /* ! 496: * Routine: ipc_hash_local_delete ! 497: * Purpose: ! 498: * Deletes an entry from the space's reverse hash table. ! 499: * Conditions: ! 500: * The space must be write-locked. ! 501: */ ! 502: ! 503: void ! 504: ipc_hash_local_delete( ! 505: ipc_space_t space, ! 506: ipc_object_t obj, ! 507: mach_port_index_t index, ! 508: ipc_entry_t entry) ! 509: { ! 510: ipc_entry_t table; ! 511: ipc_entry_num_t size; ! 512: mach_port_index_t hindex, dindex; ! 513: ! 514: assert(index != MACH_PORT_NULL); ! 515: assert(space != IS_NULL); ! 516: assert(obj != IO_NULL); ! 517: ! 518: table = space->is_table; ! 519: size = space->is_table_size; ! 520: hindex = IH_LOCAL_HASH(obj, size); ! 521: ! 522: assert(entry == &table[index]); ! 523: assert(entry->ie_object == obj); ! 524: ! 525: /* ! 526: * First check we have the right hindex for this index. ! 527: * In case of collision, we have to search farther ! 528: * along in this clump. ! 529: */ ! 530: ! 531: while (table[hindex].ie_index != index) { ! 532: if (++hindex == size) ! 533: hindex = 0; ! 534: } ! 535: ! 536: /* ! 537: * Now we want to set table[hindex].ie_index = 0. ! 538: * But if we aren't the last index in a clump, ! 539: * this might cause problems for lookups of objects ! 540: * farther along in the clump that are displaced ! 541: * due to collisions. Searches for them would fail ! 542: * at hindex instead of succeeding. ! 543: * ! 544: * So we must check the clump after hindex for objects ! 545: * that are so displaced, and move one up to the new hole. ! 546: * ! 547: * hindex - index of new hole in the clump ! 548: * dindex - index we are checking for a displaced object ! 549: * ! 550: * When we move a displaced object up into the hole, ! 551: * it creates a new hole, and we have to repeat the process ! 552: * until we get to the end of the clump. ! 553: */ ! 554: ! 555: for (dindex = hindex; index != 0; hindex = dindex) { ! 556: for (;;) { ! 557: mach_port_index_t tindex; ! 558: ipc_object_t tobj; ! 559: ! 560: if (++dindex == size) ! 561: dindex = 0; ! 562: assert(dindex != hindex); ! 563: ! 564: /* are we at the end of the clump? */ ! 565: ! 566: index = table[dindex].ie_index; ! 567: if (index == 0) ! 568: break; ! 569: ! 570: /* is this a displaced object? */ ! 571: ! 572: tobj = table[index].ie_object; ! 573: assert(tobj != IO_NULL); ! 574: tindex = IH_LOCAL_HASH(tobj, size); ! 575: ! 576: if ((dindex < hindex) ? ! 577: ((dindex < tindex) && (tindex <= hindex)) : ! 578: ((dindex < tindex) || (tindex <= hindex))) ! 579: break; ! 580: } ! 581: ! 582: table[hindex].ie_index = index; ! 583: } ! 584: } ! 585: ! 586: /* ! 587: * Routine: ipc_hash_init ! 588: * Purpose: ! 589: * Initialize the reverse hash table implementation. ! 590: */ ! 591: ! 592: void ! 593: ipc_hash_init(void) ! 594: { ! 595: ipc_hash_index_t i; ! 596: ! 597: /* if not configured, initialize ipc_hash_global_size */ ! 598: ! 599: if (ipc_hash_global_size == 0) { ! 600: ipc_hash_global_size = ipc_tree_entry_max >> 8; ! 601: if (ipc_hash_global_size < 32) ! 602: ipc_hash_global_size = 32; ! 603: } ! 604: ! 605: /* make sure it is a power of two */ ! 606: ! 607: ipc_hash_global_mask = ipc_hash_global_size - 1; ! 608: if ((ipc_hash_global_size & ipc_hash_global_mask) != 0) { ! 609: natural_t bit; ! 610: ! 611: /* round up to closest power of two */ ! 612: ! 613: for (bit = 1;; bit <<= 1) { ! 614: ipc_hash_global_mask |= bit; ! 615: ipc_hash_global_size = ipc_hash_global_mask + 1; ! 616: ! 617: if ((ipc_hash_global_size & ipc_hash_global_mask) == 0) ! 618: break; ! 619: } ! 620: } ! 621: ! 622: /* allocate ipc_hash_global_table */ ! 623: ! 624: ipc_hash_global_table = (ipc_hash_global_bucket_t) ! 625: kalloc((vm_size_t) (ipc_hash_global_size * ! 626: sizeof(struct ipc_hash_global_bucket))); ! 627: assert(ipc_hash_global_table != IHGB_NULL); ! 628: ! 629: /* and initialize it */ ! 630: ! 631: for (i = 0; i < ipc_hash_global_size; i++) { ! 632: ipc_hash_global_bucket_t bucket; ! 633: ! 634: bucket = &ipc_hash_global_table[i]; ! 635: ihgb_lock_init(bucket); ! 636: bucket->ihgb_head = ITE_NULL; ! 637: } ! 638: } ! 639: ! 640: #if MACH_IPC_DEBUG ! 641: ! 642: /* ! 643: * Routine: ipc_hash_info ! 644: * Purpose: ! 645: * Return information about the global reverse hash table. ! 646: * Fills the buffer with as much information as possible ! 647: * and returns the desired size of the buffer. ! 648: * Conditions: ! 649: * Nothing locked. The caller should provide ! 650: * possibly-pageable memory. ! 651: */ ! 652: ! 653: ! 654: ipc_hash_index_t ! 655: ipc_hash_info( ! 656: hash_info_bucket_t *info, ! 657: mach_msg_type_number_t count) ! 658: { ! 659: ipc_hash_index_t i; ! 660: ! 661: if (ipc_hash_global_size < count) ! 662: count = ipc_hash_global_size; ! 663: ! 664: for (i = 0; i < count; i++) { ! 665: ipc_hash_global_bucket_t bucket = &ipc_hash_global_table[i]; ! 666: unsigned int bucket_count = 0; ! 667: ipc_tree_entry_t entry; ! 668: ! 669: ihgb_lock(bucket); ! 670: for (entry = bucket->ihgb_head; ! 671: entry != ITE_NULL; ! 672: entry = entry->ite_next) ! 673: bucket_count++; ! 674: ihgb_unlock(bucket); ! 675: ! 676: /* don't touch pageable memory while holding locks */ ! 677: info[i].hib_count = bucket_count; ! 678: } ! 679: ! 680: return ipc_hash_global_size; ! 681: } ! 682: ! 683: #endif /* MACH_IPC_DEBUG */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.