|
|
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_hash.c ! 75: * Author: Rich Draves ! 76: * Date: 1989 ! 77: * ! 78: * Entry hash table operations. ! 79: */ ! 80: ! 81: #include <mach/boolean.h> ! 82: #include <mach/port.h> ! 83: #include <kern/lock.h> ! 84: #include <kern/kalloc.h> ! 85: #include <ipc/port.h> ! 86: #include <ipc/ipc_space.h> ! 87: #include <ipc/ipc_object.h> ! 88: #include <ipc/ipc_entry.h> ! 89: #include <ipc/ipc_hash.h> ! 90: #include <ipc/ipc_init.h> ! 91: ! 92: /* ! 93: * Forward declarations ! 94: */ ! 95: ! 96: /* Lookup (space, obj) in global hash table */ ! 97: boolean_t ipc_hash_global_lookup( ! 98: ipc_space_t space, ! 99: ipc_object_t obj, ! 100: mach_port_t *namep, ! 101: ipc_tree_entry_t *entryp); ! 102: ! 103: /* Insert an entry into the global reverse hash table */ ! 104: void ipc_hash_global_insert( ! 105: ipc_space_t space, ! 106: ipc_object_t obj, ! 107: mach_port_t name, ! 108: ipc_tree_entry_t entry); ! 109: ! 110: /* Delete an entry from the local reverse hash table */ ! 111: void ipc_hash_local_delete( ! 112: ipc_space_t space, ! 113: ipc_object_t obj, ! 114: mach_port_index_t index, ! 115: ipc_entry_t entry); ! 116: ! 117: /* ! 118: * Routine: ipc_hash_lookup ! 119: * Purpose: ! 120: * Converts (space, obj) -> (name, entry). ! 121: * Returns TRUE if an entry was found. ! 122: * Conditions: ! 123: * The space must be locked (read or write) throughout. ! 124: */ ! 125: ! 126: boolean_t ! 127: ipc_hash_lookup( ! 128: ipc_space_t space, ! 129: ipc_object_t obj, ! 130: mach_port_t *namep, ! 131: ipc_entry_t *entryp) ! 132: { ! 133: boolean_t rv; ! 134: ! 135: rv = ipc_hash_local_lookup(space, obj, namep, entryp); ! 136: if (!rv) { ! 137: if (space->is_tree_hash > 0) ! 138: rv = ipc_hash_global_lookup(space, obj, namep, ! 139: (ipc_tree_entry_t *) entryp); ! 140: } ! 141: return (rv); ! 142: } ! 143: ! 144: /* ! 145: * Routine: ipc_hash_insert ! 146: * Purpose: ! 147: * Inserts an entry into the appropriate reverse hash table, ! 148: * so that ipc_hash_lookup will find it. ! 149: * Conditions: ! 150: * The space must be write-locked. ! 151: */ ! 152: ! 153: void ! 154: ipc_hash_insert( ! 155: ipc_space_t space, ! 156: ipc_object_t obj, ! 157: mach_port_t name, ! 158: ipc_entry_t entry) ! 159: { ! 160: mach_port_index_t index; ! 161: ! 162: index = MACH_PORT_INDEX(name); ! 163: if ((index < space->is_table_size) && ! 164: (entry == &space->is_table[index])) ! 165: ipc_hash_local_insert(space, obj, index, entry); ! 166: else { ! 167: ipc_hash_global_insert(space, obj, name, ! 168: (ipc_tree_entry_t) entry); ! 169: } ! 170: } ! 171: ! 172: /* ! 173: * Routine: ipc_hash_delete ! 174: * Purpose: ! 175: * Deletes an entry from the appropriate reverse hash table. ! 176: * Conditions: ! 177: * The space must be write-locked. ! 178: */ ! 179: ! 180: void ! 181: ipc_hash_delete( ! 182: ipc_space_t space, ! 183: ipc_object_t obj, ! 184: mach_port_t name, ! 185: ipc_entry_t entry) ! 186: { ! 187: mach_port_index_t index; ! 188: ! 189: index = MACH_PORT_INDEX(name); ! 190: if ((index < space->is_table_size) && ! 191: (entry == &space->is_table[index])) ! 192: ipc_hash_local_delete(space, obj, index, entry); ! 193: else { ! 194: ipc_hash_global_delete(space, obj, name, ! 195: (ipc_tree_entry_t) entry); ! 196: } ! 197: } ! 198: ! 199: /* ! 200: * The global reverse hash table holds splay tree entries. ! 201: * It is a simple open-chaining hash table with singly-linked buckets. ! 202: * Each bucket is locked separately, with an exclusive lock. ! 203: * Within each bucket, move-to-front is used. ! 204: */ ! 205: ! 206: typedef unsigned int ipc_hash_index_t; ! 207: ! 208: ipc_hash_index_t ipc_hash_global_size; ! 209: ipc_hash_index_t ipc_hash_global_mask; ! 210: ! 211: #define IH_GLOBAL_HASH(space, obj) \ ! 212: (((((ipc_hash_index_t) (space)) >> 4) + \ ! 213: (((ipc_hash_index_t) (obj)) >> 6)) & \ ! 214: ipc_hash_global_mask) ! 215: ! 216: typedef struct ipc_hash_global_bucket { ! 217: decl_simple_lock_data(, ihgb_lock_data) ! 218: ipc_tree_entry_t ihgb_head; ! 219: } *ipc_hash_global_bucket_t; ! 220: ! 221: #define IHGB_NULL ((ipc_hash_global_bucket_t) 0) ! 222: ! 223: #define ihgb_lock_init(ihgb) simple_lock_init(&(ihgb)->ihgb_lock_data) ! 224: #define ihgb_lock(ihgb) simple_lock(&(ihgb)->ihgb_lock_data) ! 225: #define ihgb_unlock(ihgb) simple_unlock(&(ihgb)->ihgb_lock_data) ! 226: ! 227: ipc_hash_global_bucket_t ipc_hash_global_table; ! 228: ! 229: /* ! 230: * Routine: ipc_hash_global_lookup ! 231: * Purpose: ! 232: * Converts (space, obj) -> (name, entry). ! 233: * Looks in the global table, for splay tree entries. ! 234: * Returns TRUE if an entry was found. ! 235: * Conditions: ! 236: * The space must be locked (read or write) throughout. ! 237: */ ! 238: ! 239: boolean_t ! 240: ipc_hash_global_lookup( ! 241: ipc_space_t space, ! 242: ipc_object_t obj, ! 243: mach_port_t *namep, ! 244: ipc_tree_entry_t *entryp) ! 245: { ! 246: ipc_hash_global_bucket_t bucket; ! 247: ipc_tree_entry_t this, *last; ! 248: ! 249: assert(space != IS_NULL); ! 250: assert(obj != IO_NULL); ! 251: ! 252: bucket = &ipc_hash_global_table[IH_GLOBAL_HASH(space, obj)]; ! 253: ihgb_lock(bucket); ! 254: ! 255: if ((this = bucket->ihgb_head) != ITE_NULL) { ! 256: if ((this->ite_object == obj) && ! 257: (this->ite_space == space)) { ! 258: /* found it at front; no need to move */ ! 259: ! 260: *namep = this->ite_name; ! 261: *entryp = this; ! 262: } else for (last = &this->ite_next; ! 263: (this = *last) != ITE_NULL; ! 264: last = &this->ite_next) { ! 265: if ((this->ite_object == obj) && ! 266: (this->ite_space == space)) { ! 267: /* found it; move to front */ ! 268: ! 269: *last = this->ite_next; ! 270: this->ite_next = bucket->ihgb_head; ! 271: bucket->ihgb_head = this; ! 272: ! 273: *namep = this->ite_name; ! 274: *entryp = this; ! 275: break; ! 276: } ! 277: } ! 278: } ! 279: ! 280: ihgb_unlock(bucket); ! 281: return this != ITE_NULL; ! 282: } ! 283: ! 284: /* ! 285: * Routine: ipc_hash_global_insert ! 286: * Purpose: ! 287: * Inserts an entry into the global reverse hash table. ! 288: * Conditions: ! 289: * The space must be write-locked. ! 290: */ ! 291: ! 292: void ! 293: ipc_hash_global_insert( ! 294: ipc_space_t space, ! 295: ipc_object_t obj, ! 296: mach_port_t name, ! 297: ipc_tree_entry_t entry) ! 298: { ! 299: ipc_hash_global_bucket_t bucket; ! 300: ! 301: assert(entry->ite_name == name); ! 302: assert(space != IS_NULL); ! 303: assert(entry->ite_space == space); ! 304: assert(obj != IO_NULL); ! 305: assert(entry->ite_object == obj); ! 306: ! 307: space->is_tree_hash++; ! 308: assert(space->is_tree_hash <= space->is_tree_total); ! 309: ! 310: bucket = &ipc_hash_global_table[IH_GLOBAL_HASH(space, obj)]; ! 311: ihgb_lock(bucket); ! 312: ! 313: /* insert at front of bucket */ ! 314: ! 315: entry->ite_next = bucket->ihgb_head; ! 316: bucket->ihgb_head = entry; ! 317: ! 318: ihgb_unlock(bucket); ! 319: } ! 320: ! 321: /* ! 322: * Routine: ipc_hash_global_delete ! 323: * Purpose: ! 324: * Deletes an entry from the global reverse hash table. ! 325: * Conditions: ! 326: * The space must be write-locked. ! 327: */ ! 328: ! 329: void ! 330: ipc_hash_global_delete( ! 331: ipc_space_t space, ! 332: ipc_object_t obj, ! 333: mach_port_t name, ! 334: ipc_tree_entry_t entry) ! 335: { ! 336: ipc_hash_global_bucket_t bucket; ! 337: ipc_tree_entry_t this, *last; ! 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_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: *namep = MACH_PORT_MAKEB(index, entry->ie_bits); ! 439: *entryp = entry; ! 440: return TRUE; ! 441: } ! 442: ! 443: if (++hindex == size) ! 444: hindex = 0; ! 445: } ! 446: ! 447: return FALSE; ! 448: } ! 449: ! 450: /* ! 451: * Routine: ipc_hash_local_insert ! 452: * Purpose: ! 453: * Inserts an entry into the space's reverse hash table. ! 454: * Conditions: ! 455: * The space must be write-locked. ! 456: */ ! 457: ! 458: void ! 459: ipc_hash_local_insert( ! 460: ipc_space_t space, ! 461: ipc_object_t obj, ! 462: mach_port_index_t index, ! 463: ipc_entry_t entry) ! 464: { ! 465: ipc_entry_t table; ! 466: ipc_entry_num_t size; ! 467: mach_port_index_t hindex; ! 468: ! 469: assert(index != 0); ! 470: assert(space != IS_NULL); ! 471: assert(obj != IO_NULL); ! 472: ! 473: table = space->is_table; ! 474: size = space->is_table_size; ! 475: hindex = IH_LOCAL_HASH(obj, size); ! 476: ! 477: assert(entry == &table[index]); ! 478: assert(entry->ie_object == obj); ! 479: ! 480: /* ! 481: * We want to insert at hindex, but there may be collisions. ! 482: * If a collision occurs, search for the end of the clump ! 483: * and insert there. ! 484: */ ! 485: ! 486: while (table[hindex].ie_index != 0) { ! 487: if (++hindex == size) ! 488: hindex = 0; ! 489: } ! 490: ! 491: table[hindex].ie_index = index; ! 492: } ! 493: ! 494: /* ! 495: * Routine: ipc_hash_local_delete ! 496: * Purpose: ! 497: * Deletes an entry from the space's reverse hash table. ! 498: * Conditions: ! 499: * The space must be write-locked. ! 500: */ ! 501: ! 502: void ! 503: ipc_hash_local_delete( ! 504: ipc_space_t space, ! 505: ipc_object_t obj, ! 506: mach_port_index_t index, ! 507: ipc_entry_t entry) ! 508: { ! 509: ipc_entry_t table; ! 510: ipc_entry_num_t size; ! 511: mach_port_index_t hindex, dindex; ! 512: ! 513: assert(index != MACH_PORT_NULL); ! 514: assert(space != IS_NULL); ! 515: assert(obj != IO_NULL); ! 516: ! 517: table = space->is_table; ! 518: size = space->is_table_size; ! 519: hindex = IH_LOCAL_HASH(obj, size); ! 520: ! 521: assert(entry == &table[index]); ! 522: assert(entry->ie_object == obj); ! 523: ! 524: /* ! 525: * First check we have the right hindex for this index. ! 526: * In case of collision, we have to search farther ! 527: * along in this clump. ! 528: */ ! 529: ! 530: while (table[hindex].ie_index != index) { ! 531: if (++hindex == size) ! 532: hindex = 0; ! 533: } ! 534: ! 535: /* ! 536: * Now we want to set table[hindex].ie_index = 0. ! 537: * But if we aren't the last index in a clump, ! 538: * this might cause problems for lookups of objects ! 539: * farther along in the clump that are displaced ! 540: * due to collisions. Searches for them would fail ! 541: * at hindex instead of succeeding. ! 542: * ! 543: * So we must check the clump after hindex for objects ! 544: * that are so displaced, and move one up to the new hole. ! 545: * ! 546: * hindex - index of new hole in the clump ! 547: * dindex - index we are checking for a displaced object ! 548: * ! 549: * When we move a displaced object up into the hole, ! 550: * it creates a new hole, and we have to repeat the process ! 551: * until we get to the end of the clump. ! 552: */ ! 553: ! 554: for (dindex = hindex; index != 0; hindex = dindex) { ! 555: for (;;) { ! 556: mach_port_index_t tindex; ! 557: ipc_object_t tobj; ! 558: ! 559: if (++dindex == size) ! 560: dindex = 0; ! 561: assert(dindex != hindex); ! 562: ! 563: /* are we at the end of the clump? */ ! 564: ! 565: index = table[dindex].ie_index; ! 566: if (index == 0) ! 567: break; ! 568: ! 569: /* is this a displaced object? */ ! 570: ! 571: tobj = table[index].ie_object; ! 572: assert(tobj != IO_NULL); ! 573: tindex = IH_LOCAL_HASH(tobj, size); ! 574: ! 575: if ((dindex < hindex) ? ! 576: ((dindex < tindex) && (tindex <= hindex)) : ! 577: ((dindex < tindex) || (tindex <= hindex))) ! 578: break; ! 579: } ! 580: ! 581: table[hindex].ie_index = index; ! 582: } ! 583: } ! 584: ! 585: /* ! 586: * Routine: ipc_hash_init ! 587: * Purpose: ! 588: * Initialize the reverse hash table implementation. ! 589: */ ! 590: ! 591: void ! 592: ipc_hash_init(void) ! 593: { ! 594: ipc_hash_index_t i; ! 595: ! 596: /* if not configured, initialize ipc_hash_global_size */ ! 597: ! 598: if (ipc_hash_global_size == 0) { ! 599: ipc_hash_global_size = ipc_tree_entry_max >> 8; ! 600: if (ipc_hash_global_size < 32) ! 601: ipc_hash_global_size = 32; ! 602: } ! 603: ! 604: /* make sure it is a power of two */ ! 605: ! 606: ipc_hash_global_mask = ipc_hash_global_size - 1; ! 607: if ((ipc_hash_global_size & ipc_hash_global_mask) != 0) { ! 608: unsigned int bit; ! 609: ! 610: /* round up to closest power of two */ ! 611: ! 612: for (bit = 1;; bit <<= 1) { ! 613: ipc_hash_global_mask |= bit; ! 614: ipc_hash_global_size = ipc_hash_global_mask + 1; ! 615: ! 616: if ((ipc_hash_global_size & ipc_hash_global_mask) == 0) ! 617: break; ! 618: } ! 619: } ! 620: ! 621: /* allocate ipc_hash_global_table */ ! 622: ! 623: ipc_hash_global_table = (ipc_hash_global_bucket_t) ! 624: kalloc((vm_size_t) (ipc_hash_global_size * ! 625: sizeof(struct ipc_hash_global_bucket))); ! 626: assert(ipc_hash_global_table != IHGB_NULL); ! 627: ! 628: /* and initialize it */ ! 629: ! 630: for (i = 0; i < ipc_hash_global_size; i++) { ! 631: ipc_hash_global_bucket_t bucket; ! 632: ! 633: bucket = &ipc_hash_global_table[i]; ! 634: ihgb_lock_init(bucket); ! 635: bucket->ihgb_head = ITE_NULL; ! 636: } ! 637: } ! 638: ! 639: #include <mach_ipc_debug.h> ! 640: #if MACH_IPC_DEBUG ! 641: ! 642: #include <mach/kern_return.h> ! 643: #include <mach_debug/hash_info.h> ! 644: #include <vm/vm_map.h> ! 645: #include <vm/vm_kern.h> ! 646: #include <vm/vm_user.h> ! 647: ! 648: /* ! 649: * Routine: ipc_hash_info ! 650: * Purpose: ! 651: * Return information about the global reverse hash table. ! 652: * Fills the buffer with as much information as possible ! 653: * and returns the desired size of the buffer. ! 654: * Conditions: ! 655: * Nothing locked. The caller should provide ! 656: * possibly-pageable memory. ! 657: */ ! 658: ! 659: unsigned int ! 660: ipc_hash_info( ! 661: hash_info_bucket_t *info, ! 662: unsigned int count) ! 663: { ! 664: ipc_hash_index_t i; ! 665: ! 666: if (ipc_hash_global_size < count) ! 667: count = ipc_hash_global_size; ! 668: ! 669: for (i = 0; i < count; i++) { ! 670: ipc_hash_global_bucket_t bucket = &ipc_hash_global_table[i]; ! 671: unsigned int bucket_count = 0; ! 672: ipc_tree_entry_t entry; ! 673: ! 674: ihgb_lock(bucket); ! 675: for (entry = bucket->ihgb_head; ! 676: entry != ITE_NULL; ! 677: entry = entry->ite_next) ! 678: bucket_count++; ! 679: ihgb_unlock(bucket); ! 680: ! 681: /* don't touch pageable memory while holding locks */ ! 682: info[i].hib_count = bucket_count; ! 683: } ! 684: ! 685: return ipc_hash_global_size; ! 686: } ! 687: ! 688: #endif /* MACH_IPC_DEBUG */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.