|
|
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_splay.c ! 75: * Author: Rich Draves ! 76: * Date: 1989 ! 77: * ! 78: * Primitive splay tree operations. ! 79: */ ! 80: ! 81: #include <mach/port.h> ! 82: #include <kern/assert.h> ! 83: #include <kern/macro_help.h> ! 84: #include <ipc/ipc_entry.h> ! 85: #include <ipc/ipc_splay.h> ! 86: ! 87: /* ! 88: * Splay trees are self-adjusting binary search trees. ! 89: * They have the following attractive properties: ! 90: * 1) Space efficient; only two pointers per entry. ! 91: * 2) Robust performance; amortized O(log n) per operation. ! 92: * 3) Recursion not needed. ! 93: * This makes them a good fall-back data structure for those ! 94: * entries that don't fit into the lookup table. ! 95: * ! 96: * The paper by Sleator and Tarjan, JACM v. 32, no. 3, pp. 652-686, ! 97: * describes the splaying operation. ipc_splay_prim_lookup ! 98: * and ipc_splay_prim_assemble implement the top-down splay ! 99: * described on p. 669. ! 100: * ! 101: * The tree is stored in an unassembled form. If ist_root is null, ! 102: * then the tree has no entries. Otherwise, ist_name records ! 103: * the value used for the last lookup. ist_root points to the ! 104: * middle tree obtained from the top-down splay. ist_ltree and ! 105: * ist_rtree point to left and right subtrees, whose entries ! 106: * are all smaller (larger) than those in the middle tree. ! 107: * ist_ltreep and ist_rtreep are pointers to fields in the ! 108: * left and right subtrees. ist_ltreep points to the rchild field ! 109: * of the largest entry in ltree, and ist_rtreep points to the ! 110: * lchild field of the smallest entry in rtree. The pointed-to ! 111: * fields aren't initialized. If the left (right) subtree is null, ! 112: * then ist_ltreep (ist_rtreep) points to the ist_ltree (ist_rtree) ! 113: * field in the splay structure itself. ! 114: * ! 115: * The primary advantage of the unassembled form is that repeated ! 116: * unsuccessful lookups are efficient. In particular, an unsuccessful ! 117: * lookup followed by an insert only requires one splaying operation. ! 118: * ! 119: * The traversal algorithm works via pointer inversion. ! 120: * When descending down the tree, child pointers are reversed ! 121: * to point back to the parent entry. When ascending, ! 122: * the pointers are restored to their original value. ! 123: * ! 124: * The biggest potential problem with the splay tree implementation ! 125: * is that the operations, even lookup, require an exclusive lock. ! 126: * If IPC spaces are protected with exclusive locks, then ! 127: * the splay tree doesn't require its own lock, and ist_lock/ist_unlock ! 128: * needn't do anything. If IPC spaces are protected with read/write ! 129: * locks then ist_lock/ist_unlock should provide exclusive access. ! 130: * ! 131: * If it becomes important to let lookups run in parallel, ! 132: * or if the restructuring makes lookups too expensive, then ! 133: * there is hope. Use a read/write lock on the splay tree. ! 134: * Keep track of the number of entries in the tree. When doing ! 135: * a lookup, first try a non-restructuring lookup with a read lock held, ! 136: * with a bound (based on log of size of the tree) on the number of ! 137: * entries to traverse. If the lookup runs up against the bound, ! 138: * then take a write lock and do a reorganizing lookup. ! 139: * This way, if lookups only access roughly balanced parts ! 140: * of the tree, then lookups run in parallel and do no restructuring. ! 141: * ! 142: * The traversal algorithm currently requires an exclusive lock. ! 143: * If that is a problem, the tree could be changed from an lchild/rchild ! 144: * representation to a leftmost child/right sibling representation. ! 145: * In conjunction with non-restructing lookups, this would let ! 146: * lookups and traversals all run in parallel. But this representation ! 147: * is more complicated and would slow down the operations. ! 148: */ ! 149: ! 150: /* ! 151: * Boundary values to hand to ipc_splay_prim_lookup: ! 152: */ ! 153: ! 154: #define MACH_PORT_SMALLEST ((mach_port_t) 0) ! 155: #define MACH_PORT_LARGEST ((mach_port_t) ~0) ! 156: ! 157: /* ! 158: * Routine: ipc_splay_prim_lookup ! 159: * Purpose: ! 160: * Searches for the node labeled name in the splay tree. ! 161: * Returns three nodes (treep, ltreep, rtreep) and ! 162: * two pointers to nodes (ltreepp, rtreepp). ! 163: * ! 164: * ipc_splay_prim_lookup splits the supplied tree into ! 165: * three subtrees, left, middle, and right, returned ! 166: * in ltreep, treep, and rtreep. ! 167: * ! 168: * If name is present in the tree, then it is at ! 169: * the root of the middle tree. Otherwise, the root ! 170: * of the middle tree is the last node traversed. ! 171: * ! 172: * ipc_splay_prim_lookup returns a pointer into ! 173: * the left subtree, to the rchild field of its ! 174: * largest node, in ltreepp. It returns a pointer ! 175: * into the right subtree, to the lchild field of its ! 176: * smallest node, in rtreepp. ! 177: */ ! 178: ! 179: static void ! 180: ipc_splay_prim_lookup( ! 181: mach_port_t name, ! 182: ipc_tree_entry_t tree, ! 183: ipc_tree_entry_t *treep, ! 184: ipc_tree_entry_t *ltreep, ! 185: ipc_tree_entry_t **ltreepp, ! 186: ipc_tree_entry_t *rtreep, ! 187: ipc_tree_entry_t **rtreepp) ! 188: { ! 189: mach_port_t tname; /* temp name */ ! 190: ipc_tree_entry_t lchild, rchild; /* temp child pointers */ ! 191: ! 192: assert(tree != ITE_NULL); ! 193: ! 194: #define link_left \ ! 195: MACRO_BEGIN \ ! 196: *ltreep = tree; \ ! 197: ltreep = &tree->ite_rchild; \ ! 198: tree = *ltreep; \ ! 199: MACRO_END ! 200: ! 201: #define link_right \ ! 202: MACRO_BEGIN \ ! 203: *rtreep = tree; \ ! 204: rtreep = &tree->ite_lchild; \ ! 205: tree = *rtreep; \ ! 206: MACRO_END ! 207: ! 208: #define rotate_left \ ! 209: MACRO_BEGIN \ ! 210: ipc_tree_entry_t temp = tree; \ ! 211: \ ! 212: tree = temp->ite_rchild; \ ! 213: temp->ite_rchild = tree->ite_lchild; \ ! 214: tree->ite_lchild = temp; \ ! 215: MACRO_END ! 216: ! 217: #define rotate_right \ ! 218: MACRO_BEGIN \ ! 219: ipc_tree_entry_t temp = tree; \ ! 220: \ ! 221: tree = temp->ite_lchild; \ ! 222: temp->ite_lchild = tree->ite_rchild; \ ! 223: tree->ite_rchild = temp; \ ! 224: MACRO_END ! 225: ! 226: while (name != (tname = tree->ite_name)) { ! 227: if (name < tname) { ! 228: /* descend to left */ ! 229: ! 230: lchild = tree->ite_lchild; ! 231: if (lchild == ITE_NULL) ! 232: break; ! 233: tname = lchild->ite_name; ! 234: ! 235: if ((name < tname) && ! 236: (lchild->ite_lchild != ITE_NULL)) ! 237: rotate_right; ! 238: link_right; ! 239: if ((name > tname) && ! 240: (lchild->ite_rchild != ITE_NULL)) ! 241: link_left; ! 242: } else { ! 243: /* descend to right */ ! 244: ! 245: rchild = tree->ite_rchild; ! 246: if (rchild == ITE_NULL) ! 247: break; ! 248: tname = rchild->ite_name; ! 249: ! 250: if ((name > tname) && ! 251: (rchild->ite_rchild != ITE_NULL)) ! 252: rotate_left; ! 253: link_left; ! 254: if ((name < tname) && ! 255: (rchild->ite_lchild != ITE_NULL)) ! 256: link_right; ! 257: } ! 258: ! 259: assert(tree != ITE_NULL); ! 260: } ! 261: ! 262: *treep = tree; ! 263: *ltreepp = ltreep; ! 264: *rtreepp = rtreep; ! 265: ! 266: #undef link_left ! 267: #undef link_right ! 268: #undef rotate_left ! 269: #undef rotate_right ! 270: } ! 271: ! 272: /* ! 273: * Routine: ipc_splay_prim_assemble ! 274: * Purpose: ! 275: * Assembles the results of ipc_splay_prim_lookup ! 276: * into a splay tree with the found node at the root. ! 277: * ! 278: * ltree and rtree are by-reference so storing ! 279: * through ltreep and rtreep can change them. ! 280: */ ! 281: ! 282: static void ! 283: ipc_splay_prim_assemble( ! 284: ipc_tree_entry_t tree, ! 285: ipc_tree_entry_t *ltree, ! 286: ipc_tree_entry_t *ltreep, ! 287: ipc_tree_entry_t *rtree, ! 288: ipc_tree_entry_t *rtreep) ! 289: { ! 290: assert(tree != ITE_NULL); ! 291: ! 292: *ltreep = tree->ite_lchild; ! 293: *rtreep = tree->ite_rchild; ! 294: ! 295: tree->ite_lchild = *ltree; ! 296: tree->ite_rchild = *rtree; ! 297: } ! 298: ! 299: /* ! 300: * Routine: ipc_splay_tree_init ! 301: * Purpose: ! 302: * Initialize a raw splay tree for use. ! 303: */ ! 304: ! 305: void ! 306: ipc_splay_tree_init( ! 307: ipc_splay_tree_t splay) ! 308: { ! 309: splay->ist_root = ITE_NULL; ! 310: } ! 311: ! 312: /* ! 313: * Routine: ipc_splay_tree_pick ! 314: * Purpose: ! 315: * Picks and returns a random entry in a splay tree. ! 316: * Returns FALSE if the splay tree is empty. ! 317: */ ! 318: ! 319: boolean_t ! 320: ipc_splay_tree_pick( ! 321: ipc_splay_tree_t splay, ! 322: mach_port_t *namep, ! 323: ipc_tree_entry_t *entryp) ! 324: { ! 325: ipc_tree_entry_t root; ! 326: ! 327: ist_lock(splay); ! 328: ! 329: root = splay->ist_root; ! 330: if (root != ITE_NULL) { ! 331: *namep = root->ite_name; ! 332: *entryp = root; ! 333: } ! 334: ! 335: ist_unlock(splay); ! 336: ! 337: return root != ITE_NULL; ! 338: } ! 339: ! 340: /* ! 341: * Routine: ipc_splay_tree_lookup ! 342: * Purpose: ! 343: * Finds an entry in a splay tree. ! 344: * Returns ITE_NULL if not found. ! 345: */ ! 346: ! 347: ipc_tree_entry_t ! 348: ipc_splay_tree_lookup( ! 349: ipc_splay_tree_t splay, ! 350: mach_port_t name) ! 351: { ! 352: ipc_tree_entry_t root; ! 353: ! 354: ist_lock(splay); ! 355: ! 356: root = splay->ist_root; ! 357: if (root != ITE_NULL) { ! 358: if (splay->ist_name != name) { ! 359: ipc_splay_prim_assemble(root, ! 360: &splay->ist_ltree, splay->ist_ltreep, ! 361: &splay->ist_rtree, splay->ist_rtreep); ! 362: ipc_splay_prim_lookup(name, root, &root, ! 363: &splay->ist_ltree, &splay->ist_ltreep, ! 364: &splay->ist_rtree, &splay->ist_rtreep); ! 365: splay->ist_name = name; ! 366: splay->ist_root = root; ! 367: } ! 368: ! 369: if (name != root->ite_name) ! 370: root = ITE_NULL; ! 371: } ! 372: ! 373: ist_unlock(splay); ! 374: ! 375: return root; ! 376: } ! 377: ! 378: /* ! 379: * Routine: ipc_splay_tree_insert ! 380: * Purpose: ! 381: * Inserts a new entry into a splay tree. ! 382: * The caller supplies a new entry. ! 383: * The name can't already be present in the tree. ! 384: */ ! 385: ! 386: void ! 387: ipc_splay_tree_insert( ! 388: ipc_splay_tree_t splay, ! 389: mach_port_t name, ! 390: ipc_tree_entry_t entry) ! 391: { ! 392: ipc_tree_entry_t root; ! 393: ! 394: assert(entry != ITE_NULL); ! 395: ! 396: ist_lock(splay); ! 397: ! 398: root = splay->ist_root; ! 399: if (root == ITE_NULL) { ! 400: entry->ite_lchild = ITE_NULL; ! 401: entry->ite_rchild = ITE_NULL; ! 402: } else { ! 403: if (splay->ist_name != name) { ! 404: ipc_splay_prim_assemble(root, ! 405: &splay->ist_ltree, splay->ist_ltreep, ! 406: &splay->ist_rtree, splay->ist_rtreep); ! 407: ipc_splay_prim_lookup(name, root, &root, ! 408: &splay->ist_ltree, &splay->ist_ltreep, ! 409: &splay->ist_rtree, &splay->ist_rtreep); ! 410: } ! 411: ! 412: assert(root->ite_name != name); ! 413: ! 414: if (name < root->ite_name) { ! 415: assert(root->ite_lchild == ITE_NULL); ! 416: ! 417: *splay->ist_ltreep = ITE_NULL; ! 418: *splay->ist_rtreep = root; ! 419: } else { ! 420: assert(root->ite_rchild == ITE_NULL); ! 421: ! 422: *splay->ist_ltreep = root; ! 423: *splay->ist_rtreep = ITE_NULL; ! 424: } ! 425: ! 426: entry->ite_lchild = splay->ist_ltree; ! 427: entry->ite_rchild = splay->ist_rtree; ! 428: } ! 429: ! 430: entry->ite_name = name; ! 431: splay->ist_root = entry; ! 432: splay->ist_name = name; ! 433: splay->ist_ltreep = &splay->ist_ltree; ! 434: splay->ist_rtreep = &splay->ist_rtree; ! 435: ! 436: ist_unlock(splay); ! 437: } ! 438: ! 439: /* ! 440: * Routine: ipc_splay_tree_delete ! 441: * Purpose: ! 442: * Deletes an entry from a splay tree. ! 443: * The name must be present in the tree. ! 444: * Frees the entry. ! 445: * ! 446: * The "entry" argument isn't currently used. ! 447: * Other implementations might want it, though. ! 448: */ ! 449: ! 450: void ! 451: ipc_splay_tree_delete( ! 452: ipc_splay_tree_t splay, ! 453: mach_port_t name, ! 454: ipc_tree_entry_t entry) ! 455: { ! 456: ipc_tree_entry_t root, saved; ! 457: ! 458: ist_lock(splay); ! 459: ! 460: root = splay->ist_root; ! 461: assert(root != ITE_NULL); ! 462: ! 463: if (splay->ist_name != name) { ! 464: ipc_splay_prim_assemble(root, ! 465: &splay->ist_ltree, splay->ist_ltreep, ! 466: &splay->ist_rtree, splay->ist_rtreep); ! 467: ipc_splay_prim_lookup(name, root, &root, ! 468: &splay->ist_ltree, &splay->ist_ltreep, ! 469: &splay->ist_rtree, &splay->ist_rtreep); ! 470: } ! 471: ! 472: assert(root->ite_name == name); ! 473: assert(root == entry); ! 474: ! 475: *splay->ist_ltreep = root->ite_lchild; ! 476: *splay->ist_rtreep = root->ite_rchild; ! 477: ite_free(root); ! 478: ! 479: root = splay->ist_ltree; ! 480: saved = splay->ist_rtree; ! 481: ! 482: if (root == ITE_NULL) ! 483: root = saved; ! 484: else if (saved != ITE_NULL) { ! 485: /* ! 486: * Find the largest node in the left subtree, and splay it ! 487: * to the root. Then add the saved right subtree. ! 488: */ ! 489: ! 490: ipc_splay_prim_lookup(MACH_PORT_LARGEST, root, &root, ! 491: &splay->ist_ltree, &splay->ist_ltreep, ! 492: &splay->ist_rtree, &splay->ist_rtreep); ! 493: ipc_splay_prim_assemble(root, ! 494: &splay->ist_ltree, splay->ist_ltreep, ! 495: &splay->ist_rtree, splay->ist_rtreep); ! 496: ! 497: assert(root->ite_rchild == ITE_NULL); ! 498: root->ite_rchild = saved; ! 499: } ! 500: ! 501: splay->ist_root = root; ! 502: if (root != ITE_NULL) { ! 503: splay->ist_name = root->ite_name; ! 504: splay->ist_ltreep = &splay->ist_ltree; ! 505: splay->ist_rtreep = &splay->ist_rtree; ! 506: } ! 507: ! 508: ist_unlock(splay); ! 509: } ! 510: ! 511: /* ! 512: * Routine: ipc_splay_tree_split ! 513: * Purpose: ! 514: * Split a splay tree. Puts all entries smaller than "name" ! 515: * into a new tree, "small". ! 516: * ! 517: * Doesn't do locking on "small", because nobody else ! 518: * should be fiddling with the uninitialized tree. ! 519: */ ! 520: ! 521: void ! 522: ipc_splay_tree_split( ! 523: ipc_splay_tree_t splay, ! 524: mach_port_t name, ! 525: ipc_splay_tree_t small) ! 526: { ! 527: ipc_tree_entry_t root; ! 528: ! 529: ipc_splay_tree_init(small); ! 530: ! 531: ist_lock(splay); ! 532: ! 533: root = splay->ist_root; ! 534: if (root != ITE_NULL) { ! 535: /* lookup name, to get it (or last traversed) to the top */ ! 536: ! 537: if (splay->ist_name != name) { ! 538: ipc_splay_prim_assemble(root, ! 539: &splay->ist_ltree, splay->ist_ltreep, ! 540: &splay->ist_rtree, splay->ist_rtreep); ! 541: ipc_splay_prim_lookup(name, root, &root, ! 542: &splay->ist_ltree, &splay->ist_ltreep, ! 543: &splay->ist_rtree, &splay->ist_rtreep); ! 544: } ! 545: ! 546: if (root->ite_name < name) { ! 547: /* root goes into small */ ! 548: ! 549: *splay->ist_ltreep = root->ite_lchild; ! 550: *splay->ist_rtreep = ITE_NULL; ! 551: root->ite_lchild = splay->ist_ltree; ! 552: assert(root->ite_rchild == ITE_NULL); ! 553: ! 554: small->ist_root = root; ! 555: small->ist_name = root->ite_name; ! 556: small->ist_ltreep = &small->ist_ltree; ! 557: small->ist_rtreep = &small->ist_rtree; ! 558: ! 559: /* rtree goes into splay */ ! 560: ! 561: root = splay->ist_rtree; ! 562: splay->ist_root = root; ! 563: if (root != ITE_NULL) { ! 564: splay->ist_name = root->ite_name; ! 565: splay->ist_ltreep = &splay->ist_ltree; ! 566: splay->ist_rtreep = &splay->ist_rtree; ! 567: } ! 568: } else { ! 569: /* root stays in splay */ ! 570: ! 571: *splay->ist_ltreep = root->ite_lchild; ! 572: root->ite_lchild = ITE_NULL; ! 573: ! 574: splay->ist_root = root; ! 575: splay->ist_name = name; ! 576: splay->ist_ltreep = &splay->ist_ltree; ! 577: ! 578: /* ltree goes into small */ ! 579: ! 580: root = splay->ist_ltree; ! 581: small->ist_root = root; ! 582: if (root != ITE_NULL) { ! 583: small->ist_name = root->ite_name; ! 584: small->ist_ltreep = &small->ist_ltree; ! 585: small->ist_rtreep = &small->ist_rtree; ! 586: } ! 587: } ! 588: } ! 589: ! 590: ist_unlock(splay); ! 591: } ! 592: ! 593: /* ! 594: * Routine: ipc_splay_tree_join ! 595: * Purpose: ! 596: * Joins two splay trees. Merges the entries in "small", ! 597: * which must all be smaller than the entries in "splay", ! 598: * into "splay". ! 599: */ ! 600: ! 601: void ! 602: ipc_splay_tree_join( ! 603: ipc_splay_tree_t splay, ! 604: ipc_splay_tree_t small) ! 605: { ! 606: ipc_tree_entry_t sroot; ! 607: ! 608: /* pull entries out of small */ ! 609: ! 610: ist_lock(small); ! 611: ! 612: sroot = small->ist_root; ! 613: if (sroot != ITE_NULL) { ! 614: ipc_splay_prim_assemble(sroot, ! 615: &small->ist_ltree, small->ist_ltreep, ! 616: &small->ist_rtree, small->ist_rtreep); ! 617: small->ist_root = ITE_NULL; ! 618: } ! 619: ! 620: ist_unlock(small); ! 621: ! 622: /* put entries, if any, into splay */ ! 623: ! 624: if (sroot != ITE_NULL) { ! 625: ipc_tree_entry_t root; ! 626: ! 627: ist_lock(splay); ! 628: ! 629: root = splay->ist_root; ! 630: if (root == ITE_NULL) { ! 631: root = sroot; ! 632: } else { ! 633: /* get smallest entry in splay tree to top */ ! 634: ! 635: if (splay->ist_name != MACH_PORT_SMALLEST) { ! 636: ipc_splay_prim_assemble(root, ! 637: &splay->ist_ltree, splay->ist_ltreep, ! 638: &splay->ist_rtree, splay->ist_rtreep); ! 639: ipc_splay_prim_lookup(MACH_PORT_SMALLEST, ! 640: root, &root, ! 641: &splay->ist_ltree, &splay->ist_ltreep, ! 642: &splay->ist_rtree, &splay->ist_rtreep); ! 643: } ! 644: ! 645: ipc_splay_prim_assemble(root, ! 646: &splay->ist_ltree, splay->ist_ltreep, ! 647: &splay->ist_rtree, splay->ist_rtreep); ! 648: ! 649: assert(root->ite_lchild == ITE_NULL); ! 650: assert(sroot->ite_name < root->ite_name); ! 651: root->ite_lchild = sroot; ! 652: } ! 653: ! 654: splay->ist_root = root; ! 655: splay->ist_name = root->ite_name; ! 656: splay->ist_ltreep = &splay->ist_ltree; ! 657: splay->ist_rtreep = &splay->ist_rtree; ! 658: ! 659: ist_unlock(splay); ! 660: } ! 661: } ! 662: ! 663: /* ! 664: * Routine: ipc_splay_tree_bounds ! 665: * Purpose: ! 666: * Given a name, returns the largest value present ! 667: * in the tree that is smaller than or equal to the name, ! 668: * or ~0 if no such value exists. Similarly, returns ! 669: * the smallest value present that is greater than or ! 670: * equal to the name, or 0 if no such value exists. ! 671: * ! 672: * Hence, if ! 673: * lower = upper, then lower = name = upper ! 674: * and name is present in the tree ! 675: * lower = ~0 and upper = 0, ! 676: * then the tree is empty ! 677: * lower = ~0 and upper > 0, then name < upper ! 678: * and upper is smallest value in tree ! 679: * lower < ~0 and upper = 0, then lower < name ! 680: * and lower is largest value in tree ! 681: * lower < ~0 and upper > 0, then lower < name < upper ! 682: * and they are tight bounds on name ! 683: * ! 684: * (Note MACH_PORT_SMALLEST = 0 and MACH_PORT_LARGEST = ~0.) ! 685: */ ! 686: ! 687: void ! 688: ipc_splay_tree_bounds( ! 689: ipc_splay_tree_t splay, ! 690: mach_port_t name, ! 691: mach_port_t *lowerp, ! 692: mach_port_t *upperp) ! 693: { ! 694: ipc_tree_entry_t root; ! 695: ! 696: ist_lock(splay); ! 697: ! 698: root = splay->ist_root; ! 699: if (root == ITE_NULL) { ! 700: *lowerp = MACH_PORT_LARGEST; ! 701: *upperp = MACH_PORT_SMALLEST; ! 702: } else { ! 703: mach_port_t rname; ! 704: ! 705: if (splay->ist_name != name) { ! 706: ipc_splay_prim_assemble(root, ! 707: &splay->ist_ltree, splay->ist_ltreep, ! 708: &splay->ist_rtree, splay->ist_rtreep); ! 709: ipc_splay_prim_lookup(name, root, &root, ! 710: &splay->ist_ltree, &splay->ist_ltreep, ! 711: &splay->ist_rtree, &splay->ist_rtreep); ! 712: splay->ist_name = name; ! 713: splay->ist_root = root; ! 714: } ! 715: ! 716: rname = root->ite_name; ! 717: ! 718: /* ! 719: * OK, it's a hack. We convert the ltreep and rtreep ! 720: * pointers back into real entry pointers, ! 721: * so we can pick the names out of the entries. ! 722: */ ! 723: ! 724: if (rname <= name) ! 725: *lowerp = rname; ! 726: else if (splay->ist_ltreep == &splay->ist_ltree) ! 727: *lowerp = MACH_PORT_LARGEST; ! 728: else { ! 729: ipc_tree_entry_t entry; ! 730: ! 731: entry = (ipc_tree_entry_t) ! 732: ((char *)splay->ist_ltreep - ! 733: ((char *)&root->ite_rchild - ! 734: (char *)root)); ! 735: *lowerp = entry->ite_name; ! 736: } ! 737: ! 738: if (rname >= name) ! 739: *upperp = rname; ! 740: else if (splay->ist_rtreep == &splay->ist_rtree) ! 741: *upperp = MACH_PORT_SMALLEST; ! 742: else { ! 743: ipc_tree_entry_t entry; ! 744: ! 745: entry = (ipc_tree_entry_t) ! 746: ((char *)splay->ist_rtreep - ! 747: ((char *)&root->ite_lchild - ! 748: (char *)root)); ! 749: *upperp = entry->ite_name; ! 750: } ! 751: } ! 752: ! 753: ist_unlock(splay); ! 754: } ! 755: ! 756: /* ! 757: * Routine: ipc_splay_traverse_start ! 758: * Routine: ipc_splay_traverse_next ! 759: * Routine: ipc_splay_traverse_finish ! 760: * Purpose: ! 761: * Perform a symmetric order traversal of a splay tree. ! 762: * Usage: ! 763: * for (entry = ipc_splay_traverse_start(splay); ! 764: * entry != ITE_NULL; ! 765: * entry = ipc_splay_traverse_next(splay, delete)) { ! 766: * do something with entry ! 767: * } ! 768: * ipc_splay_traverse_finish(splay); ! 769: * ! 770: * If "delete" is TRUE, then the current entry ! 771: * is removed from the tree and deallocated. ! 772: * ! 773: * During the traversal, the splay tree is locked. ! 774: */ ! 775: ! 776: ipc_tree_entry_t ! 777: ipc_splay_traverse_start( ! 778: ipc_splay_tree_t splay) ! 779: { ! 780: ipc_tree_entry_t current, parent; ! 781: ! 782: ist_lock(splay); ! 783: ! 784: current = splay->ist_root; ! 785: if (current != ITE_NULL) { ! 786: ipc_splay_prim_assemble(current, ! 787: &splay->ist_ltree, splay->ist_ltreep, ! 788: &splay->ist_rtree, splay->ist_rtreep); ! 789: ! 790: parent = ITE_NULL; ! 791: ! 792: while (current->ite_lchild != ITE_NULL) { ! 793: ipc_tree_entry_t next; ! 794: ! 795: next = current->ite_lchild; ! 796: current->ite_lchild = parent; ! 797: parent = current; ! 798: current = next; ! 799: } ! 800: ! 801: splay->ist_ltree = current; ! 802: splay->ist_rtree = parent; ! 803: } ! 804: ! 805: return current; ! 806: } ! 807: ! 808: ipc_tree_entry_t ! 809: ipc_splay_traverse_next( ! 810: ipc_splay_tree_t splay, ! 811: boolean_t delete) ! 812: { ! 813: ipc_tree_entry_t current, parent; ! 814: ! 815: /* pick up where traverse_entry left off */ ! 816: ! 817: current = splay->ist_ltree; ! 818: parent = splay->ist_rtree; ! 819: assert(current != ITE_NULL); ! 820: ! 821: if (!delete) ! 822: goto traverse_right; ! 823: ! 824: /* we must delete current and patch the tree */ ! 825: ! 826: if (current->ite_lchild == ITE_NULL) { ! 827: if (current->ite_rchild == ITE_NULL) { ! 828: /* like traverse_back, but with deletion */ ! 829: ! 830: if (parent == ITE_NULL) { ! 831: ite_free(current); ! 832: ! 833: splay->ist_root = ITE_NULL; ! 834: return ITE_NULL; ! 835: } ! 836: ! 837: if (current->ite_name < parent->ite_name) { ! 838: ite_free(current); ! 839: ! 840: current = parent; ! 841: parent = current->ite_lchild; ! 842: current->ite_lchild = ITE_NULL; ! 843: goto traverse_entry; ! 844: } else { ! 845: ite_free(current); ! 846: ! 847: current = parent; ! 848: parent = current->ite_rchild; ! 849: current->ite_rchild = ITE_NULL; ! 850: goto traverse_back; ! 851: } ! 852: } else { ! 853: ipc_tree_entry_t prev; ! 854: ! 855: prev = current; ! 856: current = current->ite_rchild; ! 857: ite_free(prev); ! 858: goto traverse_left; ! 859: } ! 860: } else { ! 861: if (current->ite_rchild == ITE_NULL) { ! 862: ipc_tree_entry_t prev; ! 863: ! 864: prev = current; ! 865: current = current->ite_lchild; ! 866: ite_free(prev); ! 867: goto traverse_back; ! 868: } else { ! 869: ipc_tree_entry_t prev; ! 870: ipc_tree_entry_t ltree, rtree; ! 871: ipc_tree_entry_t *ltreep, *rtreep; ! 872: ! 873: /* replace current with largest of left children */ ! 874: ! 875: prev = current; ! 876: ipc_splay_prim_lookup(MACH_PORT_LARGEST, ! 877: current->ite_lchild, ¤t, ! 878: <ree, <reep, &rtree, &rtreep); ! 879: ipc_splay_prim_assemble(current, ! 880: <ree, ltreep, &rtree, rtreep); ! 881: ! 882: assert(current->ite_rchild == ITE_NULL); ! 883: current->ite_rchild = prev->ite_rchild; ! 884: ite_free(prev); ! 885: goto traverse_right; ! 886: } ! 887: } ! 888: /*NOTREACHED*/ ! 889: ! 890: /* ! 891: * A state machine: for each entry, we ! 892: * 1) traverse left subtree ! 893: * 2) traverse the entry ! 894: * 3) traverse right subtree ! 895: * 4) traverse back to parent ! 896: */ ! 897: ! 898: traverse_left: ! 899: if (current->ite_lchild != ITE_NULL) { ! 900: ipc_tree_entry_t next; ! 901: ! 902: next = current->ite_lchild; ! 903: current->ite_lchild = parent; ! 904: parent = current; ! 905: current = next; ! 906: goto traverse_left; ! 907: } ! 908: ! 909: traverse_entry: ! 910: splay->ist_ltree = current; ! 911: splay->ist_rtree = parent; ! 912: return current; ! 913: ! 914: traverse_right: ! 915: if (current->ite_rchild != ITE_NULL) { ! 916: ipc_tree_entry_t next; ! 917: ! 918: next = current->ite_rchild; ! 919: current->ite_rchild = parent; ! 920: parent = current; ! 921: current = next; ! 922: goto traverse_left; ! 923: } ! 924: ! 925: traverse_back: ! 926: if (parent == ITE_NULL) { ! 927: splay->ist_root = current; ! 928: return ITE_NULL; ! 929: } ! 930: ! 931: if (current->ite_name < parent->ite_name) { ! 932: ipc_tree_entry_t prev; ! 933: ! 934: prev = current; ! 935: current = parent; ! 936: parent = current->ite_lchild; ! 937: current->ite_lchild = prev; ! 938: goto traverse_entry; ! 939: } else { ! 940: ipc_tree_entry_t prev; ! 941: ! 942: prev = current; ! 943: current = parent; ! 944: parent = current->ite_rchild; ! 945: current->ite_rchild = prev; ! 946: goto traverse_back; ! 947: } ! 948: } ! 949: ! 950: void ! 951: ipc_splay_traverse_finish( ! 952: ipc_splay_tree_t splay) ! 953: { ! 954: ipc_tree_entry_t root; ! 955: ! 956: root = splay->ist_root; ! 957: if (root != ITE_NULL) { ! 958: splay->ist_name = root->ite_name; ! 959: splay->ist_ltreep = &splay->ist_ltree; ! 960: splay->ist_rtreep = &splay->ist_rtree; ! 961: } ! 962: ! 963: ist_unlock(splay); ! 964: } ! 965:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.