Annotation of kernel/ipc/ipc_splay.c, revision 1.1.1.1

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, &current,
                    878:                                &ltree, &ltreep, &rtree, &rtreep);
                    879:                        ipc_splay_prim_assemble(current,
                    880:                                &ltree, 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: 

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.