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