9c3a10fdf6
Some platforms (like those using Newlib) don't have ffs/ffsl. This commit adds a check to configure.ac for __builtin_ffsl if ffsl isn't found. __builtin_ffsl performs the same function as ffsl, and has the added benefit of being available on any platform utilizing Gcc-compatible compiler. This change does not address the used of ffs in the MALLOCX_ARENA() macro.
106 lines
2.3 KiB
C
106 lines
2.3 KiB
C
#define JEMALLOC_RTREE_C_
|
|
#include "jemalloc/internal/jemalloc_internal.h"
|
|
|
|
rtree_t *
|
|
rtree_new(unsigned bits, rtree_alloc_t *alloc, rtree_dalloc_t *dalloc)
|
|
{
|
|
rtree_t *ret;
|
|
unsigned bits_per_level, bits_in_leaf, height, i;
|
|
|
|
assert(bits > 0 && bits <= (sizeof(uintptr_t) << 3));
|
|
|
|
bits_per_level = jemalloc_ffs(pow2_ceil((RTREE_NODESIZE / sizeof(void *)))) - 1;
|
|
bits_in_leaf = jemalloc_ffs(pow2_ceil((RTREE_NODESIZE / sizeof(uint8_t)))) - 1;
|
|
if (bits > bits_in_leaf) {
|
|
height = 1 + (bits - bits_in_leaf) / bits_per_level;
|
|
if ((height-1) * bits_per_level + bits_in_leaf != bits)
|
|
height++;
|
|
} else {
|
|
height = 1;
|
|
}
|
|
assert((height-1) * bits_per_level + bits_in_leaf >= bits);
|
|
|
|
ret = (rtree_t*)alloc(offsetof(rtree_t, level2bits) +
|
|
(sizeof(unsigned) * height));
|
|
if (ret == NULL)
|
|
return (NULL);
|
|
memset(ret, 0, offsetof(rtree_t, level2bits) + (sizeof(unsigned) *
|
|
height));
|
|
|
|
ret->alloc = alloc;
|
|
ret->dalloc = dalloc;
|
|
if (malloc_mutex_init(&ret->mutex)) {
|
|
if (dalloc != NULL)
|
|
dalloc(ret);
|
|
return (NULL);
|
|
}
|
|
ret->height = height;
|
|
if (height > 1) {
|
|
if ((height-1) * bits_per_level + bits_in_leaf > bits) {
|
|
ret->level2bits[0] = (bits - bits_in_leaf) %
|
|
bits_per_level;
|
|
} else
|
|
ret->level2bits[0] = bits_per_level;
|
|
for (i = 1; i < height-1; i++)
|
|
ret->level2bits[i] = bits_per_level;
|
|
ret->level2bits[height-1] = bits_in_leaf;
|
|
} else
|
|
ret->level2bits[0] = bits;
|
|
|
|
ret->root = (void**)alloc(sizeof(void *) << ret->level2bits[0]);
|
|
if (ret->root == NULL) {
|
|
if (dalloc != NULL)
|
|
dalloc(ret);
|
|
return (NULL);
|
|
}
|
|
memset(ret->root, 0, sizeof(void *) << ret->level2bits[0]);
|
|
|
|
return (ret);
|
|
}
|
|
|
|
static void
|
|
rtree_delete_subtree(rtree_t *rtree, void **node, unsigned level)
|
|
{
|
|
|
|
if (level < rtree->height - 1) {
|
|
size_t nchildren, i;
|
|
|
|
nchildren = ZU(1) << rtree->level2bits[level];
|
|
for (i = 0; i < nchildren; i++) {
|
|
void **child = (void **)node[i];
|
|
if (child != NULL)
|
|
rtree_delete_subtree(rtree, child, level + 1);
|
|
}
|
|
}
|
|
rtree->dalloc(node);
|
|
}
|
|
|
|
void
|
|
rtree_delete(rtree_t *rtree)
|
|
{
|
|
|
|
rtree_delete_subtree(rtree, rtree->root, 0);
|
|
rtree->dalloc(rtree);
|
|
}
|
|
|
|
void
|
|
rtree_prefork(rtree_t *rtree)
|
|
{
|
|
|
|
malloc_mutex_prefork(&rtree->mutex);
|
|
}
|
|
|
|
void
|
|
rtree_postfork_parent(rtree_t *rtree)
|
|
{
|
|
|
|
malloc_mutex_postfork_parent(&rtree->mutex);
|
|
}
|
|
|
|
void
|
|
rtree_postfork_child(rtree_t *rtree)
|
|
{
|
|
|
|
malloc_mutex_postfork_child(&rtree->mutex);
|
|
}
|