1a4bd5210SJason Evans #define JEMALLOC_RTREE_C_ 2a4bd5210SJason Evans #include "jemalloc/internal/jemalloc_internal.h" 3a4bd5210SJason Evans 4*d0e79aa3SJason Evans static unsigned 5*d0e79aa3SJason Evans hmin(unsigned ha, unsigned hb) 6a4bd5210SJason Evans { 7*d0e79aa3SJason Evans 8*d0e79aa3SJason Evans return (ha < hb ? ha : hb); 9*d0e79aa3SJason Evans } 10*d0e79aa3SJason Evans 11*d0e79aa3SJason Evans /* Only the most significant bits of keys passed to rtree_[gs]et() are used. */ 12*d0e79aa3SJason Evans bool 13*d0e79aa3SJason Evans rtree_new(rtree_t *rtree, unsigned bits, rtree_node_alloc_t *alloc, 14*d0e79aa3SJason Evans rtree_node_dalloc_t *dalloc) 15*d0e79aa3SJason Evans { 16*d0e79aa3SJason Evans unsigned bits_in_leaf, height, i; 17f921d10fSJason Evans 18f921d10fSJason Evans assert(bits > 0 && bits <= (sizeof(uintptr_t) << 3)); 19a4bd5210SJason Evans 20*d0e79aa3SJason Evans bits_in_leaf = (bits % RTREE_BITS_PER_LEVEL) == 0 ? RTREE_BITS_PER_LEVEL 21*d0e79aa3SJason Evans : (bits % RTREE_BITS_PER_LEVEL); 22f921d10fSJason Evans if (bits > bits_in_leaf) { 23*d0e79aa3SJason Evans height = 1 + (bits - bits_in_leaf) / RTREE_BITS_PER_LEVEL; 24*d0e79aa3SJason Evans if ((height-1) * RTREE_BITS_PER_LEVEL + bits_in_leaf != bits) 25a4bd5210SJason Evans height++; 26*d0e79aa3SJason Evans } else 27f921d10fSJason Evans height = 1; 28*d0e79aa3SJason Evans assert((height-1) * RTREE_BITS_PER_LEVEL + bits_in_leaf == bits); 29a4bd5210SJason Evans 30*d0e79aa3SJason Evans rtree->alloc = alloc; 31*d0e79aa3SJason Evans rtree->dalloc = dalloc; 32*d0e79aa3SJason Evans rtree->height = height; 33a4bd5210SJason Evans 34*d0e79aa3SJason Evans /* Root level. */ 35*d0e79aa3SJason Evans rtree->levels[0].subtree = NULL; 36*d0e79aa3SJason Evans rtree->levels[0].bits = (height > 1) ? RTREE_BITS_PER_LEVEL : 37*d0e79aa3SJason Evans bits_in_leaf; 38*d0e79aa3SJason Evans rtree->levels[0].cumbits = rtree->levels[0].bits; 39*d0e79aa3SJason Evans /* Interior levels. */ 40*d0e79aa3SJason Evans for (i = 1; i < height-1; i++) { 41*d0e79aa3SJason Evans rtree->levels[i].subtree = NULL; 42*d0e79aa3SJason Evans rtree->levels[i].bits = RTREE_BITS_PER_LEVEL; 43*d0e79aa3SJason Evans rtree->levels[i].cumbits = rtree->levels[i-1].cumbits + 44*d0e79aa3SJason Evans RTREE_BITS_PER_LEVEL; 45a4bd5210SJason Evans } 46*d0e79aa3SJason Evans /* Leaf level. */ 47f921d10fSJason Evans if (height > 1) { 48*d0e79aa3SJason Evans rtree->levels[height-1].subtree = NULL; 49*d0e79aa3SJason Evans rtree->levels[height-1].bits = bits_in_leaf; 50*d0e79aa3SJason Evans rtree->levels[height-1].cumbits = bits; 51a4bd5210SJason Evans } 52a4bd5210SJason Evans 53*d0e79aa3SJason Evans /* Compute lookup table to be used by rtree_start_level(). */ 54*d0e79aa3SJason Evans for (i = 0; i < RTREE_HEIGHT_MAX; i++) { 55*d0e79aa3SJason Evans rtree->start_level[i] = hmin(RTREE_HEIGHT_MAX - 1 - i, height - 56*d0e79aa3SJason Evans 1); 57*d0e79aa3SJason Evans } 58*d0e79aa3SJason Evans 59*d0e79aa3SJason Evans return (false); 60a4bd5210SJason Evans } 6182872ac0SJason Evans 62f921d10fSJason Evans static void 63*d0e79aa3SJason Evans rtree_delete_subtree(rtree_t *rtree, rtree_node_elm_t *node, unsigned level) 64f921d10fSJason Evans { 65f921d10fSJason Evans 66*d0e79aa3SJason Evans if (level + 1 < rtree->height) { 67f921d10fSJason Evans size_t nchildren, i; 68f921d10fSJason Evans 69*d0e79aa3SJason Evans nchildren = ZU(1) << rtree->levels[level].bits; 70f921d10fSJason Evans for (i = 0; i < nchildren; i++) { 71*d0e79aa3SJason Evans rtree_node_elm_t *child = node[i].child; 72f921d10fSJason Evans if (child != NULL) 73f921d10fSJason Evans rtree_delete_subtree(rtree, child, level + 1); 74f921d10fSJason Evans } 75f921d10fSJason Evans } 76f921d10fSJason Evans rtree->dalloc(node); 77f921d10fSJason Evans } 78f921d10fSJason Evans 79f921d10fSJason Evans void 80f921d10fSJason Evans rtree_delete(rtree_t *rtree) 81f921d10fSJason Evans { 82*d0e79aa3SJason Evans unsigned i; 83f921d10fSJason Evans 84*d0e79aa3SJason Evans for (i = 0; i < rtree->height; i++) { 85*d0e79aa3SJason Evans rtree_node_elm_t *subtree = rtree->levels[i].subtree; 86*d0e79aa3SJason Evans if (subtree != NULL) 87*d0e79aa3SJason Evans rtree_delete_subtree(rtree, subtree, i); 88*d0e79aa3SJason Evans } 89f921d10fSJason Evans } 90f921d10fSJason Evans 91*d0e79aa3SJason Evans static rtree_node_elm_t * 92*d0e79aa3SJason Evans rtree_node_init(rtree_t *rtree, unsigned level, rtree_node_elm_t **elmp) 9382872ac0SJason Evans { 94*d0e79aa3SJason Evans rtree_node_elm_t *node; 9582872ac0SJason Evans 96*d0e79aa3SJason Evans if (atomic_cas_p((void **)elmp, NULL, RTREE_NODE_INITIALIZING)) { 97*d0e79aa3SJason Evans /* 98*d0e79aa3SJason Evans * Another thread is already in the process of initializing. 99*d0e79aa3SJason Evans * Spin-wait until initialization is complete. 100*d0e79aa3SJason Evans */ 101*d0e79aa3SJason Evans do { 102*d0e79aa3SJason Evans CPU_SPINWAIT; 103*d0e79aa3SJason Evans node = atomic_read_p((void **)elmp); 104*d0e79aa3SJason Evans } while (node == RTREE_NODE_INITIALIZING); 105*d0e79aa3SJason Evans } else { 106*d0e79aa3SJason Evans node = rtree->alloc(ZU(1) << rtree->levels[level].bits); 107*d0e79aa3SJason Evans if (node == NULL) 108*d0e79aa3SJason Evans return (NULL); 109*d0e79aa3SJason Evans atomic_write_p((void **)elmp, node); 11082872ac0SJason Evans } 11182872ac0SJason Evans 112*d0e79aa3SJason Evans return (node); 11382872ac0SJason Evans } 11482872ac0SJason Evans 115*d0e79aa3SJason Evans rtree_node_elm_t * 116*d0e79aa3SJason Evans rtree_subtree_read_hard(rtree_t *rtree, unsigned level) 11782872ac0SJason Evans { 11882872ac0SJason Evans 119*d0e79aa3SJason Evans return (rtree_node_init(rtree, level, &rtree->levels[level].subtree)); 120*d0e79aa3SJason Evans } 121*d0e79aa3SJason Evans 122*d0e79aa3SJason Evans rtree_node_elm_t * 123*d0e79aa3SJason Evans rtree_child_read_hard(rtree_t *rtree, rtree_node_elm_t *elm, unsigned level) 124*d0e79aa3SJason Evans { 125*d0e79aa3SJason Evans 126*d0e79aa3SJason Evans return (rtree_node_init(rtree, level, &elm->child)); 12782872ac0SJason Evans } 128