Annotation of XNU/osfmk/ipc/ipc_splay.c, revision 1.1.1.1

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

unix.superglobalmegacorp.com

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