Annotation of Gnu-Mach/kern/rdxtree.c, revision 1.1.1.2

1.1       root        1: /*
                      2:  * Copyright (c) 2011-2015 Richard Braun.
                      3:  * All rights reserved.
                      4:  *
                      5:  * Redistribution and use in source and binary forms, with or without
                      6:  * modification, are permitted provided that the following conditions
                      7:  * are met:
                      8:  * 1. Redistributions of source code must retain the above copyright
                      9:  *    notice, this list of conditions and the following disclaimer.
                     10:  * 2. Redistributions in binary form must reproduce the above copyright
                     11:  *    notice, this list of conditions and the following disclaimer in the
                     12:  *    documentation and/or other materials provided with the distribution.
                     13:  *
                     14:  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
                     15:  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
                     16:  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
                     17:  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
                     18:  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
                     19:  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
                     20:  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
                     21:  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
                     22:  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
                     23:  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
                     24:  *
                     25:  *
                     26:  * Upstream site with license notes :
                     27:  * http://git.sceen.net/rbraun/librbraun.git/
                     28:  */
                     29: 
                     30: #include <kern/assert.h>
                     31: #include <kern/slab.h>
                     32: #include <mach/kern_return.h>
                     33: #include <stddef.h>
                     34: #include <string.h>
                     35: 
                     36: #include "macros.h"
                     37: #include "rdxtree.h"
                     38: #include "rdxtree_i.h"
                     39: 
                     40: /* XXX */
                     41: #define CHAR_BIT       8U
                     42: #define ERR_SUCCESS    KERN_SUCCESS
                     43: #define ERR_BUSY       KERN_INVALID_ARGUMENT
                     44: #define ERR_NOMEM      KERN_RESOURCE_SHORTAGE
                     45: 
                     46: /*
                     47:  * Mask applied on an entry to obtain its address.
                     48:  */
                     49: #define RDXTREE_ENTRY_ADDR_MASK (~0x3UL)
                     50: 
                     51: /*
                     52:  * Global properties used to shape radix trees.
                     53:  */
                     54: #define RDXTREE_RADIX       6
                     55: #define RDXTREE_RADIX_SIZE  (1UL << RDXTREE_RADIX)
                     56: #define RDXTREE_RADIX_MASK  (RDXTREE_RADIX_SIZE - 1)
                     57: 
                     58: #if RDXTREE_RADIX < 6
                     59: typedef unsigned long rdxtree_bm_t;
                     60: #define rdxtree_ffs(x) __builtin_ffsl(x)
                     61: #elif RDXTREE_RADIX == 6 /* RDXTREE_RADIX < 6 */
                     62: typedef unsigned long long rdxtree_bm_t;
                     63: #define rdxtree_ffs(x) __builtin_ffsll(x)
                     64: #else /* RDXTREE_RADIX < 6 */
                     65: #error "radix too high"
                     66: #endif /* RDXTREE_RADIX < 6 */
                     67: 
                     68: /*
                     69:  * Allocation bitmap size in bits.
                     70:  */
                     71: #define RDXTREE_BM_SIZE (sizeof(rdxtree_bm_t) * CHAR_BIT)
                     72: 
                     73: /*
                     74:  * Empty/full allocation bitmap words.
                     75:  */
                     76: #define RDXTREE_BM_EMPTY    ((rdxtree_bm_t)0)
                     77: #define RDXTREE_BM_FULL \
                     78:     ((~(rdxtree_bm_t)0) >> (RDXTREE_BM_SIZE - RDXTREE_RADIX_SIZE))
                     79: 
                     80: /*
                     81:  * These macros can be replaced by actual functions in an environment
                     82:  * that provides lockless synchronization such as RCU.
                     83:  */
                     84: #define llsync_assign_ptr(ptr, value)   ((ptr) = (value))
                     85: #define llsync_read_ptr(ptr)            (ptr)
                     86: 
                     87: /*
                     88:  * Radix tree node.
                     89:  *
                     90:  * The height of a tree is the number of nodes to traverse until stored
                     91:  * pointers are reached. A height of 0 means the entries of a node (or the
                     92:  * tree root) directly point to stored pointers.
                     93:  *
                     94:  * The index is valid if and only if the parent isn't NULL.
                     95:  *
                     96:  * Concerning the allocation bitmap, a bit is set when the node it denotes,
                     97:  * or one of its children, can be used to allocate an entry. Conversely, a bit
                     98:  * is clear when the matching node and all of its children have no free entry.
                     99:  *
                    100:  * In order to support safe lockless lookups, in particular during a resize,
                    101:  * each node includes the height of its subtree, which is invariant during
                    102:  * the entire node lifetime. Since the tree height does vary, it can't be
                    103:  * used to determine whether the tree root is a node or a stored pointer.
                    104:  * This implementation assumes that all nodes and stored pointers are at least
                    105:  * 4-byte aligned, and uses the least significant bit of entries to indicate
                    106:  * the pointer type. This bit is set for internal nodes, and clear for stored
                    107:  * pointers so that they can be accessed from slots without conversion.
                    108:  */
                    109: struct rdxtree_node {
                    110:     struct rdxtree_node *parent;
                    111:     unsigned int index;
                    112:     unsigned int height;
                    113:     unsigned int nr_entries;
                    114:     rdxtree_bm_t alloc_bm;
                    115:     void *entries[RDXTREE_RADIX_SIZE];
                    116: };
                    117: 
                    118: /*
                    119:  * We allocate nodes using the slab allocator.
                    120:  */
                    121: static struct kmem_cache rdxtree_node_cache;
                    122: 
                    123: void
                    124: rdxtree_cache_init(void)
                    125: {
                    126:     kmem_cache_init(&rdxtree_node_cache, "rdxtree_node",
1.1.1.2 ! root      127:                    sizeof(struct rdxtree_node), 0, NULL, 0);
1.1       root      128: }
                    129: 
                    130: #ifdef RDXTREE_ENABLE_NODE_CREATION_FAILURES
                    131: unsigned int rdxtree_fail_node_creation_threshold;
                    132: unsigned int rdxtree_nr_node_creations;
                    133: #endif /* RDXTREE_ENABLE_NODE_CREATION_FAILURES */
                    134: 
                    135: static inline int
                    136: rdxtree_check_alignment(const void *ptr)
                    137: {
                    138:     return ((unsigned long)ptr & ~RDXTREE_ENTRY_ADDR_MASK) == 0;
                    139: }
                    140: 
                    141: static inline void *
                    142: rdxtree_entry_addr(void *entry)
                    143: {
                    144:     return (void *)((unsigned long)entry & RDXTREE_ENTRY_ADDR_MASK);
                    145: }
                    146: 
                    147: static inline int
                    148: rdxtree_entry_is_node(const void *entry)
                    149: {
                    150:     return ((unsigned long)entry & 1) != 0;
                    151: }
                    152: 
                    153: static inline void *
                    154: rdxtree_node_to_entry(struct rdxtree_node *node)
                    155: {
                    156:     return (void *)((unsigned long)node | 1);
                    157: }
                    158: 
                    159: static int
                    160: rdxtree_node_create(struct rdxtree_node **nodep, unsigned int height)
                    161: {
                    162:     struct rdxtree_node *node;
                    163: 
                    164: #ifdef RDXTREE_ENABLE_NODE_CREATION_FAILURES
                    165:     if (rdxtree_fail_node_creation_threshold != 0) {
                    166:         rdxtree_nr_node_creations++;
                    167: 
                    168:         if (rdxtree_nr_node_creations == rdxtree_fail_node_creation_threshold)
                    169:             return ERR_NOMEM;
                    170:     }
                    171: #endif /* RDXTREE_ENABLE_NODE_CREATION_FAILURES */
                    172: 
                    173:     node = (struct rdxtree_node *) kmem_cache_alloc(&rdxtree_node_cache);
                    174: 
                    175:     if (node == NULL)
                    176:         return ERR_NOMEM;
                    177: 
                    178:     assert(rdxtree_check_alignment(node));
                    179:     node->parent = NULL;
                    180:     node->height = height;
                    181:     node->nr_entries = 0;
                    182:     node->alloc_bm = RDXTREE_BM_FULL;
                    183:     memset(node->entries, 0, sizeof(node->entries));
                    184:     *nodep = node;
                    185:     return 0;
                    186: }
                    187: 
                    188: static void
                    189: rdxtree_node_schedule_destruction(struct rdxtree_node *node)
                    190: {
                    191:     /*
                    192:      * This function is intended to use the appropriate interface to defer
                    193:      * destruction until all read-side references are dropped in an
                    194:      * environment that provides lockless synchronization.
                    195:      *
                    196:      * Otherwise, it simply "schedules" destruction immediately.
                    197:      */
                    198:     kmem_cache_free(&rdxtree_node_cache, (vm_offset_t) node);
                    199: }
                    200: 
                    201: static inline void
                    202: rdxtree_node_link(struct rdxtree_node *node, struct rdxtree_node *parent,
                    203:                   unsigned int index)
                    204: {
                    205:     node->parent = parent;
                    206:     node->index = index;
                    207: }
                    208: 
                    209: static inline void
                    210: rdxtree_node_unlink(struct rdxtree_node *node)
                    211: {
                    212:     assert(node->parent != NULL);
                    213:     node->parent = NULL;
                    214: }
                    215: 
                    216: static inline int
                    217: rdxtree_node_full(struct rdxtree_node *node)
                    218: {
                    219:     return (node->nr_entries == ARRAY_SIZE(node->entries));
                    220: }
                    221: 
                    222: static inline int
                    223: rdxtree_node_empty(struct rdxtree_node *node)
                    224: {
                    225:     return (node->nr_entries == 0);
                    226: }
                    227: 
                    228: static inline void
                    229: rdxtree_node_insert(struct rdxtree_node *node, unsigned int index,
                    230:                     void *entry)
                    231: {
                    232:     assert(index < ARRAY_SIZE(node->entries));
                    233:     assert(node->entries[index] == NULL);
                    234: 
                    235:     node->nr_entries++;
                    236:     llsync_assign_ptr(node->entries[index], entry);
                    237: }
                    238: 
                    239: static inline void
                    240: rdxtree_node_insert_node(struct rdxtree_node *node, unsigned int index,
                    241:                          struct rdxtree_node *child)
                    242: {
                    243:     rdxtree_node_insert(node, index, rdxtree_node_to_entry(child));
                    244: }
                    245: 
                    246: static inline void
                    247: rdxtree_node_remove(struct rdxtree_node *node, unsigned int index)
                    248: {
                    249:     assert(index < ARRAY_SIZE(node->entries));
                    250:     assert(node->entries[index] != NULL);
                    251: 
                    252:     node->nr_entries--;
                    253:     llsync_assign_ptr(node->entries[index], NULL);
                    254: }
                    255: 
                    256: static inline void *
                    257: rdxtree_node_find(struct rdxtree_node *node, unsigned int *indexp)
                    258: {
                    259:     unsigned int index;
                    260:     void *ptr;
                    261: 
                    262:     index = *indexp;
                    263: 
                    264:     while (index < ARRAY_SIZE(node->entries)) {
                    265:         ptr = rdxtree_entry_addr(llsync_read_ptr(node->entries[index]));
                    266: 
                    267:         if (ptr != NULL) {
                    268:             *indexp = index;
                    269:             return ptr;
                    270:         }
                    271: 
                    272:         index++;
                    273:     }
                    274: 
                    275:     return NULL;
                    276: }
                    277: 
                    278: static inline void
                    279: rdxtree_node_bm_set(struct rdxtree_node *node, unsigned int index)
                    280: {
                    281:     node->alloc_bm |= (rdxtree_bm_t)1 << index;
                    282: }
                    283: 
                    284: static inline void
                    285: rdxtree_node_bm_clear(struct rdxtree_node *node, unsigned int index)
                    286: {
                    287:     node->alloc_bm &= ~((rdxtree_bm_t)1 << index);
                    288: }
                    289: 
                    290: static inline int
                    291: rdxtree_node_bm_is_set(struct rdxtree_node *node, unsigned int index)
                    292: {
                    293:     return (node->alloc_bm & ((rdxtree_bm_t)1 << index));
                    294: }
                    295: 
                    296: static inline int
                    297: rdxtree_node_bm_empty(struct rdxtree_node *node)
                    298: {
                    299:     return (node->alloc_bm == RDXTREE_BM_EMPTY);
                    300: }
                    301: 
                    302: static inline unsigned int
                    303: rdxtree_node_bm_first(struct rdxtree_node *node)
                    304: {
                    305:     return rdxtree_ffs(node->alloc_bm) - 1;
                    306: }
                    307: 
                    308: static inline rdxtree_key_t
                    309: rdxtree_max_key(unsigned int height)
                    310: {
                    311:     size_t shift;
                    312: 
                    313:     shift = RDXTREE_RADIX * height;
                    314: 
                    315:     if (likely(shift < (sizeof(rdxtree_key_t) * CHAR_BIT)))
                    316:         return ((rdxtree_key_t)1 << shift) - 1;
                    317:     else
                    318:         return ~((rdxtree_key_t)0);
                    319: }
                    320: 
                    321: static void
                    322: rdxtree_shrink(struct rdxtree *tree)
                    323: {
                    324:     struct rdxtree_node *node;
                    325:     void *entry;
                    326: 
                    327:     while (tree->height > 0) {
                    328:         node = rdxtree_entry_addr(tree->root);
                    329: 
                    330:         if (node->nr_entries != 1)
                    331:             break;
                    332: 
                    333:         entry = node->entries[0];
                    334: 
                    335:         if (entry == NULL)
                    336:             break;
                    337: 
                    338:         tree->height--;
                    339: 
                    340:         if (tree->height > 0)
                    341:             rdxtree_node_unlink(rdxtree_entry_addr(entry));
                    342: 
                    343:         llsync_assign_ptr(tree->root, entry);
                    344:         rdxtree_node_schedule_destruction(node);
                    345:     }
                    346: }
                    347: 
                    348: static int
                    349: rdxtree_grow(struct rdxtree *tree, rdxtree_key_t key)
                    350: {
                    351:     struct rdxtree_node *root, *node;
                    352:     unsigned int new_height;
                    353:     int error;
                    354: 
                    355:     new_height = tree->height + 1;
                    356: 
                    357:     while (key > rdxtree_max_key(new_height))
                    358:         new_height++;
                    359: 
                    360:     if (tree->root == NULL) {
                    361:         tree->height = new_height;
                    362:         return ERR_SUCCESS;
                    363:     }
                    364: 
                    365:     root = rdxtree_entry_addr(tree->root);
                    366: 
                    367:     do {
                    368:         error = rdxtree_node_create(&node, tree->height);
                    369: 
                    370:         if (error) {
                    371:             rdxtree_shrink(tree);
                    372:             return error;
                    373:         }
                    374: 
                    375:         if (tree->height == 0)
                    376:             rdxtree_node_bm_clear(node, 0);
                    377:         else {
                    378:             rdxtree_node_link(root, node, 0);
                    379: 
                    380:             if (rdxtree_node_bm_empty(root))
                    381:                 rdxtree_node_bm_clear(node, 0);
                    382:         }
                    383: 
                    384:         rdxtree_node_insert(node, 0, tree->root);
                    385:         tree->height++;
                    386:         llsync_assign_ptr(tree->root, rdxtree_node_to_entry(node));
                    387:         root = node;
                    388:     } while (new_height > tree->height);
                    389: 
                    390:     return ERR_SUCCESS;
                    391: }
                    392: 
                    393: static void
                    394: rdxtree_cleanup(struct rdxtree *tree, struct rdxtree_node *node)
                    395: {
                    396:     struct rdxtree_node *prev;
                    397: 
                    398:     for (;;) {
                    399:         if (likely(!rdxtree_node_empty(node))) {
                    400:             if (unlikely(node->parent == NULL))
                    401:                 rdxtree_shrink(tree);
                    402: 
                    403:             break;
                    404:         }
                    405: 
                    406:         if (node->parent == NULL) {
                    407:             tree->height = 0;
                    408:             llsync_assign_ptr(tree->root, NULL);
                    409:             rdxtree_node_schedule_destruction(node);
                    410:             break;
                    411:         }
                    412: 
                    413:         prev = node;
                    414:         node = node->parent;
                    415:         rdxtree_node_unlink(prev);
                    416:         rdxtree_node_remove(node, prev->index);
                    417:         rdxtree_node_schedule_destruction(prev);
                    418:     }
                    419: }
                    420: 
                    421: static void
                    422: rdxtree_insert_bm_clear(struct rdxtree_node *node, unsigned int index)
                    423: {
                    424:     for (;;) {
                    425:         rdxtree_node_bm_clear(node, index);
                    426: 
                    427:         if (!rdxtree_node_full(node) || (node->parent == NULL))
                    428:             break;
                    429: 
                    430:         index = node->index;
                    431:         node = node->parent;
                    432:     }
                    433: }
                    434: 
                    435: int
                    436: rdxtree_insert_common(struct rdxtree *tree, rdxtree_key_t key,
                    437:                       void *ptr, void ***slotp)
                    438: {
                    439:     struct rdxtree_node *node, *prev;
                    440:     unsigned int height, shift, index = index;
                    441:     int error;
                    442: 
                    443:     assert(ptr != NULL);
                    444:     assert(rdxtree_check_alignment(ptr));
                    445: 
                    446:     if (unlikely(key > rdxtree_max_key(tree->height))) {
                    447:         error = rdxtree_grow(tree, key);
                    448: 
                    449:         if (error)
                    450:             return error;
                    451:     }
                    452: 
                    453:     height = tree->height;
                    454: 
                    455:     if (unlikely(height == 0)) {
                    456:         if (tree->root != NULL)
                    457:             return ERR_BUSY;
                    458: 
                    459:         llsync_assign_ptr(tree->root, ptr);
                    460: 
                    461:         if (slotp != NULL)
                    462:             *slotp = &tree->root;
                    463: 
                    464:         return ERR_SUCCESS;
                    465:     }
                    466: 
                    467:     node = rdxtree_entry_addr(tree->root);
                    468:     shift = (height - 1) * RDXTREE_RADIX;
                    469:     prev = NULL;
                    470: 
                    471:     do {
                    472:         if (node == NULL) {
                    473:             error = rdxtree_node_create(&node, height - 1);
                    474: 
                    475:             if (error) {
                    476:                 if (prev == NULL)
                    477:                     tree->height = 0;
                    478:                 else
                    479:                     rdxtree_cleanup(tree, prev);
                    480: 
                    481:                 return error;
                    482:             }
                    483: 
                    484:             if (prev == NULL)
                    485:                 llsync_assign_ptr(tree->root, rdxtree_node_to_entry(node));
                    486:             else {
                    487:                 rdxtree_node_link(node, prev, index);
                    488:                 rdxtree_node_insert_node(prev, index, node);
                    489:             }
                    490:         }
                    491: 
                    492:         prev = node;
                    493:         index = (unsigned int)(key >> shift) & RDXTREE_RADIX_MASK;
                    494:         node = rdxtree_entry_addr(prev->entries[index]);
                    495:         shift -= RDXTREE_RADIX;
                    496:         height--;
                    497:     } while (height > 0);
                    498: 
                    499:     if (unlikely(node != NULL))
                    500:         return ERR_BUSY;
                    501: 
                    502:     rdxtree_node_insert(prev, index, ptr);
                    503:     rdxtree_insert_bm_clear(prev, index);
                    504: 
                    505:     if (slotp != NULL)
                    506:         *slotp = &prev->entries[index];
                    507: 
                    508:     return ERR_SUCCESS;
                    509: }
                    510: 
                    511: int
                    512: rdxtree_insert_alloc_common(struct rdxtree *tree, void *ptr,
                    513:                             rdxtree_key_t *keyp, void ***slotp)
                    514: {
                    515:     struct rdxtree_node *node, *prev;
                    516:     unsigned int height, shift, index = index;
                    517:     rdxtree_key_t key;
                    518:     int error;
                    519: 
                    520:     assert(ptr != NULL);
                    521:     assert(rdxtree_check_alignment(ptr));
                    522: 
                    523:     height = tree->height;
                    524: 
                    525:     if (unlikely(height == 0)) {
                    526:         if (tree->root == NULL) {
                    527:             llsync_assign_ptr(tree->root, ptr);
                    528:             *keyp = 0;
                    529: 
                    530:             if (slotp != NULL)
                    531:                 *slotp = &tree->root;
                    532: 
                    533:             return ERR_SUCCESS;
                    534:         }
                    535: 
                    536:         goto grow;
                    537:     }
                    538: 
                    539:     node = rdxtree_entry_addr(tree->root);
                    540:     key = 0;
                    541:     shift = (height - 1) * RDXTREE_RADIX;
                    542:     prev = NULL;
                    543: 
                    544:     do {
                    545:         if (node == NULL) {
                    546:             error = rdxtree_node_create(&node, height - 1);
                    547: 
                    548:             if (error) {
                    549:                 rdxtree_cleanup(tree, prev);
                    550:                 return error;
                    551:             }
                    552: 
                    553:             rdxtree_node_link(node, prev, index);
                    554:             rdxtree_node_insert_node(prev, index, node);
                    555:         }
                    556: 
                    557:         prev = node;
                    558:         index = rdxtree_node_bm_first(node);
                    559: 
                    560:         if (index == (unsigned int)-1)
                    561:             goto grow;
                    562: 
                    563:         key |= (rdxtree_key_t)index << shift;
                    564:         node = rdxtree_entry_addr(node->entries[index]);
                    565:         shift -= RDXTREE_RADIX;
                    566:         height--;
                    567:     } while (height > 0);
                    568: 
                    569:     rdxtree_node_insert(prev, index, ptr);
                    570:     rdxtree_insert_bm_clear(prev, index);
                    571: 
                    572:     if (slotp != NULL)
                    573:         *slotp = &prev->entries[index];
                    574: 
                    575:     goto out;
                    576: 
                    577: grow:
                    578:     key = rdxtree_max_key(height) + 1;
                    579:     error = rdxtree_insert_common(tree, key, ptr, slotp);
                    580: 
                    581:     if (error)
                    582:         return error;
                    583: 
                    584: out:
                    585:     *keyp = key;
                    586:     return ERR_SUCCESS;
                    587: }
                    588: 
                    589: static void
                    590: rdxtree_remove_bm_set(struct rdxtree_node *node, unsigned int index)
                    591: {
                    592:     do {
                    593:         rdxtree_node_bm_set(node, index);
                    594: 
                    595:         if (node->parent == NULL)
                    596:             break;
                    597: 
                    598:         index = node->index;
                    599:         node = node->parent;
                    600:     } while (!rdxtree_node_bm_is_set(node, index));
                    601: }
                    602: 
                    603: void *
                    604: rdxtree_remove(struct rdxtree *tree, rdxtree_key_t key)
                    605: {
                    606:     struct rdxtree_node *node, *prev;
                    607:     unsigned int height, shift, index;
                    608: 
                    609:     height = tree->height;
                    610: 
                    611:     if (unlikely(key > rdxtree_max_key(height)))
                    612:         return NULL;
                    613: 
                    614:     node = rdxtree_entry_addr(tree->root);
                    615: 
                    616:     if (unlikely(height == 0)) {
                    617:         llsync_assign_ptr(tree->root, NULL);
                    618:         return node;
                    619:     }
                    620: 
                    621:     shift = (height - 1) * RDXTREE_RADIX;
                    622: 
                    623:     do {
                    624:         if (node == NULL)
                    625:             return NULL;
                    626: 
                    627:         prev = node;
                    628:         index = (unsigned int)(key >> shift) & RDXTREE_RADIX_MASK;
                    629:         node = rdxtree_entry_addr(node->entries[index]);
                    630:         shift -= RDXTREE_RADIX;
                    631:         height--;
                    632:     } while (height > 0);
                    633: 
                    634:     if (node == NULL)
                    635:         return NULL;
                    636: 
                    637:     rdxtree_node_remove(prev, index);
                    638:     rdxtree_remove_bm_set(prev, index);
                    639:     rdxtree_cleanup(tree, prev);
                    640:     return node;
                    641: }
                    642: 
                    643: void *
                    644: rdxtree_lookup_common(const struct rdxtree *tree, rdxtree_key_t key,
                    645:                       int get_slot)
                    646: {
                    647:     struct rdxtree_node *node, *prev;
                    648:     unsigned int height, shift, index;
                    649:     void *entry;
                    650: 
                    651:     entry = llsync_read_ptr(tree->root);
                    652: 
                    653:     if (entry == NULL) {
                    654:         node = NULL;
                    655:         height = 0;
                    656:     } else {
                    657:         node = rdxtree_entry_addr(entry);
                    658:         height = rdxtree_entry_is_node(entry) ? node->height + 1 : 0;
                    659:     }
                    660: 
                    661:     if (key > rdxtree_max_key(height))
                    662:         return NULL;
                    663: 
                    664:     if (height == 0) {
                    665:         if (node == NULL)
                    666:             return NULL;
                    667: 
                    668:         return get_slot ? (void *)&tree->root : node;
                    669:     }
                    670: 
                    671:     shift = (height - 1) * RDXTREE_RADIX;
                    672: 
                    673:     do {
                    674:         if (node == NULL)
                    675:             return NULL;
                    676: 
                    677:         prev = node;
                    678:         index = (unsigned int)(key >> shift) & RDXTREE_RADIX_MASK;
                    679:         entry = llsync_read_ptr(node->entries[index]);
                    680:         node = rdxtree_entry_addr(entry);
                    681:         shift -= RDXTREE_RADIX;
                    682:         height--;
                    683:     } while (height > 0);
                    684: 
                    685:     if (node == NULL)
                    686:         return NULL;
                    687: 
                    688:     return get_slot ? (void *)&prev->entries[index] : node;
                    689: }
                    690: 
                    691: void *
                    692: rdxtree_replace_slot(void **slot, void *ptr)
                    693: {
                    694:     void *old;
                    695: 
                    696:     assert(ptr != NULL);
                    697:     assert(rdxtree_check_alignment(ptr));
                    698: 
                    699:     old = *slot;
                    700:     assert(old != NULL);
                    701:     assert(rdxtree_check_alignment(old));
                    702:     llsync_assign_ptr(*slot, ptr);
                    703:     return old;
                    704: }
                    705: 
                    706: static void *
                    707: rdxtree_walk_next(struct rdxtree *tree, struct rdxtree_iter *iter)
                    708: {
                    709:     struct rdxtree_node *root, *node, *prev;
                    710:     unsigned int height, shift, index, orig_index;
                    711:     rdxtree_key_t key;
                    712:     void *entry;
                    713: 
                    714:     entry = llsync_read_ptr(tree->root);
                    715: 
                    716:     if (entry == NULL)
                    717:         return NULL;
                    718: 
                    719:     if (!rdxtree_entry_is_node(entry)) {
                    720:         if (iter->key != (rdxtree_key_t)-1)
                    721:             return NULL;
                    722:         else {
                    723:             iter->key = 0;
                    724:             return rdxtree_entry_addr(entry);
                    725:         }
                    726:     }
                    727: 
                    728:     key = iter->key + 1;
                    729: 
                    730:     if ((key == 0) && (iter->node != NULL))
                    731:         return NULL;
                    732: 
                    733:     root = rdxtree_entry_addr(entry);
                    734: 
                    735: restart:
                    736:     node = root;
                    737:     height = root->height + 1;
                    738: 
                    739:     if (key > rdxtree_max_key(height))
                    740:         return NULL;
                    741: 
                    742:     shift = (height - 1) * RDXTREE_RADIX;
                    743: 
                    744:     do {
                    745:         prev = node;
                    746:         index = (key >> shift) & RDXTREE_RADIX_MASK;
                    747:         orig_index = index;
                    748:         node = rdxtree_node_find(node, &index);
                    749: 
                    750:         if (node == NULL) {
                    751:             shift += RDXTREE_RADIX;
                    752:             key = ((key >> shift) + 1) << shift;
                    753: 
                    754:             if (key == 0)
                    755:                 return NULL;
                    756: 
                    757:             goto restart;
                    758:         }
                    759: 
                    760:         if (orig_index != index)
                    761:             key = ((key >> shift) + (index - orig_index)) << shift;
                    762: 
                    763:         shift -= RDXTREE_RADIX;
                    764:         height--;
                    765:     } while (height > 0);
                    766: 
                    767:     iter->node = prev;
                    768:     iter->key = key;
                    769:     return node;
                    770: }
                    771: 
                    772: void *
                    773: rdxtree_walk(struct rdxtree *tree, struct rdxtree_iter *iter)
                    774: {
                    775:     unsigned int index, orig_index;
                    776:     void *ptr;
                    777: 
                    778:     if (iter->node == NULL)
                    779:         return rdxtree_walk_next(tree, iter);
                    780: 
                    781:     index = (iter->key + 1) & RDXTREE_RADIX_MASK;
                    782: 
                    783:     if (index != 0) {
                    784:         orig_index = index;
                    785:         ptr = rdxtree_node_find(iter->node, &index);
                    786: 
                    787:         if (ptr != NULL) {
                    788:             iter->key += (index - orig_index) + 1;
                    789:             return ptr;
                    790:         }
                    791:     }
                    792: 
                    793:     return rdxtree_walk_next(tree, iter);
                    794: }
                    795: 
                    796: void
                    797: rdxtree_remove_all(struct rdxtree *tree)
                    798: {
                    799:     struct rdxtree_node *node, *parent;
                    800:     struct rdxtree_iter iter;
                    801: 
                    802:     if (tree->height == 0) {
                    803:         if (tree->root != NULL)
                    804:             llsync_assign_ptr(tree->root, NULL);
                    805: 
                    806:         return;
                    807:     }
                    808: 
                    809:     for (;;) {
                    810:         rdxtree_iter_init(&iter);
                    811:         rdxtree_walk_next(tree, &iter);
                    812: 
                    813:         if (iter.node == NULL)
                    814:             break;
                    815: 
                    816:         node = iter.node;
                    817:         parent = node->parent;
                    818: 
                    819:         if (parent == NULL)
                    820:             rdxtree_init(tree);
                    821:         else {
                    822:             rdxtree_node_remove(parent, node->index);
                    823:             rdxtree_remove_bm_set(parent, node->index);
                    824:             rdxtree_cleanup(tree, parent);
                    825:             node->parent = NULL;
                    826:         }
                    827: 
                    828:         rdxtree_node_schedule_destruction(node);
                    829:     }
                    830: }

unix.superglobalmegacorp.com

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