Annotation of OSKit-Mach/ipc/ipc_splay.c, revision 1.1.1.1

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

unix.superglobalmegacorp.com

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