diff options
Diffstat (limited to 'deps/jemalloc/src/base.c')
| -rw-r--r-- | deps/jemalloc/src/base.c | 187 |
1 files changed, 187 insertions, 0 deletions
diff --git a/deps/jemalloc/src/base.c b/deps/jemalloc/src/base.c new file mode 100644 index 0000000..5681a3f --- /dev/null +++ b/deps/jemalloc/src/base.c @@ -0,0 +1,187 @@ +#define JEMALLOC_BASE_C_ +#include "jemalloc/internal/jemalloc_internal.h" + +/******************************************************************************/ +/* Data. */ + +static malloc_mutex_t base_mtx; +static size_t base_extent_sn_next; +static extent_tree_t base_avail_szsnad; +static extent_node_t *base_nodes; +static size_t base_allocated; +static size_t base_resident; +static size_t base_mapped; + +/******************************************************************************/ + +static extent_node_t * +base_node_try_alloc(tsdn_t *tsdn) +{ + extent_node_t *node; + + malloc_mutex_assert_owner(tsdn, &base_mtx); + + if (base_nodes == NULL) + return (NULL); + node = base_nodes; + base_nodes = *(extent_node_t **)node; + JEMALLOC_VALGRIND_MAKE_MEM_UNDEFINED(node, sizeof(extent_node_t)); + return (node); +} + +static void +base_node_dalloc(tsdn_t *tsdn, extent_node_t *node) +{ + + malloc_mutex_assert_owner(tsdn, &base_mtx); + + JEMALLOC_VALGRIND_MAKE_MEM_UNDEFINED(node, sizeof(extent_node_t)); + *(extent_node_t **)node = base_nodes; + base_nodes = node; +} + +static void +base_extent_node_init(extent_node_t *node, void *addr, size_t size) +{ + size_t sn = atomic_add_z(&base_extent_sn_next, 1) - 1; + + extent_node_init(node, NULL, addr, size, sn, true, true); +} + +static extent_node_t * +base_chunk_alloc(tsdn_t *tsdn, size_t minsize) +{ + extent_node_t *node; + size_t csize, nsize; + void *addr; + + malloc_mutex_assert_owner(tsdn, &base_mtx); + assert(minsize != 0); + node = base_node_try_alloc(tsdn); + /* Allocate enough space to also carve a node out if necessary. */ + nsize = (node == NULL) ? CACHELINE_CEILING(sizeof(extent_node_t)) : 0; + csize = CHUNK_CEILING(minsize + nsize); + addr = chunk_alloc_base(csize); + if (addr == NULL) { + if (node != NULL) + base_node_dalloc(tsdn, node); + return (NULL); + } + base_mapped += csize; + if (node == NULL) { + node = (extent_node_t *)addr; + addr = (void *)((uintptr_t)addr + nsize); + csize -= nsize; + if (config_stats) { + base_allocated += nsize; + base_resident += PAGE_CEILING(nsize); + } + } + base_extent_node_init(node, addr, csize); + return (node); +} + +/* + * base_alloc() guarantees demand-zeroed memory, in order to make multi-page + * sparse data structures such as radix tree nodes efficient with respect to + * physical memory usage. + */ +void * +base_alloc(tsdn_t *tsdn, size_t size) +{ + void *ret; + size_t csize, usize; + extent_node_t *node; + extent_node_t key; + + /* + * Round size up to nearest multiple of the cacheline size, so that + * there is no chance of false cache line sharing. + */ + csize = CACHELINE_CEILING(size); + + usize = s2u(csize); + extent_node_init(&key, NULL, NULL, usize, 0, false, false); + malloc_mutex_lock(tsdn, &base_mtx); + node = extent_tree_szsnad_nsearch(&base_avail_szsnad, &key); + if (node != NULL) { + /* Use existing space. */ + extent_tree_szsnad_remove(&base_avail_szsnad, node); + } else { + /* Try to allocate more space. */ + node = base_chunk_alloc(tsdn, csize); + } + if (node == NULL) { + ret = NULL; + goto label_return; + } + + ret = extent_node_addr_get(node); + if (extent_node_size_get(node) > csize) { + extent_node_addr_set(node, (void *)((uintptr_t)ret + csize)); + extent_node_size_set(node, extent_node_size_get(node) - csize); + extent_tree_szsnad_insert(&base_avail_szsnad, node); + } else + base_node_dalloc(tsdn, node); + if (config_stats) { + base_allocated += csize; + /* + * Add one PAGE to base_resident for every page boundary that is + * crossed by the new allocation. + */ + base_resident += PAGE_CEILING((uintptr_t)ret + csize) - + PAGE_CEILING((uintptr_t)ret); + } + JEMALLOC_VALGRIND_MAKE_MEM_DEFINED(ret, csize); +label_return: + malloc_mutex_unlock(tsdn, &base_mtx); + return (ret); +} + +void +base_stats_get(tsdn_t *tsdn, size_t *allocated, size_t *resident, + size_t *mapped) +{ + + malloc_mutex_lock(tsdn, &base_mtx); + assert(base_allocated <= base_resident); + assert(base_resident <= base_mapped); + *allocated = base_allocated; + *resident = base_resident; + *mapped = base_mapped; + malloc_mutex_unlock(tsdn, &base_mtx); +} + +bool +base_boot(void) +{ + + if (malloc_mutex_init(&base_mtx, "base", WITNESS_RANK_BASE)) + return (true); + base_extent_sn_next = 0; + extent_tree_szsnad_new(&base_avail_szsnad); + base_nodes = NULL; + + return (false); +} + +void +base_prefork(tsdn_t *tsdn) +{ + + malloc_mutex_prefork(tsdn, &base_mtx); +} + +void +base_postfork_parent(tsdn_t *tsdn) +{ + + malloc_mutex_postfork_parent(tsdn, &base_mtx); +} + +void +base_postfork_child(tsdn_t *tsdn) +{ + + malloc_mutex_postfork_child(tsdn, &base_mtx); +} |
