summaryrefslogtreecommitdiffstats
path: root/fluent-bit/lib/jemalloc-5.3.0/src
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-07-24 09:54:23 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-07-24 09:54:44 +0000
commit836b47cb7e99a977c5a23b059ca1d0b5065d310e (patch)
tree1604da8f482d02effa033c94a84be42bc0c848c3 /fluent-bit/lib/jemalloc-5.3.0/src
parentReleasing debian version 1.44.3-2. (diff)
downloadnetdata-836b47cb7e99a977c5a23b059ca1d0b5065d310e.tar.xz
netdata-836b47cb7e99a977c5a23b059ca1d0b5065d310e.zip
Merging upstream version 1.46.3.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'fluent-bit/lib/jemalloc-5.3.0/src')
-rw-r--r--fluent-bit/lib/jemalloc-5.3.0/src/arena.c1891
-rw-r--r--fluent-bit/lib/jemalloc-5.3.0/src/background_thread.c820
-rw-r--r--fluent-bit/lib/jemalloc-5.3.0/src/base.c529
-rw-r--r--fluent-bit/lib/jemalloc-5.3.0/src/bin.c69
-rw-r--r--fluent-bit/lib/jemalloc-5.3.0/src/bin_info.c30
-rw-r--r--fluent-bit/lib/jemalloc-5.3.0/src/bitmap.c120
-rw-r--r--fluent-bit/lib/jemalloc-5.3.0/src/buf_writer.c144
-rw-r--r--fluent-bit/lib/jemalloc-5.3.0/src/cache_bin.c99
-rw-r--r--fluent-bit/lib/jemalloc-5.3.0/src/ckh.c569
-rw-r--r--fluent-bit/lib/jemalloc-5.3.0/src/counter.c30
-rw-r--r--fluent-bit/lib/jemalloc-5.3.0/src/ctl.c4414
-rw-r--r--fluent-bit/lib/jemalloc-5.3.0/src/decay.c295
-rw-r--r--fluent-bit/lib/jemalloc-5.3.0/src/div.c55
-rw-r--r--fluent-bit/lib/jemalloc-5.3.0/src/ecache.c35
-rw-r--r--fluent-bit/lib/jemalloc-5.3.0/src/edata.c6
-rw-r--r--fluent-bit/lib/jemalloc-5.3.0/src/edata_cache.c154
-rw-r--r--fluent-bit/lib/jemalloc-5.3.0/src/ehooks.c275
-rw-r--r--fluent-bit/lib/jemalloc-5.3.0/src/emap.c386
-rw-r--r--fluent-bit/lib/jemalloc-5.3.0/src/eset.c282
-rw-r--r--fluent-bit/lib/jemalloc-5.3.0/src/exp_grow.c8
-rw-r--r--fluent-bit/lib/jemalloc-5.3.0/src/extent.c1326
-rw-r--r--fluent-bit/lib/jemalloc-5.3.0/src/extent_dss.c277
-rw-r--r--fluent-bit/lib/jemalloc-5.3.0/src/extent_mmap.c41
-rw-r--r--fluent-bit/lib/jemalloc-5.3.0/src/fxp.c124
-rw-r--r--fluent-bit/lib/jemalloc-5.3.0/src/hook.c195
-rw-r--r--fluent-bit/lib/jemalloc-5.3.0/src/hpa.c1044
-rw-r--r--fluent-bit/lib/jemalloc-5.3.0/src/hpa_hooks.c63
-rw-r--r--fluent-bit/lib/jemalloc-5.3.0/src/hpdata.c325
-rw-r--r--fluent-bit/lib/jemalloc-5.3.0/src/inspect.c77
-rw-r--r--fluent-bit/lib/jemalloc-5.3.0/src/jemalloc.c4476
-rw-r--r--fluent-bit/lib/jemalloc-5.3.0/src/jemalloc_cpp.cpp254
-rw-r--r--fluent-bit/lib/jemalloc-5.3.0/src/large.c322
-rw-r--r--fluent-bit/lib/jemalloc-5.3.0/src/log.c78
-rw-r--r--fluent-bit/lib/jemalloc-5.3.0/src/malloc_io.c697
-rw-r--r--fluent-bit/lib/jemalloc-5.3.0/src/mutex.c228
-rw-r--r--fluent-bit/lib/jemalloc-5.3.0/src/nstime.c289
-rw-r--r--fluent-bit/lib/jemalloc-5.3.0/src/pa.c277
-rw-r--r--fluent-bit/lib/jemalloc-5.3.0/src/pa_extra.c191
-rw-r--r--fluent-bit/lib/jemalloc-5.3.0/src/pac.c587
-rw-r--r--fluent-bit/lib/jemalloc-5.3.0/src/pages.c824
-rw-r--r--fluent-bit/lib/jemalloc-5.3.0/src/pai.c31
-rw-r--r--fluent-bit/lib/jemalloc-5.3.0/src/peak_event.c82
-rw-r--r--fluent-bit/lib/jemalloc-5.3.0/src/prof.c789
-rw-r--r--fluent-bit/lib/jemalloc-5.3.0/src/prof_data.c1447
-rw-r--r--fluent-bit/lib/jemalloc-5.3.0/src/prof_log.c717
-rw-r--r--fluent-bit/lib/jemalloc-5.3.0/src/prof_recent.c600
-rw-r--r--fluent-bit/lib/jemalloc-5.3.0/src/prof_stats.c57
-rw-r--r--fluent-bit/lib/jemalloc-5.3.0/src/prof_sys.c669
-rw-r--r--fluent-bit/lib/jemalloc-5.3.0/src/psset.c385
-rw-r--r--fluent-bit/lib/jemalloc-5.3.0/src/rtree.c261
-rw-r--r--fluent-bit/lib/jemalloc-5.3.0/src/safety_check.c36
-rw-r--r--fluent-bit/lib/jemalloc-5.3.0/src/san.c208
-rw-r--r--fluent-bit/lib/jemalloc-5.3.0/src/san_bump.c104
-rw-r--r--fluent-bit/lib/jemalloc-5.3.0/src/sc.c306
-rw-r--r--fluent-bit/lib/jemalloc-5.3.0/src/sec.c422
-rw-r--r--fluent-bit/lib/jemalloc-5.3.0/src/stats.c1973
-rw-r--r--fluent-bit/lib/jemalloc-5.3.0/src/sz.c114
-rw-r--r--fluent-bit/lib/jemalloc-5.3.0/src/tcache.c1101
-rw-r--r--fluent-bit/lib/jemalloc-5.3.0/src/test_hooks.c12
-rw-r--r--fluent-bit/lib/jemalloc-5.3.0/src/thread_event.c343
-rw-r--r--fluent-bit/lib/jemalloc-5.3.0/src/ticker.c32
-rwxr-xr-xfluent-bit/lib/jemalloc-5.3.0/src/ticker.py15
-rw-r--r--fluent-bit/lib/jemalloc-5.3.0/src/tsd.c549
-rw-r--r--fluent-bit/lib/jemalloc-5.3.0/src/witness.c122
-rw-r--r--fluent-bit/lib/jemalloc-5.3.0/src/zone.c469
65 files changed, 0 insertions, 32750 deletions
diff --git a/fluent-bit/lib/jemalloc-5.3.0/src/arena.c b/fluent-bit/lib/jemalloc-5.3.0/src/arena.c
deleted file mode 100644
index 857b27c5..00000000
--- a/fluent-bit/lib/jemalloc-5.3.0/src/arena.c
+++ /dev/null
@@ -1,1891 +0,0 @@
-#include "jemalloc/internal/jemalloc_preamble.h"
-#include "jemalloc/internal/jemalloc_internal_includes.h"
-
-#include "jemalloc/internal/assert.h"
-#include "jemalloc/internal/decay.h"
-#include "jemalloc/internal/ehooks.h"
-#include "jemalloc/internal/extent_dss.h"
-#include "jemalloc/internal/extent_mmap.h"
-#include "jemalloc/internal/san.h"
-#include "jemalloc/internal/mutex.h"
-#include "jemalloc/internal/rtree.h"
-#include "jemalloc/internal/safety_check.h"
-#include "jemalloc/internal/util.h"
-
-JEMALLOC_DIAGNOSTIC_DISABLE_SPURIOUS
-
-/******************************************************************************/
-/* Data. */
-
-/*
- * Define names for both unininitialized and initialized phases, so that
- * options and mallctl processing are straightforward.
- */
-const char *percpu_arena_mode_names[] = {
- "percpu",
- "phycpu",
- "disabled",
- "percpu",
- "phycpu"
-};
-percpu_arena_mode_t opt_percpu_arena = PERCPU_ARENA_DEFAULT;
-
-ssize_t opt_dirty_decay_ms = DIRTY_DECAY_MS_DEFAULT;
-ssize_t opt_muzzy_decay_ms = MUZZY_DECAY_MS_DEFAULT;
-
-static atomic_zd_t dirty_decay_ms_default;
-static atomic_zd_t muzzy_decay_ms_default;
-
-emap_t arena_emap_global;
-pa_central_t arena_pa_central_global;
-
-div_info_t arena_binind_div_info[SC_NBINS];
-
-size_t opt_oversize_threshold = OVERSIZE_THRESHOLD_DEFAULT;
-size_t oversize_threshold = OVERSIZE_THRESHOLD_DEFAULT;
-
-uint32_t arena_bin_offsets[SC_NBINS];
-static unsigned nbins_total;
-
-static unsigned huge_arena_ind;
-
-const arena_config_t arena_config_default = {
- /* .extent_hooks = */ (extent_hooks_t *)&ehooks_default_extent_hooks,
- /* .metadata_use_hooks = */ true,
-};
-
-/******************************************************************************/
-/*
- * Function prototypes for static functions that are referenced prior to
- * definition.
- */
-
-static bool arena_decay_dirty(tsdn_t *tsdn, arena_t *arena,
- bool is_background_thread, bool all);
-static void arena_bin_lower_slab(tsdn_t *tsdn, arena_t *arena, edata_t *slab,
- bin_t *bin);
-static void
-arena_maybe_do_deferred_work(tsdn_t *tsdn, arena_t *arena, decay_t *decay,
- size_t npages_new);
-
-/******************************************************************************/
-
-void
-arena_basic_stats_merge(tsdn_t *tsdn, arena_t *arena, unsigned *nthreads,
- const char **dss, ssize_t *dirty_decay_ms, ssize_t *muzzy_decay_ms,
- size_t *nactive, size_t *ndirty, size_t *nmuzzy) {
- *nthreads += arena_nthreads_get(arena, false);
- *dss = dss_prec_names[arena_dss_prec_get(arena)];
- *dirty_decay_ms = arena_decay_ms_get(arena, extent_state_dirty);
- *muzzy_decay_ms = arena_decay_ms_get(arena, extent_state_muzzy);
- pa_shard_basic_stats_merge(&arena->pa_shard, nactive, ndirty, nmuzzy);
-}
-
-void
-arena_stats_merge(tsdn_t *tsdn, arena_t *arena, unsigned *nthreads,
- const char **dss, ssize_t *dirty_decay_ms, ssize_t *muzzy_decay_ms,
- size_t *nactive, size_t *ndirty, size_t *nmuzzy, arena_stats_t *astats,
- bin_stats_data_t *bstats, arena_stats_large_t *lstats,
- pac_estats_t *estats, hpa_shard_stats_t *hpastats, sec_stats_t *secstats) {
- cassert(config_stats);
-
- arena_basic_stats_merge(tsdn, arena, nthreads, dss, dirty_decay_ms,
- muzzy_decay_ms, nactive, ndirty, nmuzzy);
-
- size_t base_allocated, base_resident, base_mapped, metadata_thp;
- base_stats_get(tsdn, arena->base, &base_allocated, &base_resident,
- &base_mapped, &metadata_thp);
- size_t pac_mapped_sz = pac_mapped(&arena->pa_shard.pac);
- astats->mapped += base_mapped + pac_mapped_sz;
- astats->resident += base_resident;
-
- LOCKEDINT_MTX_LOCK(tsdn, arena->stats.mtx);
-
- astats->base += base_allocated;
- atomic_load_add_store_zu(&astats->internal, arena_internal_get(arena));
- astats->metadata_thp += metadata_thp;
-
- for (szind_t i = 0; i < SC_NSIZES - SC_NBINS; i++) {
- uint64_t nmalloc = locked_read_u64(tsdn,
- LOCKEDINT_MTX(arena->stats.mtx),
- &arena->stats.lstats[i].nmalloc);
- locked_inc_u64_unsynchronized(&lstats[i].nmalloc, nmalloc);
- astats->nmalloc_large += nmalloc;
-
- uint64_t ndalloc = locked_read_u64(tsdn,
- LOCKEDINT_MTX(arena->stats.mtx),
- &arena->stats.lstats[i].ndalloc);
- locked_inc_u64_unsynchronized(&lstats[i].ndalloc, ndalloc);
- astats->ndalloc_large += ndalloc;
-
- uint64_t nrequests = locked_read_u64(tsdn,
- LOCKEDINT_MTX(arena->stats.mtx),
- &arena->stats.lstats[i].nrequests);
- locked_inc_u64_unsynchronized(&lstats[i].nrequests,
- nmalloc + nrequests);
- astats->nrequests_large += nmalloc + nrequests;
-
- /* nfill == nmalloc for large currently. */
- locked_inc_u64_unsynchronized(&lstats[i].nfills, nmalloc);
- astats->nfills_large += nmalloc;
-
- uint64_t nflush = locked_read_u64(tsdn,
- LOCKEDINT_MTX(arena->stats.mtx),
- &arena->stats.lstats[i].nflushes);
- locked_inc_u64_unsynchronized(&lstats[i].nflushes, nflush);
- astats->nflushes_large += nflush;
-
- assert(nmalloc >= ndalloc);
- assert(nmalloc - ndalloc <= SIZE_T_MAX);
- size_t curlextents = (size_t)(nmalloc - ndalloc);
- lstats[i].curlextents += curlextents;
- astats->allocated_large +=
- curlextents * sz_index2size(SC_NBINS + i);
- }
-
- pa_shard_stats_merge(tsdn, &arena->pa_shard, &astats->pa_shard_stats,
- estats, hpastats, secstats, &astats->resident);
-
- LOCKEDINT_MTX_UNLOCK(tsdn, arena->stats.mtx);
-
- /* Currently cached bytes and sanitizer-stashed bytes in tcache. */
- astats->tcache_bytes = 0;
- astats->tcache_stashed_bytes = 0;
- malloc_mutex_lock(tsdn, &arena->tcache_ql_mtx);
- cache_bin_array_descriptor_t *descriptor;
- ql_foreach(descriptor, &arena->cache_bin_array_descriptor_ql, link) {
- for (szind_t i = 0; i < nhbins; i++) {
- cache_bin_t *cache_bin = &descriptor->bins[i];
- cache_bin_sz_t ncached, nstashed;
- cache_bin_nitems_get_remote(cache_bin,
- &tcache_bin_info[i], &ncached, &nstashed);
-
- astats->tcache_bytes += ncached * sz_index2size(i);
- astats->tcache_stashed_bytes += nstashed *
- sz_index2size(i);
- }
- }
- malloc_mutex_prof_read(tsdn,
- &astats->mutex_prof_data[arena_prof_mutex_tcache_list],
- &arena->tcache_ql_mtx);
- malloc_mutex_unlock(tsdn, &arena->tcache_ql_mtx);
-
-#define READ_ARENA_MUTEX_PROF_DATA(mtx, ind) \
- malloc_mutex_lock(tsdn, &arena->mtx); \
- malloc_mutex_prof_read(tsdn, &astats->mutex_prof_data[ind], \
- &arena->mtx); \
- malloc_mutex_unlock(tsdn, &arena->mtx);
-
- /* Gather per arena mutex profiling data. */
- READ_ARENA_MUTEX_PROF_DATA(large_mtx, arena_prof_mutex_large);
- READ_ARENA_MUTEX_PROF_DATA(base->mtx,
- arena_prof_mutex_base);
-#undef READ_ARENA_MUTEX_PROF_DATA
- pa_shard_mtx_stats_read(tsdn, &arena->pa_shard,
- astats->mutex_prof_data);
-
- nstime_copy(&astats->uptime, &arena->create_time);
- nstime_update(&astats->uptime);
- nstime_subtract(&astats->uptime, &arena->create_time);
-
- for (szind_t i = 0; i < SC_NBINS; i++) {
- for (unsigned j = 0; j < bin_infos[i].n_shards; j++) {
- bin_stats_merge(tsdn, &bstats[i],
- arena_get_bin(arena, i, j));
- }
- }
-}
-
-static void
-arena_background_thread_inactivity_check(tsdn_t *tsdn, arena_t *arena,
- bool is_background_thread) {
- if (!background_thread_enabled() || is_background_thread) {
- return;
- }
- background_thread_info_t *info =
- arena_background_thread_info_get(arena);
- if (background_thread_indefinite_sleep(info)) {
- arena_maybe_do_deferred_work(tsdn, arena,
- &arena->pa_shard.pac.decay_dirty, 0);
- }
-}
-
-/*
- * React to deferred work generated by a PAI function.
- */
-void arena_handle_deferred_work(tsdn_t *tsdn, arena_t *arena) {
- witness_assert_depth_to_rank(tsdn_witness_tsdp_get(tsdn),
- WITNESS_RANK_CORE, 0);
-
- if (decay_immediately(&arena->pa_shard.pac.decay_dirty)) {
- arena_decay_dirty(tsdn, arena, false, true);
- }
- arena_background_thread_inactivity_check(tsdn, arena, false);
-}
-
-static void *
-arena_slab_reg_alloc(edata_t *slab, const bin_info_t *bin_info) {
- void *ret;
- slab_data_t *slab_data = edata_slab_data_get(slab);
- size_t regind;
-
- assert(edata_nfree_get(slab) > 0);
- assert(!bitmap_full(slab_data->bitmap, &bin_info->bitmap_info));
-
- regind = bitmap_sfu(slab_data->bitmap, &bin_info->bitmap_info);
- ret = (void *)((uintptr_t)edata_addr_get(slab) +
- (uintptr_t)(bin_info->reg_size * regind));
- edata_nfree_dec(slab);
- return ret;
-}
-
-static void
-arena_slab_reg_alloc_batch(edata_t *slab, const bin_info_t *bin_info,
- unsigned cnt, void** ptrs) {
- slab_data_t *slab_data = edata_slab_data_get(slab);
-
- assert(edata_nfree_get(slab) >= cnt);
- assert(!bitmap_full(slab_data->bitmap, &bin_info->bitmap_info));
-
-#if (! defined JEMALLOC_INTERNAL_POPCOUNTL) || (defined BITMAP_USE_TREE)
- for (unsigned i = 0; i < cnt; i++) {
- size_t regind = bitmap_sfu(slab_data->bitmap,
- &bin_info->bitmap_info);
- *(ptrs + i) = (void *)((uintptr_t)edata_addr_get(slab) +
- (uintptr_t)(bin_info->reg_size * regind));
- }
-#else
- unsigned group = 0;
- bitmap_t g = slab_data->bitmap[group];
- unsigned i = 0;
- while (i < cnt) {
- while (g == 0) {
- g = slab_data->bitmap[++group];
- }
- size_t shift = group << LG_BITMAP_GROUP_NBITS;
- size_t pop = popcount_lu(g);
- if (pop > (cnt - i)) {
- pop = cnt - i;
- }
-
- /*
- * Load from memory locations only once, outside the
- * hot loop below.
- */
- uintptr_t base = (uintptr_t)edata_addr_get(slab);
- uintptr_t regsize = (uintptr_t)bin_info->reg_size;
- while (pop--) {
- size_t bit = cfs_lu(&g);
- size_t regind = shift + bit;
- *(ptrs + i) = (void *)(base + regsize * regind);
-
- i++;
- }
- slab_data->bitmap[group] = g;
- }
-#endif
- edata_nfree_sub(slab, cnt);
-}
-
-static void
-arena_large_malloc_stats_update(tsdn_t *tsdn, arena_t *arena, size_t usize) {
- szind_t index, hindex;
-
- cassert(config_stats);
-
- if (usize < SC_LARGE_MINCLASS) {
- usize = SC_LARGE_MINCLASS;
- }
- index = sz_size2index(usize);
- hindex = (index >= SC_NBINS) ? index - SC_NBINS : 0;
-
- locked_inc_u64(tsdn, LOCKEDINT_MTX(arena->stats.mtx),
- &arena->stats.lstats[hindex].nmalloc, 1);
-}
-
-static void
-arena_large_dalloc_stats_update(tsdn_t *tsdn, arena_t *arena, size_t usize) {
- szind_t index, hindex;
-
- cassert(config_stats);
-
- if (usize < SC_LARGE_MINCLASS) {
- usize = SC_LARGE_MINCLASS;
- }
- index = sz_size2index(usize);
- hindex = (index >= SC_NBINS) ? index - SC_NBINS : 0;
-
- locked_inc_u64(tsdn, LOCKEDINT_MTX(arena->stats.mtx),
- &arena->stats.lstats[hindex].ndalloc, 1);
-}
-
-static void
-arena_large_ralloc_stats_update(tsdn_t *tsdn, arena_t *arena, size_t oldusize,
- size_t usize) {
- arena_large_malloc_stats_update(tsdn, arena, usize);
- arena_large_dalloc_stats_update(tsdn, arena, oldusize);
-}
-
-edata_t *
-arena_extent_alloc_large(tsdn_t *tsdn, arena_t *arena, size_t usize,
- size_t alignment, bool zero) {
- bool deferred_work_generated = false;
- szind_t szind = sz_size2index(usize);
- size_t esize = usize + sz_large_pad;
-
- bool guarded = san_large_extent_decide_guard(tsdn,
- arena_get_ehooks(arena), esize, alignment);
- edata_t *edata = pa_alloc(tsdn, &arena->pa_shard, esize, alignment,
- /* slab */ false, szind, zero, guarded, &deferred_work_generated);
- assert(deferred_work_generated == false);
-
- if (edata != NULL) {
- if (config_stats) {
- LOCKEDINT_MTX_LOCK(tsdn, arena->stats.mtx);
- arena_large_malloc_stats_update(tsdn, arena, usize);
- LOCKEDINT_MTX_UNLOCK(tsdn, arena->stats.mtx);
- }
- }
-
- if (edata != NULL && sz_large_pad != 0) {
- arena_cache_oblivious_randomize(tsdn, arena, edata, alignment);
- }
-
- return edata;
-}
-
-void
-arena_extent_dalloc_large_prep(tsdn_t *tsdn, arena_t *arena, edata_t *edata) {
- if (config_stats) {
- LOCKEDINT_MTX_LOCK(tsdn, arena->stats.mtx);
- arena_large_dalloc_stats_update(tsdn, arena,
- edata_usize_get(edata));
- LOCKEDINT_MTX_UNLOCK(tsdn, arena->stats.mtx);
- }
-}
-
-void
-arena_extent_ralloc_large_shrink(tsdn_t *tsdn, arena_t *arena, edata_t *edata,
- size_t oldusize) {
- size_t usize = edata_usize_get(edata);
-
- if (config_stats) {
- LOCKEDINT_MTX_LOCK(tsdn, arena->stats.mtx);
- arena_large_ralloc_stats_update(tsdn, arena, oldusize, usize);
- LOCKEDINT_MTX_UNLOCK(tsdn, arena->stats.mtx);
- }
-}
-
-void
-arena_extent_ralloc_large_expand(tsdn_t *tsdn, arena_t *arena, edata_t *edata,
- size_t oldusize) {
- size_t usize = edata_usize_get(edata);
-
- if (config_stats) {
- LOCKEDINT_MTX_LOCK(tsdn, arena->stats.mtx);
- arena_large_ralloc_stats_update(tsdn, arena, oldusize, usize);
- LOCKEDINT_MTX_UNLOCK(tsdn, arena->stats.mtx);
- }
-}
-
-/*
- * In situations where we're not forcing a decay (i.e. because the user
- * specifically requested it), should we purge ourselves, or wait for the
- * background thread to get to it.
- */
-static pac_purge_eagerness_t
-arena_decide_unforced_purge_eagerness(bool is_background_thread) {
- if (is_background_thread) {
- return PAC_PURGE_ALWAYS;
- } else if (!is_background_thread && background_thread_enabled()) {
- return PAC_PURGE_NEVER;
- } else {
- return PAC_PURGE_ON_EPOCH_ADVANCE;
- }
-}
-
-bool
-arena_decay_ms_set(tsdn_t *tsdn, arena_t *arena, extent_state_t state,
- ssize_t decay_ms) {
- pac_purge_eagerness_t eagerness = arena_decide_unforced_purge_eagerness(
- /* is_background_thread */ false);
- return pa_decay_ms_set(tsdn, &arena->pa_shard, state, decay_ms,
- eagerness);
-}
-
-ssize_t
-arena_decay_ms_get(arena_t *arena, extent_state_t state) {
- return pa_decay_ms_get(&arena->pa_shard, state);
-}
-
-static bool
-arena_decay_impl(tsdn_t *tsdn, arena_t *arena, decay_t *decay,
- pac_decay_stats_t *decay_stats, ecache_t *ecache,
- bool is_background_thread, bool all) {
- if (all) {
- malloc_mutex_lock(tsdn, &decay->mtx);
- pac_decay_all(tsdn, &arena->pa_shard.pac, decay, decay_stats,
- ecache, /* fully_decay */ all);
- malloc_mutex_unlock(tsdn, &decay->mtx);
- return false;
- }
-
- if (malloc_mutex_trylock(tsdn, &decay->mtx)) {
- /* No need to wait if another thread is in progress. */
- return true;
- }
- pac_purge_eagerness_t eagerness =
- arena_decide_unforced_purge_eagerness(is_background_thread);
- bool epoch_advanced = pac_maybe_decay_purge(tsdn, &arena->pa_shard.pac,
- decay, decay_stats, ecache, eagerness);
- size_t npages_new;
- if (epoch_advanced) {
- /* Backlog is updated on epoch advance. */
- npages_new = decay_epoch_npages_delta(decay);
- }
- malloc_mutex_unlock(tsdn, &decay->mtx);
-
- if (have_background_thread && background_thread_enabled() &&
- epoch_advanced && !is_background_thread) {
- arena_maybe_do_deferred_work(tsdn, arena, decay, npages_new);
- }
-
- return false;
-}
-
-static bool
-arena_decay_dirty(tsdn_t *tsdn, arena_t *arena, bool is_background_thread,
- bool all) {
- return arena_decay_impl(tsdn, arena, &arena->pa_shard.pac.decay_dirty,
- &arena->pa_shard.pac.stats->decay_dirty,
- &arena->pa_shard.pac.ecache_dirty, is_background_thread, all);
-}
-
-static bool
-arena_decay_muzzy(tsdn_t *tsdn, arena_t *arena, bool is_background_thread,
- bool all) {
- if (pa_shard_dont_decay_muzzy(&arena->pa_shard)) {
- return false;
- }
- return arena_decay_impl(tsdn, arena, &arena->pa_shard.pac.decay_muzzy,
- &arena->pa_shard.pac.stats->decay_muzzy,
- &arena->pa_shard.pac.ecache_muzzy, is_background_thread, all);
-}
-
-void
-arena_decay(tsdn_t *tsdn, arena_t *arena, bool is_background_thread, bool all) {
- if (all) {
- /*
- * We should take a purge of "all" to mean "save as much memory
- * as possible", including flushing any caches (for situations
- * like thread death, or manual purge calls).
- */
- sec_flush(tsdn, &arena->pa_shard.hpa_sec);
- }
- if (arena_decay_dirty(tsdn, arena, is_background_thread, all)) {
- return;
- }
- arena_decay_muzzy(tsdn, arena, is_background_thread, all);
-}
-
-static bool
-arena_should_decay_early(tsdn_t *tsdn, arena_t *arena, decay_t *decay,
- background_thread_info_t *info, nstime_t *remaining_sleep,
- size_t npages_new) {
- malloc_mutex_assert_owner(tsdn, &info->mtx);
-
- if (malloc_mutex_trylock(tsdn, &decay->mtx)) {
- return false;
- }
-
- if (!decay_gradually(decay)) {
- malloc_mutex_unlock(tsdn, &decay->mtx);
- return false;
- }
-
- nstime_init(remaining_sleep, background_thread_wakeup_time_get(info));
- if (nstime_compare(remaining_sleep, &decay->epoch) <= 0) {
- malloc_mutex_unlock(tsdn, &decay->mtx);
- return false;
- }
- nstime_subtract(remaining_sleep, &decay->epoch);
- if (npages_new > 0) {
- uint64_t npurge_new = decay_npages_purge_in(decay,
- remaining_sleep, npages_new);
- info->npages_to_purge_new += npurge_new;
- }
- malloc_mutex_unlock(tsdn, &decay->mtx);
- return info->npages_to_purge_new >
- ARENA_DEFERRED_PURGE_NPAGES_THRESHOLD;
-}
-
-/*
- * Check if deferred work needs to be done sooner than planned.
- * For decay we might want to wake up earlier because of an influx of dirty
- * pages. Rather than waiting for previously estimated time, we proactively
- * purge those pages.
- * If background thread sleeps indefinitely, always wake up because some
- * deferred work has been generated.
- */
-static void
-arena_maybe_do_deferred_work(tsdn_t *tsdn, arena_t *arena, decay_t *decay,
- size_t npages_new) {
- background_thread_info_t *info = arena_background_thread_info_get(
- arena);
- if (malloc_mutex_trylock(tsdn, &info->mtx)) {
- /*
- * Background thread may hold the mutex for a long period of
- * time. We'd like to avoid the variance on application
- * threads. So keep this non-blocking, and leave the work to a
- * future epoch.
- */
- return;
- }
- if (!background_thread_is_started(info)) {
- goto label_done;
- }
-
- nstime_t remaining_sleep;
- if (background_thread_indefinite_sleep(info)) {
- background_thread_wakeup_early(info, NULL);
- } else if (arena_should_decay_early(tsdn, arena, decay, info,
- &remaining_sleep, npages_new)) {
- info->npages_to_purge_new = 0;
- background_thread_wakeup_early(info, &remaining_sleep);
- }
-label_done:
- malloc_mutex_unlock(tsdn, &info->mtx);
-}
-
-/* Called from background threads. */
-void
-arena_do_deferred_work(tsdn_t *tsdn, arena_t *arena) {
- arena_decay(tsdn, arena, true, false);
- pa_shard_do_deferred_work(tsdn, &arena->pa_shard);
-}
-
-void
-arena_slab_dalloc(tsdn_t *tsdn, arena_t *arena, edata_t *slab) {
- bool deferred_work_generated = false;
- pa_dalloc(tsdn, &arena->pa_shard, slab, &deferred_work_generated);
- if (deferred_work_generated) {
- arena_handle_deferred_work(tsdn, arena);
- }
-}
-
-static void
-arena_bin_slabs_nonfull_insert(bin_t *bin, edata_t *slab) {
- assert(edata_nfree_get(slab) > 0);
- edata_heap_insert(&bin->slabs_nonfull, slab);
- if (config_stats) {
- bin->stats.nonfull_slabs++;
- }
-}
-
-static void
-arena_bin_slabs_nonfull_remove(bin_t *bin, edata_t *slab) {
- edata_heap_remove(&bin->slabs_nonfull, slab);
- if (config_stats) {
- bin->stats.nonfull_slabs--;
- }
-}
-
-static edata_t *
-arena_bin_slabs_nonfull_tryget(bin_t *bin) {
- edata_t *slab = edata_heap_remove_first(&bin->slabs_nonfull);
- if (slab == NULL) {
- return NULL;
- }
- if (config_stats) {
- bin->stats.reslabs++;
- bin->stats.nonfull_slabs--;
- }
- return slab;
-}
-
-static void
-arena_bin_slabs_full_insert(arena_t *arena, bin_t *bin, edata_t *slab) {
- assert(edata_nfree_get(slab) == 0);
- /*
- * Tracking extents is required by arena_reset, which is not allowed
- * for auto arenas. Bypass this step to avoid touching the edata
- * linkage (often results in cache misses) for auto arenas.
- */
- if (arena_is_auto(arena)) {
- return;
- }
- edata_list_active_append(&bin->slabs_full, slab);
-}
-
-static void
-arena_bin_slabs_full_remove(arena_t *arena, bin_t *bin, edata_t *slab) {
- if (arena_is_auto(arena)) {
- return;
- }
- edata_list_active_remove(&bin->slabs_full, slab);
-}
-
-static void
-arena_bin_reset(tsd_t *tsd, arena_t *arena, bin_t *bin) {
- edata_t *slab;
-
- malloc_mutex_lock(tsd_tsdn(tsd), &bin->lock);
- if (bin->slabcur != NULL) {
- slab = bin->slabcur;
- bin->slabcur = NULL;
- malloc_mutex_unlock(tsd_tsdn(tsd), &bin->lock);
- arena_slab_dalloc(tsd_tsdn(tsd), arena, slab);
- malloc_mutex_lock(tsd_tsdn(tsd), &bin->lock);
- }
- while ((slab = edata_heap_remove_first(&bin->slabs_nonfull)) != NULL) {
- malloc_mutex_unlock(tsd_tsdn(tsd), &bin->lock);
- arena_slab_dalloc(tsd_tsdn(tsd), arena, slab);
- malloc_mutex_lock(tsd_tsdn(tsd), &bin->lock);
- }
- for (slab = edata_list_active_first(&bin->slabs_full); slab != NULL;
- slab = edata_list_active_first(&bin->slabs_full)) {
- arena_bin_slabs_full_remove(arena, bin, slab);
- malloc_mutex_unlock(tsd_tsdn(tsd), &bin->lock);
- arena_slab_dalloc(tsd_tsdn(tsd), arena, slab);
- malloc_mutex_lock(tsd_tsdn(tsd), &bin->lock);
- }
- if (config_stats) {
- bin->stats.curregs = 0;
- bin->stats.curslabs = 0;
- }
- malloc_mutex_unlock(tsd_tsdn(tsd), &bin->lock);
-}
-
-void
-arena_reset(tsd_t *tsd, arena_t *arena) {
- /*
- * Locking in this function is unintuitive. The caller guarantees that
- * no concurrent operations are happening in this arena, but there are
- * still reasons that some locking is necessary:
- *
- * - Some of the functions in the transitive closure of calls assume
- * appropriate locks are held, and in some cases these locks are
- * temporarily dropped to avoid lock order reversal or deadlock due to
- * reentry.
- * - mallctl("epoch", ...) may concurrently refresh stats. While
- * strictly speaking this is a "concurrent operation", disallowing
- * stats refreshes would impose an inconvenient burden.
- */
-
- /* Large allocations. */
- malloc_mutex_lock(tsd_tsdn(tsd), &arena->large_mtx);
-
- for (edata_t *edata = edata_list_active_first(&arena->large);
- edata != NULL; edata = edata_list_active_first(&arena->large)) {
- void *ptr = edata_base_get(edata);
- size_t usize;
-
- malloc_mutex_unlock(tsd_tsdn(tsd), &arena->large_mtx);
- emap_alloc_ctx_t alloc_ctx;
- emap_alloc_ctx_lookup(tsd_tsdn(tsd), &arena_emap_global, ptr,
- &alloc_ctx);
- assert(alloc_ctx.szind != SC_NSIZES);
-
- if (config_stats || (config_prof && opt_prof)) {
- usize = sz_index2size(alloc_ctx.szind);
- assert(usize == isalloc(tsd_tsdn(tsd), ptr));
- }
- /* Remove large allocation from prof sample set. */
- if (config_prof && opt_prof) {
- prof_free(tsd, ptr, usize, &alloc_ctx);
- }
- large_dalloc(tsd_tsdn(tsd), edata);
- malloc_mutex_lock(tsd_tsdn(tsd), &arena->large_mtx);
- }
- malloc_mutex_unlock(tsd_tsdn(tsd), &arena->large_mtx);
-
- /* Bins. */
- for (unsigned i = 0; i < SC_NBINS; i++) {
- for (unsigned j = 0; j < bin_infos[i].n_shards; j++) {
- arena_bin_reset(tsd, arena, arena_get_bin(arena, i, j));
- }
- }
- pa_shard_reset(tsd_tsdn(tsd), &arena->pa_shard);
-}
-
-static void
-arena_prepare_base_deletion_sync_finish(tsd_t *tsd, malloc_mutex_t **mutexes,
- unsigned n_mtx) {
- for (unsigned i = 0; i < n_mtx; i++) {
- malloc_mutex_lock(tsd_tsdn(tsd), mutexes[i]);
- malloc_mutex_unlock(tsd_tsdn(tsd), mutexes[i]);
- }
-}
-
-#define ARENA_DESTROY_MAX_DELAYED_MTX 32
-static void
-arena_prepare_base_deletion_sync(tsd_t *tsd, malloc_mutex_t *mtx,
- malloc_mutex_t **delayed_mtx, unsigned *n_delayed) {
- if (!malloc_mutex_trylock(tsd_tsdn(tsd), mtx)) {
- /* No contention. */
- malloc_mutex_unlock(tsd_tsdn(tsd), mtx);
- return;
- }
- unsigned n = *n_delayed;
- assert(n < ARENA_DESTROY_MAX_DELAYED_MTX);
- /* Add another to the batch. */
- delayed_mtx[n++] = mtx;
-
- if (n == ARENA_DESTROY_MAX_DELAYED_MTX) {
- arena_prepare_base_deletion_sync_finish(tsd, delayed_mtx, n);
- n = 0;
- }
- *n_delayed = n;
-}
-
-static void
-arena_prepare_base_deletion(tsd_t *tsd, base_t *base_to_destroy) {
- /*
- * In order to coalesce, emap_try_acquire_edata_neighbor will attempt to
- * check neighbor edata's state to determine eligibility. This means
- * under certain conditions, the metadata from an arena can be accessed
- * w/o holding any locks from that arena. In order to guarantee safe
- * memory access, the metadata and the underlying base allocator needs
- * to be kept alive, until all pending accesses are done.
- *
- * 1) with opt_retain, the arena boundary implies the is_head state
- * (tracked in the rtree leaf), and the coalesce flow will stop at the
- * head state branch. Therefore no cross arena metadata access
- * possible.
- *
- * 2) w/o opt_retain, the arena id needs to be read from the edata_t,
- * meaning read only cross-arena metadata access is possible. The
- * coalesce attempt will stop at the arena_id mismatch, and is always
- * under one of the ecache locks. To allow safe passthrough of such
- * metadata accesses, the loop below will iterate through all manual
- * arenas' ecache locks. As all the metadata from this base allocator
- * have been unlinked from the rtree, after going through all the
- * relevant ecache locks, it's safe to say that a) pending accesses are
- * all finished, and b) no new access will be generated.
- */
- if (opt_retain) {
- return;
- }
- unsigned destroy_ind = base_ind_get(base_to_destroy);
- assert(destroy_ind >= manual_arena_base);
-
- tsdn_t *tsdn = tsd_tsdn(tsd);
- malloc_mutex_t *delayed_mtx[ARENA_DESTROY_MAX_DELAYED_MTX];
- unsigned n_delayed = 0, total = narenas_total_get();
- for (unsigned i = 0; i < total; i++) {
- if (i == destroy_ind) {
- continue;
- }
- arena_t *arena = arena_get(tsdn, i, false);
- if (arena == NULL) {
- continue;
- }
- pac_t *pac = &arena->pa_shard.pac;
- arena_prepare_base_deletion_sync(tsd, &pac->ecache_dirty.mtx,
- delayed_mtx, &n_delayed);
- arena_prepare_base_deletion_sync(tsd, &pac->ecache_muzzy.mtx,
- delayed_mtx, &n_delayed);
- arena_prepare_base_deletion_sync(tsd, &pac->ecache_retained.mtx,
- delayed_mtx, &n_delayed);
- }
- arena_prepare_base_deletion_sync_finish(tsd, delayed_mtx, n_delayed);
-}
-#undef ARENA_DESTROY_MAX_DELAYED_MTX
-
-void
-arena_destroy(tsd_t *tsd, arena_t *arena) {
- assert(base_ind_get(arena->base) >= narenas_auto);
- assert(arena_nthreads_get(arena, false) == 0);
- assert(arena_nthreads_get(arena, true) == 0);
-
- /*
- * No allocations have occurred since arena_reset() was called.
- * Furthermore, the caller (arena_i_destroy_ctl()) purged all cached
- * extents, so only retained extents may remain and it's safe to call
- * pa_shard_destroy_retained.
- */
- pa_shard_destroy(tsd_tsdn(tsd), &arena->pa_shard);
-
- /*
- * Remove the arena pointer from the arenas array. We rely on the fact
- * that there is no way for the application to get a dirty read from the
- * arenas array unless there is an inherent race in the application
- * involving access of an arena being concurrently destroyed. The
- * application must synchronize knowledge of the arena's validity, so as
- * long as we use an atomic write to update the arenas array, the
- * application will get a clean read any time after it synchronizes
- * knowledge that the arena is no longer valid.
- */
- arena_set(base_ind_get(arena->base), NULL);
-
- /*
- * Destroy the base allocator, which manages all metadata ever mapped by
- * this arena. The prepare function will make sure no pending access to
- * the metadata in this base anymore.
- */
- arena_prepare_base_deletion(tsd, arena->base);
- base_delete(tsd_tsdn(tsd), arena->base);
-}
-
-static edata_t *
-arena_slab_alloc(tsdn_t *tsdn, arena_t *arena, szind_t binind, unsigned binshard,
- const bin_info_t *bin_info) {
- bool deferred_work_generated = false;
- witness_assert_depth_to_rank(tsdn_witness_tsdp_get(tsdn),
- WITNESS_RANK_CORE, 0);
-
- bool guarded = san_slab_extent_decide_guard(tsdn,
- arena_get_ehooks(arena));
- edata_t *slab = pa_alloc(tsdn, &arena->pa_shard, bin_info->slab_size,
- /* alignment */ PAGE, /* slab */ true, /* szind */ binind,
- /* zero */ false, guarded, &deferred_work_generated);
-
- if (deferred_work_generated) {
- arena_handle_deferred_work(tsdn, arena);
- }
-
- if (slab == NULL) {
- return NULL;
- }
- assert(edata_slab_get(slab));
-
- /* Initialize slab internals. */
- slab_data_t *slab_data = edata_slab_data_get(slab);
- edata_nfree_binshard_set(slab, bin_info->nregs, binshard);
- bitmap_init(slab_data->bitmap, &bin_info->bitmap_info, false);
-
- return slab;
-}
-
-/*
- * Before attempting the _with_fresh_slab approaches below, the _no_fresh_slab
- * variants (i.e. through slabcur and nonfull) must be tried first.
- */
-static void
-arena_bin_refill_slabcur_with_fresh_slab(tsdn_t *tsdn, arena_t *arena,
- bin_t *bin, szind_t binind, edata_t *fresh_slab) {
- malloc_mutex_assert_owner(tsdn, &bin->lock);
- /* Only called after slabcur and nonfull both failed. */
- assert(bin->slabcur == NULL);
- assert(edata_heap_first(&bin->slabs_nonfull) == NULL);
- assert(fresh_slab != NULL);
-
- /* A new slab from arena_slab_alloc() */
- assert(edata_nfree_get(fresh_slab) == bin_infos[binind].nregs);
- if (config_stats) {
- bin->stats.nslabs++;
- bin->stats.curslabs++;
- }
- bin->slabcur = fresh_slab;
-}
-
-/* Refill slabcur and then alloc using the fresh slab */
-static void *
-arena_bin_malloc_with_fresh_slab(tsdn_t *tsdn, arena_t *arena, bin_t *bin,
- szind_t binind, edata_t *fresh_slab) {
- malloc_mutex_assert_owner(tsdn, &bin->lock);
- arena_bin_refill_slabcur_with_fresh_slab(tsdn, arena, bin, binind,
- fresh_slab);
-
- return arena_slab_reg_alloc(bin->slabcur, &bin_infos[binind]);
-}
-
-static bool
-arena_bin_refill_slabcur_no_fresh_slab(tsdn_t *tsdn, arena_t *arena,
- bin_t *bin) {
- malloc_mutex_assert_owner(tsdn, &bin->lock);
- /* Only called after arena_slab_reg_alloc[_batch] failed. */
- assert(bin->slabcur == NULL || edata_nfree_get(bin->slabcur) == 0);
-
- if (bin->slabcur != NULL) {
- arena_bin_slabs_full_insert(arena, bin, bin->slabcur);
- }
-
- /* Look for a usable slab. */
- bin->slabcur = arena_bin_slabs_nonfull_tryget(bin);
- assert(bin->slabcur == NULL || edata_nfree_get(bin->slabcur) > 0);
-
- return (bin->slabcur == NULL);
-}
-
-bin_t *
-arena_bin_choose(tsdn_t *tsdn, arena_t *arena, szind_t binind,
- unsigned *binshard_p) {
- unsigned binshard;
- if (tsdn_null(tsdn) || tsd_arena_get(tsdn_tsd(tsdn)) == NULL) {
- binshard = 0;
- } else {
- binshard = tsd_binshardsp_get(tsdn_tsd(tsdn))->binshard[binind];
- }
- assert(binshard < bin_infos[binind].n_shards);
- if (binshard_p != NULL) {
- *binshard_p = binshard;
- }
- return arena_get_bin(arena, binind, binshard);
-}
-
-void
-arena_cache_bin_fill_small(tsdn_t *tsdn, arena_t *arena,
- cache_bin_t *cache_bin, cache_bin_info_t *cache_bin_info, szind_t binind,
- const unsigned nfill) {
- assert(cache_bin_ncached_get_local(cache_bin, cache_bin_info) == 0);
-
- const bin_info_t *bin_info = &bin_infos[binind];
-
- CACHE_BIN_PTR_ARRAY_DECLARE(ptrs, nfill);
- cache_bin_init_ptr_array_for_fill(cache_bin, cache_bin_info, &ptrs,
- nfill);
- /*
- * Bin-local resources are used first: 1) bin->slabcur, and 2) nonfull
- * slabs. After both are exhausted, new slabs will be allocated through
- * arena_slab_alloc().
- *
- * Bin lock is only taken / released right before / after the while(...)
- * refill loop, with new slab allocation (which has its own locking)
- * kept outside of the loop. This setup facilitates flat combining, at
- * the cost of the nested loop (through goto label_refill).
- *
- * To optimize for cases with contention and limited resources
- * (e.g. hugepage-backed or non-overcommit arenas), each fill-iteration
- * gets one chance of slab_alloc, and a retry of bin local resources
- * after the slab allocation (regardless if slab_alloc failed, because
- * the bin lock is dropped during the slab allocation).
- *
- * In other words, new slab allocation is allowed, as long as there was
- * progress since the previous slab_alloc. This is tracked with
- * made_progress below, initialized to true to jump start the first
- * iteration.
- *
- * In other words (again), the loop will only terminate early (i.e. stop
- * with filled < nfill) after going through the three steps: a) bin
- * local exhausted, b) unlock and slab_alloc returns null, c) re-lock
- * and bin local fails again.
- */
- bool made_progress = true;
- edata_t *fresh_slab = NULL;
- bool alloc_and_retry = false;
- unsigned filled = 0;
- unsigned binshard;
- bin_t *bin = arena_bin_choose(tsdn, arena, binind, &binshard);
-
-label_refill:
- malloc_mutex_lock(tsdn, &bin->lock);
-
- while (filled < nfill) {
- /* Try batch-fill from slabcur first. */
- edata_t *slabcur = bin->slabcur;
- if (slabcur != NULL && edata_nfree_get(slabcur) > 0) {
- unsigned tofill = nfill - filled;
- unsigned nfree = edata_nfree_get(slabcur);
- unsigned cnt = tofill < nfree ? tofill : nfree;
-
- arena_slab_reg_alloc_batch(slabcur, bin_info, cnt,
- &ptrs.ptr[filled]);
- made_progress = true;
- filled += cnt;
- continue;
- }
- /* Next try refilling slabcur from nonfull slabs. */
- if (!arena_bin_refill_slabcur_no_fresh_slab(tsdn, arena, bin)) {
- assert(bin->slabcur != NULL);
- continue;
- }
-
- /* Then see if a new slab was reserved already. */
- if (fresh_slab != NULL) {
- arena_bin_refill_slabcur_with_fresh_slab(tsdn, arena,
- bin, binind, fresh_slab);
- assert(bin->slabcur != NULL);
- fresh_slab = NULL;
- continue;
- }
-
- /* Try slab_alloc if made progress (or never did slab_alloc). */
- if (made_progress) {
- assert(bin->slabcur == NULL);
- assert(fresh_slab == NULL);
- alloc_and_retry = true;
- /* Alloc a new slab then come back. */
- break;
- }
-
- /* OOM. */
-
- assert(fresh_slab == NULL);
- assert(!alloc_and_retry);
- break;
- } /* while (filled < nfill) loop. */
-
- if (config_stats && !alloc_and_retry) {
- bin->stats.nmalloc += filled;
- bin->stats.nrequests += cache_bin->tstats.nrequests;
- bin->stats.curregs += filled;
- bin->stats.nfills++;
- cache_bin->tstats.nrequests = 0;
- }
-
- malloc_mutex_unlock(tsdn, &bin->lock);
-
- if (alloc_and_retry) {
- assert(fresh_slab == NULL);
- assert(filled < nfill);
- assert(made_progress);
-
- fresh_slab = arena_slab_alloc(tsdn, arena, binind, binshard,
- bin_info);
- /* fresh_slab NULL case handled in the for loop. */
-
- alloc_and_retry = false;
- made_progress = false;
- goto label_refill;
- }
- assert(filled == nfill || (fresh_slab == NULL && !made_progress));
-
- /* Release if allocated but not used. */
- if (fresh_slab != NULL) {
- assert(edata_nfree_get(fresh_slab) == bin_info->nregs);
- arena_slab_dalloc(tsdn, arena, fresh_slab);
- fresh_slab = NULL;
- }
-
- cache_bin_finish_fill(cache_bin, cache_bin_info, &ptrs, filled);
- arena_decay_tick(tsdn, arena);
-}
-
-size_t
-arena_fill_small_fresh(tsdn_t *tsdn, arena_t *arena, szind_t binind,
- void **ptrs, size_t nfill, bool zero) {
- assert(binind < SC_NBINS);
- const bin_info_t *bin_info = &bin_infos[binind];
- const size_t nregs = bin_info->nregs;
- assert(nregs > 0);
- const size_t usize = bin_info->reg_size;
-
- const bool manual_arena = !arena_is_auto(arena);
- unsigned binshard;
- bin_t *bin = arena_bin_choose(tsdn, arena, binind, &binshard);
-
- size_t nslab = 0;
- size_t filled = 0;
- edata_t *slab = NULL;
- edata_list_active_t fulls;
- edata_list_active_init(&fulls);
-
- while (filled < nfill && (slab = arena_slab_alloc(tsdn, arena, binind,
- binshard, bin_info)) != NULL) {
- assert((size_t)edata_nfree_get(slab) == nregs);
- ++nslab;
- size_t batch = nfill - filled;
- if (batch > nregs) {
- batch = nregs;
- }
- assert(batch > 0);
- arena_slab_reg_alloc_batch(slab, bin_info, (unsigned)batch,
- &ptrs[filled]);
- assert(edata_addr_get(slab) == ptrs[filled]);
- if (zero) {
- memset(ptrs[filled], 0, batch * usize);
- }
- filled += batch;
- if (batch == nregs) {
- if (manual_arena) {
- edata_list_active_append(&fulls, slab);
- }
- slab = NULL;
- }
- }
-
- malloc_mutex_lock(tsdn, &bin->lock);
- /*
- * Only the last slab can be non-empty, and the last slab is non-empty
- * iff slab != NULL.
- */
- if (slab != NULL) {
- arena_bin_lower_slab(tsdn, arena, slab, bin);
- }
- if (manual_arena) {
- edata_list_active_concat(&bin->slabs_full, &fulls);
- }
- assert(edata_list_active_empty(&fulls));
- if (config_stats) {
- bin->stats.nslabs += nslab;
- bin->stats.curslabs += nslab;
- bin->stats.nmalloc += filled;
- bin->stats.nrequests += filled;
- bin->stats.curregs += filled;
- }
- malloc_mutex_unlock(tsdn, &bin->lock);
-
- arena_decay_tick(tsdn, arena);
- return filled;
-}
-
-/*
- * Without allocating a new slab, try arena_slab_reg_alloc() and re-fill
- * bin->slabcur if necessary.
- */
-static void *
-arena_bin_malloc_no_fresh_slab(tsdn_t *tsdn, arena_t *arena, bin_t *bin,
- szind_t binind) {
- malloc_mutex_assert_owner(tsdn, &bin->lock);
- if (bin->slabcur == NULL || edata_nfree_get(bin->slabcur) == 0) {
- if (arena_bin_refill_slabcur_no_fresh_slab(tsdn, arena, bin)) {
- return NULL;
- }
- }
-
- assert(bin->slabcur != NULL && edata_nfree_get(bin->slabcur) > 0);
- return arena_slab_reg_alloc(bin->slabcur, &bin_infos[binind]);
-}
-
-static void *
-arena_malloc_small(tsdn_t *tsdn, arena_t *arena, szind_t binind, bool zero) {
- assert(binind < SC_NBINS);
- const bin_info_t *bin_info = &bin_infos[binind];
- size_t usize = sz_index2size(binind);
- unsigned binshard;
- bin_t *bin = arena_bin_choose(tsdn, arena, binind, &binshard);
-
- malloc_mutex_lock(tsdn, &bin->lock);
- edata_t *fresh_slab = NULL;
- void *ret = arena_bin_malloc_no_fresh_slab(tsdn, arena, bin, binind);
- if (ret == NULL) {
- malloc_mutex_unlock(tsdn, &bin->lock);
- /******************************/
- fresh_slab = arena_slab_alloc(tsdn, arena, binind, binshard,
- bin_info);
- /********************************/
- malloc_mutex_lock(tsdn, &bin->lock);
- /* Retry since the lock was dropped. */
- ret = arena_bin_malloc_no_fresh_slab(tsdn, arena, bin, binind);
- if (ret == NULL) {
- if (fresh_slab == NULL) {
- /* OOM */
- malloc_mutex_unlock(tsdn, &bin->lock);
- return NULL;
- }
- ret = arena_bin_malloc_with_fresh_slab(tsdn, arena, bin,
- binind, fresh_slab);
- fresh_slab = NULL;
- }
- }
- if (config_stats) {
- bin->stats.nmalloc++;
- bin->stats.nrequests++;
- bin->stats.curregs++;
- }
- malloc_mutex_unlock(tsdn, &bin->lock);
-
- if (fresh_slab != NULL) {
- arena_slab_dalloc(tsdn, arena, fresh_slab);
- }
- if (zero) {
- memset(ret, 0, usize);
- }
- arena_decay_tick(tsdn, arena);
-
- return ret;
-}
-
-void *
-arena_malloc_hard(tsdn_t *tsdn, arena_t *arena, size_t size, szind_t ind,
- bool zero) {
- assert(!tsdn_null(tsdn) || arena != NULL);
-
- if (likely(!tsdn_null(tsdn))) {
- arena = arena_choose_maybe_huge(tsdn_tsd(tsdn), arena, size);
- }
- if (unlikely(arena == NULL)) {
- return NULL;
- }
-
- if (likely(size <= SC_SMALL_MAXCLASS)) {
- return arena_malloc_small(tsdn, arena, ind, zero);
- }
- return large_malloc(tsdn, arena, sz_index2size(ind), zero);
-}
-
-void *
-arena_palloc(tsdn_t *tsdn, arena_t *arena, size_t usize, size_t alignment,
- bool zero, tcache_t *tcache) {
- void *ret;
-
- if (usize <= SC_SMALL_MAXCLASS) {
- /* Small; alignment doesn't require special slab placement. */
-
- /* usize should be a result of sz_sa2u() */
- assert((usize & (alignment - 1)) == 0);
-
- /*
- * Small usize can't come from an alignment larger than a page.
- */
- assert(alignment <= PAGE);
-
- ret = arena_malloc(tsdn, arena, usize, sz_size2index(usize),
- zero, tcache, true);
- } else {
- if (likely(alignment <= CACHELINE)) {
- ret = large_malloc(tsdn, arena, usize, zero);
- } else {
- ret = large_palloc(tsdn, arena, usize, alignment, zero);
- }
- }
- return ret;
-}
-
-void
-arena_prof_promote(tsdn_t *tsdn, void *ptr, size_t usize) {
- cassert(config_prof);
- assert(ptr != NULL);
- assert(isalloc(tsdn, ptr) == SC_LARGE_MINCLASS);
- assert(usize <= SC_SMALL_MAXCLASS);
-
- if (config_opt_safety_checks) {
- safety_check_set_redzone(ptr, usize, SC_LARGE_MINCLASS);
- }
-
- edata_t *edata = emap_edata_lookup(tsdn, &arena_emap_global, ptr);
-
- szind_t szind = sz_size2index(usize);
- edata_szind_set(edata, szind);
- emap_remap(tsdn, &arena_emap_global, edata, szind, /* slab */ false);
-
- assert(isalloc(tsdn, ptr) == usize);
-}
-
-static size_t
-arena_prof_demote(tsdn_t *tsdn, edata_t *edata, const void *ptr) {
- cassert(config_prof);
- assert(ptr != NULL);
-
- edata_szind_set(edata, SC_NBINS);
- emap_remap(tsdn, &arena_emap_global, edata, SC_NBINS, /* slab */ false);
-
- assert(isalloc(tsdn, ptr) == SC_LARGE_MINCLASS);
-
- return SC_LARGE_MINCLASS;
-}
-
-void
-arena_dalloc_promoted(tsdn_t *tsdn, void *ptr, tcache_t *tcache,
- bool slow_path) {
- cassert(config_prof);
- assert(opt_prof);
-
- edata_t *edata = emap_edata_lookup(tsdn, &arena_emap_global, ptr);
- size_t usize = edata_usize_get(edata);
- size_t bumped_usize = arena_prof_demote(tsdn, edata, ptr);
- if (config_opt_safety_checks && usize < SC_LARGE_MINCLASS) {
- /*
- * Currently, we only do redzoning for small sampled
- * allocations.
- */
- assert(bumped_usize == SC_LARGE_MINCLASS);
- safety_check_verify_redzone(ptr, usize, bumped_usize);
- }
- if (bumped_usize <= tcache_maxclass && tcache != NULL) {
- tcache_dalloc_large(tsdn_tsd(tsdn), tcache, ptr,
- sz_size2index(bumped_usize), slow_path);
- } else {
- large_dalloc(tsdn, edata);
- }
-}
-
-static void
-arena_dissociate_bin_slab(arena_t *arena, edata_t *slab, bin_t *bin) {
- /* Dissociate slab from bin. */
- if (slab == bin->slabcur) {
- bin->slabcur = NULL;
- } else {
- szind_t binind = edata_szind_get(slab);
- const bin_info_t *bin_info = &bin_infos[binind];
-
- /*
- * The following block's conditional is necessary because if the
- * slab only contains one region, then it never gets inserted
- * into the non-full slabs heap.
- */
- if (bin_info->nregs == 1) {
- arena_bin_slabs_full_remove(arena, bin, slab);
- } else {
- arena_bin_slabs_nonfull_remove(bin, slab);
- }
- }
-}
-
-static void
-arena_bin_lower_slab(tsdn_t *tsdn, arena_t *arena, edata_t *slab,
- bin_t *bin) {
- assert(edata_nfree_get(slab) > 0);
-
- /*
- * Make sure that if bin->slabcur is non-NULL, it refers to the
- * oldest/lowest non-full slab. It is okay to NULL slabcur out rather
- * than proactively keeping it pointing at the oldest/lowest non-full
- * slab.
- */
- if (bin->slabcur != NULL && edata_snad_comp(bin->slabcur, slab) > 0) {
- /* Switch slabcur. */
- if (edata_nfree_get(bin->slabcur) > 0) {
- arena_bin_slabs_nonfull_insert(bin, bin->slabcur);
- } else {
- arena_bin_slabs_full_insert(arena, bin, bin->slabcur);
- }
- bin->slabcur = slab;
- if (config_stats) {
- bin->stats.reslabs++;
- }
- } else {
- arena_bin_slabs_nonfull_insert(bin, slab);
- }
-}
-
-static void
-arena_dalloc_bin_slab_prepare(tsdn_t *tsdn, edata_t *slab, bin_t *bin) {
- malloc_mutex_assert_owner(tsdn, &bin->lock);
-
- assert(slab != bin->slabcur);
- if (config_stats) {
- bin->stats.curslabs--;
- }
-}
-
-void
-arena_dalloc_bin_locked_handle_newly_empty(tsdn_t *tsdn, arena_t *arena,
- edata_t *slab, bin_t *bin) {
- arena_dissociate_bin_slab(arena, slab, bin);
- arena_dalloc_bin_slab_prepare(tsdn, slab, bin);
-}
-
-void
-arena_dalloc_bin_locked_handle_newly_nonempty(tsdn_t *tsdn, arena_t *arena,
- edata_t *slab, bin_t *bin) {
- arena_bin_slabs_full_remove(arena, bin, slab);
- arena_bin_lower_slab(tsdn, arena, slab, bin);
-}
-
-static void
-arena_dalloc_bin(tsdn_t *tsdn, arena_t *arena, edata_t *edata, void *ptr) {
- szind_t binind = edata_szind_get(edata);
- unsigned binshard = edata_binshard_get(edata);
- bin_t *bin = arena_get_bin(arena, binind, binshard);
-
- malloc_mutex_lock(tsdn, &bin->lock);
- arena_dalloc_bin_locked_info_t info;
- arena_dalloc_bin_locked_begin(&info, binind);
- bool ret = arena_dalloc_bin_locked_step(tsdn, arena, bin,
- &info, binind, edata, ptr);
- arena_dalloc_bin_locked_finish(tsdn, arena, bin, &info);
- malloc_mutex_unlock(tsdn, &bin->lock);
-
- if (ret) {
- arena_slab_dalloc(tsdn, arena, edata);
- }
-}
-
-void
-arena_dalloc_small(tsdn_t *tsdn, void *ptr) {
- edata_t *edata = emap_edata_lookup(tsdn, &arena_emap_global, ptr);
- arena_t *arena = arena_get_from_edata(edata);
-
- arena_dalloc_bin(tsdn, arena, edata, ptr);
- arena_decay_tick(tsdn, arena);
-}
-
-bool
-arena_ralloc_no_move(tsdn_t *tsdn, void *ptr, size_t oldsize, size_t size,
- size_t extra, bool zero, size_t *newsize) {
- bool ret;
- /* Calls with non-zero extra had to clamp extra. */
- assert(extra == 0 || size + extra <= SC_LARGE_MAXCLASS);
-
- edata_t *edata = emap_edata_lookup(tsdn, &arena_emap_global, ptr);
- if (unlikely(size > SC_LARGE_MAXCLASS)) {
- ret = true;
- goto done;
- }
-
- size_t usize_min = sz_s2u(size);
- size_t usize_max = sz_s2u(size + extra);
- if (likely(oldsize <= SC_SMALL_MAXCLASS && usize_min
- <= SC_SMALL_MAXCLASS)) {
- /*
- * Avoid moving the allocation if the size class can be left the
- * same.
- */
- assert(bin_infos[sz_size2index(oldsize)].reg_size ==
- oldsize);
- if ((usize_max > SC_SMALL_MAXCLASS
- || sz_size2index(usize_max) != sz_size2index(oldsize))
- && (size > oldsize || usize_max < oldsize)) {
- ret = true;
- goto done;
- }
-
- arena_t *arena = arena_get_from_edata(edata);
- arena_decay_tick(tsdn, arena);
- ret = false;
- } else if (oldsize >= SC_LARGE_MINCLASS
- && usize_max >= SC_LARGE_MINCLASS) {
- ret = large_ralloc_no_move(tsdn, edata, usize_min, usize_max,
- zero);
- } else {
- ret = true;
- }
-done:
- assert(edata == emap_edata_lookup(tsdn, &arena_emap_global, ptr));
- *newsize = edata_usize_get(edata);
-
- return ret;
-}
-
-static void *
-arena_ralloc_move_helper(tsdn_t *tsdn, arena_t *arena, size_t usize,
- size_t alignment, bool zero, tcache_t *tcache) {
- if (alignment == 0) {
- return arena_malloc(tsdn, arena, usize, sz_size2index(usize),
- zero, tcache, true);
- }
- usize = sz_sa2u(usize, alignment);
- if (unlikely(usize == 0 || usize > SC_LARGE_MAXCLASS)) {
- return NULL;
- }
- return ipalloct(tsdn, usize, alignment, zero, tcache, arena);
-}
-
-void *
-arena_ralloc(tsdn_t *tsdn, arena_t *arena, void *ptr, size_t oldsize,
- size_t size, size_t alignment, bool zero, tcache_t *tcache,
- hook_ralloc_args_t *hook_args) {
- size_t usize = alignment == 0 ? sz_s2u(size) : sz_sa2u(size, alignment);
- if (unlikely(usize == 0 || size > SC_LARGE_MAXCLASS)) {
- return NULL;
- }
-
- if (likely(usize <= SC_SMALL_MAXCLASS)) {
- /* Try to avoid moving the allocation. */
- UNUSED size_t newsize;
- if (!arena_ralloc_no_move(tsdn, ptr, oldsize, usize, 0, zero,
- &newsize)) {
- hook_invoke_expand(hook_args->is_realloc
- ? hook_expand_realloc : hook_expand_rallocx,
- ptr, oldsize, usize, (uintptr_t)ptr,
- hook_args->args);
- return ptr;
- }
- }
-
- if (oldsize >= SC_LARGE_MINCLASS
- && usize >= SC_LARGE_MINCLASS) {
- return large_ralloc(tsdn, arena, ptr, usize,
- alignment, zero, tcache, hook_args);
- }
-
- /*
- * size and oldsize are different enough that we need to move the
- * object. In that case, fall back to allocating new space and copying.
- */
- void *ret = arena_ralloc_move_helper(tsdn, arena, usize, alignment,
- zero, tcache);
- if (ret == NULL) {
- return NULL;
- }
-
- hook_invoke_alloc(hook_args->is_realloc
- ? hook_alloc_realloc : hook_alloc_rallocx, ret, (uintptr_t)ret,
- hook_args->args);
- hook_invoke_dalloc(hook_args->is_realloc
- ? hook_dalloc_realloc : hook_dalloc_rallocx, ptr, hook_args->args);
-
- /*
- * Junk/zero-filling were already done by
- * ipalloc()/arena_malloc().
- */
- size_t copysize = (usize < oldsize) ? usize : oldsize;
- memcpy(ret, ptr, copysize);
- isdalloct(tsdn, ptr, oldsize, tcache, NULL, true);
- return ret;
-}
-
-ehooks_t *
-arena_get_ehooks(arena_t *arena) {
- return base_ehooks_get(arena->base);
-}
-
-extent_hooks_t *
-arena_set_extent_hooks(tsd_t *tsd, arena_t *arena,
- extent_hooks_t *extent_hooks) {
- background_thread_info_t *info;
- if (have_background_thread) {
- info = arena_background_thread_info_get(arena);
- malloc_mutex_lock(tsd_tsdn(tsd), &info->mtx);
- }
- /* No using the HPA now that we have the custom hooks. */
- pa_shard_disable_hpa(tsd_tsdn(tsd), &arena->pa_shard);
- extent_hooks_t *ret = base_extent_hooks_set(arena->base, extent_hooks);
- if (have_background_thread) {
- malloc_mutex_unlock(tsd_tsdn(tsd), &info->mtx);
- }
-
- return ret;
-}
-
-dss_prec_t
-arena_dss_prec_get(arena_t *arena) {
- return (dss_prec_t)atomic_load_u(&arena->dss_prec, ATOMIC_ACQUIRE);
-}
-
-bool
-arena_dss_prec_set(arena_t *arena, dss_prec_t dss_prec) {
- if (!have_dss) {
- return (dss_prec != dss_prec_disabled);
- }
- atomic_store_u(&arena->dss_prec, (unsigned)dss_prec, ATOMIC_RELEASE);
- return false;
-}
-
-ssize_t
-arena_dirty_decay_ms_default_get(void) {
- return atomic_load_zd(&dirty_decay_ms_default, ATOMIC_RELAXED);
-}
-
-bool
-arena_dirty_decay_ms_default_set(ssize_t decay_ms) {
- if (!decay_ms_valid(decay_ms)) {
- return true;
- }
- atomic_store_zd(&dirty_decay_ms_default, decay_ms, ATOMIC_RELAXED);
- return false;
-}
-
-ssize_t
-arena_muzzy_decay_ms_default_get(void) {
- return atomic_load_zd(&muzzy_decay_ms_default, ATOMIC_RELAXED);
-}
-
-bool
-arena_muzzy_decay_ms_default_set(ssize_t decay_ms) {
- if (!decay_ms_valid(decay_ms)) {
- return true;
- }
- atomic_store_zd(&muzzy_decay_ms_default, decay_ms, ATOMIC_RELAXED);
- return false;
-}
-
-bool
-arena_retain_grow_limit_get_set(tsd_t *tsd, arena_t *arena, size_t *old_limit,
- size_t *new_limit) {
- assert(opt_retain);
- return pac_retain_grow_limit_get_set(tsd_tsdn(tsd),
- &arena->pa_shard.pac, old_limit, new_limit);
-}
-
-unsigned
-arena_nthreads_get(arena_t *arena, bool internal) {
- return atomic_load_u(&arena->nthreads[internal], ATOMIC_RELAXED);
-}
-
-void
-arena_nthreads_inc(arena_t *arena, bool internal) {
- atomic_fetch_add_u(&arena->nthreads[internal], 1, ATOMIC_RELAXED);
-}
-
-void
-arena_nthreads_dec(arena_t *arena, bool internal) {
- atomic_fetch_sub_u(&arena->nthreads[internal], 1, ATOMIC_RELAXED);
-}
-
-arena_t *
-arena_new(tsdn_t *tsdn, unsigned ind, const arena_config_t *config) {
- arena_t *arena;
- base_t *base;
- unsigned i;
-
- if (ind == 0) {
- base = b0get();
- } else {
- base = base_new(tsdn, ind, config->extent_hooks,
- config->metadata_use_hooks);
- if (base == NULL) {
- return NULL;
- }
- }
-
- size_t arena_size = sizeof(arena_t) + sizeof(bin_t) * nbins_total;
- arena = (arena_t *)base_alloc(tsdn, base, arena_size, CACHELINE);
- if (arena == NULL) {
- goto label_error;
- }
-
- atomic_store_u(&arena->nthreads[0], 0, ATOMIC_RELAXED);
- atomic_store_u(&arena->nthreads[1], 0, ATOMIC_RELAXED);
- arena->last_thd = NULL;
-
- if (config_stats) {
- if (arena_stats_init(tsdn, &arena->stats)) {
- goto label_error;
- }
-
- ql_new(&arena->tcache_ql);
- ql_new(&arena->cache_bin_array_descriptor_ql);
- if (malloc_mutex_init(&arena->tcache_ql_mtx, "tcache_ql",
- WITNESS_RANK_TCACHE_QL, malloc_mutex_rank_exclusive)) {
- goto label_error;
- }
- }
-
- atomic_store_u(&arena->dss_prec, (unsigned)extent_dss_prec_get(),
- ATOMIC_RELAXED);
-
- edata_list_active_init(&arena->large);
- if (malloc_mutex_init(&arena->large_mtx, "arena_large",
- WITNESS_RANK_ARENA_LARGE, malloc_mutex_rank_exclusive)) {
- goto label_error;
- }
-
- nstime_t cur_time;
- nstime_init_update(&cur_time);
- if (pa_shard_init(tsdn, &arena->pa_shard, &arena_pa_central_global,
- &arena_emap_global, base, ind, &arena->stats.pa_shard_stats,
- LOCKEDINT_MTX(arena->stats.mtx), &cur_time, oversize_threshold,
- arena_dirty_decay_ms_default_get(),
- arena_muzzy_decay_ms_default_get())) {
- goto label_error;
- }
-
- /* Initialize bins. */
- atomic_store_u(&arena->binshard_next, 0, ATOMIC_RELEASE);
- for (i = 0; i < nbins_total; i++) {
- bool err = bin_init(&arena->bins[i]);
- if (err) {
- goto label_error;
- }
- }
-
- arena->base = base;
- /* Set arena before creating background threads. */
- arena_set(ind, arena);
- arena->ind = ind;
-
- nstime_init_update(&arena->create_time);
-
- /*
- * We turn on the HPA if set to. There are two exceptions:
- * - Custom extent hooks (we should only return memory allocated from
- * them in that case).
- * - Arena 0 initialization. In this case, we're mid-bootstrapping, and
- * so arena_hpa_global is not yet initialized.
- */
- if (opt_hpa && ehooks_are_default(base_ehooks_get(base)) && ind != 0) {
- hpa_shard_opts_t hpa_shard_opts = opt_hpa_opts;
- hpa_shard_opts.deferral_allowed = background_thread_enabled();
- if (pa_shard_enable_hpa(tsdn, &arena->pa_shard,
- &hpa_shard_opts, &opt_hpa_sec_opts)) {
- goto label_error;
- }
- }
-
- /* We don't support reentrancy for arena 0 bootstrapping. */
- if (ind != 0) {
- /*
- * If we're here, then arena 0 already exists, so bootstrapping
- * is done enough that we should have tsd.
- */
- assert(!tsdn_null(tsdn));
- pre_reentrancy(tsdn_tsd(tsdn), arena);
- if (test_hooks_arena_new_hook) {
- test_hooks_arena_new_hook();
- }
- post_reentrancy(tsdn_tsd(tsdn));
- }
-
- return arena;
-label_error:
- if (ind != 0) {
- base_delete(tsdn, base);
- }
- return NULL;
-}
-
-arena_t *
-arena_choose_huge(tsd_t *tsd) {
- /* huge_arena_ind can be 0 during init (will use a0). */
- if (huge_arena_ind == 0) {
- assert(!malloc_initialized());
- }
-
- arena_t *huge_arena = arena_get(tsd_tsdn(tsd), huge_arena_ind, false);
- if (huge_arena == NULL) {
- /* Create the huge arena on demand. */
- assert(huge_arena_ind != 0);
- huge_arena = arena_get(tsd_tsdn(tsd), huge_arena_ind, true);
- if (huge_arena == NULL) {
- return NULL;
- }
- /*
- * Purge eagerly for huge allocations, because: 1) number of
- * huge allocations is usually small, which means ticker based
- * decay is not reliable; and 2) less immediate reuse is
- * expected for huge allocations.
- */
- if (arena_dirty_decay_ms_default_get() > 0) {
- arena_decay_ms_set(tsd_tsdn(tsd), huge_arena,
- extent_state_dirty, 0);
- }
- if (arena_muzzy_decay_ms_default_get() > 0) {
- arena_decay_ms_set(tsd_tsdn(tsd), huge_arena,
- extent_state_muzzy, 0);
- }
- }
-
- return huge_arena;
-}
-
-bool
-arena_init_huge(void) {
- bool huge_enabled;
-
- /* The threshold should be large size class. */
- if (opt_oversize_threshold > SC_LARGE_MAXCLASS ||
- opt_oversize_threshold < SC_LARGE_MINCLASS) {
- opt_oversize_threshold = 0;
- oversize_threshold = SC_LARGE_MAXCLASS + PAGE;
- huge_enabled = false;
- } else {
- /* Reserve the index for the huge arena. */
- huge_arena_ind = narenas_total_get();
- oversize_threshold = opt_oversize_threshold;
- huge_enabled = true;
- }
-
- return huge_enabled;
-}
-
-bool
-arena_is_huge(unsigned arena_ind) {
- if (huge_arena_ind == 0) {
- return false;
- }
- return (arena_ind == huge_arena_ind);
-}
-
-bool
-arena_boot(sc_data_t *sc_data, base_t *base, bool hpa) {
- arena_dirty_decay_ms_default_set(opt_dirty_decay_ms);
- arena_muzzy_decay_ms_default_set(opt_muzzy_decay_ms);
- for (unsigned i = 0; i < SC_NBINS; i++) {
- sc_t *sc = &sc_data->sc[i];
- div_init(&arena_binind_div_info[i],
- (1U << sc->lg_base) + (sc->ndelta << sc->lg_delta));
- }
-
- uint32_t cur_offset = (uint32_t)offsetof(arena_t, bins);
- for (szind_t i = 0; i < SC_NBINS; i++) {
- arena_bin_offsets[i] = cur_offset;
- nbins_total += bin_infos[i].n_shards;
- cur_offset += (uint32_t)(bin_infos[i].n_shards * sizeof(bin_t));
- }
- return pa_central_init(&arena_pa_central_global, base, hpa,
- &hpa_hooks_default);
-}
-
-void
-arena_prefork0(tsdn_t *tsdn, arena_t *arena) {
- pa_shard_prefork0(tsdn, &arena->pa_shard);
-}
-
-void
-arena_prefork1(tsdn_t *tsdn, arena_t *arena) {
- if (config_stats) {
- malloc_mutex_prefork(tsdn, &arena->tcache_ql_mtx);
- }
-}
-
-void
-arena_prefork2(tsdn_t *tsdn, arena_t *arena) {
- pa_shard_prefork2(tsdn, &arena->pa_shard);
-}
-
-void
-arena_prefork3(tsdn_t *tsdn, arena_t *arena) {
- pa_shard_prefork3(tsdn, &arena->pa_shard);
-}
-
-void
-arena_prefork4(tsdn_t *tsdn, arena_t *arena) {
- pa_shard_prefork4(tsdn, &arena->pa_shard);
-}
-
-void
-arena_prefork5(tsdn_t *tsdn, arena_t *arena) {
- pa_shard_prefork5(tsdn, &arena->pa_shard);
-}
-
-void
-arena_prefork6(tsdn_t *tsdn, arena_t *arena) {
- base_prefork(tsdn, arena->base);
-}
-
-void
-arena_prefork7(tsdn_t *tsdn, arena_t *arena) {
- malloc_mutex_prefork(tsdn, &arena->large_mtx);
-}
-
-void
-arena_prefork8(tsdn_t *tsdn, arena_t *arena) {
- for (unsigned i = 0; i < nbins_total; i++) {
- bin_prefork(tsdn, &arena->bins[i]);
- }
-}
-
-void
-arena_postfork_parent(tsdn_t *tsdn, arena_t *arena) {
- for (unsigned i = 0; i < nbins_total; i++) {
- bin_postfork_parent(tsdn, &arena->bins[i]);
- }
-
- malloc_mutex_postfork_parent(tsdn, &arena->large_mtx);
- base_postfork_parent(tsdn, arena->base);
- pa_shard_postfork_parent(tsdn, &arena->pa_shard);
- if (config_stats) {
- malloc_mutex_postfork_parent(tsdn, &arena->tcache_ql_mtx);
- }
-}
-
-void
-arena_postfork_child(tsdn_t *tsdn, arena_t *arena) {
- atomic_store_u(&arena->nthreads[0], 0, ATOMIC_RELAXED);
- atomic_store_u(&arena->nthreads[1], 0, ATOMIC_RELAXED);
- if (tsd_arena_get(tsdn_tsd(tsdn)) == arena) {
- arena_nthreads_inc(arena, false);
- }
- if (tsd_iarena_get(tsdn_tsd(tsdn)) == arena) {
- arena_nthreads_inc(arena, true);
- }
- if (config_stats) {
- ql_new(&arena->tcache_ql);
- ql_new(&arena->cache_bin_array_descriptor_ql);
- tcache_slow_t *tcache_slow = tcache_slow_get(tsdn_tsd(tsdn));
- if (tcache_slow != NULL && tcache_slow->arena == arena) {
- tcache_t *tcache = tcache_slow->tcache;
- ql_elm_new(tcache_slow, link);
- ql_tail_insert(&arena->tcache_ql, tcache_slow, link);
- cache_bin_array_descriptor_init(
- &tcache_slow->cache_bin_array_descriptor,
- tcache->bins);
- ql_tail_insert(&arena->cache_bin_array_descriptor_ql,
- &tcache_slow->cache_bin_array_descriptor, link);
- }
- }
-
- for (unsigned i = 0; i < nbins_total; i++) {
- bin_postfork_child(tsdn, &arena->bins[i]);
- }
-
- malloc_mutex_postfork_child(tsdn, &arena->large_mtx);
- base_postfork_child(tsdn, arena->base);
- pa_shard_postfork_child(tsdn, &arena->pa_shard);
- if (config_stats) {
- malloc_mutex_postfork_child(tsdn, &arena->tcache_ql_mtx);
- }
-}
diff --git a/fluent-bit/lib/jemalloc-5.3.0/src/background_thread.c b/fluent-bit/lib/jemalloc-5.3.0/src/background_thread.c
deleted file mode 100644
index 3bb8d26c..00000000
--- a/fluent-bit/lib/jemalloc-5.3.0/src/background_thread.c
+++ /dev/null
@@ -1,820 +0,0 @@
-#include "jemalloc/internal/jemalloc_preamble.h"
-#include "jemalloc/internal/jemalloc_internal_includes.h"
-
-#include "jemalloc/internal/assert.h"
-
-JEMALLOC_DIAGNOSTIC_DISABLE_SPURIOUS
-
-/******************************************************************************/
-/* Data. */
-
-/* This option should be opt-in only. */
-#define BACKGROUND_THREAD_DEFAULT false
-/* Read-only after initialization. */
-bool opt_background_thread = BACKGROUND_THREAD_DEFAULT;
-size_t opt_max_background_threads = MAX_BACKGROUND_THREAD_LIMIT + 1;
-
-/* Used for thread creation, termination and stats. */
-malloc_mutex_t background_thread_lock;
-/* Indicates global state. Atomic because decay reads this w/o locking. */
-atomic_b_t background_thread_enabled_state;
-size_t n_background_threads;
-size_t max_background_threads;
-/* Thread info per-index. */
-background_thread_info_t *background_thread_info;
-
-/******************************************************************************/
-
-#ifdef JEMALLOC_PTHREAD_CREATE_WRAPPER
-
-static int (*pthread_create_fptr)(pthread_t *__restrict, const pthread_attr_t *,
- void *(*)(void *), void *__restrict);
-
-static void
-pthread_create_wrapper_init(void) {
-#ifdef JEMALLOC_LAZY_LOCK
- if (!isthreaded) {
- isthreaded = true;
- }
-#endif
-}
-
-int
-pthread_create_wrapper(pthread_t *__restrict thread, const pthread_attr_t *attr,
- void *(*start_routine)(void *), void *__restrict arg) {
- pthread_create_wrapper_init();
-
- return pthread_create_fptr(thread, attr, start_routine, arg);
-}
-#endif /* JEMALLOC_PTHREAD_CREATE_WRAPPER */
-
-#ifndef JEMALLOC_BACKGROUND_THREAD
-#define NOT_REACHED { not_reached(); }
-bool background_thread_create(tsd_t *tsd, unsigned arena_ind) NOT_REACHED
-bool background_threads_enable(tsd_t *tsd) NOT_REACHED
-bool background_threads_disable(tsd_t *tsd) NOT_REACHED
-bool background_thread_is_started(background_thread_info_t *info) NOT_REACHED
-void background_thread_wakeup_early(background_thread_info_t *info,
- nstime_t *remaining_sleep) NOT_REACHED
-void background_thread_prefork0(tsdn_t *tsdn) NOT_REACHED
-void background_thread_prefork1(tsdn_t *tsdn) NOT_REACHED
-void background_thread_postfork_parent(tsdn_t *tsdn) NOT_REACHED
-void background_thread_postfork_child(tsdn_t *tsdn) NOT_REACHED
-bool background_thread_stats_read(tsdn_t *tsdn,
- background_thread_stats_t *stats) NOT_REACHED
-void background_thread_ctl_init(tsdn_t *tsdn) NOT_REACHED
-#undef NOT_REACHED
-#else
-
-static bool background_thread_enabled_at_fork;
-
-static void
-background_thread_info_init(tsdn_t *tsdn, background_thread_info_t *info) {
- background_thread_wakeup_time_set(tsdn, info, 0);
- info->npages_to_purge_new = 0;
- if (config_stats) {
- info->tot_n_runs = 0;
- nstime_init_zero(&info->tot_sleep_time);
- }
-}
-
-static inline bool
-set_current_thread_affinity(int cpu) {
-#if defined(JEMALLOC_HAVE_SCHED_SETAFFINITY)
- cpu_set_t cpuset;
-#else
-# ifndef __NetBSD__
- cpuset_t cpuset;
-# else
- cpuset_t *cpuset;
-# endif
-#endif
-
-#ifndef __NetBSD__
- CPU_ZERO(&cpuset);
- CPU_SET(cpu, &cpuset);
-#else
- cpuset = cpuset_create();
-#endif
-
-#if defined(JEMALLOC_HAVE_SCHED_SETAFFINITY)
- return (sched_setaffinity(0, sizeof(cpu_set_t), &cpuset) != 0);
-#else
-# ifndef __NetBSD__
- int ret = pthread_setaffinity_np(pthread_self(), sizeof(cpuset_t),
- &cpuset);
-# else
- int ret = pthread_setaffinity_np(pthread_self(), cpuset_size(cpuset),
- cpuset);
- cpuset_destroy(cpuset);
-# endif
- return ret != 0;
-#endif
-}
-
-#define BILLION UINT64_C(1000000000)
-/* Minimal sleep interval 100 ms. */
-#define BACKGROUND_THREAD_MIN_INTERVAL_NS (BILLION / 10)
-
-static void
-background_thread_sleep(tsdn_t *tsdn, background_thread_info_t *info,
- uint64_t interval) {
- if (config_stats) {
- info->tot_n_runs++;
- }
- info->npages_to_purge_new = 0;
-
- struct timeval tv;
- /* Specific clock required by timedwait. */
- gettimeofday(&tv, NULL);
- nstime_t before_sleep;
- nstime_init2(&before_sleep, tv.tv_sec, tv.tv_usec * 1000);
-
- int ret;
- if (interval == BACKGROUND_THREAD_INDEFINITE_SLEEP) {
- background_thread_wakeup_time_set(tsdn, info,
- BACKGROUND_THREAD_INDEFINITE_SLEEP);
- ret = pthread_cond_wait(&info->cond, &info->mtx.lock);
- assert(ret == 0);
- } else {
- assert(interval >= BACKGROUND_THREAD_MIN_INTERVAL_NS &&
- interval <= BACKGROUND_THREAD_INDEFINITE_SLEEP);
- /* We need malloc clock (can be different from tv). */
- nstime_t next_wakeup;
- nstime_init_update(&next_wakeup);
- nstime_iadd(&next_wakeup, interval);
- assert(nstime_ns(&next_wakeup) <
- BACKGROUND_THREAD_INDEFINITE_SLEEP);
- background_thread_wakeup_time_set(tsdn, info,
- nstime_ns(&next_wakeup));
-
- nstime_t ts_wakeup;
- nstime_copy(&ts_wakeup, &before_sleep);
- nstime_iadd(&ts_wakeup, interval);
- struct timespec ts;
- ts.tv_sec = (size_t)nstime_sec(&ts_wakeup);
- ts.tv_nsec = (size_t)nstime_nsec(&ts_wakeup);
-
- assert(!background_thread_indefinite_sleep(info));
- ret = pthread_cond_timedwait(&info->cond, &info->mtx.lock, &ts);
- assert(ret == ETIMEDOUT || ret == 0);
- }
- if (config_stats) {
- gettimeofday(&tv, NULL);
- nstime_t after_sleep;
- nstime_init2(&after_sleep, tv.tv_sec, tv.tv_usec * 1000);
- if (nstime_compare(&after_sleep, &before_sleep) > 0) {
- nstime_subtract(&after_sleep, &before_sleep);
- nstime_add(&info->tot_sleep_time, &after_sleep);
- }
- }
-}
-
-static bool
-background_thread_pause_check(tsdn_t *tsdn, background_thread_info_t *info) {
- if (unlikely(info->state == background_thread_paused)) {
- malloc_mutex_unlock(tsdn, &info->mtx);
- /* Wait on global lock to update status. */
- malloc_mutex_lock(tsdn, &background_thread_lock);
- malloc_mutex_unlock(tsdn, &background_thread_lock);
- malloc_mutex_lock(tsdn, &info->mtx);
- return true;
- }
-
- return false;
-}
-
-static inline void
-background_work_sleep_once(tsdn_t *tsdn, background_thread_info_t *info,
- unsigned ind) {
- uint64_t ns_until_deferred = BACKGROUND_THREAD_DEFERRED_MAX;
- unsigned narenas = narenas_total_get();
- bool slept_indefinitely = background_thread_indefinite_sleep(info);
-
- for (unsigned i = ind; i < narenas; i += max_background_threads) {
- arena_t *arena = arena_get(tsdn, i, false);
- if (!arena) {
- continue;
- }
- /*
- * If thread was woken up from the indefinite sleep, don't
- * do the work instantly, but rather check when the deferred
- * work that caused this thread to wake up is scheduled for.
- */
- if (!slept_indefinitely) {
- arena_do_deferred_work(tsdn, arena);
- }
- if (ns_until_deferred <= BACKGROUND_THREAD_MIN_INTERVAL_NS) {
- /* Min interval will be used. */
- continue;
- }
- uint64_t ns_arena_deferred = pa_shard_time_until_deferred_work(
- tsdn, &arena->pa_shard);
- if (ns_arena_deferred < ns_until_deferred) {
- ns_until_deferred = ns_arena_deferred;
- }
- }
-
- uint64_t sleep_ns;
- if (ns_until_deferred == BACKGROUND_THREAD_DEFERRED_MAX) {
- sleep_ns = BACKGROUND_THREAD_INDEFINITE_SLEEP;
- } else {
- sleep_ns =
- (ns_until_deferred < BACKGROUND_THREAD_MIN_INTERVAL_NS)
- ? BACKGROUND_THREAD_MIN_INTERVAL_NS
- : ns_until_deferred;
-
- }
-
- background_thread_sleep(tsdn, info, sleep_ns);
-}
-
-static bool
-background_threads_disable_single(tsd_t *tsd, background_thread_info_t *info) {
- if (info == &background_thread_info[0]) {
- malloc_mutex_assert_owner(tsd_tsdn(tsd),
- &background_thread_lock);
- } else {
- malloc_mutex_assert_not_owner(tsd_tsdn(tsd),
- &background_thread_lock);
- }
-
- pre_reentrancy(tsd, NULL);
- malloc_mutex_lock(tsd_tsdn(tsd), &info->mtx);
- bool has_thread;
- assert(info->state != background_thread_paused);
- if (info->state == background_thread_started) {
- has_thread = true;
- info->state = background_thread_stopped;
- pthread_cond_signal(&info->cond);
- } else {
- has_thread = false;
- }
- malloc_mutex_unlock(tsd_tsdn(tsd), &info->mtx);
-
- if (!has_thread) {
- post_reentrancy(tsd);
- return false;
- }
- void *ret;
- if (pthread_join(info->thread, &ret)) {
- post_reentrancy(tsd);
- return true;
- }
- assert(ret == NULL);
- n_background_threads--;
- post_reentrancy(tsd);
-
- return false;
-}
-
-static void *background_thread_entry(void *ind_arg);
-
-static int
-background_thread_create_signals_masked(pthread_t *thread,
- const pthread_attr_t *attr, void *(*start_routine)(void *), void *arg) {
- /*
- * Mask signals during thread creation so that the thread inherits
- * an empty signal set.
- */
- sigset_t set;
- sigfillset(&set);
- sigset_t oldset;
- int mask_err = pthread_sigmask(SIG_SETMASK, &set, &oldset);
- if (mask_err != 0) {
- return mask_err;
- }
- int create_err = pthread_create_wrapper(thread, attr, start_routine,
- arg);
- /*
- * Restore the signal mask. Failure to restore the signal mask here
- * changes program behavior.
- */
- int restore_err = pthread_sigmask(SIG_SETMASK, &oldset, NULL);
- if (restore_err != 0) {
- malloc_printf("<jemalloc>: background thread creation "
- "failed (%d), and signal mask restoration failed "
- "(%d)\n", create_err, restore_err);
- if (opt_abort) {
- abort();
- }
- }
- return create_err;
-}
-
-static bool
-check_background_thread_creation(tsd_t *tsd, unsigned *n_created,
- bool *created_threads) {
- bool ret = false;
- if (likely(*n_created == n_background_threads)) {
- return ret;
- }
-
- tsdn_t *tsdn = tsd_tsdn(tsd);
- malloc_mutex_unlock(tsdn, &background_thread_info[0].mtx);
- for (unsigned i = 1; i < max_background_threads; i++) {
- if (created_threads[i]) {
- continue;
- }
- background_thread_info_t *info = &background_thread_info[i];
- malloc_mutex_lock(tsdn, &info->mtx);
- /*
- * In case of the background_thread_paused state because of
- * arena reset, delay the creation.
- */
- bool create = (info->state == background_thread_started);
- malloc_mutex_unlock(tsdn, &info->mtx);
- if (!create) {
- continue;
- }
-
- pre_reentrancy(tsd, NULL);
- int err = background_thread_create_signals_masked(&info->thread,
- NULL, background_thread_entry, (void *)(uintptr_t)i);
- post_reentrancy(tsd);
-
- if (err == 0) {
- (*n_created)++;
- created_threads[i] = true;
- } else {
- malloc_printf("<jemalloc>: background thread "
- "creation failed (%d)\n", err);
- if (opt_abort) {
- abort();
- }
- }
- /* Return to restart the loop since we unlocked. */
- ret = true;
- break;
- }
- malloc_mutex_lock(tsdn, &background_thread_info[0].mtx);
-
- return ret;
-}
-
-static void
-background_thread0_work(tsd_t *tsd) {
- /* Thread0 is also responsible for launching / terminating threads. */
- VARIABLE_ARRAY(bool, created_threads, max_background_threads);
- unsigned i;
- for (i = 1; i < max_background_threads; i++) {
- created_threads[i] = false;
- }
- /* Start working, and create more threads when asked. */
- unsigned n_created = 1;
- while (background_thread_info[0].state != background_thread_stopped) {
- if (background_thread_pause_check(tsd_tsdn(tsd),
- &background_thread_info[0])) {
- continue;
- }
- if (check_background_thread_creation(tsd, &n_created,
- (bool *)&created_threads)) {
- continue;
- }
- background_work_sleep_once(tsd_tsdn(tsd),
- &background_thread_info[0], 0);
- }
-
- /*
- * Shut down other threads at exit. Note that the ctl thread is holding
- * the global background_thread mutex (and is waiting) for us.
- */
- assert(!background_thread_enabled());
- for (i = 1; i < max_background_threads; i++) {
- background_thread_info_t *info = &background_thread_info[i];
- assert(info->state != background_thread_paused);
- if (created_threads[i]) {
- background_threads_disable_single(tsd, info);
- } else {
- malloc_mutex_lock(tsd_tsdn(tsd), &info->mtx);
- if (info->state != background_thread_stopped) {
- /* The thread was not created. */
- assert(info->state ==
- background_thread_started);
- n_background_threads--;
- info->state = background_thread_stopped;
- }
- malloc_mutex_unlock(tsd_tsdn(tsd), &info->mtx);
- }
- }
- background_thread_info[0].state = background_thread_stopped;
- assert(n_background_threads == 1);
-}
-
-static void
-background_work(tsd_t *tsd, unsigned ind) {
- background_thread_info_t *info = &background_thread_info[ind];
-
- malloc_mutex_lock(tsd_tsdn(tsd), &info->mtx);
- background_thread_wakeup_time_set(tsd_tsdn(tsd), info,
- BACKGROUND_THREAD_INDEFINITE_SLEEP);
- if (ind == 0) {
- background_thread0_work(tsd);
- } else {
- while (info->state != background_thread_stopped) {
- if (background_thread_pause_check(tsd_tsdn(tsd),
- info)) {
- continue;
- }
- background_work_sleep_once(tsd_tsdn(tsd), info, ind);
- }
- }
- assert(info->state == background_thread_stopped);
- background_thread_wakeup_time_set(tsd_tsdn(tsd), info, 0);
- malloc_mutex_unlock(tsd_tsdn(tsd), &info->mtx);
-}
-
-static void *
-background_thread_entry(void *ind_arg) {
- unsigned thread_ind = (unsigned)(uintptr_t)ind_arg;
- assert(thread_ind < max_background_threads);
-#ifdef JEMALLOC_HAVE_PTHREAD_SETNAME_NP
- pthread_setname_np(pthread_self(), "jemalloc_bg_thd");
-#elif defined(__FreeBSD__) || defined(__DragonFly__)
- pthread_set_name_np(pthread_self(), "jemalloc_bg_thd");
-#endif
- if (opt_percpu_arena != percpu_arena_disabled) {
- set_current_thread_affinity((int)thread_ind);
- }
- /*
- * Start periodic background work. We use internal tsd which avoids
- * side effects, for example triggering new arena creation (which in
- * turn triggers another background thread creation).
- */
- background_work(tsd_internal_fetch(), thread_ind);
- assert(pthread_equal(pthread_self(),
- background_thread_info[thread_ind].thread));
-
- return NULL;
-}
-
-static void
-background_thread_init(tsd_t *tsd, background_thread_info_t *info) {
- malloc_mutex_assert_owner(tsd_tsdn(tsd), &background_thread_lock);
- info->state = background_thread_started;
- background_thread_info_init(tsd_tsdn(tsd), info);
- n_background_threads++;
-}
-
-static bool
-background_thread_create_locked(tsd_t *tsd, unsigned arena_ind) {
- assert(have_background_thread);
- malloc_mutex_assert_owner(tsd_tsdn(tsd), &background_thread_lock);
-
- /* We create at most NCPUs threads. */
- size_t thread_ind = arena_ind % max_background_threads;
- background_thread_info_t *info = &background_thread_info[thread_ind];
-
- bool need_new_thread;
- malloc_mutex_lock(tsd_tsdn(tsd), &info->mtx);
- need_new_thread = background_thread_enabled() &&
- (info->state == background_thread_stopped);
- if (need_new_thread) {
- background_thread_init(tsd, info);
- }
- malloc_mutex_unlock(tsd_tsdn(tsd), &info->mtx);
- if (!need_new_thread) {
- return false;
- }
- if (arena_ind != 0) {
- /* Threads are created asynchronously by Thread 0. */
- background_thread_info_t *t0 = &background_thread_info[0];
- malloc_mutex_lock(tsd_tsdn(tsd), &t0->mtx);
- assert(t0->state == background_thread_started);
- pthread_cond_signal(&t0->cond);
- malloc_mutex_unlock(tsd_tsdn(tsd), &t0->mtx);
-
- return false;
- }
-
- pre_reentrancy(tsd, NULL);
- /*
- * To avoid complications (besides reentrancy), create internal
- * background threads with the underlying pthread_create.
- */
- int err = background_thread_create_signals_masked(&info->thread, NULL,
- background_thread_entry, (void *)thread_ind);
- post_reentrancy(tsd);
-
- if (err != 0) {
- malloc_printf("<jemalloc>: arena 0 background thread creation "
- "failed (%d)\n", err);
- malloc_mutex_lock(tsd_tsdn(tsd), &info->mtx);
- info->state = background_thread_stopped;
- n_background_threads--;
- malloc_mutex_unlock(tsd_tsdn(tsd), &info->mtx);
-
- return true;
- }
-
- return false;
-}
-
-/* Create a new background thread if needed. */
-bool
-background_thread_create(tsd_t *tsd, unsigned arena_ind) {
- assert(have_background_thread);
-
- bool ret;
- malloc_mutex_lock(tsd_tsdn(tsd), &background_thread_lock);
- ret = background_thread_create_locked(tsd, arena_ind);
- malloc_mutex_unlock(tsd_tsdn(tsd), &background_thread_lock);
-
- return ret;
-}
-
-bool
-background_threads_enable(tsd_t *tsd) {
- assert(n_background_threads == 0);
- assert(background_thread_enabled());
- malloc_mutex_assert_owner(tsd_tsdn(tsd), &background_thread_lock);
-
- VARIABLE_ARRAY(bool, marked, max_background_threads);
- unsigned nmarked;
- for (unsigned i = 0; i < max_background_threads; i++) {
- marked[i] = false;
- }
- nmarked = 0;
- /* Thread 0 is required and created at the end. */
- marked[0] = true;
- /* Mark the threads we need to create for thread 0. */
- unsigned narenas = narenas_total_get();
- for (unsigned i = 1; i < narenas; i++) {
- if (marked[i % max_background_threads] ||
- arena_get(tsd_tsdn(tsd), i, false) == NULL) {
- continue;
- }
- background_thread_info_t *info = &background_thread_info[
- i % max_background_threads];
- malloc_mutex_lock(tsd_tsdn(tsd), &info->mtx);
- assert(info->state == background_thread_stopped);
- background_thread_init(tsd, info);
- malloc_mutex_unlock(tsd_tsdn(tsd), &info->mtx);
- marked[i % max_background_threads] = true;
- if (++nmarked == max_background_threads) {
- break;
- }
- }
-
- bool err = background_thread_create_locked(tsd, 0);
- if (err) {
- return true;
- }
- for (unsigned i = 0; i < narenas; i++) {
- arena_t *arena = arena_get(tsd_tsdn(tsd), i, false);
- if (arena != NULL) {
- pa_shard_set_deferral_allowed(tsd_tsdn(tsd),
- &arena->pa_shard, true);
- }
- }
- return false;
-}
-
-bool
-background_threads_disable(tsd_t *tsd) {
- assert(!background_thread_enabled());
- malloc_mutex_assert_owner(tsd_tsdn(tsd), &background_thread_lock);
-
- /* Thread 0 will be responsible for terminating other threads. */
- if (background_threads_disable_single(tsd,
- &background_thread_info[0])) {
- return true;
- }
- assert(n_background_threads == 0);
- unsigned narenas = narenas_total_get();
- for (unsigned i = 0; i < narenas; i++) {
- arena_t *arena = arena_get(tsd_tsdn(tsd), i, false);
- if (arena != NULL) {
- pa_shard_set_deferral_allowed(tsd_tsdn(tsd),
- &arena->pa_shard, false);
- }
- }
-
- return false;
-}
-
-bool
-background_thread_is_started(background_thread_info_t *info) {
- return info->state == background_thread_started;
-}
-
-void
-background_thread_wakeup_early(background_thread_info_t *info,
- nstime_t *remaining_sleep) {
- /*
- * This is an optimization to increase batching. At this point
- * we know that background thread wakes up soon, so the time to cache
- * the just freed memory is bounded and low.
- */
- if (remaining_sleep != NULL && nstime_ns(remaining_sleep) <
- BACKGROUND_THREAD_MIN_INTERVAL_NS) {
- return;
- }
- pthread_cond_signal(&info->cond);
-}
-
-void
-background_thread_prefork0(tsdn_t *tsdn) {
- malloc_mutex_prefork(tsdn, &background_thread_lock);
- background_thread_enabled_at_fork = background_thread_enabled();
-}
-
-void
-background_thread_prefork1(tsdn_t *tsdn) {
- for (unsigned i = 0; i < max_background_threads; i++) {
- malloc_mutex_prefork(tsdn, &background_thread_info[i].mtx);
- }
-}
-
-void
-background_thread_postfork_parent(tsdn_t *tsdn) {
- for (unsigned i = 0; i < max_background_threads; i++) {
- malloc_mutex_postfork_parent(tsdn,
- &background_thread_info[i].mtx);
- }
- malloc_mutex_postfork_parent(tsdn, &background_thread_lock);
-}
-
-void
-background_thread_postfork_child(tsdn_t *tsdn) {
- for (unsigned i = 0; i < max_background_threads; i++) {
- malloc_mutex_postfork_child(tsdn,
- &background_thread_info[i].mtx);
- }
- malloc_mutex_postfork_child(tsdn, &background_thread_lock);
- if (!background_thread_enabled_at_fork) {
- return;
- }
-
- /* Clear background_thread state (reset to disabled for child). */
- malloc_mutex_lock(tsdn, &background_thread_lock);
- n_background_threads = 0;
- background_thread_enabled_set(tsdn, false);
- for (unsigned i = 0; i < max_background_threads; i++) {
- background_thread_info_t *info = &background_thread_info[i];
- malloc_mutex_lock(tsdn, &info->mtx);
- info->state = background_thread_stopped;
- int ret = pthread_cond_init(&info->cond, NULL);
- assert(ret == 0);
- background_thread_info_init(tsdn, info);
- malloc_mutex_unlock(tsdn, &info->mtx);
- }
- malloc_mutex_unlock(tsdn, &background_thread_lock);
-}
-
-bool
-background_thread_stats_read(tsdn_t *tsdn, background_thread_stats_t *stats) {
- assert(config_stats);
- malloc_mutex_lock(tsdn, &background_thread_lock);
- if (!background_thread_enabled()) {
- malloc_mutex_unlock(tsdn, &background_thread_lock);
- return true;
- }
-
- nstime_init_zero(&stats->run_interval);
- memset(&stats->max_counter_per_bg_thd, 0, sizeof(mutex_prof_data_t));
-
- uint64_t num_runs = 0;
- stats->num_threads = n_background_threads;
- for (unsigned i = 0; i < max_background_threads; i++) {
- background_thread_info_t *info = &background_thread_info[i];
- if (malloc_mutex_trylock(tsdn, &info->mtx)) {
- /*
- * Each background thread run may take a long time;
- * avoid waiting on the stats if the thread is active.
- */
- continue;
- }
- if (info->state != background_thread_stopped) {
- num_runs += info->tot_n_runs;
- nstime_add(&stats->run_interval, &info->tot_sleep_time);
- malloc_mutex_prof_max_update(tsdn,
- &stats->max_counter_per_bg_thd, &info->mtx);
- }
- malloc_mutex_unlock(tsdn, &info->mtx);
- }
- stats->num_runs = num_runs;
- if (num_runs > 0) {
- nstime_idivide(&stats->run_interval, num_runs);
- }
- malloc_mutex_unlock(tsdn, &background_thread_lock);
-
- return false;
-}
-
-#undef BACKGROUND_THREAD_NPAGES_THRESHOLD
-#undef BILLION
-#undef BACKGROUND_THREAD_MIN_INTERVAL_NS
-
-#ifdef JEMALLOC_HAVE_DLSYM
-#include <dlfcn.h>
-#endif
-
-static bool
-pthread_create_fptr_init(void) {
- if (pthread_create_fptr != NULL) {
- return false;
- }
- /*
- * Try the next symbol first, because 1) when use lazy_lock we have a
- * wrapper for pthread_create; and 2) application may define its own
- * wrapper as well (and can call malloc within the wrapper).
- */
-#ifdef JEMALLOC_HAVE_DLSYM
- pthread_create_fptr = dlsym(RTLD_NEXT, "pthread_create");
-#else
- pthread_create_fptr = NULL;
-#endif
- if (pthread_create_fptr == NULL) {
- if (config_lazy_lock) {
- malloc_write("<jemalloc>: Error in dlsym(RTLD_NEXT, "
- "\"pthread_create\")\n");
- abort();
- } else {
- /* Fall back to the default symbol. */
- pthread_create_fptr = pthread_create;
- }
- }
-
- return false;
-}
-
-/*
- * When lazy lock is enabled, we need to make sure setting isthreaded before
- * taking any background_thread locks. This is called early in ctl (instead of
- * wait for the pthread_create calls to trigger) because the mutex is required
- * before creating background threads.
- */
-void
-background_thread_ctl_init(tsdn_t *tsdn) {
- malloc_mutex_assert_not_owner(tsdn, &background_thread_lock);
-#ifdef JEMALLOC_PTHREAD_CREATE_WRAPPER
- pthread_create_fptr_init();
- pthread_create_wrapper_init();
-#endif
-}
-
-#endif /* defined(JEMALLOC_BACKGROUND_THREAD) */
-
-bool
-background_thread_boot0(void) {
- if (!have_background_thread && opt_background_thread) {
- malloc_printf("<jemalloc>: option background_thread currently "
- "supports pthread only\n");
- return true;
- }
-#ifdef JEMALLOC_PTHREAD_CREATE_WRAPPER
- if ((config_lazy_lock || opt_background_thread) &&
- pthread_create_fptr_init()) {
- return true;
- }
-#endif
- return false;
-}
-
-bool
-background_thread_boot1(tsdn_t *tsdn, base_t *base) {
-#ifdef JEMALLOC_BACKGROUND_THREAD
- assert(have_background_thread);
- assert(narenas_total_get() > 0);
-
- if (opt_max_background_threads > MAX_BACKGROUND_THREAD_LIMIT) {
- opt_max_background_threads = DEFAULT_NUM_BACKGROUND_THREAD;
- }
- max_background_threads = opt_max_background_threads;
-
- background_thread_enabled_set(tsdn, opt_background_thread);
- if (malloc_mutex_init(&background_thread_lock,
- "background_thread_global",
- WITNESS_RANK_BACKGROUND_THREAD_GLOBAL,
- malloc_mutex_rank_exclusive)) {
- return true;
- }
-
- background_thread_info = (background_thread_info_t *)base_alloc(tsdn,
- base, opt_max_background_threads *
- sizeof(background_thread_info_t), CACHELINE);
- if (background_thread_info == NULL) {
- return true;
- }
-
- for (unsigned i = 0; i < max_background_threads; i++) {
- background_thread_info_t *info = &background_thread_info[i];
- /* Thread mutex is rank_inclusive because of thread0. */
- if (malloc_mutex_init(&info->mtx, "background_thread",
- WITNESS_RANK_BACKGROUND_THREAD,
- malloc_mutex_address_ordered)) {
- return true;
- }
- if (pthread_cond_init(&info->cond, NULL)) {
- return true;
- }
- malloc_mutex_lock(tsdn, &info->mtx);
- info->state = background_thread_stopped;
- background_thread_info_init(tsdn, info);
- malloc_mutex_unlock(tsdn, &info->mtx);
- }
-#endif
-
- return false;
-}
diff --git a/fluent-bit/lib/jemalloc-5.3.0/src/base.c b/fluent-bit/lib/jemalloc-5.3.0/src/base.c
deleted file mode 100644
index 7f4d6756..00000000
--- a/fluent-bit/lib/jemalloc-5.3.0/src/base.c
+++ /dev/null
@@ -1,529 +0,0 @@
-#include "jemalloc/internal/jemalloc_preamble.h"
-#include "jemalloc/internal/jemalloc_internal_includes.h"
-
-#include "jemalloc/internal/assert.h"
-#include "jemalloc/internal/extent_mmap.h"
-#include "jemalloc/internal/mutex.h"
-#include "jemalloc/internal/sz.h"
-
-/*
- * In auto mode, arenas switch to huge pages for the base allocator on the
- * second base block. a0 switches to thp on the 5th block (after 20 megabytes
- * of metadata), since more metadata (e.g. rtree nodes) come from a0's base.
- */
-
-#define BASE_AUTO_THP_THRESHOLD 2
-#define BASE_AUTO_THP_THRESHOLD_A0 5
-
-/******************************************************************************/
-/* Data. */
-
-static base_t *b0;
-
-metadata_thp_mode_t opt_metadata_thp = METADATA_THP_DEFAULT;
-
-const char *metadata_thp_mode_names[] = {
- "disabled",
- "auto",
- "always"
-};
-
-/******************************************************************************/
-
-static inline bool
-metadata_thp_madvise(void) {
- return (metadata_thp_enabled() &&
- (init_system_thp_mode == thp_mode_default));
-}
-
-static void *
-base_map(tsdn_t *tsdn, ehooks_t *ehooks, unsigned ind, size_t size) {
- void *addr;
- bool zero = true;
- bool commit = true;
-
- /* Use huge page sizes and alignment regardless of opt_metadata_thp. */
- assert(size == HUGEPAGE_CEILING(size));
- size_t alignment = HUGEPAGE;
- if (ehooks_are_default(ehooks)) {
- addr = extent_alloc_mmap(NULL, size, alignment, &zero, &commit);
- if (have_madvise_huge && addr) {
- pages_set_thp_state(addr, size);
- }
- } else {
- addr = ehooks_alloc(tsdn, ehooks, NULL, size, alignment, &zero,
- &commit);
- }
-
- return addr;
-}
-
-static void
-base_unmap(tsdn_t *tsdn, ehooks_t *ehooks, unsigned ind, void *addr,
- size_t size) {
- /*
- * Cascade through dalloc, decommit, purge_forced, and purge_lazy,
- * stopping at first success. This cascade is performed for consistency
- * with the cascade in extent_dalloc_wrapper() because an application's
- * custom hooks may not support e.g. dalloc. This function is only ever
- * called as a side effect of arena destruction, so although it might
- * seem pointless to do anything besides dalloc here, the application
- * may in fact want the end state of all associated virtual memory to be
- * in some consistent-but-allocated state.
- */
- if (ehooks_are_default(ehooks)) {
- if (!extent_dalloc_mmap(addr, size)) {
- goto label_done;
- }
- if (!pages_decommit(addr, size)) {
- goto label_done;
- }
- if (!pages_purge_forced(addr, size)) {
- goto label_done;
- }
- if (!pages_purge_lazy(addr, size)) {
- goto label_done;
- }
- /* Nothing worked. This should never happen. */
- not_reached();
- } else {
- if (!ehooks_dalloc(tsdn, ehooks, addr, size, true)) {
- goto label_done;
- }
- if (!ehooks_decommit(tsdn, ehooks, addr, size, 0, size)) {
- goto label_done;
- }
- if (!ehooks_purge_forced(tsdn, ehooks, addr, size, 0, size)) {
- goto label_done;
- }
- if (!ehooks_purge_lazy(tsdn, ehooks, addr, size, 0, size)) {
- goto label_done;
- }
- /* Nothing worked. That's the application's problem. */
- }
-label_done:
- if (metadata_thp_madvise()) {
- /* Set NOHUGEPAGE after unmap to avoid kernel defrag. */
- assert(((uintptr_t)addr & HUGEPAGE_MASK) == 0 &&
- (size & HUGEPAGE_MASK) == 0);
- pages_nohuge(addr, size);
- }
-}
-
-static void
-base_edata_init(size_t *extent_sn_next, edata_t *edata, void *addr,
- size_t size) {
- size_t sn;
-
- sn = *extent_sn_next;
- (*extent_sn_next)++;
-
- edata_binit(edata, addr, size, sn);
-}
-
-static size_t
-base_get_num_blocks(base_t *base, bool with_new_block) {
- base_block_t *b = base->blocks;
- assert(b != NULL);
-
- size_t n_blocks = with_new_block ? 2 : 1;
- while (b->next != NULL) {
- n_blocks++;
- b = b->next;
- }
-
- return n_blocks;
-}
-
-static void
-base_auto_thp_switch(tsdn_t *tsdn, base_t *base) {
- assert(opt_metadata_thp == metadata_thp_auto);
- malloc_mutex_assert_owner(tsdn, &base->mtx);
- if (base->auto_thp_switched) {
- return;
- }
- /* Called when adding a new block. */
- bool should_switch;
- if (base_ind_get(base) != 0) {
- should_switch = (base_get_num_blocks(base, true) ==
- BASE_AUTO_THP_THRESHOLD);
- } else {
- should_switch = (base_get_num_blocks(base, true) ==
- BASE_AUTO_THP_THRESHOLD_A0);
- }
- if (!should_switch) {
- return;
- }
-
- base->auto_thp_switched = true;
- assert(!config_stats || base->n_thp == 0);
- /* Make the initial blocks THP lazily. */
- base_block_t *block = base->blocks;
- while (block != NULL) {
- assert((block->size & HUGEPAGE_MASK) == 0);
- pages_huge(block, block->size);
- if (config_stats) {
- base->n_thp += HUGEPAGE_CEILING(block->size -
- edata_bsize_get(&block->edata)) >> LG_HUGEPAGE;
- }
- block = block->next;
- assert(block == NULL || (base_ind_get(base) == 0));
- }
-}
-
-static void *
-base_extent_bump_alloc_helper(edata_t *edata, size_t *gap_size, size_t size,
- size_t alignment) {
- void *ret;
-
- assert(alignment == ALIGNMENT_CEILING(alignment, QUANTUM));
- assert(size == ALIGNMENT_CEILING(size, alignment));
-
- *gap_size = ALIGNMENT_CEILING((uintptr_t)edata_addr_get(edata),
- alignment) - (uintptr_t)edata_addr_get(edata);
- ret = (void *)((uintptr_t)edata_addr_get(edata) + *gap_size);
- assert(edata_bsize_get(edata) >= *gap_size + size);
- edata_binit(edata, (void *)((uintptr_t)edata_addr_get(edata) +
- *gap_size + size), edata_bsize_get(edata) - *gap_size - size,
- edata_sn_get(edata));
- return ret;
-}
-
-static void
-base_extent_bump_alloc_post(base_t *base, edata_t *edata, size_t gap_size,
- void *addr, size_t size) {
- if (edata_bsize_get(edata) > 0) {
- /*
- * Compute the index for the largest size class that does not
- * exceed extent's size.
- */
- szind_t index_floor =
- sz_size2index(edata_bsize_get(edata) + 1) - 1;
- edata_heap_insert(&base->avail[index_floor], edata);
- }
-
- if (config_stats) {
- base->allocated += size;
- /*
- * Add one PAGE to base_resident for every page boundary that is
- * crossed by the new allocation. Adjust n_thp similarly when
- * metadata_thp is enabled.
- */
- base->resident += PAGE_CEILING((uintptr_t)addr + size) -
- PAGE_CEILING((uintptr_t)addr - gap_size);
- assert(base->allocated <= base->resident);
- assert(base->resident <= base->mapped);
- if (metadata_thp_madvise() && (opt_metadata_thp ==
- metadata_thp_always || base->auto_thp_switched)) {
- base->n_thp += (HUGEPAGE_CEILING((uintptr_t)addr + size)
- - HUGEPAGE_CEILING((uintptr_t)addr - gap_size)) >>
- LG_HUGEPAGE;
- assert(base->mapped >= base->n_thp << LG_HUGEPAGE);
- }
- }
-}
-
-static void *
-base_extent_bump_alloc(base_t *base, edata_t *edata, size_t size,
- size_t alignment) {
- void *ret;
- size_t gap_size;
-
- ret = base_extent_bump_alloc_helper(edata, &gap_size, size, alignment);
- base_extent_bump_alloc_post(base, edata, gap_size, ret, size);
- return ret;
-}
-
-/*
- * Allocate a block of virtual memory that is large enough to start with a
- * base_block_t header, followed by an object of specified size and alignment.
- * On success a pointer to the initialized base_block_t header is returned.
- */
-static base_block_t *
-base_block_alloc(tsdn_t *tsdn, base_t *base, ehooks_t *ehooks, unsigned ind,
- pszind_t *pind_last, size_t *extent_sn_next, size_t size,
- size_t alignment) {
- alignment = ALIGNMENT_CEILING(alignment, QUANTUM);
- size_t usize = ALIGNMENT_CEILING(size, alignment);
- size_t header_size = sizeof(base_block_t);
- size_t gap_size = ALIGNMENT_CEILING(header_size, alignment) -
- header_size;
- /*
- * Create increasingly larger blocks in order to limit the total number
- * of disjoint virtual memory ranges. Choose the next size in the page
- * size class series (skipping size classes that are not a multiple of
- * HUGEPAGE), or a size large enough to satisfy the requested size and
- * alignment, whichever is larger.
- */
- size_t min_block_size = HUGEPAGE_CEILING(sz_psz2u(header_size + gap_size
- + usize));
- pszind_t pind_next = (*pind_last + 1 < sz_psz2ind(SC_LARGE_MAXCLASS)) ?
- *pind_last + 1 : *pind_last;
- size_t next_block_size = HUGEPAGE_CEILING(sz_pind2sz(pind_next));
- size_t block_size = (min_block_size > next_block_size) ? min_block_size
- : next_block_size;
- base_block_t *block = (base_block_t *)base_map(tsdn, ehooks, ind,
- block_size);
- if (block == NULL) {
- return NULL;
- }
-
- if (metadata_thp_madvise()) {
- void *addr = (void *)block;
- assert(((uintptr_t)addr & HUGEPAGE_MASK) == 0 &&
- (block_size & HUGEPAGE_MASK) == 0);
- if (opt_metadata_thp == metadata_thp_always) {
- pages_huge(addr, block_size);
- } else if (opt_metadata_thp == metadata_thp_auto &&
- base != NULL) {
- /* base != NULL indicates this is not a new base. */
- malloc_mutex_lock(tsdn, &base->mtx);
- base_auto_thp_switch(tsdn, base);
- if (base->auto_thp_switched) {
- pages_huge(addr, block_size);
- }
- malloc_mutex_unlock(tsdn, &base->mtx);
- }
- }
-
- *pind_last = sz_psz2ind(block_size);
- block->size = block_size;
- block->next = NULL;
- assert(block_size >= header_size);
- base_edata_init(extent_sn_next, &block->edata,
- (void *)((uintptr_t)block + header_size), block_size - header_size);
- return block;
-}
-
-/*
- * Allocate an extent that is at least as large as specified size, with
- * specified alignment.
- */
-static edata_t *
-base_extent_alloc(tsdn_t *tsdn, base_t *base, size_t size, size_t alignment) {
- malloc_mutex_assert_owner(tsdn, &base->mtx);
-
- ehooks_t *ehooks = base_ehooks_get_for_metadata(base);
- /*
- * Drop mutex during base_block_alloc(), because an extent hook will be
- * called.
- */
- malloc_mutex_unlock(tsdn, &base->mtx);
- base_block_t *block = base_block_alloc(tsdn, base, ehooks,
- base_ind_get(base), &base->pind_last, &base->extent_sn_next, size,
- alignment);
- malloc_mutex_lock(tsdn, &base->mtx);
- if (block == NULL) {
- return NULL;
- }
- block->next = base->blocks;
- base->blocks = block;
- if (config_stats) {
- base->allocated += sizeof(base_block_t);
- base->resident += PAGE_CEILING(sizeof(base_block_t));
- base->mapped += block->size;
- if (metadata_thp_madvise() &&
- !(opt_metadata_thp == metadata_thp_auto
- && !base->auto_thp_switched)) {
- assert(base->n_thp > 0);
- base->n_thp += HUGEPAGE_CEILING(sizeof(base_block_t)) >>
- LG_HUGEPAGE;
- }
- assert(base->allocated <= base->resident);
- assert(base->resident <= base->mapped);
- assert(base->n_thp << LG_HUGEPAGE <= base->mapped);
- }
- return &block->edata;
-}
-
-base_t *
-b0get(void) {
- return b0;
-}
-
-base_t *
-base_new(tsdn_t *tsdn, unsigned ind, const extent_hooks_t *extent_hooks,
- bool metadata_use_hooks) {
- pszind_t pind_last = 0;
- size_t extent_sn_next = 0;
-
- /*
- * The base will contain the ehooks eventually, but it itself is
- * allocated using them. So we use some stack ehooks to bootstrap its
- * memory, and then initialize the ehooks within the base_t.
- */
- ehooks_t fake_ehooks;
- ehooks_init(&fake_ehooks, metadata_use_hooks ?
- (extent_hooks_t *)extent_hooks :
- (extent_hooks_t *)&ehooks_default_extent_hooks, ind);
-
- base_block_t *block = base_block_alloc(tsdn, NULL, &fake_ehooks, ind,
- &pind_last, &extent_sn_next, sizeof(base_t), QUANTUM);
- if (block == NULL) {
- return NULL;
- }
-
- size_t gap_size;
- size_t base_alignment = CACHELINE;
- size_t base_size = ALIGNMENT_CEILING(sizeof(base_t), base_alignment);
- base_t *base = (base_t *)base_extent_bump_alloc_helper(&block->edata,
- &gap_size, base_size, base_alignment);
- ehooks_init(&base->ehooks, (extent_hooks_t *)extent_hooks, ind);
- ehooks_init(&base->ehooks_base, metadata_use_hooks ?
- (extent_hooks_t *)extent_hooks :
- (extent_hooks_t *)&ehooks_default_extent_hooks, ind);
- if (malloc_mutex_init(&base->mtx, "base", WITNESS_RANK_BASE,
- malloc_mutex_rank_exclusive)) {
- base_unmap(tsdn, &fake_ehooks, ind, block, block->size);
- return NULL;
- }
- base->pind_last = pind_last;
- base->extent_sn_next = extent_sn_next;
- base->blocks = block;
- base->auto_thp_switched = false;
- for (szind_t i = 0; i < SC_NSIZES; i++) {
- edata_heap_new(&base->avail[i]);
- }
- if (config_stats) {
- base->allocated = sizeof(base_block_t);
- base->resident = PAGE_CEILING(sizeof(base_block_t));
- base->mapped = block->size;
- base->n_thp = (opt_metadata_thp == metadata_thp_always) &&
- metadata_thp_madvise() ? HUGEPAGE_CEILING(sizeof(base_block_t))
- >> LG_HUGEPAGE : 0;
- assert(base->allocated <= base->resident);
- assert(base->resident <= base->mapped);
- assert(base->n_thp << LG_HUGEPAGE <= base->mapped);
- }
- base_extent_bump_alloc_post(base, &block->edata, gap_size, base,
- base_size);
-
- return base;
-}
-
-void
-base_delete(tsdn_t *tsdn, base_t *base) {
- ehooks_t *ehooks = base_ehooks_get_for_metadata(base);
- base_block_t *next = base->blocks;
- do {
- base_block_t *block = next;
- next = block->next;
- base_unmap(tsdn, ehooks, base_ind_get(base), block,
- block->size);
- } while (next != NULL);
-}
-
-ehooks_t *
-base_ehooks_get(base_t *base) {
- return &base->ehooks;
-}
-
-ehooks_t *
-base_ehooks_get_for_metadata(base_t *base) {
- return &base->ehooks_base;
-}
-
-extent_hooks_t *
-base_extent_hooks_set(base_t *base, extent_hooks_t *extent_hooks) {
- extent_hooks_t *old_extent_hooks =
- ehooks_get_extent_hooks_ptr(&base->ehooks);
- ehooks_init(&base->ehooks, extent_hooks, ehooks_ind_get(&base->ehooks));
- return old_extent_hooks;
-}
-
-static void *
-base_alloc_impl(tsdn_t *tsdn, base_t *base, size_t size, size_t alignment,
- size_t *esn) {
- alignment = QUANTUM_CEILING(alignment);
- size_t usize = ALIGNMENT_CEILING(size, alignment);
- size_t asize = usize + alignment - QUANTUM;
-
- edata_t *edata = NULL;
- malloc_mutex_lock(tsdn, &base->mtx);
- for (szind_t i = sz_size2index(asize); i < SC_NSIZES; i++) {
- edata = edata_heap_remove_first(&base->avail[i]);
- if (edata != NULL) {
- /* Use existing space. */
- break;
- }
- }
- if (edata == NULL) {
- /* Try to allocate more space. */
- edata = base_extent_alloc(tsdn, base, usize, alignment);
- }
- void *ret;
- if (edata == NULL) {
- ret = NULL;
- goto label_return;
- }
-
- ret = base_extent_bump_alloc(base, edata, usize, alignment);
- if (esn != NULL) {
- *esn = (size_t)edata_sn_get(edata);
- }
-label_return:
- malloc_mutex_unlock(tsdn, &base->mtx);
- return ret;
-}
-
-/*
- * base_alloc() returns zeroed memory, which is always demand-zeroed for the
- * auto arenas, in order to make multi-page sparse data structures such as radix
- * tree nodes efficient with respect to physical memory usage. Upon success a
- * pointer to at least size bytes with specified alignment is returned. Note
- * that size is rounded up to the nearest multiple of alignment to avoid false
- * sharing.
- */
-void *
-base_alloc(tsdn_t *tsdn, base_t *base, size_t size, size_t alignment) {
- return base_alloc_impl(tsdn, base, size, alignment, NULL);
-}
-
-edata_t *
-base_alloc_edata(tsdn_t *tsdn, base_t *base) {
- size_t esn;
- edata_t *edata = base_alloc_impl(tsdn, base, sizeof(edata_t),
- EDATA_ALIGNMENT, &esn);
- if (edata == NULL) {
- return NULL;
- }
- edata_esn_set(edata, esn);
- return edata;
-}
-
-void
-base_stats_get(tsdn_t *tsdn, base_t *base, size_t *allocated, size_t *resident,
- size_t *mapped, size_t *n_thp) {
- cassert(config_stats);
-
- 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;
- *n_thp = base->n_thp;
- malloc_mutex_unlock(tsdn, &base->mtx);
-}
-
-void
-base_prefork(tsdn_t *tsdn, base_t *base) {
- malloc_mutex_prefork(tsdn, &base->mtx);
-}
-
-void
-base_postfork_parent(tsdn_t *tsdn, base_t *base) {
- malloc_mutex_postfork_parent(tsdn, &base->mtx);
-}
-
-void
-base_postfork_child(tsdn_t *tsdn, base_t *base) {
- malloc_mutex_postfork_child(tsdn, &base->mtx);
-}
-
-bool
-base_boot(tsdn_t *tsdn) {
- b0 = base_new(tsdn, 0, (extent_hooks_t *)&ehooks_default_extent_hooks,
- /* metadata_use_hooks */ true);
- return (b0 == NULL);
-}
diff --git a/fluent-bit/lib/jemalloc-5.3.0/src/bin.c b/fluent-bit/lib/jemalloc-5.3.0/src/bin.c
deleted file mode 100644
index fa204587..00000000
--- a/fluent-bit/lib/jemalloc-5.3.0/src/bin.c
+++ /dev/null
@@ -1,69 +0,0 @@
-#include "jemalloc/internal/jemalloc_preamble.h"
-#include "jemalloc/internal/jemalloc_internal_includes.h"
-
-#include "jemalloc/internal/assert.h"
-#include "jemalloc/internal/bin.h"
-#include "jemalloc/internal/sc.h"
-#include "jemalloc/internal/witness.h"
-
-bool
-bin_update_shard_size(unsigned bin_shard_sizes[SC_NBINS], size_t start_size,
- size_t end_size, size_t nshards) {
- if (nshards > BIN_SHARDS_MAX || nshards == 0) {
- return true;
- }
-
- if (start_size > SC_SMALL_MAXCLASS) {
- return false;
- }
- if (end_size > SC_SMALL_MAXCLASS) {
- end_size = SC_SMALL_MAXCLASS;
- }
-
- /* Compute the index since this may happen before sz init. */
- szind_t ind1 = sz_size2index_compute(start_size);
- szind_t ind2 = sz_size2index_compute(end_size);
- for (unsigned i = ind1; i <= ind2; i++) {
- bin_shard_sizes[i] = (unsigned)nshards;
- }
-
- return false;
-}
-
-void
-bin_shard_sizes_boot(unsigned bin_shard_sizes[SC_NBINS]) {
- /* Load the default number of shards. */
- for (unsigned i = 0; i < SC_NBINS; i++) {
- bin_shard_sizes[i] = N_BIN_SHARDS_DEFAULT;
- }
-}
-
-bool
-bin_init(bin_t *bin) {
- if (malloc_mutex_init(&bin->lock, "bin", WITNESS_RANK_BIN,
- malloc_mutex_rank_exclusive)) {
- return true;
- }
- bin->slabcur = NULL;
- edata_heap_new(&bin->slabs_nonfull);
- edata_list_active_init(&bin->slabs_full);
- if (config_stats) {
- memset(&bin->stats, 0, sizeof(bin_stats_t));
- }
- return false;
-}
-
-void
-bin_prefork(tsdn_t *tsdn, bin_t *bin) {
- malloc_mutex_prefork(tsdn, &bin->lock);
-}
-
-void
-bin_postfork_parent(tsdn_t *tsdn, bin_t *bin) {
- malloc_mutex_postfork_parent(tsdn, &bin->lock);
-}
-
-void
-bin_postfork_child(tsdn_t *tsdn, bin_t *bin) {
- malloc_mutex_postfork_child(tsdn, &bin->lock);
-}
diff --git a/fluent-bit/lib/jemalloc-5.3.0/src/bin_info.c b/fluent-bit/lib/jemalloc-5.3.0/src/bin_info.c
deleted file mode 100644
index 8629ef88..00000000
--- a/fluent-bit/lib/jemalloc-5.3.0/src/bin_info.c
+++ /dev/null
@@ -1,30 +0,0 @@
-#include "jemalloc/internal/jemalloc_preamble.h"
-#include "jemalloc/internal/jemalloc_internal_includes.h"
-
-#include "jemalloc/internal/bin_info.h"
-
-bin_info_t bin_infos[SC_NBINS];
-
-static void
-bin_infos_init(sc_data_t *sc_data, unsigned bin_shard_sizes[SC_NBINS],
- bin_info_t infos[SC_NBINS]) {
- for (unsigned i = 0; i < SC_NBINS; i++) {
- bin_info_t *bin_info = &infos[i];
- sc_t *sc = &sc_data->sc[i];
- bin_info->reg_size = ((size_t)1U << sc->lg_base)
- + ((size_t)sc->ndelta << sc->lg_delta);
- bin_info->slab_size = (sc->pgs << LG_PAGE);
- bin_info->nregs =
- (uint32_t)(bin_info->slab_size / bin_info->reg_size);
- bin_info->n_shards = bin_shard_sizes[i];
- bitmap_info_t bitmap_info = BITMAP_INFO_INITIALIZER(
- bin_info->nregs);
- bin_info->bitmap_info = bitmap_info;
- }
-}
-
-void
-bin_info_boot(sc_data_t *sc_data, unsigned bin_shard_sizes[SC_NBINS]) {
- assert(sc_data->initialized);
- bin_infos_init(sc_data, bin_shard_sizes, bin_infos);
-}
diff --git a/fluent-bit/lib/jemalloc-5.3.0/src/bitmap.c b/fluent-bit/lib/jemalloc-5.3.0/src/bitmap.c
deleted file mode 100644
index 0ccedc5d..00000000
--- a/fluent-bit/lib/jemalloc-5.3.0/src/bitmap.c
+++ /dev/null
@@ -1,120 +0,0 @@
-#include "jemalloc/internal/jemalloc_preamble.h"
-#include "jemalloc/internal/jemalloc_internal_includes.h"
-
-#include "jemalloc/internal/assert.h"
-
-/******************************************************************************/
-
-#ifdef BITMAP_USE_TREE
-
-void
-bitmap_info_init(bitmap_info_t *binfo, size_t nbits) {
- unsigned i;
- size_t group_count;
-
- assert(nbits > 0);
- assert(nbits <= (ZU(1) << LG_BITMAP_MAXBITS));
-
- /*
- * Compute the number of groups necessary to store nbits bits, and
- * progressively work upward through the levels until reaching a level
- * that requires only one group.
- */
- binfo->levels[0].group_offset = 0;
- group_count = BITMAP_BITS2GROUPS(nbits);
- for (i = 1; group_count > 1; i++) {
- assert(i < BITMAP_MAX_LEVELS);
- binfo->levels[i].group_offset = binfo->levels[i-1].group_offset
- + group_count;
- group_count = BITMAP_BITS2GROUPS(group_count);
- }
- binfo->levels[i].group_offset = binfo->levels[i-1].group_offset
- + group_count;
- assert(binfo->levels[i].group_offset <= BITMAP_GROUPS_MAX);
- binfo->nlevels = i;
- binfo->nbits = nbits;
-}
-
-static size_t
-bitmap_info_ngroups(const bitmap_info_t *binfo) {
- return binfo->levels[binfo->nlevels].group_offset;
-}
-
-void
-bitmap_init(bitmap_t *bitmap, const bitmap_info_t *binfo, bool fill) {
- size_t extra;
- unsigned i;
-
- /*
- * Bits are actually inverted with regard to the external bitmap
- * interface.
- */
-
- if (fill) {
- /* The "filled" bitmap starts out with all 0 bits. */
- memset(bitmap, 0, bitmap_size(binfo));
- return;
- }
-
- /*
- * The "empty" bitmap starts out with all 1 bits, except for trailing
- * unused bits (if any). Note that each group uses bit 0 to correspond
- * to the first logical bit in the group, so extra bits are the most
- * significant bits of the last group.
- */
- memset(bitmap, 0xffU, bitmap_size(binfo));
- extra = (BITMAP_GROUP_NBITS - (binfo->nbits & BITMAP_GROUP_NBITS_MASK))
- & BITMAP_GROUP_NBITS_MASK;
- if (extra != 0) {
- bitmap[binfo->levels[1].group_offset - 1] >>= extra;
- }
- for (i = 1; i < binfo->nlevels; i++) {
- size_t group_count = binfo->levels[i].group_offset -
- binfo->levels[i-1].group_offset;
- extra = (BITMAP_GROUP_NBITS - (group_count &
- BITMAP_GROUP_NBITS_MASK)) & BITMAP_GROUP_NBITS_MASK;
- if (extra != 0) {
- bitmap[binfo->levels[i+1].group_offset - 1] >>= extra;
- }
- }
-}
-
-#else /* BITMAP_USE_TREE */
-
-void
-bitmap_info_init(bitmap_info_t *binfo, size_t nbits) {
- assert(nbits > 0);
- assert(nbits <= (ZU(1) << LG_BITMAP_MAXBITS));
-
- binfo->ngroups = BITMAP_BITS2GROUPS(nbits);
- binfo->nbits = nbits;
-}
-
-static size_t
-bitmap_info_ngroups(const bitmap_info_t *binfo) {
- return binfo->ngroups;
-}
-
-void
-bitmap_init(bitmap_t *bitmap, const bitmap_info_t *binfo, bool fill) {
- size_t extra;
-
- if (fill) {
- memset(bitmap, 0, bitmap_size(binfo));
- return;
- }
-
- memset(bitmap, 0xffU, bitmap_size(binfo));
- extra = (BITMAP_GROUP_NBITS - (binfo->nbits & BITMAP_GROUP_NBITS_MASK))
- & BITMAP_GROUP_NBITS_MASK;
- if (extra != 0) {
- bitmap[binfo->ngroups - 1] >>= extra;
- }
-}
-
-#endif /* BITMAP_USE_TREE */
-
-size_t
-bitmap_size(const bitmap_info_t *binfo) {
- return (bitmap_info_ngroups(binfo) << LG_SIZEOF_BITMAP);
-}
diff --git a/fluent-bit/lib/jemalloc-5.3.0/src/buf_writer.c b/fluent-bit/lib/jemalloc-5.3.0/src/buf_writer.c
deleted file mode 100644
index 7c6f7940..00000000
--- a/fluent-bit/lib/jemalloc-5.3.0/src/buf_writer.c
+++ /dev/null
@@ -1,144 +0,0 @@
-#include "jemalloc/internal/jemalloc_preamble.h"
-#include "jemalloc/internal/jemalloc_internal_includes.h"
-
-#include "jemalloc/internal/buf_writer.h"
-#include "jemalloc/internal/malloc_io.h"
-
-static void *
-buf_writer_allocate_internal_buf(tsdn_t *tsdn, size_t buf_len) {
-#ifdef JEMALLOC_JET
- if (buf_len > SC_LARGE_MAXCLASS) {
- return NULL;
- }
-#else
- assert(buf_len <= SC_LARGE_MAXCLASS);
-#endif
- return iallocztm(tsdn, buf_len, sz_size2index(buf_len), false, NULL,
- true, arena_get(tsdn, 0, false), true);
-}
-
-static void
-buf_writer_free_internal_buf(tsdn_t *tsdn, void *buf) {
- if (buf != NULL) {
- idalloctm(tsdn, buf, NULL, NULL, true, true);
- }
-}
-
-static void
-buf_writer_assert(buf_writer_t *buf_writer) {
- assert(buf_writer != NULL);
- assert(buf_writer->write_cb != NULL);
- if (buf_writer->buf != NULL) {
- assert(buf_writer->buf_size > 0);
- } else {
- assert(buf_writer->buf_size == 0);
- assert(buf_writer->internal_buf);
- }
- assert(buf_writer->buf_end <= buf_writer->buf_size);
-}
-
-bool
-buf_writer_init(tsdn_t *tsdn, buf_writer_t *buf_writer, write_cb_t *write_cb,
- void *cbopaque, char *buf, size_t buf_len) {
- if (write_cb != NULL) {
- buf_writer->write_cb = write_cb;
- } else {
- buf_writer->write_cb = je_malloc_message != NULL ?
- je_malloc_message : wrtmessage;
- }
- buf_writer->cbopaque = cbopaque;
- assert(buf_len >= 2);
- if (buf != NULL) {
- buf_writer->buf = buf;
- buf_writer->internal_buf = false;
- } else {
- buf_writer->buf = buf_writer_allocate_internal_buf(tsdn,
- buf_len);
- buf_writer->internal_buf = true;
- }
- if (buf_writer->buf != NULL) {
- buf_writer->buf_size = buf_len - 1; /* Allowing for '\0'. */
- } else {
- buf_writer->buf_size = 0;
- }
- buf_writer->buf_end = 0;
- buf_writer_assert(buf_writer);
- return buf_writer->buf == NULL;
-}
-
-void
-buf_writer_flush(buf_writer_t *buf_writer) {
- buf_writer_assert(buf_writer);
- if (buf_writer->buf == NULL) {
- return;
- }
- buf_writer->buf[buf_writer->buf_end] = '\0';
- buf_writer->write_cb(buf_writer->cbopaque, buf_writer->buf);
- buf_writer->buf_end = 0;
- buf_writer_assert(buf_writer);
-}
-
-void
-buf_writer_cb(void *buf_writer_arg, const char *s) {
- buf_writer_t *buf_writer = (buf_writer_t *)buf_writer_arg;
- buf_writer_assert(buf_writer);
- if (buf_writer->buf == NULL) {
- buf_writer->write_cb(buf_writer->cbopaque, s);
- return;
- }
- size_t i, slen, n;
- for (i = 0, slen = strlen(s); i < slen; i += n) {
- if (buf_writer->buf_end == buf_writer->buf_size) {
- buf_writer_flush(buf_writer);
- }
- size_t s_remain = slen - i;
- size_t buf_remain = buf_writer->buf_size - buf_writer->buf_end;
- n = s_remain < buf_remain ? s_remain : buf_remain;
- memcpy(buf_writer->buf + buf_writer->buf_end, s + i, n);
- buf_writer->buf_end += n;
- buf_writer_assert(buf_writer);
- }
- assert(i == slen);
-}
-
-void
-buf_writer_terminate(tsdn_t *tsdn, buf_writer_t *buf_writer) {
- buf_writer_assert(buf_writer);
- buf_writer_flush(buf_writer);
- if (buf_writer->internal_buf) {
- buf_writer_free_internal_buf(tsdn, buf_writer->buf);
- }
-}
-
-void
-buf_writer_pipe(buf_writer_t *buf_writer, read_cb_t *read_cb,
- void *read_cbopaque) {
- /*
- * A tiny local buffer in case the buffered writer failed to allocate
- * at init.
- */
- static char backup_buf[16];
- static buf_writer_t backup_buf_writer;
-
- buf_writer_assert(buf_writer);
- assert(read_cb != NULL);
- if (buf_writer->buf == NULL) {
- buf_writer_init(TSDN_NULL, &backup_buf_writer,
- buf_writer->write_cb, buf_writer->cbopaque, backup_buf,
- sizeof(backup_buf));
- buf_writer = &backup_buf_writer;
- }
- assert(buf_writer->buf != NULL);
- ssize_t nread = 0;
- do {
- buf_writer->buf_end += nread;
- buf_writer_assert(buf_writer);
- if (buf_writer->buf_end == buf_writer->buf_size) {
- buf_writer_flush(buf_writer);
- }
- nread = read_cb(read_cbopaque,
- buf_writer->buf + buf_writer->buf_end,
- buf_writer->buf_size - buf_writer->buf_end);
- } while (nread > 0);
- buf_writer_flush(buf_writer);
-}
diff --git a/fluent-bit/lib/jemalloc-5.3.0/src/cache_bin.c b/fluent-bit/lib/jemalloc-5.3.0/src/cache_bin.c
deleted file mode 100644
index 9ae072a0..00000000
--- a/fluent-bit/lib/jemalloc-5.3.0/src/cache_bin.c
+++ /dev/null
@@ -1,99 +0,0 @@
-#include "jemalloc/internal/jemalloc_preamble.h"
-#include "jemalloc/internal/jemalloc_internal_includes.h"
-
-#include "jemalloc/internal/bit_util.h"
-#include "jemalloc/internal/cache_bin.h"
-#include "jemalloc/internal/safety_check.h"
-
-void
-cache_bin_info_init(cache_bin_info_t *info,
- cache_bin_sz_t ncached_max) {
- assert(ncached_max <= CACHE_BIN_NCACHED_MAX);
- size_t stack_size = (size_t)ncached_max * sizeof(void *);
- assert(stack_size < ((size_t)1 << (sizeof(cache_bin_sz_t) * 8)));
- info->ncached_max = (cache_bin_sz_t)ncached_max;
-}
-
-void
-cache_bin_info_compute_alloc(cache_bin_info_t *infos, szind_t ninfos,
- size_t *size, size_t *alignment) {
- /* For the total bin stack region (per tcache), reserve 2 more slots so
- * that
- * 1) the empty position can be safely read on the fast path before
- * checking "is_empty"; and
- * 2) the cur_ptr can go beyond the empty position by 1 step safely on
- * the fast path (i.e. no overflow).
- */
- *size = sizeof(void *) * 2;
- for (szind_t i = 0; i < ninfos; i++) {
- assert(infos[i].ncached_max > 0);
- *size += infos[i].ncached_max * sizeof(void *);
- }
-
- /*
- * Align to at least PAGE, to minimize the # of TLBs needed by the
- * smaller sizes; also helps if the larger sizes don't get used at all.
- */
- *alignment = PAGE;
-}
-
-void
-cache_bin_preincrement(cache_bin_info_t *infos, szind_t ninfos, void *alloc,
- size_t *cur_offset) {
- if (config_debug) {
- size_t computed_size;
- size_t computed_alignment;
-
- /* Pointer should be as aligned as we asked for. */
- cache_bin_info_compute_alloc(infos, ninfos, &computed_size,
- &computed_alignment);
- assert(((uintptr_t)alloc & (computed_alignment - 1)) == 0);
- }
-
- *(uintptr_t *)((uintptr_t)alloc + *cur_offset) =
- cache_bin_preceding_junk;
- *cur_offset += sizeof(void *);
-}
-
-void
-cache_bin_postincrement(cache_bin_info_t *infos, szind_t ninfos, void *alloc,
- size_t *cur_offset) {
- *(uintptr_t *)((uintptr_t)alloc + *cur_offset) =
- cache_bin_trailing_junk;
- *cur_offset += sizeof(void *);
-}
-
-void
-cache_bin_init(cache_bin_t *bin, cache_bin_info_t *info, void *alloc,
- size_t *cur_offset) {
- /*
- * The full_position points to the lowest available space. Allocations
- * will access the slots toward higher addresses (for the benefit of
- * adjacent prefetch).
- */
- void *stack_cur = (void *)((uintptr_t)alloc + *cur_offset);
- void *full_position = stack_cur;
- uint16_t bin_stack_size = info->ncached_max * sizeof(void *);
-
- *cur_offset += bin_stack_size;
- void *empty_position = (void *)((uintptr_t)alloc + *cur_offset);
-
- /* Init to the empty position. */
- bin->stack_head = (void **)empty_position;
- bin->low_bits_low_water = (uint16_t)(uintptr_t)bin->stack_head;
- bin->low_bits_full = (uint16_t)(uintptr_t)full_position;
- bin->low_bits_empty = (uint16_t)(uintptr_t)empty_position;
- cache_bin_sz_t free_spots = cache_bin_diff(bin,
- bin->low_bits_full, (uint16_t)(uintptr_t)bin->stack_head,
- /* racy */ false);
- assert(free_spots == bin_stack_size);
- assert(cache_bin_ncached_get_local(bin, info) == 0);
- assert(cache_bin_empty_position_get(bin) == empty_position);
-
- assert(bin_stack_size > 0 || empty_position == full_position);
-}
-
-bool
-cache_bin_still_zero_initialized(cache_bin_t *bin) {
- return bin->stack_head == NULL;
-}
diff --git a/fluent-bit/lib/jemalloc-5.3.0/src/ckh.c b/fluent-bit/lib/jemalloc-5.3.0/src/ckh.c
deleted file mode 100644
index 8db4319c..00000000
--- a/fluent-bit/lib/jemalloc-5.3.0/src/ckh.c
+++ /dev/null
@@ -1,569 +0,0 @@
-/*
- *******************************************************************************
- * Implementation of (2^1+,2) cuckoo hashing, where 2^1+ indicates that each
- * hash bucket contains 2^n cells, for n >= 1, and 2 indicates that two hash
- * functions are employed. The original cuckoo hashing algorithm was described
- * in:
- *
- * Pagh, R., F.F. Rodler (2004) Cuckoo Hashing. Journal of Algorithms
- * 51(2):122-144.
- *
- * Generalization of cuckoo hashing was discussed in:
- *
- * Erlingsson, U., M. Manasse, F. McSherry (2006) A cool and practical
- * alternative to traditional hash tables. In Proceedings of the 7th
- * Workshop on Distributed Data and Structures (WDAS'06), Santa Clara, CA,
- * January 2006.
- *
- * This implementation uses precisely two hash functions because that is the
- * fewest that can work, and supporting multiple hashes is an implementation
- * burden. Here is a reproduction of Figure 1 from Erlingsson et al. (2006)
- * that shows approximate expected maximum load factors for various
- * configurations:
- *
- * | #cells/bucket |
- * #hashes | 1 | 2 | 4 | 8 |
- * --------+-------+-------+-------+-------+
- * 1 | 0.006 | 0.006 | 0.03 | 0.12 |
- * 2 | 0.49 | 0.86 |>0.93< |>0.96< |
- * 3 | 0.91 | 0.97 | 0.98 | 0.999 |
- * 4 | 0.97 | 0.99 | 0.999 | |
- *
- * The number of cells per bucket is chosen such that a bucket fits in one cache
- * line. So, on 32- and 64-bit systems, we use (8,2) and (4,2) cuckoo hashing,
- * respectively.
- *
- ******************************************************************************/
-#include "jemalloc/internal/jemalloc_preamble.h"
-
-#include "jemalloc/internal/ckh.h"
-
-#include "jemalloc/internal/jemalloc_internal_includes.h"
-
-#include "jemalloc/internal/assert.h"
-#include "jemalloc/internal/hash.h"
-#include "jemalloc/internal/malloc_io.h"
-#include "jemalloc/internal/prng.h"
-#include "jemalloc/internal/util.h"
-
-/******************************************************************************/
-/* Function prototypes for non-inline static functions. */
-
-static bool ckh_grow(tsd_t *tsd, ckh_t *ckh);
-static void ckh_shrink(tsd_t *tsd, ckh_t *ckh);
-
-/******************************************************************************/
-
-/*
- * Search bucket for key and return the cell number if found; SIZE_T_MAX
- * otherwise.
- */
-static size_t
-ckh_bucket_search(ckh_t *ckh, size_t bucket, const void *key) {
- ckhc_t *cell;
- unsigned i;
-
- for (i = 0; i < (ZU(1) << LG_CKH_BUCKET_CELLS); i++) {
- cell = &ckh->tab[(bucket << LG_CKH_BUCKET_CELLS) + i];
- if (cell->key != NULL && ckh->keycomp(key, cell->key)) {
- return (bucket << LG_CKH_BUCKET_CELLS) + i;
- }
- }
-
- return SIZE_T_MAX;
-}
-
-/*
- * Search table for key and return cell number if found; SIZE_T_MAX otherwise.
- */
-static size_t
-ckh_isearch(ckh_t *ckh, const void *key) {
- size_t hashes[2], bucket, cell;
-
- assert(ckh != NULL);
-
- ckh->hash(key, hashes);
-
- /* Search primary bucket. */
- bucket = hashes[0] & ((ZU(1) << ckh->lg_curbuckets) - 1);
- cell = ckh_bucket_search(ckh, bucket, key);
- if (cell != SIZE_T_MAX) {
- return cell;
- }
-
- /* Search secondary bucket. */
- bucket = hashes[1] & ((ZU(1) << ckh->lg_curbuckets) - 1);
- cell = ckh_bucket_search(ckh, bucket, key);
- return cell;
-}
-
-static bool
-ckh_try_bucket_insert(ckh_t *ckh, size_t bucket, const void *key,
- const void *data) {
- ckhc_t *cell;
- unsigned offset, i;
-
- /*
- * Cycle through the cells in the bucket, starting at a random position.
- * The randomness avoids worst-case search overhead as buckets fill up.
- */
- offset = (unsigned)prng_lg_range_u64(&ckh->prng_state,
- LG_CKH_BUCKET_CELLS);
- for (i = 0; i < (ZU(1) << LG_CKH_BUCKET_CELLS); i++) {
- cell = &ckh->tab[(bucket << LG_CKH_BUCKET_CELLS) +
- ((i + offset) & ((ZU(1) << LG_CKH_BUCKET_CELLS) - 1))];
- if (cell->key == NULL) {
- cell->key = key;
- cell->data = data;
- ckh->count++;
- return false;
- }
- }
-
- return true;
-}
-
-/*
- * No space is available in bucket. Randomly evict an item, then try to find an
- * alternate location for that item. Iteratively repeat this
- * eviction/relocation procedure until either success or detection of an
- * eviction/relocation bucket cycle.
- */
-static bool
-ckh_evict_reloc_insert(ckh_t *ckh, size_t argbucket, void const **argkey,
- void const **argdata) {
- const void *key, *data, *tkey, *tdata;
- ckhc_t *cell;
- size_t hashes[2], bucket, tbucket;
- unsigned i;
-
- bucket = argbucket;
- key = *argkey;
- data = *argdata;
- while (true) {
- /*
- * Choose a random item within the bucket to evict. This is
- * critical to correct function, because without (eventually)
- * evicting all items within a bucket during iteration, it
- * would be possible to get stuck in an infinite loop if there
- * were an item for which both hashes indicated the same
- * bucket.
- */
- i = (unsigned)prng_lg_range_u64(&ckh->prng_state,
- LG_CKH_BUCKET_CELLS);
- cell = &ckh->tab[(bucket << LG_CKH_BUCKET_CELLS) + i];
- assert(cell->key != NULL);
-
- /* Swap cell->{key,data} and {key,data} (evict). */
- tkey = cell->key; tdata = cell->data;
- cell->key = key; cell->data = data;
- key = tkey; data = tdata;
-
-#ifdef CKH_COUNT
- ckh->nrelocs++;
-#endif
-
- /* Find the alternate bucket for the evicted item. */
- ckh->hash(key, hashes);
- tbucket = hashes[1] & ((ZU(1) << ckh->lg_curbuckets) - 1);
- if (tbucket == bucket) {
- tbucket = hashes[0] & ((ZU(1) << ckh->lg_curbuckets)
- - 1);
- /*
- * It may be that (tbucket == bucket) still, if the
- * item's hashes both indicate this bucket. However,
- * we are guaranteed to eventually escape this bucket
- * during iteration, assuming pseudo-random item
- * selection (true randomness would make infinite
- * looping a remote possibility). The reason we can
- * never get trapped forever is that there are two
- * cases:
- *
- * 1) This bucket == argbucket, so we will quickly
- * detect an eviction cycle and terminate.
- * 2) An item was evicted to this bucket from another,
- * which means that at least one item in this bucket
- * has hashes that indicate distinct buckets.
- */
- }
- /* Check for a cycle. */
- if (tbucket == argbucket) {
- *argkey = key;
- *argdata = data;
- return true;
- }
-
- bucket = tbucket;
- if (!ckh_try_bucket_insert(ckh, bucket, key, data)) {
- return false;
- }
- }
-}
-
-static bool
-ckh_try_insert(ckh_t *ckh, void const**argkey, void const**argdata) {
- size_t hashes[2], bucket;
- const void *key = *argkey;
- const void *data = *argdata;
-
- ckh->hash(key, hashes);
-
- /* Try to insert in primary bucket. */
- bucket = hashes[0] & ((ZU(1) << ckh->lg_curbuckets) - 1);
- if (!ckh_try_bucket_insert(ckh, bucket, key, data)) {
- return false;
- }
-
- /* Try to insert in secondary bucket. */
- bucket = hashes[1] & ((ZU(1) << ckh->lg_curbuckets) - 1);
- if (!ckh_try_bucket_insert(ckh, bucket, key, data)) {
- return false;
- }
-
- /*
- * Try to find a place for this item via iterative eviction/relocation.
- */
- return ckh_evict_reloc_insert(ckh, bucket, argkey, argdata);
-}
-
-/*
- * Try to rebuild the hash table from scratch by inserting all items from the
- * old table into the new.
- */
-static bool
-ckh_rebuild(ckh_t *ckh, ckhc_t *aTab) {
- size_t count, i, nins;
- const void *key, *data;
-
- count = ckh->count;
- ckh->count = 0;
- for (i = nins = 0; nins < count; i++) {
- if (aTab[i].key != NULL) {
- key = aTab[i].key;
- data = aTab[i].data;
- if (ckh_try_insert(ckh, &key, &data)) {
- ckh->count = count;
- return true;
- }
- nins++;
- }
- }
-
- return false;
-}
-
-static bool
-ckh_grow(tsd_t *tsd, ckh_t *ckh) {
- bool ret;
- ckhc_t *tab, *ttab;
- unsigned lg_prevbuckets, lg_curcells;
-
-#ifdef CKH_COUNT
- ckh->ngrows++;
-#endif
-
- /*
- * It is possible (though unlikely, given well behaved hashes) that the
- * table will have to be doubled more than once in order to create a
- * usable table.
- */
- lg_prevbuckets = ckh->lg_curbuckets;
- lg_curcells = ckh->lg_curbuckets + LG_CKH_BUCKET_CELLS;
- while (true) {
- size_t usize;
-
- lg_curcells++;
- usize = sz_sa2u(sizeof(ckhc_t) << lg_curcells, CACHELINE);
- if (unlikely(usize == 0
- || usize > SC_LARGE_MAXCLASS)) {
- ret = true;
- goto label_return;
- }
- tab = (ckhc_t *)ipallocztm(tsd_tsdn(tsd), usize, CACHELINE,
- true, NULL, true, arena_ichoose(tsd, NULL));
- if (tab == NULL) {
- ret = true;
- goto label_return;
- }
- /* Swap in new table. */
- ttab = ckh->tab;
- ckh->tab = tab;
- tab = ttab;
- ckh->lg_curbuckets = lg_curcells - LG_CKH_BUCKET_CELLS;
-
- if (!ckh_rebuild(ckh, tab)) {
- idalloctm(tsd_tsdn(tsd), tab, NULL, NULL, true, true);
- break;
- }
-
- /* Rebuilding failed, so back out partially rebuilt table. */
- idalloctm(tsd_tsdn(tsd), ckh->tab, NULL, NULL, true, true);
- ckh->tab = tab;
- ckh->lg_curbuckets = lg_prevbuckets;
- }
-
- ret = false;
-label_return:
- return ret;
-}
-
-static void
-ckh_shrink(tsd_t *tsd, ckh_t *ckh) {
- ckhc_t *tab, *ttab;
- size_t usize;
- unsigned lg_prevbuckets, lg_curcells;
-
- /*
- * It is possible (though unlikely, given well behaved hashes) that the
- * table rebuild will fail.
- */
- lg_prevbuckets = ckh->lg_curbuckets;
- lg_curcells = ckh->lg_curbuckets + LG_CKH_BUCKET_CELLS - 1;
- usize = sz_sa2u(sizeof(ckhc_t) << lg_curcells, CACHELINE);
- if (unlikely(usize == 0 || usize > SC_LARGE_MAXCLASS)) {
- return;
- }
- tab = (ckhc_t *)ipallocztm(tsd_tsdn(tsd), usize, CACHELINE, true, NULL,
- true, arena_ichoose(tsd, NULL));
- if (tab == NULL) {
- /*
- * An OOM error isn't worth propagating, since it doesn't
- * prevent this or future operations from proceeding.
- */
- return;
- }
- /* Swap in new table. */
- ttab = ckh->tab;
- ckh->tab = tab;
- tab = ttab;
- ckh->lg_curbuckets = lg_curcells - LG_CKH_BUCKET_CELLS;
-
- if (!ckh_rebuild(ckh, tab)) {
- idalloctm(tsd_tsdn(tsd), tab, NULL, NULL, true, true);
-#ifdef CKH_COUNT
- ckh->nshrinks++;
-#endif
- return;
- }
-
- /* Rebuilding failed, so back out partially rebuilt table. */
- idalloctm(tsd_tsdn(tsd), ckh->tab, NULL, NULL, true, true);
- ckh->tab = tab;
- ckh->lg_curbuckets = lg_prevbuckets;
-#ifdef CKH_COUNT
- ckh->nshrinkfails++;
-#endif
-}
-
-bool
-ckh_new(tsd_t *tsd, ckh_t *ckh, size_t minitems, ckh_hash_t *ckh_hash,
- ckh_keycomp_t *keycomp) {
- bool ret;
- size_t mincells, usize;
- unsigned lg_mincells;
-
- assert(minitems > 0);
- assert(ckh_hash != NULL);
- assert(keycomp != NULL);
-
-#ifdef CKH_COUNT
- ckh->ngrows = 0;
- ckh->nshrinks = 0;
- ckh->nshrinkfails = 0;
- ckh->ninserts = 0;
- ckh->nrelocs = 0;
-#endif
- ckh->prng_state = 42; /* Value doesn't really matter. */
- ckh->count = 0;
-
- /*
- * Find the minimum power of 2 that is large enough to fit minitems
- * entries. We are using (2+,2) cuckoo hashing, which has an expected
- * maximum load factor of at least ~0.86, so 0.75 is a conservative load
- * factor that will typically allow mincells items to fit without ever
- * growing the table.
- */
- assert(LG_CKH_BUCKET_CELLS > 0);
- mincells = ((minitems + (3 - (minitems % 3))) / 3) << 2;
- for (lg_mincells = LG_CKH_BUCKET_CELLS;
- (ZU(1) << lg_mincells) < mincells;
- lg_mincells++) {
- /* Do nothing. */
- }
- ckh->lg_minbuckets = lg_mincells - LG_CKH_BUCKET_CELLS;
- ckh->lg_curbuckets = lg_mincells - LG_CKH_BUCKET_CELLS;
- ckh->hash = ckh_hash;
- ckh->keycomp = keycomp;
-
- usize = sz_sa2u(sizeof(ckhc_t) << lg_mincells, CACHELINE);
- if (unlikely(usize == 0 || usize > SC_LARGE_MAXCLASS)) {
- ret = true;
- goto label_return;
- }
- ckh->tab = (ckhc_t *)ipallocztm(tsd_tsdn(tsd), usize, CACHELINE, true,
- NULL, true, arena_ichoose(tsd, NULL));
- if (ckh->tab == NULL) {
- ret = true;
- goto label_return;
- }
-
- ret = false;
-label_return:
- return ret;
-}
-
-void
-ckh_delete(tsd_t *tsd, ckh_t *ckh) {
- assert(ckh != NULL);
-
-#ifdef CKH_VERBOSE
- malloc_printf(
- "%s(%p): ngrows: %"FMTu64", nshrinks: %"FMTu64","
- " nshrinkfails: %"FMTu64", ninserts: %"FMTu64","
- " nrelocs: %"FMTu64"\n", __func__, ckh,
- (unsigned long long)ckh->ngrows,
- (unsigned long long)ckh->nshrinks,
- (unsigned long long)ckh->nshrinkfails,
- (unsigned long long)ckh->ninserts,
- (unsigned long long)ckh->nrelocs);
-#endif
-
- idalloctm(tsd_tsdn(tsd), ckh->tab, NULL, NULL, true, true);
- if (config_debug) {
- memset(ckh, JEMALLOC_FREE_JUNK, sizeof(ckh_t));
- }
-}
-
-size_t
-ckh_count(ckh_t *ckh) {
- assert(ckh != NULL);
-
- return ckh->count;
-}
-
-bool
-ckh_iter(ckh_t *ckh, size_t *tabind, void **key, void **data) {
- size_t i, ncells;
-
- for (i = *tabind, ncells = (ZU(1) << (ckh->lg_curbuckets +
- LG_CKH_BUCKET_CELLS)); i < ncells; i++) {
- if (ckh->tab[i].key != NULL) {
- if (key != NULL) {
- *key = (void *)ckh->tab[i].key;
- }
- if (data != NULL) {
- *data = (void *)ckh->tab[i].data;
- }
- *tabind = i + 1;
- return false;
- }
- }
-
- return true;
-}
-
-bool
-ckh_insert(tsd_t *tsd, ckh_t *ckh, const void *key, const void *data) {
- bool ret;
-
- assert(ckh != NULL);
- assert(ckh_search(ckh, key, NULL, NULL));
-
-#ifdef CKH_COUNT
- ckh->ninserts++;
-#endif
-
- while (ckh_try_insert(ckh, &key, &data)) {
- if (ckh_grow(tsd, ckh)) {
- ret = true;
- goto label_return;
- }
- }
-
- ret = false;
-label_return:
- return ret;
-}
-
-bool
-ckh_remove(tsd_t *tsd, ckh_t *ckh, const void *searchkey, void **key,
- void **data) {
- size_t cell;
-
- assert(ckh != NULL);
-
- cell = ckh_isearch(ckh, searchkey);
- if (cell != SIZE_T_MAX) {
- if (key != NULL) {
- *key = (void *)ckh->tab[cell].key;
- }
- if (data != NULL) {
- *data = (void *)ckh->tab[cell].data;
- }
- ckh->tab[cell].key = NULL;
- ckh->tab[cell].data = NULL; /* Not necessary. */
-
- ckh->count--;
- /* Try to halve the table if it is less than 1/4 full. */
- if (ckh->count < (ZU(1) << (ckh->lg_curbuckets
- + LG_CKH_BUCKET_CELLS - 2)) && ckh->lg_curbuckets
- > ckh->lg_minbuckets) {
- /* Ignore error due to OOM. */
- ckh_shrink(tsd, ckh);
- }
-
- return false;
- }
-
- return true;
-}
-
-bool
-ckh_search(ckh_t *ckh, const void *searchkey, void **key, void **data) {
- size_t cell;
-
- assert(ckh != NULL);
-
- cell = ckh_isearch(ckh, searchkey);
- if (cell != SIZE_T_MAX) {
- if (key != NULL) {
- *key = (void *)ckh->tab[cell].key;
- }
- if (data != NULL) {
- *data = (void *)ckh->tab[cell].data;
- }
- return false;
- }
-
- return true;
-}
-
-void
-ckh_string_hash(const void *key, size_t r_hash[2]) {
- hash(key, strlen((const char *)key), 0x94122f33U, r_hash);
-}
-
-bool
-ckh_string_keycomp(const void *k1, const void *k2) {
- assert(k1 != NULL);
- assert(k2 != NULL);
-
- return !strcmp((char *)k1, (char *)k2);
-}
-
-void
-ckh_pointer_hash(const void *key, size_t r_hash[2]) {
- union {
- const void *v;
- size_t i;
- } u;
-
- assert(sizeof(u.v) == sizeof(u.i));
- u.v = key;
- hash(&u.i, sizeof(u.i), 0xd983396eU, r_hash);
-}
-
-bool
-ckh_pointer_keycomp(const void *k1, const void *k2) {
- return (k1 == k2);
-}
diff --git a/fluent-bit/lib/jemalloc-5.3.0/src/counter.c b/fluent-bit/lib/jemalloc-5.3.0/src/counter.c
deleted file mode 100644
index 8f1ae3af..00000000
--- a/fluent-bit/lib/jemalloc-5.3.0/src/counter.c
+++ /dev/null
@@ -1,30 +0,0 @@
-#include "jemalloc/internal/jemalloc_preamble.h"
-#include "jemalloc/internal/jemalloc_internal_includes.h"
-
-#include "jemalloc/internal/counter.h"
-
-bool
-counter_accum_init(counter_accum_t *counter, uint64_t interval) {
- if (LOCKEDINT_MTX_INIT(counter->mtx, "counter_accum",
- WITNESS_RANK_COUNTER_ACCUM, malloc_mutex_rank_exclusive)) {
- return true;
- }
- locked_init_u64_unsynchronized(&counter->accumbytes, 0);
- counter->interval = interval;
- return false;
-}
-
-void
-counter_prefork(tsdn_t *tsdn, counter_accum_t *counter) {
- LOCKEDINT_MTX_PREFORK(tsdn, counter->mtx);
-}
-
-void
-counter_postfork_parent(tsdn_t *tsdn, counter_accum_t *counter) {
- LOCKEDINT_MTX_POSTFORK_PARENT(tsdn, counter->mtx);
-}
-
-void
-counter_postfork_child(tsdn_t *tsdn, counter_accum_t *counter) {
- LOCKEDINT_MTX_POSTFORK_CHILD(tsdn, counter->mtx);
-}
diff --git a/fluent-bit/lib/jemalloc-5.3.0/src/ctl.c b/fluent-bit/lib/jemalloc-5.3.0/src/ctl.c
deleted file mode 100644
index 135271ba..00000000
--- a/fluent-bit/lib/jemalloc-5.3.0/src/ctl.c
+++ /dev/null
@@ -1,4414 +0,0 @@
-#include "jemalloc/internal/jemalloc_preamble.h"
-#include "jemalloc/internal/jemalloc_internal_includes.h"
-
-#include "jemalloc/internal/assert.h"
-#include "jemalloc/internal/ctl.h"
-#include "jemalloc/internal/extent_dss.h"
-#include "jemalloc/internal/extent_mmap.h"
-#include "jemalloc/internal/inspect.h"
-#include "jemalloc/internal/mutex.h"
-#include "jemalloc/internal/nstime.h"
-#include "jemalloc/internal/peak_event.h"
-#include "jemalloc/internal/prof_data.h"
-#include "jemalloc/internal/prof_log.h"
-#include "jemalloc/internal/prof_recent.h"
-#include "jemalloc/internal/prof_stats.h"
-#include "jemalloc/internal/prof_sys.h"
-#include "jemalloc/internal/safety_check.h"
-#include "jemalloc/internal/sc.h"
-#include "jemalloc/internal/util.h"
-
-/******************************************************************************/
-/* Data. */
-
-/*
- * ctl_mtx protects the following:
- * - ctl_stats->*
- */
-static malloc_mutex_t ctl_mtx;
-static bool ctl_initialized;
-static ctl_stats_t *ctl_stats;
-static ctl_arenas_t *ctl_arenas;
-
-/******************************************************************************/
-/* Helpers for named and indexed nodes. */
-
-static const ctl_named_node_t *
-ctl_named_node(const ctl_node_t *node) {
- return ((node->named) ? (const ctl_named_node_t *)node : NULL);
-}
-
-static const ctl_named_node_t *
-ctl_named_children(const ctl_named_node_t *node, size_t index) {
- const ctl_named_node_t *children = ctl_named_node(node->children);
-
- return (children ? &children[index] : NULL);
-}
-
-static const ctl_indexed_node_t *
-ctl_indexed_node(const ctl_node_t *node) {
- return (!node->named ? (const ctl_indexed_node_t *)node : NULL);
-}
-
-/******************************************************************************/
-/* Function prototypes for non-inline static functions. */
-
-#define CTL_PROTO(n) \
-static int n##_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, \
- void *oldp, size_t *oldlenp, void *newp, size_t newlen);
-
-#define INDEX_PROTO(n) \
-static const ctl_named_node_t *n##_index(tsdn_t *tsdn, \
- const size_t *mib, size_t miblen, size_t i);
-
-CTL_PROTO(version)
-CTL_PROTO(epoch)
-CTL_PROTO(background_thread)
-CTL_PROTO(max_background_threads)
-CTL_PROTO(thread_tcache_enabled)
-CTL_PROTO(thread_tcache_flush)
-CTL_PROTO(thread_peak_read)
-CTL_PROTO(thread_peak_reset)
-CTL_PROTO(thread_prof_name)
-CTL_PROTO(thread_prof_active)
-CTL_PROTO(thread_arena)
-CTL_PROTO(thread_allocated)
-CTL_PROTO(thread_allocatedp)
-CTL_PROTO(thread_deallocated)
-CTL_PROTO(thread_deallocatedp)
-CTL_PROTO(thread_idle)
-CTL_PROTO(config_cache_oblivious)
-CTL_PROTO(config_debug)
-CTL_PROTO(config_fill)
-CTL_PROTO(config_lazy_lock)
-CTL_PROTO(config_malloc_conf)
-CTL_PROTO(config_opt_safety_checks)
-CTL_PROTO(config_prof)
-CTL_PROTO(config_prof_libgcc)
-CTL_PROTO(config_prof_libunwind)
-CTL_PROTO(config_stats)
-CTL_PROTO(config_utrace)
-CTL_PROTO(config_xmalloc)
-CTL_PROTO(opt_abort)
-CTL_PROTO(opt_abort_conf)
-CTL_PROTO(opt_cache_oblivious)
-CTL_PROTO(opt_trust_madvise)
-CTL_PROTO(opt_confirm_conf)
-CTL_PROTO(opt_hpa)
-CTL_PROTO(opt_hpa_slab_max_alloc)
-CTL_PROTO(opt_hpa_hugification_threshold)
-CTL_PROTO(opt_hpa_hugify_delay_ms)
-CTL_PROTO(opt_hpa_min_purge_interval_ms)
-CTL_PROTO(opt_hpa_dirty_mult)
-CTL_PROTO(opt_hpa_sec_nshards)
-CTL_PROTO(opt_hpa_sec_max_alloc)
-CTL_PROTO(opt_hpa_sec_max_bytes)
-CTL_PROTO(opt_hpa_sec_bytes_after_flush)
-CTL_PROTO(opt_hpa_sec_batch_fill_extra)
-CTL_PROTO(opt_metadata_thp)
-CTL_PROTO(opt_retain)
-CTL_PROTO(opt_dss)
-CTL_PROTO(opt_narenas)
-CTL_PROTO(opt_percpu_arena)
-CTL_PROTO(opt_oversize_threshold)
-CTL_PROTO(opt_background_thread)
-CTL_PROTO(opt_mutex_max_spin)
-CTL_PROTO(opt_max_background_threads)
-CTL_PROTO(opt_dirty_decay_ms)
-CTL_PROTO(opt_muzzy_decay_ms)
-CTL_PROTO(opt_stats_print)
-CTL_PROTO(opt_stats_print_opts)
-CTL_PROTO(opt_stats_interval)
-CTL_PROTO(opt_stats_interval_opts)
-CTL_PROTO(opt_junk)
-CTL_PROTO(opt_zero)
-CTL_PROTO(opt_utrace)
-CTL_PROTO(opt_xmalloc)
-CTL_PROTO(opt_experimental_infallible_new)
-CTL_PROTO(opt_tcache)
-CTL_PROTO(opt_tcache_max)
-CTL_PROTO(opt_tcache_nslots_small_min)
-CTL_PROTO(opt_tcache_nslots_small_max)
-CTL_PROTO(opt_tcache_nslots_large)
-CTL_PROTO(opt_lg_tcache_nslots_mul)
-CTL_PROTO(opt_tcache_gc_incr_bytes)
-CTL_PROTO(opt_tcache_gc_delay_bytes)
-CTL_PROTO(opt_lg_tcache_flush_small_div)
-CTL_PROTO(opt_lg_tcache_flush_large_div)
-CTL_PROTO(opt_thp)
-CTL_PROTO(opt_lg_extent_max_active_fit)
-CTL_PROTO(opt_prof)
-CTL_PROTO(opt_prof_prefix)
-CTL_PROTO(opt_prof_active)
-CTL_PROTO(opt_prof_thread_active_init)
-CTL_PROTO(opt_lg_prof_sample)
-CTL_PROTO(opt_lg_prof_interval)
-CTL_PROTO(opt_prof_gdump)
-CTL_PROTO(opt_prof_final)
-CTL_PROTO(opt_prof_leak)
-CTL_PROTO(opt_prof_leak_error)
-CTL_PROTO(opt_prof_accum)
-CTL_PROTO(opt_prof_recent_alloc_max)
-CTL_PROTO(opt_prof_stats)
-CTL_PROTO(opt_prof_sys_thread_name)
-CTL_PROTO(opt_prof_time_res)
-CTL_PROTO(opt_lg_san_uaf_align)
-CTL_PROTO(opt_zero_realloc)
-CTL_PROTO(tcache_create)
-CTL_PROTO(tcache_flush)
-CTL_PROTO(tcache_destroy)
-CTL_PROTO(arena_i_initialized)
-CTL_PROTO(arena_i_decay)
-CTL_PROTO(arena_i_purge)
-CTL_PROTO(arena_i_reset)
-CTL_PROTO(arena_i_destroy)
-CTL_PROTO(arena_i_dss)
-CTL_PROTO(arena_i_oversize_threshold)
-CTL_PROTO(arena_i_dirty_decay_ms)
-CTL_PROTO(arena_i_muzzy_decay_ms)
-CTL_PROTO(arena_i_extent_hooks)
-CTL_PROTO(arena_i_retain_grow_limit)
-INDEX_PROTO(arena_i)
-CTL_PROTO(arenas_bin_i_size)
-CTL_PROTO(arenas_bin_i_nregs)
-CTL_PROTO(arenas_bin_i_slab_size)
-CTL_PROTO(arenas_bin_i_nshards)
-INDEX_PROTO(arenas_bin_i)
-CTL_PROTO(arenas_lextent_i_size)
-INDEX_PROTO(arenas_lextent_i)
-CTL_PROTO(arenas_narenas)
-CTL_PROTO(arenas_dirty_decay_ms)
-CTL_PROTO(arenas_muzzy_decay_ms)
-CTL_PROTO(arenas_quantum)
-CTL_PROTO(arenas_page)
-CTL_PROTO(arenas_tcache_max)
-CTL_PROTO(arenas_nbins)
-CTL_PROTO(arenas_nhbins)
-CTL_PROTO(arenas_nlextents)
-CTL_PROTO(arenas_create)
-CTL_PROTO(arenas_lookup)
-CTL_PROTO(prof_thread_active_init)
-CTL_PROTO(prof_active)
-CTL_PROTO(prof_dump)
-CTL_PROTO(prof_gdump)
-CTL_PROTO(prof_prefix)
-CTL_PROTO(prof_reset)
-CTL_PROTO(prof_interval)
-CTL_PROTO(lg_prof_sample)
-CTL_PROTO(prof_log_start)
-CTL_PROTO(prof_log_stop)
-CTL_PROTO(prof_stats_bins_i_live)
-CTL_PROTO(prof_stats_bins_i_accum)
-INDEX_PROTO(prof_stats_bins_i)
-CTL_PROTO(prof_stats_lextents_i_live)
-CTL_PROTO(prof_stats_lextents_i_accum)
-INDEX_PROTO(prof_stats_lextents_i)
-CTL_PROTO(stats_arenas_i_small_allocated)
-CTL_PROTO(stats_arenas_i_small_nmalloc)
-CTL_PROTO(stats_arenas_i_small_ndalloc)
-CTL_PROTO(stats_arenas_i_small_nrequests)
-CTL_PROTO(stats_arenas_i_small_nfills)
-CTL_PROTO(stats_arenas_i_small_nflushes)
-CTL_PROTO(stats_arenas_i_large_allocated)
-CTL_PROTO(stats_arenas_i_large_nmalloc)
-CTL_PROTO(stats_arenas_i_large_ndalloc)
-CTL_PROTO(stats_arenas_i_large_nrequests)
-CTL_PROTO(stats_arenas_i_large_nfills)
-CTL_PROTO(stats_arenas_i_large_nflushes)
-CTL_PROTO(stats_arenas_i_bins_j_nmalloc)
-CTL_PROTO(stats_arenas_i_bins_j_ndalloc)
-CTL_PROTO(stats_arenas_i_bins_j_nrequests)
-CTL_PROTO(stats_arenas_i_bins_j_curregs)
-CTL_PROTO(stats_arenas_i_bins_j_nfills)
-CTL_PROTO(stats_arenas_i_bins_j_nflushes)
-CTL_PROTO(stats_arenas_i_bins_j_nslabs)
-CTL_PROTO(stats_arenas_i_bins_j_nreslabs)
-CTL_PROTO(stats_arenas_i_bins_j_curslabs)
-CTL_PROTO(stats_arenas_i_bins_j_nonfull_slabs)
-INDEX_PROTO(stats_arenas_i_bins_j)
-CTL_PROTO(stats_arenas_i_lextents_j_nmalloc)
-CTL_PROTO(stats_arenas_i_lextents_j_ndalloc)
-CTL_PROTO(stats_arenas_i_lextents_j_nrequests)
-CTL_PROTO(stats_arenas_i_lextents_j_curlextents)
-INDEX_PROTO(stats_arenas_i_lextents_j)
-CTL_PROTO(stats_arenas_i_extents_j_ndirty)
-CTL_PROTO(stats_arenas_i_extents_j_nmuzzy)
-CTL_PROTO(stats_arenas_i_extents_j_nretained)
-CTL_PROTO(stats_arenas_i_extents_j_dirty_bytes)
-CTL_PROTO(stats_arenas_i_extents_j_muzzy_bytes)
-CTL_PROTO(stats_arenas_i_extents_j_retained_bytes)
-INDEX_PROTO(stats_arenas_i_extents_j)
-CTL_PROTO(stats_arenas_i_hpa_shard_npurge_passes)
-CTL_PROTO(stats_arenas_i_hpa_shard_npurges)
-CTL_PROTO(stats_arenas_i_hpa_shard_nhugifies)
-CTL_PROTO(stats_arenas_i_hpa_shard_ndehugifies)
-
-/* We have a set of stats for full slabs. */
-CTL_PROTO(stats_arenas_i_hpa_shard_full_slabs_npageslabs_nonhuge)
-CTL_PROTO(stats_arenas_i_hpa_shard_full_slabs_npageslabs_huge)
-CTL_PROTO(stats_arenas_i_hpa_shard_full_slabs_nactive_nonhuge)
-CTL_PROTO(stats_arenas_i_hpa_shard_full_slabs_nactive_huge)
-CTL_PROTO(stats_arenas_i_hpa_shard_full_slabs_ndirty_nonhuge)
-CTL_PROTO(stats_arenas_i_hpa_shard_full_slabs_ndirty_huge)
-
-/* A parallel set for the empty slabs. */
-CTL_PROTO(stats_arenas_i_hpa_shard_empty_slabs_npageslabs_nonhuge)
-CTL_PROTO(stats_arenas_i_hpa_shard_empty_slabs_npageslabs_huge)
-CTL_PROTO(stats_arenas_i_hpa_shard_empty_slabs_nactive_nonhuge)
-CTL_PROTO(stats_arenas_i_hpa_shard_empty_slabs_nactive_huge)
-CTL_PROTO(stats_arenas_i_hpa_shard_empty_slabs_ndirty_nonhuge)
-CTL_PROTO(stats_arenas_i_hpa_shard_empty_slabs_ndirty_huge)
-
-/*
- * And one for the slabs that are neither empty nor full, but indexed by how
- * full they are.
- */
-CTL_PROTO(stats_arenas_i_hpa_shard_nonfull_slabs_j_npageslabs_nonhuge)
-CTL_PROTO(stats_arenas_i_hpa_shard_nonfull_slabs_j_npageslabs_huge)
-CTL_PROTO(stats_arenas_i_hpa_shard_nonfull_slabs_j_nactive_nonhuge)
-CTL_PROTO(stats_arenas_i_hpa_shard_nonfull_slabs_j_nactive_huge)
-CTL_PROTO(stats_arenas_i_hpa_shard_nonfull_slabs_j_ndirty_nonhuge)
-CTL_PROTO(stats_arenas_i_hpa_shard_nonfull_slabs_j_ndirty_huge)
-
-INDEX_PROTO(stats_arenas_i_hpa_shard_nonfull_slabs_j)
-CTL_PROTO(stats_arenas_i_nthreads)
-CTL_PROTO(stats_arenas_i_uptime)
-CTL_PROTO(stats_arenas_i_dss)
-CTL_PROTO(stats_arenas_i_dirty_decay_ms)
-CTL_PROTO(stats_arenas_i_muzzy_decay_ms)
-CTL_PROTO(stats_arenas_i_pactive)
-CTL_PROTO(stats_arenas_i_pdirty)
-CTL_PROTO(stats_arenas_i_pmuzzy)
-CTL_PROTO(stats_arenas_i_mapped)
-CTL_PROTO(stats_arenas_i_retained)
-CTL_PROTO(stats_arenas_i_extent_avail)
-CTL_PROTO(stats_arenas_i_dirty_npurge)
-CTL_PROTO(stats_arenas_i_dirty_nmadvise)
-CTL_PROTO(stats_arenas_i_dirty_purged)
-CTL_PROTO(stats_arenas_i_muzzy_npurge)
-CTL_PROTO(stats_arenas_i_muzzy_nmadvise)
-CTL_PROTO(stats_arenas_i_muzzy_purged)
-CTL_PROTO(stats_arenas_i_base)
-CTL_PROTO(stats_arenas_i_internal)
-CTL_PROTO(stats_arenas_i_metadata_thp)
-CTL_PROTO(stats_arenas_i_tcache_bytes)
-CTL_PROTO(stats_arenas_i_tcache_stashed_bytes)
-CTL_PROTO(stats_arenas_i_resident)
-CTL_PROTO(stats_arenas_i_abandoned_vm)
-CTL_PROTO(stats_arenas_i_hpa_sec_bytes)
-INDEX_PROTO(stats_arenas_i)
-CTL_PROTO(stats_allocated)
-CTL_PROTO(stats_active)
-CTL_PROTO(stats_background_thread_num_threads)
-CTL_PROTO(stats_background_thread_num_runs)
-CTL_PROTO(stats_background_thread_run_interval)
-CTL_PROTO(stats_metadata)
-CTL_PROTO(stats_metadata_thp)
-CTL_PROTO(stats_resident)
-CTL_PROTO(stats_mapped)
-CTL_PROTO(stats_retained)
-CTL_PROTO(stats_zero_reallocs)
-CTL_PROTO(experimental_hooks_install)
-CTL_PROTO(experimental_hooks_remove)
-CTL_PROTO(experimental_hooks_prof_backtrace)
-CTL_PROTO(experimental_hooks_prof_dump)
-CTL_PROTO(experimental_hooks_safety_check_abort)
-CTL_PROTO(experimental_thread_activity_callback)
-CTL_PROTO(experimental_utilization_query)
-CTL_PROTO(experimental_utilization_batch_query)
-CTL_PROTO(experimental_arenas_i_pactivep)
-INDEX_PROTO(experimental_arenas_i)
-CTL_PROTO(experimental_prof_recent_alloc_max)
-CTL_PROTO(experimental_prof_recent_alloc_dump)
-CTL_PROTO(experimental_batch_alloc)
-CTL_PROTO(experimental_arenas_create_ext)
-
-#define MUTEX_STATS_CTL_PROTO_GEN(n) \
-CTL_PROTO(stats_##n##_num_ops) \
-CTL_PROTO(stats_##n##_num_wait) \
-CTL_PROTO(stats_##n##_num_spin_acq) \
-CTL_PROTO(stats_##n##_num_owner_switch) \
-CTL_PROTO(stats_##n##_total_wait_time) \
-CTL_PROTO(stats_##n##_max_wait_time) \
-CTL_PROTO(stats_##n##_max_num_thds)
-
-/* Global mutexes. */
-#define OP(mtx) MUTEX_STATS_CTL_PROTO_GEN(mutexes_##mtx)
-MUTEX_PROF_GLOBAL_MUTEXES
-#undef OP
-
-/* Per arena mutexes. */
-#define OP(mtx) MUTEX_STATS_CTL_PROTO_GEN(arenas_i_mutexes_##mtx)
-MUTEX_PROF_ARENA_MUTEXES
-#undef OP
-
-/* Arena bin mutexes. */
-MUTEX_STATS_CTL_PROTO_GEN(arenas_i_bins_j_mutex)
-#undef MUTEX_STATS_CTL_PROTO_GEN
-
-CTL_PROTO(stats_mutexes_reset)
-
-/******************************************************************************/
-/* mallctl tree. */
-
-#define NAME(n) {true}, n
-#define CHILD(t, c) \
- sizeof(c##_node) / sizeof(ctl_##t##_node_t), \
- (ctl_node_t *)c##_node, \
- NULL
-#define CTL(c) 0, NULL, c##_ctl
-
-/*
- * Only handles internal indexed nodes, since there are currently no external
- * ones.
- */
-#define INDEX(i) {false}, i##_index
-
-static const ctl_named_node_t thread_tcache_node[] = {
- {NAME("enabled"), CTL(thread_tcache_enabled)},
- {NAME("flush"), CTL(thread_tcache_flush)}
-};
-
-static const ctl_named_node_t thread_peak_node[] = {
- {NAME("read"), CTL(thread_peak_read)},
- {NAME("reset"), CTL(thread_peak_reset)},
-};
-
-static const ctl_named_node_t thread_prof_node[] = {
- {NAME("name"), CTL(thread_prof_name)},
- {NAME("active"), CTL(thread_prof_active)}
-};
-
-static const ctl_named_node_t thread_node[] = {
- {NAME("arena"), CTL(thread_arena)},
- {NAME("allocated"), CTL(thread_allocated)},
- {NAME("allocatedp"), CTL(thread_allocatedp)},
- {NAME("deallocated"), CTL(thread_deallocated)},
- {NAME("deallocatedp"), CTL(thread_deallocatedp)},
- {NAME("tcache"), CHILD(named, thread_tcache)},
- {NAME("peak"), CHILD(named, thread_peak)},
- {NAME("prof"), CHILD(named, thread_prof)},
- {NAME("idle"), CTL(thread_idle)}
-};
-
-static const ctl_named_node_t config_node[] = {
- {NAME("cache_oblivious"), CTL(config_cache_oblivious)},
- {NAME("debug"), CTL(config_debug)},
- {NAME("fill"), CTL(config_fill)},
- {NAME("lazy_lock"), CTL(config_lazy_lock)},
- {NAME("malloc_conf"), CTL(config_malloc_conf)},
- {NAME("opt_safety_checks"), CTL(config_opt_safety_checks)},
- {NAME("prof"), CTL(config_prof)},
- {NAME("prof_libgcc"), CTL(config_prof_libgcc)},
- {NAME("prof_libunwind"), CTL(config_prof_libunwind)},
- {NAME("stats"), CTL(config_stats)},
- {NAME("utrace"), CTL(config_utrace)},
- {NAME("xmalloc"), CTL(config_xmalloc)}
-};
-
-static const ctl_named_node_t opt_node[] = {
- {NAME("abort"), CTL(opt_abort)},
- {NAME("abort_conf"), CTL(opt_abort_conf)},
- {NAME("cache_oblivious"), CTL(opt_cache_oblivious)},
- {NAME("trust_madvise"), CTL(opt_trust_madvise)},
- {NAME("confirm_conf"), CTL(opt_confirm_conf)},
- {NAME("hpa"), CTL(opt_hpa)},
- {NAME("hpa_slab_max_alloc"), CTL(opt_hpa_slab_max_alloc)},
- {NAME("hpa_hugification_threshold"),
- CTL(opt_hpa_hugification_threshold)},
- {NAME("hpa_hugify_delay_ms"), CTL(opt_hpa_hugify_delay_ms)},
- {NAME("hpa_min_purge_interval_ms"), CTL(opt_hpa_min_purge_interval_ms)},
- {NAME("hpa_dirty_mult"), CTL(opt_hpa_dirty_mult)},
- {NAME("hpa_sec_nshards"), CTL(opt_hpa_sec_nshards)},
- {NAME("hpa_sec_max_alloc"), CTL(opt_hpa_sec_max_alloc)},
- {NAME("hpa_sec_max_bytes"), CTL(opt_hpa_sec_max_bytes)},
- {NAME("hpa_sec_bytes_after_flush"),
- CTL(opt_hpa_sec_bytes_after_flush)},
- {NAME("hpa_sec_batch_fill_extra"),
- CTL(opt_hpa_sec_batch_fill_extra)},
- {NAME("metadata_thp"), CTL(opt_metadata_thp)},
- {NAME("retain"), CTL(opt_retain)},
- {NAME("dss"), CTL(opt_dss)},
- {NAME("narenas"), CTL(opt_narenas)},
- {NAME("percpu_arena"), CTL(opt_percpu_arena)},
- {NAME("oversize_threshold"), CTL(opt_oversize_threshold)},
- {NAME("mutex_max_spin"), CTL(opt_mutex_max_spin)},
- {NAME("background_thread"), CTL(opt_background_thread)},
- {NAME("max_background_threads"), CTL(opt_max_background_threads)},
- {NAME("dirty_decay_ms"), CTL(opt_dirty_decay_ms)},
- {NAME("muzzy_decay_ms"), CTL(opt_muzzy_decay_ms)},
- {NAME("stats_print"), CTL(opt_stats_print)},
- {NAME("stats_print_opts"), CTL(opt_stats_print_opts)},
- {NAME("stats_interval"), CTL(opt_stats_interval)},
- {NAME("stats_interval_opts"), CTL(opt_stats_interval_opts)},
- {NAME("junk"), CTL(opt_junk)},
- {NAME("zero"), CTL(opt_zero)},
- {NAME("utrace"), CTL(opt_utrace)},
- {NAME("xmalloc"), CTL(opt_xmalloc)},
- {NAME("experimental_infallible_new"),
- CTL(opt_experimental_infallible_new)},
- {NAME("tcache"), CTL(opt_tcache)},
- {NAME("tcache_max"), CTL(opt_tcache_max)},
- {NAME("tcache_nslots_small_min"),
- CTL(opt_tcache_nslots_small_min)},
- {NAME("tcache_nslots_small_max"),
- CTL(opt_tcache_nslots_small_max)},
- {NAME("tcache_nslots_large"), CTL(opt_tcache_nslots_large)},
- {NAME("lg_tcache_nslots_mul"), CTL(opt_lg_tcache_nslots_mul)},
- {NAME("tcache_gc_incr_bytes"), CTL(opt_tcache_gc_incr_bytes)},
- {NAME("tcache_gc_delay_bytes"), CTL(opt_tcache_gc_delay_bytes)},
- {NAME("lg_tcache_flush_small_div"),
- CTL(opt_lg_tcache_flush_small_div)},
- {NAME("lg_tcache_flush_large_div"),
- CTL(opt_lg_tcache_flush_large_div)},
- {NAME("thp"), CTL(opt_thp)},
- {NAME("lg_extent_max_active_fit"), CTL(opt_lg_extent_max_active_fit)},
- {NAME("prof"), CTL(opt_prof)},
- {NAME("prof_prefix"), CTL(opt_prof_prefix)},
- {NAME("prof_active"), CTL(opt_prof_active)},
- {NAME("prof_thread_active_init"), CTL(opt_prof_thread_active_init)},
- {NAME("lg_prof_sample"), CTL(opt_lg_prof_sample)},
- {NAME("lg_prof_interval"), CTL(opt_lg_prof_interval)},
- {NAME("prof_gdump"), CTL(opt_prof_gdump)},
- {NAME("prof_final"), CTL(opt_prof_final)},
- {NAME("prof_leak"), CTL(opt_prof_leak)},
- {NAME("prof_leak_error"), CTL(opt_prof_leak_error)},
- {NAME("prof_accum"), CTL(opt_prof_accum)},
- {NAME("prof_recent_alloc_max"), CTL(opt_prof_recent_alloc_max)},
- {NAME("prof_stats"), CTL(opt_prof_stats)},
- {NAME("prof_sys_thread_name"), CTL(opt_prof_sys_thread_name)},
- {NAME("prof_time_resolution"), CTL(opt_prof_time_res)},
- {NAME("lg_san_uaf_align"), CTL(opt_lg_san_uaf_align)},
- {NAME("zero_realloc"), CTL(opt_zero_realloc)}
-};
-
-static const ctl_named_node_t tcache_node[] = {
- {NAME("create"), CTL(tcache_create)},
- {NAME("flush"), CTL(tcache_flush)},
- {NAME("destroy"), CTL(tcache_destroy)}
-};
-
-static const ctl_named_node_t arena_i_node[] = {
- {NAME("initialized"), CTL(arena_i_initialized)},
- {NAME("decay"), CTL(arena_i_decay)},
- {NAME("purge"), CTL(arena_i_purge)},
- {NAME("reset"), CTL(arena_i_reset)},
- {NAME("destroy"), CTL(arena_i_destroy)},
- {NAME("dss"), CTL(arena_i_dss)},
- /*
- * Undocumented for now, since we anticipate an arena API in flux after
- * we cut the last 5-series release.
- */
- {NAME("oversize_threshold"), CTL(arena_i_oversize_threshold)},
- {NAME("dirty_decay_ms"), CTL(arena_i_dirty_decay_ms)},
- {NAME("muzzy_decay_ms"), CTL(arena_i_muzzy_decay_ms)},
- {NAME("extent_hooks"), CTL(arena_i_extent_hooks)},
- {NAME("retain_grow_limit"), CTL(arena_i_retain_grow_limit)}
-};
-static const ctl_named_node_t super_arena_i_node[] = {
- {NAME(""), CHILD(named, arena_i)}
-};
-
-static const ctl_indexed_node_t arena_node[] = {
- {INDEX(arena_i)}
-};
-
-static const ctl_named_node_t arenas_bin_i_node[] = {
- {NAME("size"), CTL(arenas_bin_i_size)},
- {NAME("nregs"), CTL(arenas_bin_i_nregs)},
- {NAME("slab_size"), CTL(arenas_bin_i_slab_size)},
- {NAME("nshards"), CTL(arenas_bin_i_nshards)}
-};
-static const ctl_named_node_t super_arenas_bin_i_node[] = {
- {NAME(""), CHILD(named, arenas_bin_i)}
-};
-
-static const ctl_indexed_node_t arenas_bin_node[] = {
- {INDEX(arenas_bin_i)}
-};
-
-static const ctl_named_node_t arenas_lextent_i_node[] = {
- {NAME("size"), CTL(arenas_lextent_i_size)}
-};
-static const ctl_named_node_t super_arenas_lextent_i_node[] = {
- {NAME(""), CHILD(named, arenas_lextent_i)}
-};
-
-static const ctl_indexed_node_t arenas_lextent_node[] = {
- {INDEX(arenas_lextent_i)}
-};
-
-static const ctl_named_node_t arenas_node[] = {
- {NAME("narenas"), CTL(arenas_narenas)},
- {NAME("dirty_decay_ms"), CTL(arenas_dirty_decay_ms)},
- {NAME("muzzy_decay_ms"), CTL(arenas_muzzy_decay_ms)},
- {NAME("quantum"), CTL(arenas_quantum)},
- {NAME("page"), CTL(arenas_page)},
- {NAME("tcache_max"), CTL(arenas_tcache_max)},
- {NAME("nbins"), CTL(arenas_nbins)},
- {NAME("nhbins"), CTL(arenas_nhbins)},
- {NAME("bin"), CHILD(indexed, arenas_bin)},
- {NAME("nlextents"), CTL(arenas_nlextents)},
- {NAME("lextent"), CHILD(indexed, arenas_lextent)},
- {NAME("create"), CTL(arenas_create)},
- {NAME("lookup"), CTL(arenas_lookup)}
-};
-
-static const ctl_named_node_t prof_stats_bins_i_node[] = {
- {NAME("live"), CTL(prof_stats_bins_i_live)},
- {NAME("accum"), CTL(prof_stats_bins_i_accum)}
-};
-
-static const ctl_named_node_t super_prof_stats_bins_i_node[] = {
- {NAME(""), CHILD(named, prof_stats_bins_i)}
-};
-
-static const ctl_indexed_node_t prof_stats_bins_node[] = {
- {INDEX(prof_stats_bins_i)}
-};
-
-static const ctl_named_node_t prof_stats_lextents_i_node[] = {
- {NAME("live"), CTL(prof_stats_lextents_i_live)},
- {NAME("accum"), CTL(prof_stats_lextents_i_accum)}
-};
-
-static const ctl_named_node_t super_prof_stats_lextents_i_node[] = {
- {NAME(""), CHILD(named, prof_stats_lextents_i)}
-};
-
-static const ctl_indexed_node_t prof_stats_lextents_node[] = {
- {INDEX(prof_stats_lextents_i)}
-};
-
-static const ctl_named_node_t prof_stats_node[] = {
- {NAME("bins"), CHILD(indexed, prof_stats_bins)},
- {NAME("lextents"), CHILD(indexed, prof_stats_lextents)},
-};
-
-static const ctl_named_node_t prof_node[] = {
- {NAME("thread_active_init"), CTL(prof_thread_active_init)},
- {NAME("active"), CTL(prof_active)},
- {NAME("dump"), CTL(prof_dump)},
- {NAME("gdump"), CTL(prof_gdump)},
- {NAME("prefix"), CTL(prof_prefix)},
- {NAME("reset"), CTL(prof_reset)},
- {NAME("interval"), CTL(prof_interval)},
- {NAME("lg_sample"), CTL(lg_prof_sample)},
- {NAME("log_start"), CTL(prof_log_start)},
- {NAME("log_stop"), CTL(prof_log_stop)},
- {NAME("stats"), CHILD(named, prof_stats)}
-};
-
-static const ctl_named_node_t stats_arenas_i_small_node[] = {
- {NAME("allocated"), CTL(stats_arenas_i_small_allocated)},
- {NAME("nmalloc"), CTL(stats_arenas_i_small_nmalloc)},
- {NAME("ndalloc"), CTL(stats_arenas_i_small_ndalloc)},
- {NAME("nrequests"), CTL(stats_arenas_i_small_nrequests)},
- {NAME("nfills"), CTL(stats_arenas_i_small_nfills)},
- {NAME("nflushes"), CTL(stats_arenas_i_small_nflushes)}
-};
-
-static const ctl_named_node_t stats_arenas_i_large_node[] = {
- {NAME("allocated"), CTL(stats_arenas_i_large_allocated)},
- {NAME("nmalloc"), CTL(stats_arenas_i_large_nmalloc)},
- {NAME("ndalloc"), CTL(stats_arenas_i_large_ndalloc)},
- {NAME("nrequests"), CTL(stats_arenas_i_large_nrequests)},
- {NAME("nfills"), CTL(stats_arenas_i_large_nfills)},
- {NAME("nflushes"), CTL(stats_arenas_i_large_nflushes)}
-};
-
-#define MUTEX_PROF_DATA_NODE(prefix) \
-static const ctl_named_node_t stats_##prefix##_node[] = { \
- {NAME("num_ops"), \
- CTL(stats_##prefix##_num_ops)}, \
- {NAME("num_wait"), \
- CTL(stats_##prefix##_num_wait)}, \
- {NAME("num_spin_acq"), \
- CTL(stats_##prefix##_num_spin_acq)}, \
- {NAME("num_owner_switch"), \
- CTL(stats_##prefix##_num_owner_switch)}, \
- {NAME("total_wait_time"), \
- CTL(stats_##prefix##_total_wait_time)}, \
- {NAME("max_wait_time"), \
- CTL(stats_##prefix##_max_wait_time)}, \
- {NAME("max_num_thds"), \
- CTL(stats_##prefix##_max_num_thds)} \
- /* Note that # of current waiting thread not provided. */ \
-};
-
-MUTEX_PROF_DATA_NODE(arenas_i_bins_j_mutex)
-
-static const ctl_named_node_t stats_arenas_i_bins_j_node[] = {
- {NAME("nmalloc"), CTL(stats_arenas_i_bins_j_nmalloc)},
- {NAME("ndalloc"), CTL(stats_arenas_i_bins_j_ndalloc)},
- {NAME("nrequests"), CTL(stats_arenas_i_bins_j_nrequests)},
- {NAME("curregs"), CTL(stats_arenas_i_bins_j_curregs)},
- {NAME("nfills"), CTL(stats_arenas_i_bins_j_nfills)},
- {NAME("nflushes"), CTL(stats_arenas_i_bins_j_nflushes)},
- {NAME("nslabs"), CTL(stats_arenas_i_bins_j_nslabs)},
- {NAME("nreslabs"), CTL(stats_arenas_i_bins_j_nreslabs)},
- {NAME("curslabs"), CTL(stats_arenas_i_bins_j_curslabs)},
- {NAME("nonfull_slabs"), CTL(stats_arenas_i_bins_j_nonfull_slabs)},
- {NAME("mutex"), CHILD(named, stats_arenas_i_bins_j_mutex)}
-};
-
-static const ctl_named_node_t super_stats_arenas_i_bins_j_node[] = {
- {NAME(""), CHILD(named, stats_arenas_i_bins_j)}
-};
-
-static const ctl_indexed_node_t stats_arenas_i_bins_node[] = {
- {INDEX(stats_arenas_i_bins_j)}
-};
-
-static const ctl_named_node_t stats_arenas_i_lextents_j_node[] = {
- {NAME("nmalloc"), CTL(stats_arenas_i_lextents_j_nmalloc)},
- {NAME("ndalloc"), CTL(stats_arenas_i_lextents_j_ndalloc)},
- {NAME("nrequests"), CTL(stats_arenas_i_lextents_j_nrequests)},
- {NAME("curlextents"), CTL(stats_arenas_i_lextents_j_curlextents)}
-};
-static const ctl_named_node_t super_stats_arenas_i_lextents_j_node[] = {
- {NAME(""), CHILD(named, stats_arenas_i_lextents_j)}
-};
-
-static const ctl_indexed_node_t stats_arenas_i_lextents_node[] = {
- {INDEX(stats_arenas_i_lextents_j)}
-};
-
-static const ctl_named_node_t stats_arenas_i_extents_j_node[] = {
- {NAME("ndirty"), CTL(stats_arenas_i_extents_j_ndirty)},
- {NAME("nmuzzy"), CTL(stats_arenas_i_extents_j_nmuzzy)},
- {NAME("nretained"), CTL(stats_arenas_i_extents_j_nretained)},
- {NAME("dirty_bytes"), CTL(stats_arenas_i_extents_j_dirty_bytes)},
- {NAME("muzzy_bytes"), CTL(stats_arenas_i_extents_j_muzzy_bytes)},
- {NAME("retained_bytes"), CTL(stats_arenas_i_extents_j_retained_bytes)}
-};
-
-static const ctl_named_node_t super_stats_arenas_i_extents_j_node[] = {
- {NAME(""), CHILD(named, stats_arenas_i_extents_j)}
-};
-
-static const ctl_indexed_node_t stats_arenas_i_extents_node[] = {
- {INDEX(stats_arenas_i_extents_j)}
-};
-
-#define OP(mtx) MUTEX_PROF_DATA_NODE(arenas_i_mutexes_##mtx)
-MUTEX_PROF_ARENA_MUTEXES
-#undef OP
-
-static const ctl_named_node_t stats_arenas_i_mutexes_node[] = {
-#define OP(mtx) {NAME(#mtx), CHILD(named, stats_arenas_i_mutexes_##mtx)},
-MUTEX_PROF_ARENA_MUTEXES
-#undef OP
-};
-
-static const ctl_named_node_t stats_arenas_i_hpa_shard_full_slabs_node[] = {
- {NAME("npageslabs_nonhuge"),
- CTL(stats_arenas_i_hpa_shard_full_slabs_npageslabs_nonhuge)},
- {NAME("npageslabs_huge"),
- CTL(stats_arenas_i_hpa_shard_full_slabs_npageslabs_huge)},
- {NAME("nactive_nonhuge"),
- CTL(stats_arenas_i_hpa_shard_full_slabs_nactive_nonhuge)},
- {NAME("nactive_huge"),
- CTL(stats_arenas_i_hpa_shard_full_slabs_nactive_huge)},
- {NAME("ndirty_nonhuge"),
- CTL(stats_arenas_i_hpa_shard_full_slabs_ndirty_nonhuge)},
- {NAME("ndirty_huge"),
- CTL(stats_arenas_i_hpa_shard_full_slabs_ndirty_huge)}
-};
-
-static const ctl_named_node_t stats_arenas_i_hpa_shard_empty_slabs_node[] = {
- {NAME("npageslabs_nonhuge"),
- CTL(stats_arenas_i_hpa_shard_empty_slabs_npageslabs_nonhuge)},
- {NAME("npageslabs_huge"),
- CTL(stats_arenas_i_hpa_shard_empty_slabs_npageslabs_huge)},
- {NAME("nactive_nonhuge"),
- CTL(stats_arenas_i_hpa_shard_empty_slabs_nactive_nonhuge)},
- {NAME("nactive_huge"),
- CTL(stats_arenas_i_hpa_shard_empty_slabs_nactive_huge)},
- {NAME("ndirty_nonhuge"),
- CTL(stats_arenas_i_hpa_shard_empty_slabs_ndirty_nonhuge)},
- {NAME("ndirty_huge"),
- CTL(stats_arenas_i_hpa_shard_empty_slabs_ndirty_huge)}
-};
-
-static const ctl_named_node_t stats_arenas_i_hpa_shard_nonfull_slabs_j_node[] = {
- {NAME("npageslabs_nonhuge"),
- CTL(stats_arenas_i_hpa_shard_nonfull_slabs_j_npageslabs_nonhuge)},
- {NAME("npageslabs_huge"),
- CTL(stats_arenas_i_hpa_shard_nonfull_slabs_j_npageslabs_huge)},
- {NAME("nactive_nonhuge"),
- CTL(stats_arenas_i_hpa_shard_nonfull_slabs_j_nactive_nonhuge)},
- {NAME("nactive_huge"),
- CTL(stats_arenas_i_hpa_shard_nonfull_slabs_j_nactive_huge)},
- {NAME("ndirty_nonhuge"),
- CTL(stats_arenas_i_hpa_shard_nonfull_slabs_j_ndirty_nonhuge)},
- {NAME("ndirty_huge"),
- CTL(stats_arenas_i_hpa_shard_nonfull_slabs_j_ndirty_huge)}
-};
-
-static const ctl_named_node_t super_stats_arenas_i_hpa_shard_nonfull_slabs_j_node[] = {
- {NAME(""),
- CHILD(named, stats_arenas_i_hpa_shard_nonfull_slabs_j)}
-};
-
-static const ctl_indexed_node_t stats_arenas_i_hpa_shard_nonfull_slabs_node[] =
-{
- {INDEX(stats_arenas_i_hpa_shard_nonfull_slabs_j)}
-};
-
-static const ctl_named_node_t stats_arenas_i_hpa_shard_node[] = {
- {NAME("full_slabs"), CHILD(named,
- stats_arenas_i_hpa_shard_full_slabs)},
- {NAME("empty_slabs"), CHILD(named,
- stats_arenas_i_hpa_shard_empty_slabs)},
- {NAME("nonfull_slabs"), CHILD(indexed,
- stats_arenas_i_hpa_shard_nonfull_slabs)},
-
- {NAME("npurge_passes"), CTL(stats_arenas_i_hpa_shard_npurge_passes)},
- {NAME("npurges"), CTL(stats_arenas_i_hpa_shard_npurges)},
- {NAME("nhugifies"), CTL(stats_arenas_i_hpa_shard_nhugifies)},
- {NAME("ndehugifies"), CTL(stats_arenas_i_hpa_shard_ndehugifies)}
-};
-
-static const ctl_named_node_t stats_arenas_i_node[] = {
- {NAME("nthreads"), CTL(stats_arenas_i_nthreads)},
- {NAME("uptime"), CTL(stats_arenas_i_uptime)},
- {NAME("dss"), CTL(stats_arenas_i_dss)},
- {NAME("dirty_decay_ms"), CTL(stats_arenas_i_dirty_decay_ms)},
- {NAME("muzzy_decay_ms"), CTL(stats_arenas_i_muzzy_decay_ms)},
- {NAME("pactive"), CTL(stats_arenas_i_pactive)},
- {NAME("pdirty"), CTL(stats_arenas_i_pdirty)},
- {NAME("pmuzzy"), CTL(stats_arenas_i_pmuzzy)},
- {NAME("mapped"), CTL(stats_arenas_i_mapped)},
- {NAME("retained"), CTL(stats_arenas_i_retained)},
- {NAME("extent_avail"), CTL(stats_arenas_i_extent_avail)},
- {NAME("dirty_npurge"), CTL(stats_arenas_i_dirty_npurge)},
- {NAME("dirty_nmadvise"), CTL(stats_arenas_i_dirty_nmadvise)},
- {NAME("dirty_purged"), CTL(stats_arenas_i_dirty_purged)},
- {NAME("muzzy_npurge"), CTL(stats_arenas_i_muzzy_npurge)},
- {NAME("muzzy_nmadvise"), CTL(stats_arenas_i_muzzy_nmadvise)},
- {NAME("muzzy_purged"), CTL(stats_arenas_i_muzzy_purged)},
- {NAME("base"), CTL(stats_arenas_i_base)},
- {NAME("internal"), CTL(stats_arenas_i_internal)},
- {NAME("metadata_thp"), CTL(stats_arenas_i_metadata_thp)},
- {NAME("tcache_bytes"), CTL(stats_arenas_i_tcache_bytes)},
- {NAME("tcache_stashed_bytes"),
- CTL(stats_arenas_i_tcache_stashed_bytes)},
- {NAME("resident"), CTL(stats_arenas_i_resident)},
- {NAME("abandoned_vm"), CTL(stats_arenas_i_abandoned_vm)},
- {NAME("hpa_sec_bytes"), CTL(stats_arenas_i_hpa_sec_bytes)},
- {NAME("small"), CHILD(named, stats_arenas_i_small)},
- {NAME("large"), CHILD(named, stats_arenas_i_large)},
- {NAME("bins"), CHILD(indexed, stats_arenas_i_bins)},
- {NAME("lextents"), CHILD(indexed, stats_arenas_i_lextents)},
- {NAME("extents"), CHILD(indexed, stats_arenas_i_extents)},
- {NAME("mutexes"), CHILD(named, stats_arenas_i_mutexes)},
- {NAME("hpa_shard"), CHILD(named, stats_arenas_i_hpa_shard)}
-};
-static const ctl_named_node_t super_stats_arenas_i_node[] = {
- {NAME(""), CHILD(named, stats_arenas_i)}
-};
-
-static const ctl_indexed_node_t stats_arenas_node[] = {
- {INDEX(stats_arenas_i)}
-};
-
-static const ctl_named_node_t stats_background_thread_node[] = {
- {NAME("num_threads"), CTL(stats_background_thread_num_threads)},
- {NAME("num_runs"), CTL(stats_background_thread_num_runs)},
- {NAME("run_interval"), CTL(stats_background_thread_run_interval)}
-};
-
-#define OP(mtx) MUTEX_PROF_DATA_NODE(mutexes_##mtx)
-MUTEX_PROF_GLOBAL_MUTEXES
-#undef OP
-
-static const ctl_named_node_t stats_mutexes_node[] = {
-#define OP(mtx) {NAME(#mtx), CHILD(named, stats_mutexes_##mtx)},
-MUTEX_PROF_GLOBAL_MUTEXES
-#undef OP
- {NAME("reset"), CTL(stats_mutexes_reset)}
-};
-#undef MUTEX_PROF_DATA_NODE
-
-static const ctl_named_node_t stats_node[] = {
- {NAME("allocated"), CTL(stats_allocated)},
- {NAME("active"), CTL(stats_active)},
- {NAME("metadata"), CTL(stats_metadata)},
- {NAME("metadata_thp"), CTL(stats_metadata_thp)},
- {NAME("resident"), CTL(stats_resident)},
- {NAME("mapped"), CTL(stats_mapped)},
- {NAME("retained"), CTL(stats_retained)},
- {NAME("background_thread"),
- CHILD(named, stats_background_thread)},
- {NAME("mutexes"), CHILD(named, stats_mutexes)},
- {NAME("arenas"), CHILD(indexed, stats_arenas)},
- {NAME("zero_reallocs"), CTL(stats_zero_reallocs)},
-};
-
-static const ctl_named_node_t experimental_hooks_node[] = {
- {NAME("install"), CTL(experimental_hooks_install)},
- {NAME("remove"), CTL(experimental_hooks_remove)},
- {NAME("prof_backtrace"), CTL(experimental_hooks_prof_backtrace)},
- {NAME("prof_dump"), CTL(experimental_hooks_prof_dump)},
- {NAME("safety_check_abort"), CTL(experimental_hooks_safety_check_abort)},
-};
-
-static const ctl_named_node_t experimental_thread_node[] = {
- {NAME("activity_callback"),
- CTL(experimental_thread_activity_callback)}
-};
-
-static const ctl_named_node_t experimental_utilization_node[] = {
- {NAME("query"), CTL(experimental_utilization_query)},
- {NAME("batch_query"), CTL(experimental_utilization_batch_query)}
-};
-
-static const ctl_named_node_t experimental_arenas_i_node[] = {
- {NAME("pactivep"), CTL(experimental_arenas_i_pactivep)}
-};
-static const ctl_named_node_t super_experimental_arenas_i_node[] = {
- {NAME(""), CHILD(named, experimental_arenas_i)}
-};
-
-static const ctl_indexed_node_t experimental_arenas_node[] = {
- {INDEX(experimental_arenas_i)}
-};
-
-static const ctl_named_node_t experimental_prof_recent_node[] = {
- {NAME("alloc_max"), CTL(experimental_prof_recent_alloc_max)},
- {NAME("alloc_dump"), CTL(experimental_prof_recent_alloc_dump)},
-};
-
-static const ctl_named_node_t experimental_node[] = {
- {NAME("hooks"), CHILD(named, experimental_hooks)},
- {NAME("utilization"), CHILD(named, experimental_utilization)},
- {NAME("arenas"), CHILD(indexed, experimental_arenas)},
- {NAME("arenas_create_ext"), CTL(experimental_arenas_create_ext)},
- {NAME("prof_recent"), CHILD(named, experimental_prof_recent)},
- {NAME("batch_alloc"), CTL(experimental_batch_alloc)},
- {NAME("thread"), CHILD(named, experimental_thread)}
-};
-
-static const ctl_named_node_t root_node[] = {
- {NAME("version"), CTL(version)},
- {NAME("epoch"), CTL(epoch)},
- {NAME("background_thread"), CTL(background_thread)},
- {NAME("max_background_threads"), CTL(max_background_threads)},
- {NAME("thread"), CHILD(named, thread)},
- {NAME("config"), CHILD(named, config)},
- {NAME("opt"), CHILD(named, opt)},
- {NAME("tcache"), CHILD(named, tcache)},
- {NAME("arena"), CHILD(indexed, arena)},
- {NAME("arenas"), CHILD(named, arenas)},
- {NAME("prof"), CHILD(named, prof)},
- {NAME("stats"), CHILD(named, stats)},
- {NAME("experimental"), CHILD(named, experimental)}
-};
-static const ctl_named_node_t super_root_node[] = {
- {NAME(""), CHILD(named, root)}
-};
-
-#undef NAME
-#undef CHILD
-#undef CTL
-#undef INDEX
-
-/******************************************************************************/
-
-/*
- * Sets *dst + *src non-atomically. This is safe, since everything is
- * synchronized by the ctl mutex.
- */
-static void
-ctl_accum_locked_u64(locked_u64_t *dst, locked_u64_t *src) {
- locked_inc_u64_unsynchronized(dst,
- locked_read_u64_unsynchronized(src));
-}
-
-static void
-ctl_accum_atomic_zu(atomic_zu_t *dst, atomic_zu_t *src) {
- size_t cur_dst = atomic_load_zu(dst, ATOMIC_RELAXED);
- size_t cur_src = atomic_load_zu(src, ATOMIC_RELAXED);
- atomic_store_zu(dst, cur_dst + cur_src, ATOMIC_RELAXED);
-}
-
-/******************************************************************************/
-
-static unsigned
-arenas_i2a_impl(size_t i, bool compat, bool validate) {
- unsigned a;
-
- switch (i) {
- case MALLCTL_ARENAS_ALL:
- a = 0;
- break;
- case MALLCTL_ARENAS_DESTROYED:
- a = 1;
- break;
- default:
- if (compat && i == ctl_arenas->narenas) {
- /*
- * Provide deprecated backward compatibility for
- * accessing the merged stats at index narenas rather
- * than via MALLCTL_ARENAS_ALL. This is scheduled for
- * removal in 6.0.0.
- */
- a = 0;
- } else if (validate && i >= ctl_arenas->narenas) {
- a = UINT_MAX;
- } else {
- /*
- * This function should never be called for an index
- * more than one past the range of indices that have
- * initialized ctl data.
- */
- assert(i < ctl_arenas->narenas || (!validate && i ==
- ctl_arenas->narenas));
- a = (unsigned)i + 2;
- }
- break;
- }
-
- return a;
-}
-
-static unsigned
-arenas_i2a(size_t i) {
- return arenas_i2a_impl(i, true, false);
-}
-
-static ctl_arena_t *
-arenas_i_impl(tsd_t *tsd, size_t i, bool compat, bool init) {
- ctl_arena_t *ret;
-
- assert(!compat || !init);
-
- ret = ctl_arenas->arenas[arenas_i2a_impl(i, compat, false)];
- if (init && ret == NULL) {
- if (config_stats) {
- struct container_s {
- ctl_arena_t ctl_arena;
- ctl_arena_stats_t astats;
- };
- struct container_s *cont =
- (struct container_s *)base_alloc(tsd_tsdn(tsd),
- b0get(), sizeof(struct container_s), QUANTUM);
- if (cont == NULL) {
- return NULL;
- }
- ret = &cont->ctl_arena;
- ret->astats = &cont->astats;
- } else {
- ret = (ctl_arena_t *)base_alloc(tsd_tsdn(tsd), b0get(),
- sizeof(ctl_arena_t), QUANTUM);
- if (ret == NULL) {
- return NULL;
- }
- }
- ret->arena_ind = (unsigned)i;
- ctl_arenas->arenas[arenas_i2a_impl(i, compat, false)] = ret;
- }
-
- assert(ret == NULL || arenas_i2a(ret->arena_ind) == arenas_i2a(i));
- return ret;
-}
-
-static ctl_arena_t *
-arenas_i(size_t i) {
- ctl_arena_t *ret = arenas_i_impl(tsd_fetch(), i, true, false);
- assert(ret != NULL);
- return ret;
-}
-
-static void
-ctl_arena_clear(ctl_arena_t *ctl_arena) {
- ctl_arena->nthreads = 0;
- ctl_arena->dss = dss_prec_names[dss_prec_limit];
- ctl_arena->dirty_decay_ms = -1;
- ctl_arena->muzzy_decay_ms = -1;
- ctl_arena->pactive = 0;
- ctl_arena->pdirty = 0;
- ctl_arena->pmuzzy = 0;
- if (config_stats) {
- memset(&ctl_arena->astats->astats, 0, sizeof(arena_stats_t));
- ctl_arena->astats->allocated_small = 0;
- ctl_arena->astats->nmalloc_small = 0;
- ctl_arena->astats->ndalloc_small = 0;
- ctl_arena->astats->nrequests_small = 0;
- ctl_arena->astats->nfills_small = 0;
- ctl_arena->astats->nflushes_small = 0;
- memset(ctl_arena->astats->bstats, 0, SC_NBINS *
- sizeof(bin_stats_data_t));
- memset(ctl_arena->astats->lstats, 0, (SC_NSIZES - SC_NBINS) *
- sizeof(arena_stats_large_t));
- memset(ctl_arena->astats->estats, 0, SC_NPSIZES *
- sizeof(pac_estats_t));
- memset(&ctl_arena->astats->hpastats, 0,
- sizeof(hpa_shard_stats_t));
- memset(&ctl_arena->astats->secstats, 0,
- sizeof(sec_stats_t));
- }
-}
-
-static void
-ctl_arena_stats_amerge(tsdn_t *tsdn, ctl_arena_t *ctl_arena, arena_t *arena) {
- unsigned i;
-
- if (config_stats) {
- arena_stats_merge(tsdn, arena, &ctl_arena->nthreads,
- &ctl_arena->dss, &ctl_arena->dirty_decay_ms,
- &ctl_arena->muzzy_decay_ms, &ctl_arena->pactive,
- &ctl_arena->pdirty, &ctl_arena->pmuzzy,
- &ctl_arena->astats->astats, ctl_arena->astats->bstats,
- ctl_arena->astats->lstats, ctl_arena->astats->estats,
- &ctl_arena->astats->hpastats, &ctl_arena->astats->secstats);
-
- for (i = 0; i < SC_NBINS; i++) {
- bin_stats_t *bstats =
- &ctl_arena->astats->bstats[i].stats_data;
- ctl_arena->astats->allocated_small += bstats->curregs *
- sz_index2size(i);
- ctl_arena->astats->nmalloc_small += bstats->nmalloc;
- ctl_arena->astats->ndalloc_small += bstats->ndalloc;
- ctl_arena->astats->nrequests_small += bstats->nrequests;
- ctl_arena->astats->nfills_small += bstats->nfills;
- ctl_arena->astats->nflushes_small += bstats->nflushes;
- }
- } else {
- arena_basic_stats_merge(tsdn, arena, &ctl_arena->nthreads,
- &ctl_arena->dss, &ctl_arena->dirty_decay_ms,
- &ctl_arena->muzzy_decay_ms, &ctl_arena->pactive,
- &ctl_arena->pdirty, &ctl_arena->pmuzzy);
- }
-}
-
-static void
-ctl_arena_stats_sdmerge(ctl_arena_t *ctl_sdarena, ctl_arena_t *ctl_arena,
- bool destroyed) {
- unsigned i;
-
- if (!destroyed) {
- ctl_sdarena->nthreads += ctl_arena->nthreads;
- ctl_sdarena->pactive += ctl_arena->pactive;
- ctl_sdarena->pdirty += ctl_arena->pdirty;
- ctl_sdarena->pmuzzy += ctl_arena->pmuzzy;
- } else {
- assert(ctl_arena->nthreads == 0);
- assert(ctl_arena->pactive == 0);
- assert(ctl_arena->pdirty == 0);
- assert(ctl_arena->pmuzzy == 0);
- }
-
- if (config_stats) {
- ctl_arena_stats_t *sdstats = ctl_sdarena->astats;
- ctl_arena_stats_t *astats = ctl_arena->astats;
-
- if (!destroyed) {
- sdstats->astats.mapped += astats->astats.mapped;
- sdstats->astats.pa_shard_stats.pac_stats.retained
- += astats->astats.pa_shard_stats.pac_stats.retained;
- sdstats->astats.pa_shard_stats.edata_avail
- += astats->astats.pa_shard_stats.edata_avail;
- }
-
- ctl_accum_locked_u64(
- &sdstats->astats.pa_shard_stats.pac_stats.decay_dirty.npurge,
- &astats->astats.pa_shard_stats.pac_stats.decay_dirty.npurge);
- ctl_accum_locked_u64(
- &sdstats->astats.pa_shard_stats.pac_stats.decay_dirty.nmadvise,
- &astats->astats.pa_shard_stats.pac_stats.decay_dirty.nmadvise);
- ctl_accum_locked_u64(
- &sdstats->astats.pa_shard_stats.pac_stats.decay_dirty.purged,
- &astats->astats.pa_shard_stats.pac_stats.decay_dirty.purged);
-
- ctl_accum_locked_u64(
- &sdstats->astats.pa_shard_stats.pac_stats.decay_muzzy.npurge,
- &astats->astats.pa_shard_stats.pac_stats.decay_muzzy.npurge);
- ctl_accum_locked_u64(
- &sdstats->astats.pa_shard_stats.pac_stats.decay_muzzy.nmadvise,
- &astats->astats.pa_shard_stats.pac_stats.decay_muzzy.nmadvise);
- ctl_accum_locked_u64(
- &sdstats->astats.pa_shard_stats.pac_stats.decay_muzzy.purged,
- &astats->astats.pa_shard_stats.pac_stats.decay_muzzy.purged);
-
-#define OP(mtx) malloc_mutex_prof_merge( \
- &(sdstats->astats.mutex_prof_data[ \
- arena_prof_mutex_##mtx]), \
- &(astats->astats.mutex_prof_data[ \
- arena_prof_mutex_##mtx]));
-MUTEX_PROF_ARENA_MUTEXES
-#undef OP
- if (!destroyed) {
- sdstats->astats.base += astats->astats.base;
- sdstats->astats.resident += astats->astats.resident;
- sdstats->astats.metadata_thp += astats->astats.metadata_thp;
- ctl_accum_atomic_zu(&sdstats->astats.internal,
- &astats->astats.internal);
- } else {
- assert(atomic_load_zu(
- &astats->astats.internal, ATOMIC_RELAXED) == 0);
- }
-
- if (!destroyed) {
- sdstats->allocated_small += astats->allocated_small;
- } else {
- assert(astats->allocated_small == 0);
- }
- sdstats->nmalloc_small += astats->nmalloc_small;
- sdstats->ndalloc_small += astats->ndalloc_small;
- sdstats->nrequests_small += astats->nrequests_small;
- sdstats->nfills_small += astats->nfills_small;
- sdstats->nflushes_small += astats->nflushes_small;
-
- if (!destroyed) {
- sdstats->astats.allocated_large +=
- astats->astats.allocated_large;
- } else {
- assert(astats->astats.allocated_large == 0);
- }
- sdstats->astats.nmalloc_large += astats->astats.nmalloc_large;
- sdstats->astats.ndalloc_large += astats->astats.ndalloc_large;
- sdstats->astats.nrequests_large
- += astats->astats.nrequests_large;
- sdstats->astats.nflushes_large += astats->astats.nflushes_large;
- ctl_accum_atomic_zu(
- &sdstats->astats.pa_shard_stats.pac_stats.abandoned_vm,
- &astats->astats.pa_shard_stats.pac_stats.abandoned_vm);
-
- sdstats->astats.tcache_bytes += astats->astats.tcache_bytes;
- sdstats->astats.tcache_stashed_bytes +=
- astats->astats.tcache_stashed_bytes;
-
- if (ctl_arena->arena_ind == 0) {
- sdstats->astats.uptime = astats->astats.uptime;
- }
-
- /* Merge bin stats. */
- for (i = 0; i < SC_NBINS; i++) {
- bin_stats_t *bstats = &astats->bstats[i].stats_data;
- bin_stats_t *merged = &sdstats->bstats[i].stats_data;
- merged->nmalloc += bstats->nmalloc;
- merged->ndalloc += bstats->ndalloc;
- merged->nrequests += bstats->nrequests;
- if (!destroyed) {
- merged->curregs += bstats->curregs;
- } else {
- assert(bstats->curregs == 0);
- }
- merged->nfills += bstats->nfills;
- merged->nflushes += bstats->nflushes;
- merged->nslabs += bstats->nslabs;
- merged->reslabs += bstats->reslabs;
- if (!destroyed) {
- merged->curslabs += bstats->curslabs;
- merged->nonfull_slabs += bstats->nonfull_slabs;
- } else {
- assert(bstats->curslabs == 0);
- assert(bstats->nonfull_slabs == 0);
- }
- malloc_mutex_prof_merge(&sdstats->bstats[i].mutex_data,
- &astats->bstats[i].mutex_data);
- }
-
- /* Merge stats for large allocations. */
- for (i = 0; i < SC_NSIZES - SC_NBINS; i++) {
- ctl_accum_locked_u64(&sdstats->lstats[i].nmalloc,
- &astats->lstats[i].nmalloc);
- ctl_accum_locked_u64(&sdstats->lstats[i].ndalloc,
- &astats->lstats[i].ndalloc);
- ctl_accum_locked_u64(&sdstats->lstats[i].nrequests,
- &astats->lstats[i].nrequests);
- if (!destroyed) {
- sdstats->lstats[i].curlextents +=
- astats->lstats[i].curlextents;
- } else {
- assert(astats->lstats[i].curlextents == 0);
- }
- }
-
- /* Merge extents stats. */
- for (i = 0; i < SC_NPSIZES; i++) {
- sdstats->estats[i].ndirty += astats->estats[i].ndirty;
- sdstats->estats[i].nmuzzy += astats->estats[i].nmuzzy;
- sdstats->estats[i].nretained
- += astats->estats[i].nretained;
- sdstats->estats[i].dirty_bytes
- += astats->estats[i].dirty_bytes;
- sdstats->estats[i].muzzy_bytes
- += astats->estats[i].muzzy_bytes;
- sdstats->estats[i].retained_bytes
- += astats->estats[i].retained_bytes;
- }
-
- /* Merge HPA stats. */
- hpa_shard_stats_accum(&sdstats->hpastats, &astats->hpastats);
- sec_stats_accum(&sdstats->secstats, &astats->secstats);
- }
-}
-
-static void
-ctl_arena_refresh(tsdn_t *tsdn, arena_t *arena, ctl_arena_t *ctl_sdarena,
- unsigned i, bool destroyed) {
- ctl_arena_t *ctl_arena = arenas_i(i);
-
- ctl_arena_clear(ctl_arena);
- ctl_arena_stats_amerge(tsdn, ctl_arena, arena);
- /* Merge into sum stats as well. */
- ctl_arena_stats_sdmerge(ctl_sdarena, ctl_arena, destroyed);
-}
-
-static unsigned
-ctl_arena_init(tsd_t *tsd, const arena_config_t *config) {
- unsigned arena_ind;
- ctl_arena_t *ctl_arena;
-
- if ((ctl_arena = ql_last(&ctl_arenas->destroyed, destroyed_link)) !=
- NULL) {
- ql_remove(&ctl_arenas->destroyed, ctl_arena, destroyed_link);
- arena_ind = ctl_arena->arena_ind;
- } else {
- arena_ind = ctl_arenas->narenas;
- }
-
- /* Trigger stats allocation. */
- if (arenas_i_impl(tsd, arena_ind, false, true) == NULL) {
- return UINT_MAX;
- }
-
- /* Initialize new arena. */
- if (arena_init(tsd_tsdn(tsd), arena_ind, config) == NULL) {
- return UINT_MAX;
- }
-
- if (arena_ind == ctl_arenas->narenas) {
- ctl_arenas->narenas++;
- }
-
- return arena_ind;
-}
-
-static void
-ctl_background_thread_stats_read(tsdn_t *tsdn) {
- background_thread_stats_t *stats = &ctl_stats->background_thread;
- if (!have_background_thread ||
- background_thread_stats_read(tsdn, stats)) {
- memset(stats, 0, sizeof(background_thread_stats_t));
- nstime_init_zero(&stats->run_interval);
- }
- malloc_mutex_prof_copy(
- &ctl_stats->mutex_prof_data[global_prof_mutex_max_per_bg_thd],
- &stats->max_counter_per_bg_thd);
-}
-
-static void
-ctl_refresh(tsdn_t *tsdn) {
- unsigned i;
- ctl_arena_t *ctl_sarena = arenas_i(MALLCTL_ARENAS_ALL);
- VARIABLE_ARRAY(arena_t *, tarenas, ctl_arenas->narenas);
-
- /*
- * Clear sum stats, since they will be merged into by
- * ctl_arena_refresh().
- */
- ctl_arena_clear(ctl_sarena);
-
- for (i = 0; i < ctl_arenas->narenas; i++) {
- tarenas[i] = arena_get(tsdn, i, false);
- }
-
- for (i = 0; i < ctl_arenas->narenas; i++) {
- ctl_arena_t *ctl_arena = arenas_i(i);
- bool initialized = (tarenas[i] != NULL);
-
- ctl_arena->initialized = initialized;
- if (initialized) {
- ctl_arena_refresh(tsdn, tarenas[i], ctl_sarena, i,
- false);
- }
- }
-
- if (config_stats) {
- ctl_stats->allocated = ctl_sarena->astats->allocated_small +
- ctl_sarena->astats->astats.allocated_large;
- ctl_stats->active = (ctl_sarena->pactive << LG_PAGE);
- ctl_stats->metadata = ctl_sarena->astats->astats.base +
- atomic_load_zu(&ctl_sarena->astats->astats.internal,
- ATOMIC_RELAXED);
- ctl_stats->resident = ctl_sarena->astats->astats.resident;
- ctl_stats->metadata_thp =
- ctl_sarena->astats->astats.metadata_thp;
- ctl_stats->mapped = ctl_sarena->astats->astats.mapped;
- ctl_stats->retained = ctl_sarena->astats->astats
- .pa_shard_stats.pac_stats.retained;
-
- ctl_background_thread_stats_read(tsdn);
-
-#define READ_GLOBAL_MUTEX_PROF_DATA(i, mtx) \
- malloc_mutex_lock(tsdn, &mtx); \
- malloc_mutex_prof_read(tsdn, &ctl_stats->mutex_prof_data[i], &mtx); \
- malloc_mutex_unlock(tsdn, &mtx);
-
- if (config_prof && opt_prof) {
- READ_GLOBAL_MUTEX_PROF_DATA(
- global_prof_mutex_prof, bt2gctx_mtx);
- READ_GLOBAL_MUTEX_PROF_DATA(
- global_prof_mutex_prof_thds_data, tdatas_mtx);
- READ_GLOBAL_MUTEX_PROF_DATA(
- global_prof_mutex_prof_dump, prof_dump_mtx);
- READ_GLOBAL_MUTEX_PROF_DATA(
- global_prof_mutex_prof_recent_alloc,
- prof_recent_alloc_mtx);
- READ_GLOBAL_MUTEX_PROF_DATA(
- global_prof_mutex_prof_recent_dump,
- prof_recent_dump_mtx);
- READ_GLOBAL_MUTEX_PROF_DATA(
- global_prof_mutex_prof_stats, prof_stats_mtx);
- }
- if (have_background_thread) {
- READ_GLOBAL_MUTEX_PROF_DATA(
- global_prof_mutex_background_thread,
- background_thread_lock);
- } else {
- memset(&ctl_stats->mutex_prof_data[
- global_prof_mutex_background_thread], 0,
- sizeof(mutex_prof_data_t));
- }
- /* We own ctl mutex already. */
- malloc_mutex_prof_read(tsdn,
- &ctl_stats->mutex_prof_data[global_prof_mutex_ctl],
- &ctl_mtx);
-#undef READ_GLOBAL_MUTEX_PROF_DATA
- }
- ctl_arenas->epoch++;
-}
-
-static bool
-ctl_init(tsd_t *tsd) {
- bool ret;
- tsdn_t *tsdn = tsd_tsdn(tsd);
-
- malloc_mutex_lock(tsdn, &ctl_mtx);
- if (!ctl_initialized) {
- ctl_arena_t *ctl_sarena, *ctl_darena;
- unsigned i;
-
- /*
- * Allocate demand-zeroed space for pointers to the full
- * range of supported arena indices.
- */
- if (ctl_arenas == NULL) {
- ctl_arenas = (ctl_arenas_t *)base_alloc(tsdn,
- b0get(), sizeof(ctl_arenas_t), QUANTUM);
- if (ctl_arenas == NULL) {
- ret = true;
- goto label_return;
- }
- }
-
- if (config_stats && ctl_stats == NULL) {
- ctl_stats = (ctl_stats_t *)base_alloc(tsdn, b0get(),
- sizeof(ctl_stats_t), QUANTUM);
- if (ctl_stats == NULL) {
- ret = true;
- goto label_return;
- }
- }
-
- /*
- * Allocate space for the current full range of arenas
- * here rather than doing it lazily elsewhere, in order
- * to limit when OOM-caused errors can occur.
- */
- if ((ctl_sarena = arenas_i_impl(tsd, MALLCTL_ARENAS_ALL, false,
- true)) == NULL) {
- ret = true;
- goto label_return;
- }
- ctl_sarena->initialized = true;
-
- if ((ctl_darena = arenas_i_impl(tsd, MALLCTL_ARENAS_DESTROYED,
- false, true)) == NULL) {
- ret = true;
- goto label_return;
- }
- ctl_arena_clear(ctl_darena);
- /*
- * Don't toggle ctl_darena to initialized until an arena is
- * actually destroyed, so that arena.<i>.initialized can be used
- * to query whether the stats are relevant.
- */
-
- ctl_arenas->narenas = narenas_total_get();
- for (i = 0; i < ctl_arenas->narenas; i++) {
- if (arenas_i_impl(tsd, i, false, true) == NULL) {
- ret = true;
- goto label_return;
- }
- }
-
- ql_new(&ctl_arenas->destroyed);
- ctl_refresh(tsdn);
-
- ctl_initialized = true;
- }
-
- ret = false;
-label_return:
- malloc_mutex_unlock(tsdn, &ctl_mtx);
- return ret;
-}
-
-static int
-ctl_lookup(tsdn_t *tsdn, const ctl_named_node_t *starting_node,
- const char *name, const ctl_named_node_t **ending_nodep, size_t *mibp,
- size_t *depthp) {
- int ret;
- const char *elm, *tdot, *dot;
- size_t elen, i, j;
- const ctl_named_node_t *node;
-
- elm = name;
- /* Equivalent to strchrnul(). */
- dot = ((tdot = strchr(elm, '.')) != NULL) ? tdot : strchr(elm, '\0');
- elen = (size_t)((uintptr_t)dot - (uintptr_t)elm);
- if (elen == 0) {
- ret = ENOENT;
- goto label_return;
- }
- node = starting_node;
- for (i = 0; i < *depthp; i++) {
- assert(node);
- assert(node->nchildren > 0);
- if (ctl_named_node(node->children) != NULL) {
- const ctl_named_node_t *pnode = node;
-
- /* Children are named. */
- for (j = 0; j < node->nchildren; j++) {
- const ctl_named_node_t *child =
- ctl_named_children(node, j);
- if (strlen(child->name) == elen &&
- strncmp(elm, child->name, elen) == 0) {
- node = child;
- mibp[i] = j;
- break;
- }
- }
- if (node == pnode) {
- ret = ENOENT;
- goto label_return;
- }
- } else {
- uintmax_t index;
- const ctl_indexed_node_t *inode;
-
- /* Children are indexed. */
- index = malloc_strtoumax(elm, NULL, 10);
- if (index == UINTMAX_MAX || index > SIZE_T_MAX) {
- ret = ENOENT;
- goto label_return;
- }
-
- inode = ctl_indexed_node(node->children);
- node = inode->index(tsdn, mibp, *depthp, (size_t)index);
- if (node == NULL) {
- ret = ENOENT;
- goto label_return;
- }
-
- mibp[i] = (size_t)index;
- }
-
- /* Reached the end? */
- if (node->ctl != NULL || *dot == '\0') {
- /* Terminal node. */
- if (*dot != '\0') {
- /*
- * The name contains more elements than are
- * in this path through the tree.
- */
- ret = ENOENT;
- goto label_return;
- }
- /* Complete lookup successful. */
- *depthp = i + 1;
- break;
- }
-
- /* Update elm. */
- elm = &dot[1];
- dot = ((tdot = strchr(elm, '.')) != NULL) ? tdot :
- strchr(elm, '\0');
- elen = (size_t)((uintptr_t)dot - (uintptr_t)elm);
- }
- if (ending_nodep != NULL) {
- *ending_nodep = node;
- }
-
- ret = 0;
-label_return:
- return ret;
-}
-
-int
-ctl_byname(tsd_t *tsd, const char *name, void *oldp, size_t *oldlenp,
- void *newp, size_t newlen) {
- int ret;
- size_t depth;
- size_t mib[CTL_MAX_DEPTH];
- const ctl_named_node_t *node;
-
- if (!ctl_initialized && ctl_init(tsd)) {
- ret = EAGAIN;
- goto label_return;
- }
-
- depth = CTL_MAX_DEPTH;
- ret = ctl_lookup(tsd_tsdn(tsd), super_root_node, name, &node, mib,
- &depth);
- if (ret != 0) {
- goto label_return;
- }
-
- if (node != NULL && node->ctl) {
- ret = node->ctl(tsd, mib, depth, oldp, oldlenp, newp, newlen);
- } else {
- /* The name refers to a partial path through the ctl tree. */
- ret = ENOENT;
- }
-
-label_return:
- return(ret);
-}
-
-int
-ctl_nametomib(tsd_t *tsd, const char *name, size_t *mibp, size_t *miblenp) {
- int ret;
-
- if (!ctl_initialized && ctl_init(tsd)) {
- ret = EAGAIN;
- goto label_return;
- }
-
- ret = ctl_lookup(tsd_tsdn(tsd), super_root_node, name, NULL, mibp,
- miblenp);
-label_return:
- return(ret);
-}
-
-static int
-ctl_lookupbymib(tsdn_t *tsdn, const ctl_named_node_t **ending_nodep,
- const size_t *mib, size_t miblen) {
- int ret;
-
- const ctl_named_node_t *node = super_root_node;
- for (size_t i = 0; i < miblen; i++) {
- assert(node);
- assert(node->nchildren > 0);
- if (ctl_named_node(node->children) != NULL) {
- /* Children are named. */
- if (node->nchildren <= mib[i]) {
- ret = ENOENT;
- goto label_return;
- }
- node = ctl_named_children(node, mib[i]);
- } else {
- const ctl_indexed_node_t *inode;
-
- /* Indexed element. */
- inode = ctl_indexed_node(node->children);
- node = inode->index(tsdn, mib, miblen, mib[i]);
- if (node == NULL) {
- ret = ENOENT;
- goto label_return;
- }
- }
- }
- assert(ending_nodep != NULL);
- *ending_nodep = node;
- ret = 0;
-
-label_return:
- return(ret);
-}
-
-int
-ctl_bymib(tsd_t *tsd, const size_t *mib, size_t miblen, void *oldp,
- size_t *oldlenp, void *newp, size_t newlen) {
- int ret;
- const ctl_named_node_t *node;
-
- if (!ctl_initialized && ctl_init(tsd)) {
- ret = EAGAIN;
- goto label_return;
- }
-
- ret = ctl_lookupbymib(tsd_tsdn(tsd), &node, mib, miblen);
- if (ret != 0) {
- goto label_return;
- }
-
- /* Call the ctl function. */
- if (node && node->ctl) {
- ret = node->ctl(tsd, mib, miblen, oldp, oldlenp, newp, newlen);
- } else {
- /* Partial MIB. */
- ret = ENOENT;
- }
-
-label_return:
- return(ret);
-}
-
-int
-ctl_mibnametomib(tsd_t *tsd, size_t *mib, size_t miblen, const char *name,
- size_t *miblenp) {
- int ret;
- const ctl_named_node_t *node;
-
- if (!ctl_initialized && ctl_init(tsd)) {
- ret = EAGAIN;
- goto label_return;
- }
-
- ret = ctl_lookupbymib(tsd_tsdn(tsd), &node, mib, miblen);
- if (ret != 0) {
- goto label_return;
- }
- if (node == NULL || node->ctl != NULL) {
- ret = ENOENT;
- goto label_return;
- }
-
- assert(miblenp != NULL);
- assert(*miblenp >= miblen);
- *miblenp -= miblen;
- ret = ctl_lookup(tsd_tsdn(tsd), node, name, NULL, mib + miblen,
- miblenp);
- *miblenp += miblen;
-label_return:
- return(ret);
-}
-
-int
-ctl_bymibname(tsd_t *tsd, size_t *mib, size_t miblen, const char *name,
- size_t *miblenp, void *oldp, size_t *oldlenp, void *newp, size_t newlen) {
- int ret;
- const ctl_named_node_t *node;
-
- if (!ctl_initialized && ctl_init(tsd)) {
- ret = EAGAIN;
- goto label_return;
- }
-
- ret = ctl_lookupbymib(tsd_tsdn(tsd), &node, mib, miblen);
- if (ret != 0) {
- goto label_return;
- }
- if (node == NULL || node->ctl != NULL) {
- ret = ENOENT;
- goto label_return;
- }
-
- assert(miblenp != NULL);
- assert(*miblenp >= miblen);
- *miblenp -= miblen;
- /*
- * The same node supplies the starting node and stores the ending node.
- */
- ret = ctl_lookup(tsd_tsdn(tsd), node, name, &node, mib + miblen,
- miblenp);
- *miblenp += miblen;
- if (ret != 0) {
- goto label_return;
- }
-
- if (node != NULL && node->ctl) {
- ret = node->ctl(tsd, mib, *miblenp, oldp, oldlenp, newp,
- newlen);
- } else {
- /* The name refers to a partial path through the ctl tree. */
- ret = ENOENT;
- }
-
-label_return:
- return(ret);
-}
-
-bool
-ctl_boot(void) {
- if (malloc_mutex_init(&ctl_mtx, "ctl", WITNESS_RANK_CTL,
- malloc_mutex_rank_exclusive)) {
- return true;
- }
-
- ctl_initialized = false;
-
- return false;
-}
-
-void
-ctl_prefork(tsdn_t *tsdn) {
- malloc_mutex_prefork(tsdn, &ctl_mtx);
-}
-
-void
-ctl_postfork_parent(tsdn_t *tsdn) {
- malloc_mutex_postfork_parent(tsdn, &ctl_mtx);
-}
-
-void
-ctl_postfork_child(tsdn_t *tsdn) {
- malloc_mutex_postfork_child(tsdn, &ctl_mtx);
-}
-
-void
-ctl_mtx_assert_held(tsdn_t *tsdn) {
- malloc_mutex_assert_owner(tsdn, &ctl_mtx);
-}
-
-/******************************************************************************/
-/* *_ctl() functions. */
-
-#define READONLY() do { \
- if (newp != NULL || newlen != 0) { \
- ret = EPERM; \
- goto label_return; \
- } \
-} while (0)
-
-#define WRITEONLY() do { \
- if (oldp != NULL || oldlenp != NULL) { \
- ret = EPERM; \
- goto label_return; \
- } \
-} while (0)
-
-/* Can read or write, but not both. */
-#define READ_XOR_WRITE() do { \
- if ((oldp != NULL && oldlenp != NULL) && (newp != NULL || \
- newlen != 0)) { \
- ret = EPERM; \
- goto label_return; \
- } \
-} while (0)
-
-/* Can neither read nor write. */
-#define NEITHER_READ_NOR_WRITE() do { \
- if (oldp != NULL || oldlenp != NULL || newp != NULL || \
- newlen != 0) { \
- ret = EPERM; \
- goto label_return; \
- } \
-} while (0)
-
-/* Verify that the space provided is enough. */
-#define VERIFY_READ(t) do { \
- if (oldp == NULL || oldlenp == NULL || *oldlenp != sizeof(t)) { \
- *oldlenp = 0; \
- ret = EINVAL; \
- goto label_return; \
- } \
-} while (0)
-
-#define READ(v, t) do { \
- if (oldp != NULL && oldlenp != NULL) { \
- if (*oldlenp != sizeof(t)) { \
- size_t copylen = (sizeof(t) <= *oldlenp) \
- ? sizeof(t) : *oldlenp; \
- memcpy(oldp, (void *)&(v), copylen); \
- *oldlenp = copylen; \
- ret = EINVAL; \
- goto label_return; \
- } \
- *(t *)oldp = (v); \
- } \
-} while (0)
-
-#define WRITE(v, t) do { \
- if (newp != NULL) { \
- if (newlen != sizeof(t)) { \
- ret = EINVAL; \
- goto label_return; \
- } \
- (v) = *(t *)newp; \
- } \
-} while (0)
-
-#define ASSURED_WRITE(v, t) do { \
- if (newp == NULL || newlen != sizeof(t)) { \
- ret = EINVAL; \
- goto label_return; \
- } \
- (v) = *(t *)newp; \
-} while (0)
-
-#define MIB_UNSIGNED(v, i) do { \
- if (mib[i] > UINT_MAX) { \
- ret = EFAULT; \
- goto label_return; \
- } \
- v = (unsigned)mib[i]; \
-} while (0)
-
-/*
- * There's a lot of code duplication in the following macros due to limitations
- * in how nested cpp macros are expanded.
- */
-#define CTL_RO_CLGEN(c, l, n, v, t) \
-static int \
-n##_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, void *oldp, \
- size_t *oldlenp, void *newp, size_t newlen) { \
- int ret; \
- t oldval; \
- \
- if (!(c)) { \
- return ENOENT; \
- } \
- if (l) { \
- malloc_mutex_lock(tsd_tsdn(tsd), &ctl_mtx); \
- } \
- READONLY(); \
- oldval = (v); \
- READ(oldval, t); \
- \
- ret = 0; \
-label_return: \
- if (l) { \
- malloc_mutex_unlock(tsd_tsdn(tsd), &ctl_mtx); \
- } \
- return ret; \
-}
-
-#define CTL_RO_CGEN(c, n, v, t) \
-static int \
-n##_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, \
- void *oldp, size_t *oldlenp, void *newp, size_t newlen) { \
- int ret; \
- t oldval; \
- \
- if (!(c)) { \
- return ENOENT; \
- } \
- malloc_mutex_lock(tsd_tsdn(tsd), &ctl_mtx); \
- READONLY(); \
- oldval = (v); \
- READ(oldval, t); \
- \
- ret = 0; \
-label_return: \
- malloc_mutex_unlock(tsd_tsdn(tsd), &ctl_mtx); \
- return ret; \
-}
-
-#define CTL_RO_GEN(n, v, t) \
-static int \
-n##_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, void *oldp, \
- size_t *oldlenp, void *newp, size_t newlen) { \
- int ret; \
- t oldval; \
- \
- malloc_mutex_lock(tsd_tsdn(tsd), &ctl_mtx); \
- READONLY(); \
- oldval = (v); \
- READ(oldval, t); \
- \
- ret = 0; \
-label_return: \
- malloc_mutex_unlock(tsd_tsdn(tsd), &ctl_mtx); \
- return ret; \
-}
-
-/*
- * ctl_mtx is not acquired, under the assumption that no pertinent data will
- * mutate during the call.
- */
-#define CTL_RO_NL_CGEN(c, n, v, t) \
-static int \
-n##_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, \
- void *oldp, size_t *oldlenp, void *newp, size_t newlen) { \
- int ret; \
- t oldval; \
- \
- if (!(c)) { \
- return ENOENT; \
- } \
- READONLY(); \
- oldval = (v); \
- READ(oldval, t); \
- \
- ret = 0; \
-label_return: \
- return ret; \
-}
-
-#define CTL_RO_NL_GEN(n, v, t) \
-static int \
-n##_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, \
- void *oldp, size_t *oldlenp, void *newp, size_t newlen) { \
- int ret; \
- t oldval; \
- \
- READONLY(); \
- oldval = (v); \
- READ(oldval, t); \
- \
- ret = 0; \
-label_return: \
- return ret; \
-}
-
-#define CTL_RO_CONFIG_GEN(n, t) \
-static int \
-n##_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, \
- void *oldp, size_t *oldlenp, void *newp, size_t newlen) { \
- int ret; \
- t oldval; \
- \
- READONLY(); \
- oldval = n; \
- READ(oldval, t); \
- \
- ret = 0; \
-label_return: \
- return ret; \
-}
-
-/******************************************************************************/
-
-CTL_RO_NL_GEN(version, JEMALLOC_VERSION, const char *)
-
-static int
-epoch_ctl(tsd_t *tsd, const size_t *mib, size_t miblen,
- void *oldp, size_t *oldlenp, void *newp, size_t newlen) {
- int ret;
- UNUSED uint64_t newval;
-
- malloc_mutex_lock(tsd_tsdn(tsd), &ctl_mtx);
- WRITE(newval, uint64_t);
- if (newp != NULL) {
- ctl_refresh(tsd_tsdn(tsd));
- }
- READ(ctl_arenas->epoch, uint64_t);
-
- ret = 0;
-label_return:
- malloc_mutex_unlock(tsd_tsdn(tsd), &ctl_mtx);
- return ret;
-}
-
-static int
-background_thread_ctl(tsd_t *tsd, const size_t *mib,
- size_t miblen, void *oldp, size_t *oldlenp,
- void *newp, size_t newlen) {
- int ret;
- bool oldval;
-
- if (!have_background_thread) {
- return ENOENT;
- }
- background_thread_ctl_init(tsd_tsdn(tsd));
-
- malloc_mutex_lock(tsd_tsdn(tsd), &ctl_mtx);
- malloc_mutex_lock(tsd_tsdn(tsd), &background_thread_lock);
- if (newp == NULL) {
- oldval = background_thread_enabled();
- READ(oldval, bool);
- } else {
- if (newlen != sizeof(bool)) {
- ret = EINVAL;
- goto label_return;
- }
- oldval = background_thread_enabled();
- READ(oldval, bool);
-
- bool newval = *(bool *)newp;
- if (newval == oldval) {
- ret = 0;
- goto label_return;
- }
-
- background_thread_enabled_set(tsd_tsdn(tsd), newval);
- if (newval) {
- if (background_threads_enable(tsd)) {
- ret = EFAULT;
- goto label_return;
- }
- } else {
- if (background_threads_disable(tsd)) {
- ret = EFAULT;
- goto label_return;
- }
- }
- }
- ret = 0;
-label_return:
- malloc_mutex_unlock(tsd_tsdn(tsd), &background_thread_lock);
- malloc_mutex_unlock(tsd_tsdn(tsd), &ctl_mtx);
-
- return ret;
-}
-
-static int
-max_background_threads_ctl(tsd_t *tsd, const size_t *mib,
- size_t miblen, void *oldp, size_t *oldlenp, void *newp,
- size_t newlen) {
- int ret;
- size_t oldval;
-
- if (!have_background_thread) {
- return ENOENT;
- }
- background_thread_ctl_init(tsd_tsdn(tsd));
-
- malloc_mutex_lock(tsd_tsdn(tsd), &ctl_mtx);
- malloc_mutex_lock(tsd_tsdn(tsd), &background_thread_lock);
- if (newp == NULL) {
- oldval = max_background_threads;
- READ(oldval, size_t);
- } else {
- if (newlen != sizeof(size_t)) {
- ret = EINVAL;
- goto label_return;
- }
- oldval = max_background_threads;
- READ(oldval, size_t);
-
- size_t newval = *(size_t *)newp;
- if (newval == oldval) {
- ret = 0;
- goto label_return;
- }
- if (newval > opt_max_background_threads) {
- ret = EINVAL;
- goto label_return;
- }
-
- if (background_thread_enabled()) {
- background_thread_enabled_set(tsd_tsdn(tsd), false);
- if (background_threads_disable(tsd)) {
- ret = EFAULT;
- goto label_return;
- }
- max_background_threads = newval;
- background_thread_enabled_set(tsd_tsdn(tsd), true);
- if (background_threads_enable(tsd)) {
- ret = EFAULT;
- goto label_return;
- }
- } else {
- max_background_threads = newval;
- }
- }
- ret = 0;
-label_return:
- malloc_mutex_unlock(tsd_tsdn(tsd), &background_thread_lock);
- malloc_mutex_unlock(tsd_tsdn(tsd), &ctl_mtx);
-
- return ret;
-}
-
-/******************************************************************************/
-
-CTL_RO_CONFIG_GEN(config_cache_oblivious, bool)
-CTL_RO_CONFIG_GEN(config_debug, bool)
-CTL_RO_CONFIG_GEN(config_fill, bool)
-CTL_RO_CONFIG_GEN(config_lazy_lock, bool)
-CTL_RO_CONFIG_GEN(config_malloc_conf, const char *)
-CTL_RO_CONFIG_GEN(config_opt_safety_checks, bool)
-CTL_RO_CONFIG_GEN(config_prof, bool)
-CTL_RO_CONFIG_GEN(config_prof_libgcc, bool)
-CTL_RO_CONFIG_GEN(config_prof_libunwind, bool)
-CTL_RO_CONFIG_GEN(config_stats, bool)
-CTL_RO_CONFIG_GEN(config_utrace, bool)
-CTL_RO_CONFIG_GEN(config_xmalloc, bool)
-
-/******************************************************************************/
-
-CTL_RO_NL_GEN(opt_abort, opt_abort, bool)
-CTL_RO_NL_GEN(opt_abort_conf, opt_abort_conf, bool)
-CTL_RO_NL_GEN(opt_cache_oblivious, opt_cache_oblivious, bool)
-CTL_RO_NL_GEN(opt_trust_madvise, opt_trust_madvise, bool)
-CTL_RO_NL_GEN(opt_confirm_conf, opt_confirm_conf, bool)
-
-/* HPA options. */
-CTL_RO_NL_GEN(opt_hpa, opt_hpa, bool)
-CTL_RO_NL_GEN(opt_hpa_hugification_threshold,
- opt_hpa_opts.hugification_threshold, size_t)
-CTL_RO_NL_GEN(opt_hpa_hugify_delay_ms, opt_hpa_opts.hugify_delay_ms, uint64_t)
-CTL_RO_NL_GEN(opt_hpa_min_purge_interval_ms, opt_hpa_opts.min_purge_interval_ms,
- uint64_t)
-
-/*
- * This will have to change before we publicly document this option; fxp_t and
- * its representation are internal implementation details.
- */
-CTL_RO_NL_GEN(opt_hpa_dirty_mult, opt_hpa_opts.dirty_mult, fxp_t)
-CTL_RO_NL_GEN(opt_hpa_slab_max_alloc, opt_hpa_opts.slab_max_alloc, size_t)
-
-/* HPA SEC options */
-CTL_RO_NL_GEN(opt_hpa_sec_nshards, opt_hpa_sec_opts.nshards, size_t)
-CTL_RO_NL_GEN(opt_hpa_sec_max_alloc, opt_hpa_sec_opts.max_alloc, size_t)
-CTL_RO_NL_GEN(opt_hpa_sec_max_bytes, opt_hpa_sec_opts.max_bytes, size_t)
-CTL_RO_NL_GEN(opt_hpa_sec_bytes_after_flush, opt_hpa_sec_opts.bytes_after_flush,
- size_t)
-CTL_RO_NL_GEN(opt_hpa_sec_batch_fill_extra, opt_hpa_sec_opts.batch_fill_extra,
- size_t)
-
-CTL_RO_NL_GEN(opt_metadata_thp, metadata_thp_mode_names[opt_metadata_thp],
- const char *)
-CTL_RO_NL_GEN(opt_retain, opt_retain, bool)
-CTL_RO_NL_GEN(opt_dss, opt_dss, const char *)
-CTL_RO_NL_GEN(opt_narenas, opt_narenas, unsigned)
-CTL_RO_NL_GEN(opt_percpu_arena, percpu_arena_mode_names[opt_percpu_arena],
- const char *)
-CTL_RO_NL_GEN(opt_mutex_max_spin, opt_mutex_max_spin, int64_t)
-CTL_RO_NL_GEN(opt_oversize_threshold, opt_oversize_threshold, size_t)
-CTL_RO_NL_GEN(opt_background_thread, opt_background_thread, bool)
-CTL_RO_NL_GEN(opt_max_background_threads, opt_max_background_threads, size_t)
-CTL_RO_NL_GEN(opt_dirty_decay_ms, opt_dirty_decay_ms, ssize_t)
-CTL_RO_NL_GEN(opt_muzzy_decay_ms, opt_muzzy_decay_ms, ssize_t)
-CTL_RO_NL_GEN(opt_stats_print, opt_stats_print, bool)
-CTL_RO_NL_GEN(opt_stats_print_opts, opt_stats_print_opts, const char *)
-CTL_RO_NL_GEN(opt_stats_interval, opt_stats_interval, int64_t)
-CTL_RO_NL_GEN(opt_stats_interval_opts, opt_stats_interval_opts, const char *)
-CTL_RO_NL_CGEN(config_fill, opt_junk, opt_junk, const char *)
-CTL_RO_NL_CGEN(config_fill, opt_zero, opt_zero, bool)
-CTL_RO_NL_CGEN(config_utrace, opt_utrace, opt_utrace, bool)
-CTL_RO_NL_CGEN(config_xmalloc, opt_xmalloc, opt_xmalloc, bool)
-CTL_RO_NL_CGEN(config_enable_cxx, opt_experimental_infallible_new,
- opt_experimental_infallible_new, bool)
-CTL_RO_NL_GEN(opt_tcache, opt_tcache, bool)
-CTL_RO_NL_GEN(opt_tcache_max, opt_tcache_max, size_t)
-CTL_RO_NL_GEN(opt_tcache_nslots_small_min, opt_tcache_nslots_small_min,
- unsigned)
-CTL_RO_NL_GEN(opt_tcache_nslots_small_max, opt_tcache_nslots_small_max,
- unsigned)
-CTL_RO_NL_GEN(opt_tcache_nslots_large, opt_tcache_nslots_large, unsigned)
-CTL_RO_NL_GEN(opt_lg_tcache_nslots_mul, opt_lg_tcache_nslots_mul, ssize_t)
-CTL_RO_NL_GEN(opt_tcache_gc_incr_bytes, opt_tcache_gc_incr_bytes, size_t)
-CTL_RO_NL_GEN(opt_tcache_gc_delay_bytes, opt_tcache_gc_delay_bytes, size_t)
-CTL_RO_NL_GEN(opt_lg_tcache_flush_small_div, opt_lg_tcache_flush_small_div,
- unsigned)
-CTL_RO_NL_GEN(opt_lg_tcache_flush_large_div, opt_lg_tcache_flush_large_div,
- unsigned)
-CTL_RO_NL_GEN(opt_thp, thp_mode_names[opt_thp], const char *)
-CTL_RO_NL_GEN(opt_lg_extent_max_active_fit, opt_lg_extent_max_active_fit,
- size_t)
-CTL_RO_NL_CGEN(config_prof, opt_prof, opt_prof, bool)
-CTL_RO_NL_CGEN(config_prof, opt_prof_prefix, opt_prof_prefix, const char *)
-CTL_RO_NL_CGEN(config_prof, opt_prof_active, opt_prof_active, bool)
-CTL_RO_NL_CGEN(config_prof, opt_prof_thread_active_init,
- opt_prof_thread_active_init, bool)
-CTL_RO_NL_CGEN(config_prof, opt_lg_prof_sample, opt_lg_prof_sample, size_t)
-CTL_RO_NL_CGEN(config_prof, opt_prof_accum, opt_prof_accum, bool)
-CTL_RO_NL_CGEN(config_prof, opt_lg_prof_interval, opt_lg_prof_interval, ssize_t)
-CTL_RO_NL_CGEN(config_prof, opt_prof_gdump, opt_prof_gdump, bool)
-CTL_RO_NL_CGEN(config_prof, opt_prof_final, opt_prof_final, bool)
-CTL_RO_NL_CGEN(config_prof, opt_prof_leak, opt_prof_leak, bool)
-CTL_RO_NL_CGEN(config_prof, opt_prof_leak_error, opt_prof_leak_error, bool)
-CTL_RO_NL_CGEN(config_prof, opt_prof_recent_alloc_max,
- opt_prof_recent_alloc_max, ssize_t)
-CTL_RO_NL_CGEN(config_prof, opt_prof_stats, opt_prof_stats, bool)
-CTL_RO_NL_CGEN(config_prof, opt_prof_sys_thread_name, opt_prof_sys_thread_name,
- bool)
-CTL_RO_NL_CGEN(config_prof, opt_prof_time_res,
- prof_time_res_mode_names[opt_prof_time_res], const char *)
-CTL_RO_NL_CGEN(config_uaf_detection, opt_lg_san_uaf_align,
- opt_lg_san_uaf_align, ssize_t)
-CTL_RO_NL_GEN(opt_zero_realloc,
- zero_realloc_mode_names[opt_zero_realloc_action], const char *)
-
-/******************************************************************************/
-
-static int
-thread_arena_ctl(tsd_t *tsd, const size_t *mib, size_t miblen,
- void *oldp, size_t *oldlenp, void *newp, size_t newlen) {
- int ret;
- arena_t *oldarena;
- unsigned newind, oldind;
-
- oldarena = arena_choose(tsd, NULL);
- if (oldarena == NULL) {
- return EAGAIN;
- }
- newind = oldind = arena_ind_get(oldarena);
- WRITE(newind, unsigned);
- READ(oldind, unsigned);
-
- if (newind != oldind) {
- arena_t *newarena;
-
- if (newind >= narenas_total_get()) {
- /* New arena index is out of range. */
- ret = EFAULT;
- goto label_return;
- }
-
- if (have_percpu_arena &&
- PERCPU_ARENA_ENABLED(opt_percpu_arena)) {
- if (newind < percpu_arena_ind_limit(opt_percpu_arena)) {
- /*
- * If perCPU arena is enabled, thread_arena
- * control is not allowed for the auto arena
- * range.
- */
- ret = EPERM;
- goto label_return;
- }
- }
-
- /* Initialize arena if necessary. */
- newarena = arena_get(tsd_tsdn(tsd), newind, true);
- if (newarena == NULL) {
- ret = EAGAIN;
- goto label_return;
- }
- /* Set new arena/tcache associations. */
- arena_migrate(tsd, oldarena, newarena);
- if (tcache_available(tsd)) {
- tcache_arena_reassociate(tsd_tsdn(tsd),
- tsd_tcache_slowp_get(tsd), tsd_tcachep_get(tsd),
- newarena);
- }
- }
-
- ret = 0;
-label_return:
- return ret;
-}
-
-CTL_RO_NL_GEN(thread_allocated, tsd_thread_allocated_get(tsd), uint64_t)
-CTL_RO_NL_GEN(thread_allocatedp, tsd_thread_allocatedp_get(tsd), uint64_t *)
-CTL_RO_NL_GEN(thread_deallocated, tsd_thread_deallocated_get(tsd), uint64_t)
-CTL_RO_NL_GEN(thread_deallocatedp, tsd_thread_deallocatedp_get(tsd), uint64_t *)
-
-static int
-thread_tcache_enabled_ctl(tsd_t *tsd, const size_t *mib,
- size_t miblen, void *oldp, size_t *oldlenp, void *newp,
- size_t newlen) {
- int ret;
- bool oldval;
-
- oldval = tcache_enabled_get(tsd);
- if (newp != NULL) {
- if (newlen != sizeof(bool)) {
- ret = EINVAL;
- goto label_return;
- }
- tcache_enabled_set(tsd, *(bool *)newp);
- }
- READ(oldval, bool);
-
- ret = 0;
-label_return:
- return ret;
-}
-
-static int
-thread_tcache_flush_ctl(tsd_t *tsd, const size_t *mib,
- size_t miblen, void *oldp, size_t *oldlenp, void *newp,
- size_t newlen) {
- int ret;
-
- if (!tcache_available(tsd)) {
- ret = EFAULT;
- goto label_return;
- }
-
- NEITHER_READ_NOR_WRITE();
-
- tcache_flush(tsd);
-
- ret = 0;
-label_return:
- return ret;
-}
-
-static int
-thread_peak_read_ctl(tsd_t *tsd, const size_t *mib,
- size_t miblen, void *oldp, size_t *oldlenp, void *newp,
- size_t newlen) {
- int ret;
- if (!config_stats) {
- return ENOENT;
- }
- READONLY();
- peak_event_update(tsd);
- uint64_t result = peak_event_max(tsd);
- READ(result, uint64_t);
- ret = 0;
-label_return:
- return ret;
-}
-
-static int
-thread_peak_reset_ctl(tsd_t *tsd, const size_t *mib,
- size_t miblen, void *oldp, size_t *oldlenp, void *newp,
- size_t newlen) {
- int ret;
- if (!config_stats) {
- return ENOENT;
- }
- NEITHER_READ_NOR_WRITE();
- peak_event_zero(tsd);
- ret = 0;
-label_return:
- return ret;
-}
-
-static int
-thread_prof_name_ctl(tsd_t *tsd, const size_t *mib,
- size_t miblen, void *oldp, size_t *oldlenp, void *newp,
- size_t newlen) {
- int ret;
-
- if (!config_prof || !opt_prof) {
- return ENOENT;
- }
-
- READ_XOR_WRITE();
-
- if (newp != NULL) {
- if (newlen != sizeof(const char *)) {
- ret = EINVAL;
- goto label_return;
- }
-
- if ((ret = prof_thread_name_set(tsd, *(const char **)newp)) !=
- 0) {
- goto label_return;
- }
- } else {
- const char *oldname = prof_thread_name_get(tsd);
- READ(oldname, const char *);
- }
-
- ret = 0;
-label_return:
- return ret;
-}
-
-static int
-thread_prof_active_ctl(tsd_t *tsd, const size_t *mib,
- size_t miblen, void *oldp, size_t *oldlenp, void *newp,
- size_t newlen) {
- int ret;
- bool oldval;
-
- if (!config_prof) {
- return ENOENT;
- }
-
- oldval = opt_prof ? prof_thread_active_get(tsd) : false;
- if (newp != NULL) {
- if (!opt_prof) {
- ret = ENOENT;
- goto label_return;
- }
- if (newlen != sizeof(bool)) {
- ret = EINVAL;
- goto label_return;
- }
- if (prof_thread_active_set(tsd, *(bool *)newp)) {
- ret = EAGAIN;
- goto label_return;
- }
- }
- READ(oldval, bool);
-
- ret = 0;
-label_return:
- return ret;
-}
-
-static int
-thread_idle_ctl(tsd_t *tsd, const size_t *mib,
- size_t miblen, void *oldp, size_t *oldlenp, void *newp,
- size_t newlen) {
- int ret;
-
- NEITHER_READ_NOR_WRITE();
-
- if (tcache_available(tsd)) {
- tcache_flush(tsd);
- }
- /*
- * This heuristic is perhaps not the most well-considered. But it
- * matches the only idling policy we have experience with in the status
- * quo. Over time we should investigate more principled approaches.
- */
- if (opt_narenas > ncpus * 2) {
- arena_t *arena = arena_choose(tsd, NULL);
- if (arena != NULL) {
- arena_decay(tsd_tsdn(tsd), arena, false, true);
- }
- /*
- * The missing arena case is not actually an error; a thread
- * might be idle before it associates itself to one. This is
- * unusual, but not wrong.
- */
- }
-
- ret = 0;
-label_return:
- return ret;
-}
-
-/******************************************************************************/
-
-static int
-tcache_create_ctl(tsd_t *tsd, const size_t *mib, size_t miblen,
- void *oldp, size_t *oldlenp, void *newp, size_t newlen) {
- int ret;
- unsigned tcache_ind;
-
- READONLY();
- VERIFY_READ(unsigned);
- if (tcaches_create(tsd, b0get(), &tcache_ind)) {
- ret = EFAULT;
- goto label_return;
- }
- READ(tcache_ind, unsigned);
-
- ret = 0;
-label_return:
- return ret;
-}
-
-static int
-tcache_flush_ctl(tsd_t *tsd, const size_t *mib, size_t miblen,
- void *oldp, size_t *oldlenp, void *newp, size_t newlen) {
- int ret;
- unsigned tcache_ind;
-
- WRITEONLY();
- ASSURED_WRITE(tcache_ind, unsigned);
- tcaches_flush(tsd, tcache_ind);
-
- ret = 0;
-label_return:
- return ret;
-}
-
-static int
-tcache_destroy_ctl(tsd_t *tsd, const size_t *mib, size_t miblen,
- void *oldp, size_t *oldlenp, void *newp, size_t newlen) {
- int ret;
- unsigned tcache_ind;
-
- WRITEONLY();
- ASSURED_WRITE(tcache_ind, unsigned);
- tcaches_destroy(tsd, tcache_ind);
-
- ret = 0;
-label_return:
- return ret;
-}
-
-/******************************************************************************/
-
-static int
-arena_i_initialized_ctl(tsd_t *tsd, const size_t *mib, size_t miblen,
- void *oldp, size_t *oldlenp, void *newp, size_t newlen) {
- int ret;
- tsdn_t *tsdn = tsd_tsdn(tsd);
- unsigned arena_ind;
- bool initialized;
-
- READONLY();
- MIB_UNSIGNED(arena_ind, 1);
-
- malloc_mutex_lock(tsdn, &ctl_mtx);
- initialized = arenas_i(arena_ind)->initialized;
- malloc_mutex_unlock(tsdn, &ctl_mtx);
-
- READ(initialized, bool);
-
- ret = 0;
-label_return:
- return ret;
-}
-
-static void
-arena_i_decay(tsdn_t *tsdn, unsigned arena_ind, bool all) {
- malloc_mutex_lock(tsdn, &ctl_mtx);
- {
- unsigned narenas = ctl_arenas->narenas;
-
- /*
- * Access via index narenas is deprecated, and scheduled for
- * removal in 6.0.0.
- */
- if (arena_ind == MALLCTL_ARENAS_ALL || arena_ind == narenas) {
- unsigned i;
- VARIABLE_ARRAY(arena_t *, tarenas, narenas);
-
- for (i = 0; i < narenas; i++) {
- tarenas[i] = arena_get(tsdn, i, false);
- }
-
- /*
- * No further need to hold ctl_mtx, since narenas and
- * tarenas contain everything needed below.
- */
- malloc_mutex_unlock(tsdn, &ctl_mtx);
-
- for (i = 0; i < narenas; i++) {
- if (tarenas[i] != NULL) {
- arena_decay(tsdn, tarenas[i], false,
- all);
- }
- }
- } else {
- arena_t *tarena;
-
- assert(arena_ind < narenas);
-
- tarena = arena_get(tsdn, arena_ind, false);
-
- /* No further need to hold ctl_mtx. */
- malloc_mutex_unlock(tsdn, &ctl_mtx);
-
- if (tarena != NULL) {
- arena_decay(tsdn, tarena, false, all);
- }
- }
- }
-}
-
-static int
-arena_i_decay_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, void *oldp,
- size_t *oldlenp, void *newp, size_t newlen) {
- int ret;
- unsigned arena_ind;
-
- NEITHER_READ_NOR_WRITE();
- MIB_UNSIGNED(arena_ind, 1);
- arena_i_decay(tsd_tsdn(tsd), arena_ind, false);
-
- ret = 0;
-label_return:
- return ret;
-}
-
-static int
-arena_i_purge_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, void *oldp,
- size_t *oldlenp, void *newp, size_t newlen) {
- int ret;
- unsigned arena_ind;
-
- NEITHER_READ_NOR_WRITE();
- MIB_UNSIGNED(arena_ind, 1);
- arena_i_decay(tsd_tsdn(tsd), arena_ind, true);
-
- ret = 0;
-label_return:
- return ret;
-}
-
-static int
-arena_i_reset_destroy_helper(tsd_t *tsd, const size_t *mib, size_t miblen,
- void *oldp, size_t *oldlenp, void *newp, size_t newlen, unsigned *arena_ind,
- arena_t **arena) {
- int ret;
-
- NEITHER_READ_NOR_WRITE();
- MIB_UNSIGNED(*arena_ind, 1);
-
- *arena = arena_get(tsd_tsdn(tsd), *arena_ind, false);
- if (*arena == NULL || arena_is_auto(*arena)) {
- ret = EFAULT;
- goto label_return;
- }
-
- ret = 0;
-label_return:
- return ret;
-}
-
-static void
-arena_reset_prepare_background_thread(tsd_t *tsd, unsigned arena_ind) {
- /* Temporarily disable the background thread during arena reset. */
- if (have_background_thread) {
- malloc_mutex_lock(tsd_tsdn(tsd), &background_thread_lock);
- if (background_thread_enabled()) {
- background_thread_info_t *info =
- background_thread_info_get(arena_ind);
- assert(info->state == background_thread_started);
- malloc_mutex_lock(tsd_tsdn(tsd), &info->mtx);
- info->state = background_thread_paused;
- malloc_mutex_unlock(tsd_tsdn(tsd), &info->mtx);
- }
- }
-}
-
-static void
-arena_reset_finish_background_thread(tsd_t *tsd, unsigned arena_ind) {
- if (have_background_thread) {
- if (background_thread_enabled()) {
- background_thread_info_t *info =
- background_thread_info_get(arena_ind);
- assert(info->state == background_thread_paused);
- malloc_mutex_lock(tsd_tsdn(tsd), &info->mtx);
- info->state = background_thread_started;
- malloc_mutex_unlock(tsd_tsdn(tsd), &info->mtx);
- }
- malloc_mutex_unlock(tsd_tsdn(tsd), &background_thread_lock);
- }
-}
-
-static int
-arena_i_reset_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, void *oldp,
- size_t *oldlenp, void *newp, size_t newlen) {
- int ret;
- unsigned arena_ind;
- arena_t *arena;
-
- ret = arena_i_reset_destroy_helper(tsd, mib, miblen, oldp, oldlenp,
- newp, newlen, &arena_ind, &arena);
- if (ret != 0) {
- return ret;
- }
-
- arena_reset_prepare_background_thread(tsd, arena_ind);
- arena_reset(tsd, arena);
- arena_reset_finish_background_thread(tsd, arena_ind);
-
- return ret;
-}
-
-static int
-arena_i_destroy_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, void *oldp,
- size_t *oldlenp, void *newp, size_t newlen) {
- int ret;
- unsigned arena_ind;
- arena_t *arena;
- ctl_arena_t *ctl_darena, *ctl_arena;
-
- malloc_mutex_lock(tsd_tsdn(tsd), &ctl_mtx);
-
- ret = arena_i_reset_destroy_helper(tsd, mib, miblen, oldp, oldlenp,
- newp, newlen, &arena_ind, &arena);
- if (ret != 0) {
- goto label_return;
- }
-
- if (arena_nthreads_get(arena, false) != 0 || arena_nthreads_get(arena,
- true) != 0) {
- ret = EFAULT;
- goto label_return;
- }
-
- arena_reset_prepare_background_thread(tsd, arena_ind);
- /* Merge stats after resetting and purging arena. */
- arena_reset(tsd, arena);
- arena_decay(tsd_tsdn(tsd), arena, false, true);
- ctl_darena = arenas_i(MALLCTL_ARENAS_DESTROYED);
- ctl_darena->initialized = true;
- ctl_arena_refresh(tsd_tsdn(tsd), arena, ctl_darena, arena_ind, true);
- /* Destroy arena. */
- arena_destroy(tsd, arena);
- ctl_arena = arenas_i(arena_ind);
- ctl_arena->initialized = false;
- /* Record arena index for later recycling via arenas.create. */
- ql_elm_new(ctl_arena, destroyed_link);
- ql_tail_insert(&ctl_arenas->destroyed, ctl_arena, destroyed_link);
- arena_reset_finish_background_thread(tsd, arena_ind);
-
- assert(ret == 0);
-label_return:
- malloc_mutex_unlock(tsd_tsdn(tsd), &ctl_mtx);
-
- return ret;
-}
-
-static int
-arena_i_dss_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, void *oldp,
- size_t *oldlenp, void *newp, size_t newlen) {
- int ret;
- const char *dss = NULL;
- unsigned arena_ind;
- dss_prec_t dss_prec_old = dss_prec_limit;
- dss_prec_t dss_prec = dss_prec_limit;
-
- malloc_mutex_lock(tsd_tsdn(tsd), &ctl_mtx);
- WRITE(dss, const char *);
- MIB_UNSIGNED(arena_ind, 1);
- if (dss != NULL) {
- int i;
- bool match = false;
-
- for (i = 0; i < dss_prec_limit; i++) {
- if (strcmp(dss_prec_names[i], dss) == 0) {
- dss_prec = i;
- match = true;
- break;
- }
- }
-
- if (!match) {
- ret = EINVAL;
- goto label_return;
- }
- }
-
- /*
- * Access via index narenas is deprecated, and scheduled for removal in
- * 6.0.0.
- */
- if (arena_ind == MALLCTL_ARENAS_ALL || arena_ind ==
- ctl_arenas->narenas) {
- if (dss_prec != dss_prec_limit &&
- extent_dss_prec_set(dss_prec)) {
- ret = EFAULT;
- goto label_return;
- }
- dss_prec_old = extent_dss_prec_get();
- } else {
- arena_t *arena = arena_get(tsd_tsdn(tsd), arena_ind, false);
- if (arena == NULL || (dss_prec != dss_prec_limit &&
- arena_dss_prec_set(arena, dss_prec))) {
- ret = EFAULT;
- goto label_return;
- }
- dss_prec_old = arena_dss_prec_get(arena);
- }
-
- dss = dss_prec_names[dss_prec_old];
- READ(dss, const char *);
-
- ret = 0;
-label_return:
- malloc_mutex_unlock(tsd_tsdn(tsd), &ctl_mtx);
- return ret;
-}
-
-static int
-arena_i_oversize_threshold_ctl(tsd_t *tsd, const size_t *mib, size_t miblen,
- void *oldp, size_t *oldlenp, void *newp, size_t newlen) {
- int ret;
-
- unsigned arena_ind;
- MIB_UNSIGNED(arena_ind, 1);
-
- arena_t *arena = arena_get(tsd_tsdn(tsd), arena_ind, false);
- if (arena == NULL) {
- ret = EFAULT;
- goto label_return;
- }
-
- if (oldp != NULL && oldlenp != NULL) {
- size_t oldval = atomic_load_zu(
- &arena->pa_shard.pac.oversize_threshold, ATOMIC_RELAXED);
- READ(oldval, size_t);
- }
- if (newp != NULL) {
- if (newlen != sizeof(size_t)) {
- ret = EINVAL;
- goto label_return;
- }
- atomic_store_zu(&arena->pa_shard.pac.oversize_threshold,
- *(size_t *)newp, ATOMIC_RELAXED);
- }
- ret = 0;
-label_return:
- return ret;
-}
-
-static int
-arena_i_decay_ms_ctl_impl(tsd_t *tsd, const size_t *mib, size_t miblen,
- void *oldp, size_t *oldlenp, void *newp, size_t newlen, bool dirty) {
- int ret;
- unsigned arena_ind;
- arena_t *arena;
-
- MIB_UNSIGNED(arena_ind, 1);
- arena = arena_get(tsd_tsdn(tsd), arena_ind, false);
- if (arena == NULL) {
- ret = EFAULT;
- goto label_return;
- }
- extent_state_t state = dirty ? extent_state_dirty : extent_state_muzzy;
-
- if (oldp != NULL && oldlenp != NULL) {
- size_t oldval = arena_decay_ms_get(arena, state);
- READ(oldval, ssize_t);
- }
- if (newp != NULL) {
- if (newlen != sizeof(ssize_t)) {
- ret = EINVAL;
- goto label_return;
- }
- if (arena_is_huge(arena_ind) && *(ssize_t *)newp > 0) {
- /*
- * By default the huge arena purges eagerly. If it is
- * set to non-zero decay time afterwards, background
- * thread might be needed.
- */
- if (background_thread_create(tsd, arena_ind)) {
- ret = EFAULT;
- goto label_return;
- }
- }
-
- if (arena_decay_ms_set(tsd_tsdn(tsd), arena, state,
- *(ssize_t *)newp)) {
- ret = EFAULT;
- goto label_return;
- }
- }
-
- ret = 0;
-label_return:
- return ret;
-}
-
-static int
-arena_i_dirty_decay_ms_ctl(tsd_t *tsd, const size_t *mib, size_t miblen,
- void *oldp, size_t *oldlenp, void *newp, size_t newlen) {
- return arena_i_decay_ms_ctl_impl(tsd, mib, miblen, oldp, oldlenp, newp,
- newlen, true);
-}
-
-static int
-arena_i_muzzy_decay_ms_ctl(tsd_t *tsd, const size_t *mib, size_t miblen,
- void *oldp, size_t *oldlenp, void *newp, size_t newlen) {
- return arena_i_decay_ms_ctl_impl(tsd, mib, miblen, oldp, oldlenp, newp,
- newlen, false);
-}
-
-static int
-arena_i_extent_hooks_ctl(tsd_t *tsd, const size_t *mib, size_t miblen,
- void *oldp, size_t *oldlenp, void *newp, size_t newlen) {
- int ret;
- unsigned arena_ind;
- arena_t *arena;
-
- malloc_mutex_lock(tsd_tsdn(tsd), &ctl_mtx);
- MIB_UNSIGNED(arena_ind, 1);
- if (arena_ind < narenas_total_get()) {
- extent_hooks_t *old_extent_hooks;
- arena = arena_get(tsd_tsdn(tsd), arena_ind, false);
- if (arena == NULL) {
- if (arena_ind >= narenas_auto) {
- ret = EFAULT;
- goto label_return;
- }
- old_extent_hooks =
- (extent_hooks_t *)&ehooks_default_extent_hooks;
- READ(old_extent_hooks, extent_hooks_t *);
- if (newp != NULL) {
- /* Initialize a new arena as a side effect. */
- extent_hooks_t *new_extent_hooks
- JEMALLOC_CC_SILENCE_INIT(NULL);
- WRITE(new_extent_hooks, extent_hooks_t *);
- arena_config_t config = arena_config_default;
- config.extent_hooks = new_extent_hooks;
-
- arena = arena_init(tsd_tsdn(tsd), arena_ind,
- &config);
- if (arena == NULL) {
- ret = EFAULT;
- goto label_return;
- }
- }
- } else {
- if (newp != NULL) {
- extent_hooks_t *new_extent_hooks
- JEMALLOC_CC_SILENCE_INIT(NULL);
- WRITE(new_extent_hooks, extent_hooks_t *);
- old_extent_hooks = arena_set_extent_hooks(tsd,
- arena, new_extent_hooks);
- READ(old_extent_hooks, extent_hooks_t *);
- } else {
- old_extent_hooks =
- ehooks_get_extent_hooks_ptr(
- arena_get_ehooks(arena));
- READ(old_extent_hooks, extent_hooks_t *);
- }
- }
- } else {
- ret = EFAULT;
- goto label_return;
- }
- ret = 0;
-label_return:
- malloc_mutex_unlock(tsd_tsdn(tsd), &ctl_mtx);
- return ret;
-}
-
-static int
-arena_i_retain_grow_limit_ctl(tsd_t *tsd, const size_t *mib,
- size_t miblen, void *oldp, size_t *oldlenp, void *newp,
- size_t newlen) {
- int ret;
- unsigned arena_ind;
- arena_t *arena;
-
- if (!opt_retain) {
- /* Only relevant when retain is enabled. */
- return ENOENT;
- }
-
- malloc_mutex_lock(tsd_tsdn(tsd), &ctl_mtx);
- MIB_UNSIGNED(arena_ind, 1);
- if (arena_ind < narenas_total_get() && (arena =
- arena_get(tsd_tsdn(tsd), arena_ind, false)) != NULL) {
- size_t old_limit, new_limit;
- if (newp != NULL) {
- WRITE(new_limit, size_t);
- }
- bool err = arena_retain_grow_limit_get_set(tsd, arena,
- &old_limit, newp != NULL ? &new_limit : NULL);
- if (!err) {
- READ(old_limit, size_t);
- ret = 0;
- } else {
- ret = EFAULT;
- }
- } else {
- ret = EFAULT;
- }
-label_return:
- malloc_mutex_unlock(tsd_tsdn(tsd), &ctl_mtx);
- return ret;
-}
-
-static const ctl_named_node_t *
-arena_i_index(tsdn_t *tsdn, const size_t *mib, size_t miblen,
- size_t i) {
- const ctl_named_node_t *ret;
-
- malloc_mutex_lock(tsdn, &ctl_mtx);
- switch (i) {
- case MALLCTL_ARENAS_ALL:
- case MALLCTL_ARENAS_DESTROYED:
- break;
- default:
- if (i > ctl_arenas->narenas) {
- ret = NULL;
- goto label_return;
- }
- break;
- }
-
- ret = super_arena_i_node;
-label_return:
- malloc_mutex_unlock(tsdn, &ctl_mtx);
- return ret;
-}
-
-/******************************************************************************/
-
-static int
-arenas_narenas_ctl(tsd_t *tsd, const size_t *mib, size_t miblen,
- void *oldp, size_t *oldlenp, void *newp, size_t newlen) {
- int ret;
- unsigned narenas;
-
- malloc_mutex_lock(tsd_tsdn(tsd), &ctl_mtx);
- READONLY();
- narenas = ctl_arenas->narenas;
- READ(narenas, unsigned);
-
- ret = 0;
-label_return:
- malloc_mutex_unlock(tsd_tsdn(tsd), &ctl_mtx);
- return ret;
-}
-
-static int
-arenas_decay_ms_ctl_impl(tsd_t *tsd, const size_t *mib,
- size_t miblen, void *oldp, size_t *oldlenp, void *newp,
- size_t newlen, bool dirty) {
- int ret;
-
- if (oldp != NULL && oldlenp != NULL) {
- size_t oldval = (dirty ? arena_dirty_decay_ms_default_get() :
- arena_muzzy_decay_ms_default_get());
- READ(oldval, ssize_t);
- }
- if (newp != NULL) {
- if (newlen != sizeof(ssize_t)) {
- ret = EINVAL;
- goto label_return;
- }
- if (dirty ? arena_dirty_decay_ms_default_set(*(ssize_t *)newp)
- : arena_muzzy_decay_ms_default_set(*(ssize_t *)newp)) {
- ret = EFAULT;
- goto label_return;
- }
- }
-
- ret = 0;
-label_return:
- return ret;
-}
-
-static int
-arenas_dirty_decay_ms_ctl(tsd_t *tsd, const size_t *mib, size_t miblen,
- void *oldp, size_t *oldlenp, void *newp, size_t newlen) {
- return arenas_decay_ms_ctl_impl(tsd, mib, miblen, oldp, oldlenp, newp,
- newlen, true);
-}
-
-static int
-arenas_muzzy_decay_ms_ctl(tsd_t *tsd, const size_t *mib, size_t miblen,
- void *oldp, size_t *oldlenp, void *newp, size_t newlen) {
- return arenas_decay_ms_ctl_impl(tsd, mib, miblen, oldp, oldlenp, newp,
- newlen, false);
-}
-
-CTL_RO_NL_GEN(arenas_quantum, QUANTUM, size_t)
-CTL_RO_NL_GEN(arenas_page, PAGE, size_t)
-CTL_RO_NL_GEN(arenas_tcache_max, tcache_maxclass, size_t)
-CTL_RO_NL_GEN(arenas_nbins, SC_NBINS, unsigned)
-CTL_RO_NL_GEN(arenas_nhbins, nhbins, unsigned)
-CTL_RO_NL_GEN(arenas_bin_i_size, bin_infos[mib[2]].reg_size, size_t)
-CTL_RO_NL_GEN(arenas_bin_i_nregs, bin_infos[mib[2]].nregs, uint32_t)
-CTL_RO_NL_GEN(arenas_bin_i_slab_size, bin_infos[mib[2]].slab_size, size_t)
-CTL_RO_NL_GEN(arenas_bin_i_nshards, bin_infos[mib[2]].n_shards, uint32_t)
-static const ctl_named_node_t *
-arenas_bin_i_index(tsdn_t *tsdn, const size_t *mib,
- size_t miblen, size_t i) {
- if (i > SC_NBINS) {
- return NULL;
- }
- return super_arenas_bin_i_node;
-}
-
-CTL_RO_NL_GEN(arenas_nlextents, SC_NSIZES - SC_NBINS, unsigned)
-CTL_RO_NL_GEN(arenas_lextent_i_size, sz_index2size(SC_NBINS+(szind_t)mib[2]),
- size_t)
-static const ctl_named_node_t *
-arenas_lextent_i_index(tsdn_t *tsdn, const size_t *mib,
- size_t miblen, size_t i) {
- if (i > SC_NSIZES - SC_NBINS) {
- return NULL;
- }
- return super_arenas_lextent_i_node;
-}
-
-static int
-arenas_create_ctl(tsd_t *tsd, const size_t *mib, size_t miblen,
- void *oldp, size_t *oldlenp, void *newp, size_t newlen) {
- int ret;
- unsigned arena_ind;
-
- malloc_mutex_lock(tsd_tsdn(tsd), &ctl_mtx);
-
- VERIFY_READ(unsigned);
- arena_config_t config = arena_config_default;
- WRITE(config.extent_hooks, extent_hooks_t *);
- if ((arena_ind = ctl_arena_init(tsd, &config)) == UINT_MAX) {
- ret = EAGAIN;
- goto label_return;
- }
- READ(arena_ind, unsigned);
-
- ret = 0;
-label_return:
- malloc_mutex_unlock(tsd_tsdn(tsd), &ctl_mtx);
- return ret;
-}
-
-static int
-experimental_arenas_create_ext_ctl(tsd_t *tsd,
- const size_t *mib, size_t miblen,
- void *oldp, size_t *oldlenp, void *newp, size_t newlen) {
- int ret;
- unsigned arena_ind;
-
- malloc_mutex_lock(tsd_tsdn(tsd), &ctl_mtx);
-
- arena_config_t config = arena_config_default;
- VERIFY_READ(unsigned);
- WRITE(config, arena_config_t);
-
- if ((arena_ind = ctl_arena_init(tsd, &config)) == UINT_MAX) {
- ret = EAGAIN;
- goto label_return;
- }
- READ(arena_ind, unsigned);
- ret = 0;
-label_return:
- malloc_mutex_unlock(tsd_tsdn(tsd), &ctl_mtx);
- return ret;
-}
-
-static int
-arenas_lookup_ctl(tsd_t *tsd, const size_t *mib,
- size_t miblen, void *oldp, size_t *oldlenp, void *newp,
- size_t newlen) {
- int ret;
- unsigned arena_ind;
- void *ptr;
- edata_t *edata;
- arena_t *arena;
-
- ptr = NULL;
- ret = EINVAL;
- malloc_mutex_lock(tsd_tsdn(tsd), &ctl_mtx);
- WRITE(ptr, void *);
- edata = emap_edata_lookup(tsd_tsdn(tsd), &arena_emap_global, ptr);
- if (edata == NULL) {
- goto label_return;
- }
-
- arena = arena_get_from_edata(edata);
- if (arena == NULL) {
- goto label_return;
- }
-
- arena_ind = arena_ind_get(arena);
- READ(arena_ind, unsigned);
-
- ret = 0;
-label_return:
- malloc_mutex_unlock(tsd_tsdn(tsd), &ctl_mtx);
- return ret;
-}
-
-/******************************************************************************/
-
-static int
-prof_thread_active_init_ctl(tsd_t *tsd, const size_t *mib,
- size_t miblen, void *oldp, size_t *oldlenp, void *newp,
- size_t newlen) {
- int ret;
- bool oldval;
-
- if (!config_prof) {
- return ENOENT;
- }
-
- if (newp != NULL) {
- if (!opt_prof) {
- ret = ENOENT;
- goto label_return;
- }
- if (newlen != sizeof(bool)) {
- ret = EINVAL;
- goto label_return;
- }
- oldval = prof_thread_active_init_set(tsd_tsdn(tsd),
- *(bool *)newp);
- } else {
- oldval = opt_prof ? prof_thread_active_init_get(tsd_tsdn(tsd)) :
- false;
- }
- READ(oldval, bool);
-
- ret = 0;
-label_return:
- return ret;
-}
-
-static int
-prof_active_ctl(tsd_t *tsd, const size_t *mib, size_t miblen,
- void *oldp, size_t *oldlenp, void *newp, size_t newlen) {
- int ret;
- bool oldval;
-
- if (!config_prof) {
- ret = ENOENT;
- goto label_return;
- }
-
- if (newp != NULL) {
- if (newlen != sizeof(bool)) {
- ret = EINVAL;
- goto label_return;
- }
- bool val = *(bool *)newp;
- if (!opt_prof) {
- if (val) {
- ret = ENOENT;
- goto label_return;
- } else {
- /* No change needed (already off). */
- oldval = false;
- }
- } else {
- oldval = prof_active_set(tsd_tsdn(tsd), val);
- }
- } else {
- oldval = opt_prof ? prof_active_get(tsd_tsdn(tsd)) : false;
- }
- READ(oldval, bool);
-
- ret = 0;
-label_return:
- return ret;
-}
-
-static int
-prof_dump_ctl(tsd_t *tsd, const size_t *mib, size_t miblen,
- void *oldp, size_t *oldlenp, void *newp, size_t newlen) {
- int ret;
- const char *filename = NULL;
-
- if (!config_prof || !opt_prof) {
- return ENOENT;
- }
-
- WRITEONLY();
- WRITE(filename, const char *);
-
- if (prof_mdump(tsd, filename)) {
- ret = EFAULT;
- goto label_return;
- }
-
- ret = 0;
-label_return:
- return ret;
-}
-
-static int
-prof_gdump_ctl(tsd_t *tsd, const size_t *mib, size_t miblen,
- void *oldp, size_t *oldlenp, void *newp, size_t newlen) {
- int ret;
- bool oldval;
-
- if (!config_prof) {
- return ENOENT;
- }
-
- if (newp != NULL) {
- if (!opt_prof) {
- ret = ENOENT;
- goto label_return;
- }
- if (newlen != sizeof(bool)) {
- ret = EINVAL;
- goto label_return;
- }
- oldval = prof_gdump_set(tsd_tsdn(tsd), *(bool *)newp);
- } else {
- oldval = opt_prof ? prof_gdump_get(tsd_tsdn(tsd)) : false;
- }
- READ(oldval, bool);
-
- ret = 0;
-label_return:
- return ret;
-}
-
-static int
-prof_prefix_ctl(tsd_t *tsd, const size_t *mib, size_t miblen,
- void *oldp, size_t *oldlenp, void *newp, size_t newlen) {
- int ret;
- const char *prefix = NULL;
-
- if (!config_prof || !opt_prof) {
- return ENOENT;
- }
-
- malloc_mutex_lock(tsd_tsdn(tsd), &ctl_mtx);
- WRITEONLY();
- WRITE(prefix, const char *);
-
- ret = prof_prefix_set(tsd_tsdn(tsd), prefix) ? EFAULT : 0;
-label_return:
- malloc_mutex_unlock(tsd_tsdn(tsd), &ctl_mtx);
- return ret;
-}
-
-static int
-prof_reset_ctl(tsd_t *tsd, const size_t *mib, size_t miblen,
- void *oldp, size_t *oldlenp, void *newp, size_t newlen) {
- int ret;
- size_t lg_sample = lg_prof_sample;
-
- if (!config_prof || !opt_prof) {
- return ENOENT;
- }
-
- WRITEONLY();
- WRITE(lg_sample, size_t);
- if (lg_sample >= (sizeof(uint64_t) << 3)) {
- lg_sample = (sizeof(uint64_t) << 3) - 1;
- }
-
- prof_reset(tsd, lg_sample);
-
- ret = 0;
-label_return:
- return ret;
-}
-
-CTL_RO_NL_CGEN(config_prof, prof_interval, prof_interval, uint64_t)
-CTL_RO_NL_CGEN(config_prof, lg_prof_sample, lg_prof_sample, size_t)
-
-static int
-prof_log_start_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, void *oldp,
- size_t *oldlenp, void *newp, size_t newlen) {
- int ret;
-
- const char *filename = NULL;
-
- if (!config_prof || !opt_prof) {
- return ENOENT;
- }
-
- WRITEONLY();
- WRITE(filename, const char *);
-
- if (prof_log_start(tsd_tsdn(tsd), filename)) {
- ret = EFAULT;
- goto label_return;
- }
-
- ret = 0;
-label_return:
- return ret;
-}
-
-static int
-prof_log_stop_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, void *oldp,
- size_t *oldlenp, void *newp, size_t newlen) {
- if (!config_prof || !opt_prof) {
- return ENOENT;
- }
-
- if (prof_log_stop(tsd_tsdn(tsd))) {
- return EFAULT;
- }
-
- return 0;
-}
-
-static int
-experimental_hooks_prof_backtrace_ctl(tsd_t *tsd, const size_t *mib,
- size_t miblen, void *oldp, size_t *oldlenp, void *newp, size_t newlen) {
- int ret;
-
- if (oldp == NULL && newp == NULL) {
- ret = EINVAL;
- goto label_return;
- }
- if (oldp != NULL) {
- prof_backtrace_hook_t old_hook =
- prof_backtrace_hook_get();
- READ(old_hook, prof_backtrace_hook_t);
- }
- if (newp != NULL) {
- if (!opt_prof) {
- ret = ENOENT;
- goto label_return;
- }
- prof_backtrace_hook_t new_hook JEMALLOC_CC_SILENCE_INIT(NULL);
- WRITE(new_hook, prof_backtrace_hook_t);
- if (new_hook == NULL) {
- ret = EINVAL;
- goto label_return;
- }
- prof_backtrace_hook_set(new_hook);
- }
- ret = 0;
-label_return:
- return ret;
-}
-
-static int
-experimental_hooks_prof_dump_ctl(tsd_t *tsd, const size_t *mib,
- size_t miblen, void *oldp, size_t *oldlenp, void *newp, size_t newlen) {
- int ret;
-
- if (oldp == NULL && newp == NULL) {
- ret = EINVAL;
- goto label_return;
- }
- if (oldp != NULL) {
- prof_dump_hook_t old_hook =
- prof_dump_hook_get();
- READ(old_hook, prof_dump_hook_t);
- }
- if (newp != NULL) {
- if (!opt_prof) {
- ret = ENOENT;
- goto label_return;
- }
- prof_dump_hook_t new_hook JEMALLOC_CC_SILENCE_INIT(NULL);
- WRITE(new_hook, prof_dump_hook_t);
- prof_dump_hook_set(new_hook);
- }
- ret = 0;
-label_return:
- return ret;
-}
-
-/* For integration test purpose only. No plan to move out of experimental. */
-static int
-experimental_hooks_safety_check_abort_ctl(tsd_t *tsd, const size_t *mib,
- size_t miblen, void *oldp, size_t *oldlenp, void *newp, size_t newlen) {
- int ret;
-
- WRITEONLY();
- if (newp != NULL) {
- if (newlen != sizeof(safety_check_abort_hook_t)) {
- ret = EINVAL;
- goto label_return;
- }
- safety_check_abort_hook_t hook JEMALLOC_CC_SILENCE_INIT(NULL);
- WRITE(hook, safety_check_abort_hook_t);
- safety_check_set_abort(hook);
- }
- ret = 0;
-label_return:
- return ret;
-}
-
-/******************************************************************************/
-
-CTL_RO_CGEN(config_stats, stats_allocated, ctl_stats->allocated, size_t)
-CTL_RO_CGEN(config_stats, stats_active, ctl_stats->active, size_t)
-CTL_RO_CGEN(config_stats, stats_metadata, ctl_stats->metadata, size_t)
-CTL_RO_CGEN(config_stats, stats_metadata_thp, ctl_stats->metadata_thp, size_t)
-CTL_RO_CGEN(config_stats, stats_resident, ctl_stats->resident, size_t)
-CTL_RO_CGEN(config_stats, stats_mapped, ctl_stats->mapped, size_t)
-CTL_RO_CGEN(config_stats, stats_retained, ctl_stats->retained, size_t)
-
-CTL_RO_CGEN(config_stats, stats_background_thread_num_threads,
- ctl_stats->background_thread.num_threads, size_t)
-CTL_RO_CGEN(config_stats, stats_background_thread_num_runs,
- ctl_stats->background_thread.num_runs, uint64_t)
-CTL_RO_CGEN(config_stats, stats_background_thread_run_interval,
- nstime_ns(&ctl_stats->background_thread.run_interval), uint64_t)
-
-CTL_RO_CGEN(config_stats, stats_zero_reallocs,
- atomic_load_zu(&zero_realloc_count, ATOMIC_RELAXED), size_t)
-
-CTL_RO_GEN(stats_arenas_i_dss, arenas_i(mib[2])->dss, const char *)
-CTL_RO_GEN(stats_arenas_i_dirty_decay_ms, arenas_i(mib[2])->dirty_decay_ms,
- ssize_t)
-CTL_RO_GEN(stats_arenas_i_muzzy_decay_ms, arenas_i(mib[2])->muzzy_decay_ms,
- ssize_t)
-CTL_RO_GEN(stats_arenas_i_nthreads, arenas_i(mib[2])->nthreads, unsigned)
-CTL_RO_GEN(stats_arenas_i_uptime,
- nstime_ns(&arenas_i(mib[2])->astats->astats.uptime), uint64_t)
-CTL_RO_GEN(stats_arenas_i_pactive, arenas_i(mib[2])->pactive, size_t)
-CTL_RO_GEN(stats_arenas_i_pdirty, arenas_i(mib[2])->pdirty, size_t)
-CTL_RO_GEN(stats_arenas_i_pmuzzy, arenas_i(mib[2])->pmuzzy, size_t)
-CTL_RO_CGEN(config_stats, stats_arenas_i_mapped,
- arenas_i(mib[2])->astats->astats.mapped, size_t)
-CTL_RO_CGEN(config_stats, stats_arenas_i_retained,
- arenas_i(mib[2])->astats->astats.pa_shard_stats.pac_stats.retained, size_t)
-CTL_RO_CGEN(config_stats, stats_arenas_i_extent_avail,
- arenas_i(mib[2])->astats->astats.pa_shard_stats.edata_avail, size_t)
-
-CTL_RO_CGEN(config_stats, stats_arenas_i_dirty_npurge,
- locked_read_u64_unsynchronized(
- &arenas_i(mib[2])->astats->astats.pa_shard_stats.pac_stats.decay_dirty.npurge),
- uint64_t)
-CTL_RO_CGEN(config_stats, stats_arenas_i_dirty_nmadvise,
- locked_read_u64_unsynchronized(
- &arenas_i(mib[2])->astats->astats.pa_shard_stats.pac_stats.decay_dirty.nmadvise),
- uint64_t)
-CTL_RO_CGEN(config_stats, stats_arenas_i_dirty_purged,
- locked_read_u64_unsynchronized(
- &arenas_i(mib[2])->astats->astats.pa_shard_stats.pac_stats.decay_dirty.purged),
- uint64_t)
-
-CTL_RO_CGEN(config_stats, stats_arenas_i_muzzy_npurge,
- locked_read_u64_unsynchronized(
- &arenas_i(mib[2])->astats->astats.pa_shard_stats.pac_stats.decay_muzzy.npurge),
- uint64_t)
-CTL_RO_CGEN(config_stats, stats_arenas_i_muzzy_nmadvise,
- locked_read_u64_unsynchronized(
- &arenas_i(mib[2])->astats->astats.pa_shard_stats.pac_stats.decay_muzzy.nmadvise),
- uint64_t)
-CTL_RO_CGEN(config_stats, stats_arenas_i_muzzy_purged,
- locked_read_u64_unsynchronized(
- &arenas_i(mib[2])->astats->astats.pa_shard_stats.pac_stats.decay_muzzy.purged),
- uint64_t)
-
-CTL_RO_CGEN(config_stats, stats_arenas_i_base,
- arenas_i(mib[2])->astats->astats.base,
- size_t)
-CTL_RO_CGEN(config_stats, stats_arenas_i_internal,
- atomic_load_zu(&arenas_i(mib[2])->astats->astats.internal, ATOMIC_RELAXED),
- size_t)
-CTL_RO_CGEN(config_stats, stats_arenas_i_metadata_thp,
- arenas_i(mib[2])->astats->astats.metadata_thp, size_t)
-CTL_RO_CGEN(config_stats, stats_arenas_i_tcache_bytes,
- arenas_i(mib[2])->astats->astats.tcache_bytes, size_t)
-CTL_RO_CGEN(config_stats, stats_arenas_i_tcache_stashed_bytes,
- arenas_i(mib[2])->astats->astats.tcache_stashed_bytes, size_t)
-CTL_RO_CGEN(config_stats, stats_arenas_i_resident,
- arenas_i(mib[2])->astats->astats.resident,
- size_t)
-CTL_RO_CGEN(config_stats, stats_arenas_i_abandoned_vm,
- atomic_load_zu(
- &arenas_i(mib[2])->astats->astats.pa_shard_stats.pac_stats.abandoned_vm,
- ATOMIC_RELAXED), size_t)
-
-CTL_RO_CGEN(config_stats, stats_arenas_i_hpa_sec_bytes,
- arenas_i(mib[2])->astats->secstats.bytes, size_t)
-
-CTL_RO_CGEN(config_stats, stats_arenas_i_small_allocated,
- arenas_i(mib[2])->astats->allocated_small, size_t)
-CTL_RO_CGEN(config_stats, stats_arenas_i_small_nmalloc,
- arenas_i(mib[2])->astats->nmalloc_small, uint64_t)
-CTL_RO_CGEN(config_stats, stats_arenas_i_small_ndalloc,
- arenas_i(mib[2])->astats->ndalloc_small, uint64_t)
-CTL_RO_CGEN(config_stats, stats_arenas_i_small_nrequests,
- arenas_i(mib[2])->astats->nrequests_small, uint64_t)
-CTL_RO_CGEN(config_stats, stats_arenas_i_small_nfills,
- arenas_i(mib[2])->astats->nfills_small, uint64_t)
-CTL_RO_CGEN(config_stats, stats_arenas_i_small_nflushes,
- arenas_i(mib[2])->astats->nflushes_small, uint64_t)
-CTL_RO_CGEN(config_stats, stats_arenas_i_large_allocated,
- arenas_i(mib[2])->astats->astats.allocated_large, size_t)
-CTL_RO_CGEN(config_stats, stats_arenas_i_large_nmalloc,
- arenas_i(mib[2])->astats->astats.nmalloc_large, uint64_t)
-CTL_RO_CGEN(config_stats, stats_arenas_i_large_ndalloc,
- arenas_i(mib[2])->astats->astats.ndalloc_large, uint64_t)
-CTL_RO_CGEN(config_stats, stats_arenas_i_large_nrequests,
- arenas_i(mib[2])->astats->astats.nrequests_large, uint64_t)
-/*
- * Note: "nmalloc_large" here instead of "nfills" in the read. This is
- * intentional (large has no batch fill).
- */
-CTL_RO_CGEN(config_stats, stats_arenas_i_large_nfills,
- arenas_i(mib[2])->astats->astats.nmalloc_large, uint64_t)
-CTL_RO_CGEN(config_stats, stats_arenas_i_large_nflushes,
- arenas_i(mib[2])->astats->astats.nflushes_large, uint64_t)
-
-/* Lock profiling related APIs below. */
-#define RO_MUTEX_CTL_GEN(n, l) \
-CTL_RO_CGEN(config_stats, stats_##n##_num_ops, \
- l.n_lock_ops, uint64_t) \
-CTL_RO_CGEN(config_stats, stats_##n##_num_wait, \
- l.n_wait_times, uint64_t) \
-CTL_RO_CGEN(config_stats, stats_##n##_num_spin_acq, \
- l.n_spin_acquired, uint64_t) \
-CTL_RO_CGEN(config_stats, stats_##n##_num_owner_switch, \
- l.n_owner_switches, uint64_t) \
-CTL_RO_CGEN(config_stats, stats_##n##_total_wait_time, \
- nstime_ns(&l.tot_wait_time), uint64_t) \
-CTL_RO_CGEN(config_stats, stats_##n##_max_wait_time, \
- nstime_ns(&l.max_wait_time), uint64_t) \
-CTL_RO_CGEN(config_stats, stats_##n##_max_num_thds, \
- l.max_n_thds, uint32_t)
-
-/* Global mutexes. */
-#define OP(mtx) \
- RO_MUTEX_CTL_GEN(mutexes_##mtx, \
- ctl_stats->mutex_prof_data[global_prof_mutex_##mtx])
-MUTEX_PROF_GLOBAL_MUTEXES
-#undef OP
-
-/* Per arena mutexes */
-#define OP(mtx) RO_MUTEX_CTL_GEN(arenas_i_mutexes_##mtx, \
- arenas_i(mib[2])->astats->astats.mutex_prof_data[arena_prof_mutex_##mtx])
-MUTEX_PROF_ARENA_MUTEXES
-#undef OP
-
-/* tcache bin mutex */
-RO_MUTEX_CTL_GEN(arenas_i_bins_j_mutex,
- arenas_i(mib[2])->astats->bstats[mib[4]].mutex_data)
-#undef RO_MUTEX_CTL_GEN
-
-/* Resets all mutex stats, including global, arena and bin mutexes. */
-static int
-stats_mutexes_reset_ctl(tsd_t *tsd, const size_t *mib,
- size_t miblen, void *oldp, size_t *oldlenp,
- void *newp, size_t newlen) {
- if (!config_stats) {
- return ENOENT;
- }
-
- tsdn_t *tsdn = tsd_tsdn(tsd);
-
-#define MUTEX_PROF_RESET(mtx) \
- malloc_mutex_lock(tsdn, &mtx); \
- malloc_mutex_prof_data_reset(tsdn, &mtx); \
- malloc_mutex_unlock(tsdn, &mtx);
-
- /* Global mutexes: ctl and prof. */
- MUTEX_PROF_RESET(ctl_mtx);
- if (have_background_thread) {
- MUTEX_PROF_RESET(background_thread_lock);
- }
- if (config_prof && opt_prof) {
- MUTEX_PROF_RESET(bt2gctx_mtx);
- MUTEX_PROF_RESET(tdatas_mtx);
- MUTEX_PROF_RESET(prof_dump_mtx);
- MUTEX_PROF_RESET(prof_recent_alloc_mtx);
- MUTEX_PROF_RESET(prof_recent_dump_mtx);
- MUTEX_PROF_RESET(prof_stats_mtx);
- }
-
- /* Per arena mutexes. */
- unsigned n = narenas_total_get();
-
- for (unsigned i = 0; i < n; i++) {
- arena_t *arena = arena_get(tsdn, i, false);
- if (!arena) {
- continue;
- }
- MUTEX_PROF_RESET(arena->large_mtx);
- MUTEX_PROF_RESET(arena->pa_shard.edata_cache.mtx);
- MUTEX_PROF_RESET(arena->pa_shard.pac.ecache_dirty.mtx);
- MUTEX_PROF_RESET(arena->pa_shard.pac.ecache_muzzy.mtx);
- MUTEX_PROF_RESET(arena->pa_shard.pac.ecache_retained.mtx);
- MUTEX_PROF_RESET(arena->pa_shard.pac.decay_dirty.mtx);
- MUTEX_PROF_RESET(arena->pa_shard.pac.decay_muzzy.mtx);
- MUTEX_PROF_RESET(arena->tcache_ql_mtx);
- MUTEX_PROF_RESET(arena->base->mtx);
-
- for (szind_t j = 0; j < SC_NBINS; j++) {
- for (unsigned k = 0; k < bin_infos[j].n_shards; k++) {
- bin_t *bin = arena_get_bin(arena, j, k);
- MUTEX_PROF_RESET(bin->lock);
- }
- }
- }
-#undef MUTEX_PROF_RESET
- return 0;
-}
-
-CTL_RO_CGEN(config_stats, stats_arenas_i_bins_j_nmalloc,
- arenas_i(mib[2])->astats->bstats[mib[4]].stats_data.nmalloc, uint64_t)
-CTL_RO_CGEN(config_stats, stats_arenas_i_bins_j_ndalloc,
- arenas_i(mib[2])->astats->bstats[mib[4]].stats_data.ndalloc, uint64_t)
-CTL_RO_CGEN(config_stats, stats_arenas_i_bins_j_nrequests,
- arenas_i(mib[2])->astats->bstats[mib[4]].stats_data.nrequests, uint64_t)
-CTL_RO_CGEN(config_stats, stats_arenas_i_bins_j_curregs,
- arenas_i(mib[2])->astats->bstats[mib[4]].stats_data.curregs, size_t)
-CTL_RO_CGEN(config_stats, stats_arenas_i_bins_j_nfills,
- arenas_i(mib[2])->astats->bstats[mib[4]].stats_data.nfills, uint64_t)
-CTL_RO_CGEN(config_stats, stats_arenas_i_bins_j_nflushes,
- arenas_i(mib[2])->astats->bstats[mib[4]].stats_data.nflushes, uint64_t)
-CTL_RO_CGEN(config_stats, stats_arenas_i_bins_j_nslabs,
- arenas_i(mib[2])->astats->bstats[mib[4]].stats_data.nslabs, uint64_t)
-CTL_RO_CGEN(config_stats, stats_arenas_i_bins_j_nreslabs,
- arenas_i(mib[2])->astats->bstats[mib[4]].stats_data.reslabs, uint64_t)
-CTL_RO_CGEN(config_stats, stats_arenas_i_bins_j_curslabs,
- arenas_i(mib[2])->astats->bstats[mib[4]].stats_data.curslabs, size_t)
-CTL_RO_CGEN(config_stats, stats_arenas_i_bins_j_nonfull_slabs,
- arenas_i(mib[2])->astats->bstats[mib[4]].stats_data.nonfull_slabs, size_t)
-
-static const ctl_named_node_t *
-stats_arenas_i_bins_j_index(tsdn_t *tsdn, const size_t *mib,
- size_t miblen, size_t j) {
- if (j > SC_NBINS) {
- return NULL;
- }
- return super_stats_arenas_i_bins_j_node;
-}
-
-CTL_RO_CGEN(config_stats, stats_arenas_i_lextents_j_nmalloc,
- locked_read_u64_unsynchronized(
- &arenas_i(mib[2])->astats->lstats[mib[4]].nmalloc), uint64_t)
-CTL_RO_CGEN(config_stats, stats_arenas_i_lextents_j_ndalloc,
- locked_read_u64_unsynchronized(
- &arenas_i(mib[2])->astats->lstats[mib[4]].ndalloc), uint64_t)
-CTL_RO_CGEN(config_stats, stats_arenas_i_lextents_j_nrequests,
- locked_read_u64_unsynchronized(
- &arenas_i(mib[2])->astats->lstats[mib[4]].nrequests), uint64_t)
-CTL_RO_CGEN(config_stats, stats_arenas_i_lextents_j_curlextents,
- arenas_i(mib[2])->astats->lstats[mib[4]].curlextents, size_t)
-
-static const ctl_named_node_t *
-stats_arenas_i_lextents_j_index(tsdn_t *tsdn, const size_t *mib,
- size_t miblen, size_t j) {
- if (j > SC_NSIZES - SC_NBINS) {
- return NULL;
- }
- return super_stats_arenas_i_lextents_j_node;
-}
-
-CTL_RO_CGEN(config_stats, stats_arenas_i_extents_j_ndirty,
- arenas_i(mib[2])->astats->estats[mib[4]].ndirty, size_t);
-CTL_RO_CGEN(config_stats, stats_arenas_i_extents_j_nmuzzy,
- arenas_i(mib[2])->astats->estats[mib[4]].nmuzzy, size_t);
-CTL_RO_CGEN(config_stats, stats_arenas_i_extents_j_nretained,
- arenas_i(mib[2])->astats->estats[mib[4]].nretained, size_t);
-CTL_RO_CGEN(config_stats, stats_arenas_i_extents_j_dirty_bytes,
- arenas_i(mib[2])->astats->estats[mib[4]].dirty_bytes, size_t);
-CTL_RO_CGEN(config_stats, stats_arenas_i_extents_j_muzzy_bytes,
- arenas_i(mib[2])->astats->estats[mib[4]].muzzy_bytes, size_t);
-CTL_RO_CGEN(config_stats, stats_arenas_i_extents_j_retained_bytes,
- arenas_i(mib[2])->astats->estats[mib[4]].retained_bytes, size_t);
-
-static const ctl_named_node_t *
-stats_arenas_i_extents_j_index(tsdn_t *tsdn, const size_t *mib,
- size_t miblen, size_t j) {
- if (j >= SC_NPSIZES) {
- return NULL;
- }
- return super_stats_arenas_i_extents_j_node;
-}
-
-CTL_RO_CGEN(config_stats, stats_arenas_i_hpa_shard_npurge_passes,
- arenas_i(mib[2])->astats->hpastats.nonderived_stats.npurge_passes, uint64_t);
-CTL_RO_CGEN(config_stats, stats_arenas_i_hpa_shard_npurges,
- arenas_i(mib[2])->astats->hpastats.nonderived_stats.npurges, uint64_t);
-CTL_RO_CGEN(config_stats, stats_arenas_i_hpa_shard_nhugifies,
- arenas_i(mib[2])->astats->hpastats.nonderived_stats.nhugifies, uint64_t);
-CTL_RO_CGEN(config_stats, stats_arenas_i_hpa_shard_ndehugifies,
- arenas_i(mib[2])->astats->hpastats.nonderived_stats.ndehugifies, uint64_t);
-
-/* Full, nonhuge */
-CTL_RO_CGEN(config_stats, stats_arenas_i_hpa_shard_full_slabs_npageslabs_nonhuge,
- arenas_i(mib[2])->astats->hpastats.psset_stats.full_slabs[0].npageslabs,
- size_t);
-CTL_RO_CGEN(config_stats, stats_arenas_i_hpa_shard_full_slabs_nactive_nonhuge,
- arenas_i(mib[2])->astats->hpastats.psset_stats.full_slabs[0].nactive, size_t);
-CTL_RO_CGEN(config_stats, stats_arenas_i_hpa_shard_full_slabs_ndirty_nonhuge,
- arenas_i(mib[2])->astats->hpastats.psset_stats.full_slabs[0].ndirty, size_t);
-
-/* Full, huge */
-CTL_RO_CGEN(config_stats, stats_arenas_i_hpa_shard_full_slabs_npageslabs_huge,
- arenas_i(mib[2])->astats->hpastats.psset_stats.full_slabs[1].npageslabs,
- size_t);
-CTL_RO_CGEN(config_stats, stats_arenas_i_hpa_shard_full_slabs_nactive_huge,
- arenas_i(mib[2])->astats->hpastats.psset_stats.full_slabs[1].nactive, size_t);
-CTL_RO_CGEN(config_stats, stats_arenas_i_hpa_shard_full_slabs_ndirty_huge,
- arenas_i(mib[2])->astats->hpastats.psset_stats.full_slabs[1].ndirty, size_t);
-
-/* Empty, nonhuge */
-CTL_RO_CGEN(config_stats, stats_arenas_i_hpa_shard_empty_slabs_npageslabs_nonhuge,
- arenas_i(mib[2])->astats->hpastats.psset_stats.empty_slabs[0].npageslabs,
- size_t);
-CTL_RO_CGEN(config_stats, stats_arenas_i_hpa_shard_empty_slabs_nactive_nonhuge,
- arenas_i(mib[2])->astats->hpastats.psset_stats.empty_slabs[0].nactive, size_t);
-CTL_RO_CGEN(config_stats, stats_arenas_i_hpa_shard_empty_slabs_ndirty_nonhuge,
- arenas_i(mib[2])->astats->hpastats.psset_stats.empty_slabs[0].ndirty, size_t);
-
-/* Empty, huge */
-CTL_RO_CGEN(config_stats, stats_arenas_i_hpa_shard_empty_slabs_npageslabs_huge,
- arenas_i(mib[2])->astats->hpastats.psset_stats.empty_slabs[1].npageslabs,
- size_t);
-CTL_RO_CGEN(config_stats, stats_arenas_i_hpa_shard_empty_slabs_nactive_huge,
- arenas_i(mib[2])->astats->hpastats.psset_stats.empty_slabs[1].nactive, size_t);
-CTL_RO_CGEN(config_stats, stats_arenas_i_hpa_shard_empty_slabs_ndirty_huge,
- arenas_i(mib[2])->astats->hpastats.psset_stats.empty_slabs[1].ndirty, size_t);
-
-/* Nonfull, nonhuge */
-CTL_RO_CGEN(config_stats, stats_arenas_i_hpa_shard_nonfull_slabs_j_npageslabs_nonhuge,
- arenas_i(mib[2])->astats->hpastats.psset_stats.nonfull_slabs[mib[5]][0].npageslabs,
- size_t);
-CTL_RO_CGEN(config_stats, stats_arenas_i_hpa_shard_nonfull_slabs_j_nactive_nonhuge,
- arenas_i(mib[2])->astats->hpastats.psset_stats.nonfull_slabs[mib[5]][0].nactive,
- size_t);
-CTL_RO_CGEN(config_stats, stats_arenas_i_hpa_shard_nonfull_slabs_j_ndirty_nonhuge,
- arenas_i(mib[2])->astats->hpastats.psset_stats.nonfull_slabs[mib[5]][0].ndirty,
- size_t);
-
-/* Nonfull, huge */
-CTL_RO_CGEN(config_stats, stats_arenas_i_hpa_shard_nonfull_slabs_j_npageslabs_huge,
- arenas_i(mib[2])->astats->hpastats.psset_stats.nonfull_slabs[mib[5]][1].npageslabs,
- size_t);
-CTL_RO_CGEN(config_stats, stats_arenas_i_hpa_shard_nonfull_slabs_j_nactive_huge,
- arenas_i(mib[2])->astats->hpastats.psset_stats.nonfull_slabs[mib[5]][1].nactive,
- size_t);
-CTL_RO_CGEN(config_stats, stats_arenas_i_hpa_shard_nonfull_slabs_j_ndirty_huge,
- arenas_i(mib[2])->astats->hpastats.psset_stats.nonfull_slabs[mib[5]][1].ndirty,
- size_t);
-
-static const ctl_named_node_t *
-stats_arenas_i_hpa_shard_nonfull_slabs_j_index(tsdn_t *tsdn, const size_t *mib,
- size_t miblen, size_t j) {
- if (j >= PSSET_NPSIZES) {
- return NULL;
- }
- return super_stats_arenas_i_hpa_shard_nonfull_slabs_j_node;
-}
-
-static bool
-ctl_arenas_i_verify(size_t i) {
- size_t a = arenas_i2a_impl(i, true, true);
- if (a == UINT_MAX || !ctl_arenas->arenas[a]->initialized) {
- return true;
- }
-
- return false;
-}
-
-static const ctl_named_node_t *
-stats_arenas_i_index(tsdn_t *tsdn, const size_t *mib,
- size_t miblen, size_t i) {
- const ctl_named_node_t *ret;
-
- malloc_mutex_lock(tsdn, &ctl_mtx);
- if (ctl_arenas_i_verify(i)) {
- ret = NULL;
- goto label_return;
- }
-
- ret = super_stats_arenas_i_node;
-label_return:
- malloc_mutex_unlock(tsdn, &ctl_mtx);
- return ret;
-}
-
-static int
-experimental_hooks_install_ctl(tsd_t *tsd, const size_t *mib, size_t miblen,
- void *oldp, size_t *oldlenp, void *newp, size_t newlen) {
- int ret;
- if (oldp == NULL || oldlenp == NULL|| newp == NULL) {
- ret = EINVAL;
- goto label_return;
- }
- /*
- * Note: this is a *private* struct. This is an experimental interface;
- * forcing the user to know the jemalloc internals well enough to
- * extract the ABI hopefully ensures nobody gets too comfortable with
- * this API, which can change at a moment's notice.
- */
- hooks_t hooks;
- WRITE(hooks, hooks_t);
- void *handle = hook_install(tsd_tsdn(tsd), &hooks);
- if (handle == NULL) {
- ret = EAGAIN;
- goto label_return;
- }
- READ(handle, void *);
-
- ret = 0;
-label_return:
- return ret;
-}
-
-static int
-experimental_hooks_remove_ctl(tsd_t *tsd, const size_t *mib, size_t miblen,
- void *oldp, size_t *oldlenp, void *newp, size_t newlen) {
- int ret;
- WRITEONLY();
- void *handle = NULL;
- WRITE(handle, void *);
- if (handle == NULL) {
- ret = EINVAL;
- goto label_return;
- }
- hook_remove(tsd_tsdn(tsd), handle);
- ret = 0;
-label_return:
- return ret;
-}
-
-static int
-experimental_thread_activity_callback_ctl(tsd_t *tsd, const size_t *mib,
- size_t miblen, void *oldp, size_t *oldlenp, void *newp, size_t newlen) {
- int ret;
-
- if (!config_stats) {
- return ENOENT;
- }
-
- activity_callback_thunk_t t_old = tsd_activity_callback_thunk_get(tsd);
- READ(t_old, activity_callback_thunk_t);
-
- if (newp != NULL) {
- /*
- * This initialization is unnecessary. If it's omitted, though,
- * clang gets confused and warns on the subsequent use of t_new.
- */
- activity_callback_thunk_t t_new = {NULL, NULL};
- WRITE(t_new, activity_callback_thunk_t);
- tsd_activity_callback_thunk_set(tsd, t_new);
- }
- ret = 0;
-label_return:
- return ret;
-}
-
-/*
- * Output six memory utilization entries for an input pointer, the first one of
- * type (void *) and the remaining five of type size_t, describing the following
- * (in the same order):
- *
- * (a) memory address of the extent a potential reallocation would go into,
- * == the five fields below describe about the extent the pointer resides in ==
- * (b) number of free regions in the extent,
- * (c) number of regions in the extent,
- * (d) size of the extent in terms of bytes,
- * (e) total number of free regions in the bin the extent belongs to, and
- * (f) total number of regions in the bin the extent belongs to.
- *
- * Note that "(e)" and "(f)" are only available when stats are enabled;
- * otherwise their values are undefined.
- *
- * This API is mainly intended for small class allocations, where extents are
- * used as slab. Note that if the bin the extent belongs to is completely
- * full, "(a)" will be NULL.
- *
- * In case of large class allocations, "(a)" will be NULL, and "(e)" and "(f)"
- * will be zero (if stats are enabled; otherwise undefined). The other three
- * fields will be properly set though the values are trivial: "(b)" will be 0,
- * "(c)" will be 1, and "(d)" will be the usable size.
- *
- * The input pointer and size are respectively passed in by newp and newlen,
- * and the output fields and size are respectively oldp and *oldlenp.
- *
- * It can be beneficial to define the following macros to make it easier to
- * access the output:
- *
- * #define SLABCUR_READ(out) (*(void **)out)
- * #define COUNTS(out) ((size_t *)((void **)out + 1))
- * #define NFREE_READ(out) COUNTS(out)[0]
- * #define NREGS_READ(out) COUNTS(out)[1]
- * #define SIZE_READ(out) COUNTS(out)[2]
- * #define BIN_NFREE_READ(out) COUNTS(out)[3]
- * #define BIN_NREGS_READ(out) COUNTS(out)[4]
- *
- * and then write e.g. NFREE_READ(oldp) to fetch the output. See the unit test
- * test_query in test/unit/extent_util.c for an example.
- *
- * For a typical defragmentation workflow making use of this API for
- * understanding the fragmentation level, please refer to the comment for
- * experimental_utilization_batch_query_ctl.
- *
- * It's up to the application how to determine the significance of
- * fragmentation relying on the outputs returned. Possible choices are:
- *
- * (a) if extent utilization ratio is below certain threshold,
- * (b) if extent memory consumption is above certain threshold,
- * (c) if extent utilization ratio is significantly below bin utilization ratio,
- * (d) if input pointer deviates a lot from potential reallocation address, or
- * (e) some selection/combination of the above.
- *
- * The caller needs to make sure that the input/output arguments are valid,
- * in particular, that the size of the output is correct, i.e.:
- *
- * *oldlenp = sizeof(void *) + sizeof(size_t) * 5
- *
- * Otherwise, the function immediately returns EINVAL without touching anything.
- *
- * In the rare case where there's no associated extent found for the input
- * pointer, the function zeros out all output fields and return. Please refer
- * to the comment for experimental_utilization_batch_query_ctl to understand the
- * motivation from C++.
- */
-static int
-experimental_utilization_query_ctl(tsd_t *tsd, const size_t *mib,
- size_t miblen, void *oldp, size_t *oldlenp, void *newp, size_t newlen) {
- int ret;
-
- assert(sizeof(inspect_extent_util_stats_verbose_t)
- == sizeof(void *) + sizeof(size_t) * 5);
-
- if (oldp == NULL || oldlenp == NULL
- || *oldlenp != sizeof(inspect_extent_util_stats_verbose_t)
- || newp == NULL) {
- ret = EINVAL;
- goto label_return;
- }
-
- void *ptr = NULL;
- WRITE(ptr, void *);
- inspect_extent_util_stats_verbose_t *util_stats
- = (inspect_extent_util_stats_verbose_t *)oldp;
- inspect_extent_util_stats_verbose_get(tsd_tsdn(tsd), ptr,
- &util_stats->nfree, &util_stats->nregs, &util_stats->size,
- &util_stats->bin_nfree, &util_stats->bin_nregs,
- &util_stats->slabcur_addr);
- ret = 0;
-
-label_return:
- return ret;
-}
-
-/*
- * Given an input array of pointers, output three memory utilization entries of
- * type size_t for each input pointer about the extent it resides in:
- *
- * (a) number of free regions in the extent,
- * (b) number of regions in the extent, and
- * (c) size of the extent in terms of bytes.
- *
- * This API is mainly intended for small class allocations, where extents are
- * used as slab. In case of large class allocations, the outputs are trivial:
- * "(a)" will be 0, "(b)" will be 1, and "(c)" will be the usable size.
- *
- * Note that multiple input pointers may reside on a same extent so the output
- * fields may contain duplicates.
- *
- * The format of the input/output looks like:
- *
- * input[0]: 1st_pointer_to_query | output[0]: 1st_extent_n_free_regions
- * | output[1]: 1st_extent_n_regions
- * | output[2]: 1st_extent_size
- * input[1]: 2nd_pointer_to_query | output[3]: 2nd_extent_n_free_regions
- * | output[4]: 2nd_extent_n_regions
- * | output[5]: 2nd_extent_size
- * ... | ...
- *
- * The input array and size are respectively passed in by newp and newlen, and
- * the output array and size are respectively oldp and *oldlenp.
- *
- * It can be beneficial to define the following macros to make it easier to
- * access the output:
- *
- * #define NFREE_READ(out, i) out[(i) * 3]
- * #define NREGS_READ(out, i) out[(i) * 3 + 1]
- * #define SIZE_READ(out, i) out[(i) * 3 + 2]
- *
- * and then write e.g. NFREE_READ(oldp, i) to fetch the output. See the unit
- * test test_batch in test/unit/extent_util.c for a concrete example.
- *
- * A typical workflow would be composed of the following steps:
- *
- * (1) flush tcache: mallctl("thread.tcache.flush", ...)
- * (2) initialize input array of pointers to query fragmentation
- * (3) allocate output array to hold utilization statistics
- * (4) query utilization: mallctl("experimental.utilization.batch_query", ...)
- * (5) (optional) decide if it's worthwhile to defragment; otherwise stop here
- * (6) disable tcache: mallctl("thread.tcache.enabled", ...)
- * (7) defragment allocations with significant fragmentation, e.g.:
- * for each allocation {
- * if it's fragmented {
- * malloc(...);
- * memcpy(...);
- * free(...);
- * }
- * }
- * (8) enable tcache: mallctl("thread.tcache.enabled", ...)
- *
- * The application can determine the significance of fragmentation themselves
- * relying on the statistics returned, both at the overall level i.e. step "(5)"
- * and at individual allocation level i.e. within step "(7)". Possible choices
- * are:
- *
- * (a) whether memory utilization ratio is below certain threshold,
- * (b) whether memory consumption is above certain threshold, or
- * (c) some combination of the two.
- *
- * The caller needs to make sure that the input/output arrays are valid and
- * their sizes are proper as well as matched, meaning:
- *
- * (a) newlen = n_pointers * sizeof(const void *)
- * (b) *oldlenp = n_pointers * sizeof(size_t) * 3
- * (c) n_pointers > 0
- *
- * Otherwise, the function immediately returns EINVAL without touching anything.
- *
- * In the rare case where there's no associated extent found for some pointers,
- * rather than immediately terminating the computation and raising an error,
- * the function simply zeros out the corresponding output fields and continues
- * the computation until all input pointers are handled. The motivations of
- * such a design are as follows:
- *
- * (a) The function always either processes nothing or processes everything, and
- * never leaves the output half touched and half untouched.
- *
- * (b) It facilitates usage needs especially common in C++. A vast variety of
- * C++ objects are instantiated with multiple dynamic memory allocations. For
- * example, std::string and std::vector typically use at least two allocations,
- * one for the metadata and one for the actual content. Other types may use
- * even more allocations. When inquiring about utilization statistics, the
- * caller often wants to examine into all such allocations, especially internal
- * one(s), rather than just the topmost one. The issue comes when some
- * implementations do certain optimizations to reduce/aggregate some internal
- * allocations, e.g. putting short strings directly into the metadata, and such
- * decisions are not known to the caller. Therefore, we permit pointers to
- * memory usages that may not be returned by previous malloc calls, and we
- * provide the caller a convenient way to identify such cases.
- */
-static int
-experimental_utilization_batch_query_ctl(tsd_t *tsd, const size_t *mib,
- size_t miblen, void *oldp, size_t *oldlenp, void *newp, size_t newlen) {
- int ret;
-
- assert(sizeof(inspect_extent_util_stats_t) == sizeof(size_t) * 3);
-
- const size_t len = newlen / sizeof(const void *);
- if (oldp == NULL || oldlenp == NULL || newp == NULL || newlen == 0
- || newlen != len * sizeof(const void *)
- || *oldlenp != len * sizeof(inspect_extent_util_stats_t)) {
- ret = EINVAL;
- goto label_return;
- }
-
- void **ptrs = (void **)newp;
- inspect_extent_util_stats_t *util_stats =
- (inspect_extent_util_stats_t *)oldp;
- size_t i;
- for (i = 0; i < len; ++i) {
- inspect_extent_util_stats_get(tsd_tsdn(tsd), ptrs[i],
- &util_stats[i].nfree, &util_stats[i].nregs,
- &util_stats[i].size);
- }
- ret = 0;
-
-label_return:
- return ret;
-}
-
-static const ctl_named_node_t *
-experimental_arenas_i_index(tsdn_t *tsdn, const size_t *mib,
- size_t miblen, size_t i) {
- const ctl_named_node_t *ret;
-
- malloc_mutex_lock(tsdn, &ctl_mtx);
- if (ctl_arenas_i_verify(i)) {
- ret = NULL;
- goto label_return;
- }
- ret = super_experimental_arenas_i_node;
-label_return:
- malloc_mutex_unlock(tsdn, &ctl_mtx);
- return ret;
-}
-
-static int
-experimental_arenas_i_pactivep_ctl(tsd_t *tsd, const size_t *mib,
- size_t miblen, void *oldp, size_t *oldlenp, void *newp, size_t newlen) {
- if (!config_stats) {
- return ENOENT;
- }
- if (oldp == NULL || oldlenp == NULL || *oldlenp != sizeof(size_t *)) {
- return EINVAL;
- }
-
- unsigned arena_ind;
- arena_t *arena;
- int ret;
- size_t *pactivep;
-
- malloc_mutex_lock(tsd_tsdn(tsd), &ctl_mtx);
- READONLY();
- MIB_UNSIGNED(arena_ind, 2);
- if (arena_ind < narenas_total_get() && (arena =
- arena_get(tsd_tsdn(tsd), arena_ind, false)) != NULL) {
-#if defined(JEMALLOC_GCC_ATOMIC_ATOMICS) || \
- defined(JEMALLOC_GCC_SYNC_ATOMICS) || defined(_MSC_VER)
- /* Expose the underlying counter for fast read. */
- pactivep = (size_t *)&(arena->pa_shard.nactive.repr);
- READ(pactivep, size_t *);
- ret = 0;
-#else
- ret = EFAULT;
-#endif
- } else {
- ret = EFAULT;
- }
-label_return:
- malloc_mutex_unlock(tsd_tsdn(tsd), &ctl_mtx);
- return ret;
-}
-
-static int
-experimental_prof_recent_alloc_max_ctl(tsd_t *tsd, const size_t *mib,
- size_t miblen, void *oldp, size_t *oldlenp, void *newp, size_t newlen) {
- int ret;
-
- if (!(config_prof && opt_prof)) {
- ret = ENOENT;
- goto label_return;
- }
-
- ssize_t old_max;
- if (newp != NULL) {
- if (newlen != sizeof(ssize_t)) {
- ret = EINVAL;
- goto label_return;
- }
- ssize_t max = *(ssize_t *)newp;
- if (max < -1) {
- ret = EINVAL;
- goto label_return;
- }
- old_max = prof_recent_alloc_max_ctl_write(tsd, max);
- } else {
- old_max = prof_recent_alloc_max_ctl_read();
- }
- READ(old_max, ssize_t);
-
- ret = 0;
-
-label_return:
- return ret;
-}
-
-typedef struct write_cb_packet_s write_cb_packet_t;
-struct write_cb_packet_s {
- write_cb_t *write_cb;
- void *cbopaque;
-};
-
-static int
-experimental_prof_recent_alloc_dump_ctl(tsd_t *tsd, const size_t *mib,
- size_t miblen, void *oldp, size_t *oldlenp, void *newp, size_t newlen) {
- int ret;
-
- if (!(config_prof && opt_prof)) {
- ret = ENOENT;
- goto label_return;
- }
-
- assert(sizeof(write_cb_packet_t) == sizeof(void *) * 2);
-
- WRITEONLY();
- write_cb_packet_t write_cb_packet;
- ASSURED_WRITE(write_cb_packet, write_cb_packet_t);
-
- prof_recent_alloc_dump(tsd, write_cb_packet.write_cb,
- write_cb_packet.cbopaque);
-
- ret = 0;
-
-label_return:
- return ret;
-}
-
-typedef struct batch_alloc_packet_s batch_alloc_packet_t;
-struct batch_alloc_packet_s {
- void **ptrs;
- size_t num;
- size_t size;
- int flags;
-};
-
-static int
-experimental_batch_alloc_ctl(tsd_t *tsd, const size_t *mib,
- size_t miblen, void *oldp, size_t *oldlenp, void *newp, size_t newlen) {
- int ret;
-
- VERIFY_READ(size_t);
-
- batch_alloc_packet_t batch_alloc_packet;
- ASSURED_WRITE(batch_alloc_packet, batch_alloc_packet_t);
- size_t filled = batch_alloc(batch_alloc_packet.ptrs,
- batch_alloc_packet.num, batch_alloc_packet.size,
- batch_alloc_packet.flags);
- READ(filled, size_t);
-
- ret = 0;
-
-label_return:
- return ret;
-}
-
-static int
-prof_stats_bins_i_live_ctl(tsd_t *tsd, const size_t *mib, size_t miblen,
- void *oldp, size_t *oldlenp, void *newp, size_t newlen) {
- int ret;
- unsigned binind;
- prof_stats_t stats;
-
- if (!(config_prof && opt_prof && opt_prof_stats)) {
- ret = ENOENT;
- goto label_return;
- }
-
- READONLY();
- MIB_UNSIGNED(binind, 3);
- if (binind >= SC_NBINS) {
- ret = EINVAL;
- goto label_return;
- }
- prof_stats_get_live(tsd, (szind_t)binind, &stats);
- READ(stats, prof_stats_t);
-
- ret = 0;
-label_return:
- return ret;
-}
-
-static int
-prof_stats_bins_i_accum_ctl(tsd_t *tsd, const size_t *mib, size_t miblen,
- void *oldp, size_t *oldlenp, void *newp, size_t newlen) {
- int ret;
- unsigned binind;
- prof_stats_t stats;
-
- if (!(config_prof && opt_prof && opt_prof_stats)) {
- ret = ENOENT;
- goto label_return;
- }
-
- READONLY();
- MIB_UNSIGNED(binind, 3);
- if (binind >= SC_NBINS) {
- ret = EINVAL;
- goto label_return;
- }
- prof_stats_get_accum(tsd, (szind_t)binind, &stats);
- READ(stats, prof_stats_t);
-
- ret = 0;
-label_return:
- return ret;
-}
-
-static const ctl_named_node_t *
-prof_stats_bins_i_index(tsdn_t *tsdn, const size_t *mib, size_t miblen,
- size_t i) {
- if (!(config_prof && opt_prof && opt_prof_stats)) {
- return NULL;
- }
- if (i >= SC_NBINS) {
- return NULL;
- }
- return super_prof_stats_bins_i_node;
-}
-
-static int
-prof_stats_lextents_i_live_ctl(tsd_t *tsd, const size_t *mib, size_t miblen,
- void *oldp, size_t *oldlenp, void *newp, size_t newlen) {
- int ret;
- unsigned lextent_ind;
- prof_stats_t stats;
-
- if (!(config_prof && opt_prof && opt_prof_stats)) {
- ret = ENOENT;
- goto label_return;
- }
-
- READONLY();
- MIB_UNSIGNED(lextent_ind, 3);
- if (lextent_ind >= SC_NSIZES - SC_NBINS) {
- ret = EINVAL;
- goto label_return;
- }
- prof_stats_get_live(tsd, (szind_t)(lextent_ind + SC_NBINS), &stats);
- READ(stats, prof_stats_t);
-
- ret = 0;
-label_return:
- return ret;
-}
-
-static int
-prof_stats_lextents_i_accum_ctl(tsd_t *tsd, const size_t *mib, size_t miblen,
- void *oldp, size_t *oldlenp, void *newp, size_t newlen) {
- int ret;
- unsigned lextent_ind;
- prof_stats_t stats;
-
- if (!(config_prof && opt_prof && opt_prof_stats)) {
- ret = ENOENT;
- goto label_return;
- }
-
- READONLY();
- MIB_UNSIGNED(lextent_ind, 3);
- if (lextent_ind >= SC_NSIZES - SC_NBINS) {
- ret = EINVAL;
- goto label_return;
- }
- prof_stats_get_accum(tsd, (szind_t)(lextent_ind + SC_NBINS), &stats);
- READ(stats, prof_stats_t);
-
- ret = 0;
-label_return:
- return ret;
-}
-
-static const ctl_named_node_t *
-prof_stats_lextents_i_index(tsdn_t *tsdn, const size_t *mib, size_t miblen,
- size_t i) {
- if (!(config_prof && opt_prof && opt_prof_stats)) {
- return NULL;
- }
- if (i >= SC_NSIZES - SC_NBINS) {
- return NULL;
- }
- return super_prof_stats_lextents_i_node;
-}
diff --git a/fluent-bit/lib/jemalloc-5.3.0/src/decay.c b/fluent-bit/lib/jemalloc-5.3.0/src/decay.c
deleted file mode 100644
index d801b2bc..00000000
--- a/fluent-bit/lib/jemalloc-5.3.0/src/decay.c
+++ /dev/null
@@ -1,295 +0,0 @@
-#include "jemalloc/internal/jemalloc_preamble.h"
-#include "jemalloc/internal/jemalloc_internal_includes.h"
-
-#include "jemalloc/internal/decay.h"
-
-static const uint64_t h_steps[SMOOTHSTEP_NSTEPS] = {
-#define STEP(step, h, x, y) \
- h,
- SMOOTHSTEP
-#undef STEP
-};
-
-/*
- * Generate a new deadline that is uniformly random within the next epoch after
- * the current one.
- */
-void
-decay_deadline_init(decay_t *decay) {
- nstime_copy(&decay->deadline, &decay->epoch);
- nstime_add(&decay->deadline, &decay->interval);
- if (decay_ms_read(decay) > 0) {
- nstime_t jitter;
-
- nstime_init(&jitter, prng_range_u64(&decay->jitter_state,
- nstime_ns(&decay->interval)));
- nstime_add(&decay->deadline, &jitter);
- }
-}
-
-void
-decay_reinit(decay_t *decay, nstime_t *cur_time, ssize_t decay_ms) {
- atomic_store_zd(&decay->time_ms, decay_ms, ATOMIC_RELAXED);
- if (decay_ms > 0) {
- nstime_init(&decay->interval, (uint64_t)decay_ms *
- KQU(1000000));
- nstime_idivide(&decay->interval, SMOOTHSTEP_NSTEPS);
- }
-
- nstime_copy(&decay->epoch, cur_time);
- decay->jitter_state = (uint64_t)(uintptr_t)decay;
- decay_deadline_init(decay);
- decay->nunpurged = 0;
- memset(decay->backlog, 0, SMOOTHSTEP_NSTEPS * sizeof(size_t));
-}
-
-bool
-decay_init(decay_t *decay, nstime_t *cur_time, ssize_t decay_ms) {
- if (config_debug) {
- for (size_t i = 0; i < sizeof(decay_t); i++) {
- assert(((char *)decay)[i] == 0);
- }
- decay->ceil_npages = 0;
- }
- if (malloc_mutex_init(&decay->mtx, "decay", WITNESS_RANK_DECAY,
- malloc_mutex_rank_exclusive)) {
- return true;
- }
- decay->purging = false;
- decay_reinit(decay, cur_time, decay_ms);
- return false;
-}
-
-bool
-decay_ms_valid(ssize_t decay_ms) {
- if (decay_ms < -1) {
- return false;
- }
- if (decay_ms == -1 || (uint64_t)decay_ms <= NSTIME_SEC_MAX *
- KQU(1000)) {
- return true;
- }
- return false;
-}
-
-static void
-decay_maybe_update_time(decay_t *decay, nstime_t *new_time) {
- if (unlikely(!nstime_monotonic() && nstime_compare(&decay->epoch,
- new_time) > 0)) {
- /*
- * Time went backwards. Move the epoch back in time and
- * generate a new deadline, with the expectation that time
- * typically flows forward for long enough periods of time that
- * epochs complete. Unfortunately, this strategy is susceptible
- * to clock jitter triggering premature epoch advances, but
- * clock jitter estimation and compensation isn't feasible here
- * because calls into this code are event-driven.
- */
- nstime_copy(&decay->epoch, new_time);
- decay_deadline_init(decay);
- } else {
- /* Verify that time does not go backwards. */
- assert(nstime_compare(&decay->epoch, new_time) <= 0);
- }
-}
-
-static size_t
-decay_backlog_npages_limit(const decay_t *decay) {
- /*
- * For each element of decay_backlog, multiply by the corresponding
- * fixed-point smoothstep decay factor. Sum the products, then divide
- * to round down to the nearest whole number of pages.
- */
- uint64_t sum = 0;
- for (unsigned i = 0; i < SMOOTHSTEP_NSTEPS; i++) {
- sum += decay->backlog[i] * h_steps[i];
- }
- size_t npages_limit_backlog = (size_t)(sum >> SMOOTHSTEP_BFP);
-
- return npages_limit_backlog;
-}
-
-/*
- * Update backlog, assuming that 'nadvance_u64' time intervals have passed.
- * Trailing 'nadvance_u64' records should be erased and 'current_npages' is
- * placed as the newest record.
- */
-static void
-decay_backlog_update(decay_t *decay, uint64_t nadvance_u64,
- size_t current_npages) {
- if (nadvance_u64 >= SMOOTHSTEP_NSTEPS) {
- memset(decay->backlog, 0, (SMOOTHSTEP_NSTEPS-1) *
- sizeof(size_t));
- } else {
- size_t nadvance_z = (size_t)nadvance_u64;
-
- assert((uint64_t)nadvance_z == nadvance_u64);
-
- memmove(decay->backlog, &decay->backlog[nadvance_z],
- (SMOOTHSTEP_NSTEPS - nadvance_z) * sizeof(size_t));
- if (nadvance_z > 1) {
- memset(&decay->backlog[SMOOTHSTEP_NSTEPS -
- nadvance_z], 0, (nadvance_z-1) * sizeof(size_t));
- }
- }
-
- size_t npages_delta = (current_npages > decay->nunpurged) ?
- current_npages - decay->nunpurged : 0;
- decay->backlog[SMOOTHSTEP_NSTEPS-1] = npages_delta;
-
- if (config_debug) {
- if (current_npages > decay->ceil_npages) {
- decay->ceil_npages = current_npages;
- }
- size_t npages_limit = decay_backlog_npages_limit(decay);
- assert(decay->ceil_npages >= npages_limit);
- if (decay->ceil_npages > npages_limit) {
- decay->ceil_npages = npages_limit;
- }
- }
-}
-
-static inline bool
-decay_deadline_reached(const decay_t *decay, const nstime_t *time) {
- return (nstime_compare(&decay->deadline, time) <= 0);
-}
-
-uint64_t
-decay_npages_purge_in(decay_t *decay, nstime_t *time, size_t npages_new) {
- uint64_t decay_interval_ns = decay_epoch_duration_ns(decay);
- size_t n_epoch = (size_t)(nstime_ns(time) / decay_interval_ns);
-
- uint64_t npages_purge;
- if (n_epoch >= SMOOTHSTEP_NSTEPS) {
- npages_purge = npages_new;
- } else {
- uint64_t h_steps_max = h_steps[SMOOTHSTEP_NSTEPS - 1];
- assert(h_steps_max >=
- h_steps[SMOOTHSTEP_NSTEPS - 1 - n_epoch]);
- npages_purge = npages_new * (h_steps_max -
- h_steps[SMOOTHSTEP_NSTEPS - 1 - n_epoch]);
- npages_purge >>= SMOOTHSTEP_BFP;
- }
- return npages_purge;
-}
-
-bool
-decay_maybe_advance_epoch(decay_t *decay, nstime_t *new_time,
- size_t npages_current) {
- /* Handle possible non-monotonicity of time. */
- decay_maybe_update_time(decay, new_time);
-
- if (!decay_deadline_reached(decay, new_time)) {
- return false;
- }
- nstime_t delta;
- nstime_copy(&delta, new_time);
- nstime_subtract(&delta, &decay->epoch);
-
- uint64_t nadvance_u64 = nstime_divide(&delta, &decay->interval);
- assert(nadvance_u64 > 0);
-
- /* Add nadvance_u64 decay intervals to epoch. */
- nstime_copy(&delta, &decay->interval);
- nstime_imultiply(&delta, nadvance_u64);
- nstime_add(&decay->epoch, &delta);
-
- /* Set a new deadline. */
- decay_deadline_init(decay);
-
- /* Update the backlog. */
- decay_backlog_update(decay, nadvance_u64, npages_current);
-
- decay->npages_limit = decay_backlog_npages_limit(decay);
- decay->nunpurged = (decay->npages_limit > npages_current) ?
- decay->npages_limit : npages_current;
-
- return true;
-}
-
-/*
- * Calculate how many pages should be purged after 'interval'.
- *
- * First, calculate how many pages should remain at the moment, then subtract
- * the number of pages that should remain after 'interval'. The difference is
- * how many pages should be purged until then.
- *
- * The number of pages that should remain at a specific moment is calculated
- * like this: pages(now) = sum(backlog[i] * h_steps[i]). After 'interval'
- * passes, backlog would shift 'interval' positions to the left and sigmoid
- * curve would be applied starting with backlog[interval].
- *
- * The implementation doesn't directly map to the description, but it's
- * essentially the same calculation, optimized to avoid iterating over
- * [interval..SMOOTHSTEP_NSTEPS) twice.
- */
-static inline size_t
-decay_npurge_after_interval(decay_t *decay, size_t interval) {
- size_t i;
- uint64_t sum = 0;
- for (i = 0; i < interval; i++) {
- sum += decay->backlog[i] * h_steps[i];
- }
- for (; i < SMOOTHSTEP_NSTEPS; i++) {
- sum += decay->backlog[i] *
- (h_steps[i] - h_steps[i - interval]);
- }
-
- return (size_t)(sum >> SMOOTHSTEP_BFP);
-}
-
-uint64_t decay_ns_until_purge(decay_t *decay, size_t npages_current,
- uint64_t npages_threshold) {
- if (!decay_gradually(decay)) {
- return DECAY_UNBOUNDED_TIME_TO_PURGE;
- }
- uint64_t decay_interval_ns = decay_epoch_duration_ns(decay);
- assert(decay_interval_ns > 0);
- if (npages_current == 0) {
- unsigned i;
- for (i = 0; i < SMOOTHSTEP_NSTEPS; i++) {
- if (decay->backlog[i] > 0) {
- break;
- }
- }
- if (i == SMOOTHSTEP_NSTEPS) {
- /* No dirty pages recorded. Sleep indefinitely. */
- return DECAY_UNBOUNDED_TIME_TO_PURGE;
- }
- }
- if (npages_current <= npages_threshold) {
- /* Use max interval. */
- return decay_interval_ns * SMOOTHSTEP_NSTEPS;
- }
-
- /* Minimal 2 intervals to ensure reaching next epoch deadline. */
- size_t lb = 2;
- size_t ub = SMOOTHSTEP_NSTEPS;
-
- size_t npurge_lb, npurge_ub;
- npurge_lb = decay_npurge_after_interval(decay, lb);
- if (npurge_lb > npages_threshold) {
- return decay_interval_ns * lb;
- }
- npurge_ub = decay_npurge_after_interval(decay, ub);
- if (npurge_ub < npages_threshold) {
- return decay_interval_ns * ub;
- }
-
- unsigned n_search = 0;
- size_t target, npurge;
- while ((npurge_lb + npages_threshold < npurge_ub) && (lb + 2 < ub)) {
- target = (lb + ub) / 2;
- npurge = decay_npurge_after_interval(decay, target);
- if (npurge > npages_threshold) {
- ub = target;
- npurge_ub = npurge;
- } else {
- lb = target;
- npurge_lb = npurge;
- }
- assert(n_search < lg_floor(SMOOTHSTEP_NSTEPS) + 1);
- ++n_search;
- }
- return decay_interval_ns * (ub + lb) / 2;
-}
diff --git a/fluent-bit/lib/jemalloc-5.3.0/src/div.c b/fluent-bit/lib/jemalloc-5.3.0/src/div.c
deleted file mode 100644
index 808892a1..00000000
--- a/fluent-bit/lib/jemalloc-5.3.0/src/div.c
+++ /dev/null
@@ -1,55 +0,0 @@
-#include "jemalloc/internal/jemalloc_preamble.h"
-
-#include "jemalloc/internal/div.h"
-
-#include "jemalloc/internal/assert.h"
-
-/*
- * Suppose we have n = q * d, all integers. We know n and d, and want q = n / d.
- *
- * For any k, we have (here, all division is exact; not C-style rounding):
- * floor(ceil(2^k / d) * n / 2^k) = floor((2^k + r) / d * n / 2^k), where
- * r = (-2^k) mod d.
- *
- * Expanding this out:
- * ... = floor(2^k / d * n / 2^k + r / d * n / 2^k)
- * = floor(n / d + (r / d) * (n / 2^k)).
- *
- * The fractional part of n / d is 0 (because of the assumption that d divides n
- * exactly), so we have:
- * ... = n / d + floor((r / d) * (n / 2^k))
- *
- * So that our initial expression is equal to the quantity we seek, so long as
- * (r / d) * (n / 2^k) < 1.
- *
- * r is a remainder mod d, so r < d and r / d < 1 always. We can make
- * n / 2 ^ k < 1 by setting k = 32. This gets us a value of magic that works.
- */
-
-void
-div_init(div_info_t *div_info, size_t d) {
- /* Nonsensical. */
- assert(d != 0);
- /*
- * This would make the value of magic too high to fit into a uint32_t
- * (we would want magic = 2^32 exactly). This would mess with code gen
- * on 32-bit machines.
- */
- assert(d != 1);
-
- uint64_t two_to_k = ((uint64_t)1 << 32);
- uint32_t magic = (uint32_t)(two_to_k / d);
-
- /*
- * We want magic = ceil(2^k / d), but C gives us floor. We have to
- * increment it unless the result was exact (i.e. unless d is a power of
- * two).
- */
- if (two_to_k % d != 0) {
- magic++;
- }
- div_info->magic = magic;
-#ifdef JEMALLOC_DEBUG
- div_info->d = d;
-#endif
-}
diff --git a/fluent-bit/lib/jemalloc-5.3.0/src/ecache.c b/fluent-bit/lib/jemalloc-5.3.0/src/ecache.c
deleted file mode 100644
index a242227d..00000000
--- a/fluent-bit/lib/jemalloc-5.3.0/src/ecache.c
+++ /dev/null
@@ -1,35 +0,0 @@
-#include "jemalloc/internal/jemalloc_preamble.h"
-#include "jemalloc/internal/jemalloc_internal_includes.h"
-
-#include "jemalloc/internal/san.h"
-
-bool
-ecache_init(tsdn_t *tsdn, ecache_t *ecache, extent_state_t state, unsigned ind,
- bool delay_coalesce) {
- if (malloc_mutex_init(&ecache->mtx, "extents", WITNESS_RANK_EXTENTS,
- malloc_mutex_rank_exclusive)) {
- return true;
- }
- ecache->state = state;
- ecache->ind = ind;
- ecache->delay_coalesce = delay_coalesce;
- eset_init(&ecache->eset, state);
- eset_init(&ecache->guarded_eset, state);
-
- return false;
-}
-
-void
-ecache_prefork(tsdn_t *tsdn, ecache_t *ecache) {
- malloc_mutex_prefork(tsdn, &ecache->mtx);
-}
-
-void
-ecache_postfork_parent(tsdn_t *tsdn, ecache_t *ecache) {
- malloc_mutex_postfork_parent(tsdn, &ecache->mtx);
-}
-
-void
-ecache_postfork_child(tsdn_t *tsdn, ecache_t *ecache) {
- malloc_mutex_postfork_child(tsdn, &ecache->mtx);
-}
diff --git a/fluent-bit/lib/jemalloc-5.3.0/src/edata.c b/fluent-bit/lib/jemalloc-5.3.0/src/edata.c
deleted file mode 100644
index 82b6f565..00000000
--- a/fluent-bit/lib/jemalloc-5.3.0/src/edata.c
+++ /dev/null
@@ -1,6 +0,0 @@
-#include "jemalloc/internal/jemalloc_preamble.h"
-#include "jemalloc/internal/jemalloc_internal_includes.h"
-
-ph_gen(, edata_avail, edata_t, avail_link,
- edata_esnead_comp)
-ph_gen(, edata_heap, edata_t, heap_link, edata_snad_comp)
diff --git a/fluent-bit/lib/jemalloc-5.3.0/src/edata_cache.c b/fluent-bit/lib/jemalloc-5.3.0/src/edata_cache.c
deleted file mode 100644
index 6bc1848c..00000000
--- a/fluent-bit/lib/jemalloc-5.3.0/src/edata_cache.c
+++ /dev/null
@@ -1,154 +0,0 @@
-#include "jemalloc/internal/jemalloc_preamble.h"
-#include "jemalloc/internal/jemalloc_internal_includes.h"
-
-bool
-edata_cache_init(edata_cache_t *edata_cache, base_t *base) {
- edata_avail_new(&edata_cache->avail);
- /*
- * This is not strictly necessary, since the edata_cache_t is only
- * created inside an arena, which is zeroed on creation. But this is
- * handy as a safety measure.
- */
- atomic_store_zu(&edata_cache->count, 0, ATOMIC_RELAXED);
- if (malloc_mutex_init(&edata_cache->mtx, "edata_cache",
- WITNESS_RANK_EDATA_CACHE, malloc_mutex_rank_exclusive)) {
- return true;
- }
- edata_cache->base = base;
- return false;
-}
-
-edata_t *
-edata_cache_get(tsdn_t *tsdn, edata_cache_t *edata_cache) {
- malloc_mutex_lock(tsdn, &edata_cache->mtx);
- edata_t *edata = edata_avail_first(&edata_cache->avail);
- if (edata == NULL) {
- malloc_mutex_unlock(tsdn, &edata_cache->mtx);
- return base_alloc_edata(tsdn, edata_cache->base);
- }
- edata_avail_remove(&edata_cache->avail, edata);
- atomic_load_sub_store_zu(&edata_cache->count, 1);
- malloc_mutex_unlock(tsdn, &edata_cache->mtx);
- return edata;
-}
-
-void
-edata_cache_put(tsdn_t *tsdn, edata_cache_t *edata_cache, edata_t *edata) {
- malloc_mutex_lock(tsdn, &edata_cache->mtx);
- edata_avail_insert(&edata_cache->avail, edata);
- atomic_load_add_store_zu(&edata_cache->count, 1);
- malloc_mutex_unlock(tsdn, &edata_cache->mtx);
-}
-
-void
-edata_cache_prefork(tsdn_t *tsdn, edata_cache_t *edata_cache) {
- malloc_mutex_prefork(tsdn, &edata_cache->mtx);
-}
-
-void
-edata_cache_postfork_parent(tsdn_t *tsdn, edata_cache_t *edata_cache) {
- malloc_mutex_postfork_parent(tsdn, &edata_cache->mtx);
-}
-
-void
-edata_cache_postfork_child(tsdn_t *tsdn, edata_cache_t *edata_cache) {
- malloc_mutex_postfork_child(tsdn, &edata_cache->mtx);
-}
-
-void
-edata_cache_fast_init(edata_cache_fast_t *ecs, edata_cache_t *fallback) {
- edata_list_inactive_init(&ecs->list);
- ecs->fallback = fallback;
- ecs->disabled = false;
-}
-
-static void
-edata_cache_fast_try_fill_from_fallback(tsdn_t *tsdn,
- edata_cache_fast_t *ecs) {
- edata_t *edata;
- malloc_mutex_lock(tsdn, &ecs->fallback->mtx);
- for (int i = 0; i < EDATA_CACHE_FAST_FILL; i++) {
- edata = edata_avail_remove_first(&ecs->fallback->avail);
- if (edata == NULL) {
- break;
- }
- edata_list_inactive_append(&ecs->list, edata);
- atomic_load_sub_store_zu(&ecs->fallback->count, 1);
- }
- malloc_mutex_unlock(tsdn, &ecs->fallback->mtx);
-}
-
-edata_t *
-edata_cache_fast_get(tsdn_t *tsdn, edata_cache_fast_t *ecs) {
- witness_assert_depth_to_rank(tsdn_witness_tsdp_get(tsdn),
- WITNESS_RANK_EDATA_CACHE, 0);
-
- if (ecs->disabled) {
- assert(edata_list_inactive_first(&ecs->list) == NULL);
- return edata_cache_get(tsdn, ecs->fallback);
- }
-
- edata_t *edata = edata_list_inactive_first(&ecs->list);
- if (edata != NULL) {
- edata_list_inactive_remove(&ecs->list, edata);
- return edata;
- }
- /* Slow path; requires synchronization. */
- edata_cache_fast_try_fill_from_fallback(tsdn, ecs);
- edata = edata_list_inactive_first(&ecs->list);
- if (edata != NULL) {
- edata_list_inactive_remove(&ecs->list, edata);
- } else {
- /*
- * Slowest path (fallback was also empty); allocate something
- * new.
- */
- edata = base_alloc_edata(tsdn, ecs->fallback->base);
- }
- return edata;
-}
-
-static void
-edata_cache_fast_flush_all(tsdn_t *tsdn, edata_cache_fast_t *ecs) {
- /*
- * You could imagine smarter cache management policies (like
- * only flushing down to some threshold in anticipation of
- * future get requests). But just flushing everything provides
- * a good opportunity to defrag too, and lets us share code between the
- * flush and disable pathways.
- */
- edata_t *edata;
- size_t nflushed = 0;
- malloc_mutex_lock(tsdn, &ecs->fallback->mtx);
- while ((edata = edata_list_inactive_first(&ecs->list)) != NULL) {
- edata_list_inactive_remove(&ecs->list, edata);
- edata_avail_insert(&ecs->fallback->avail, edata);
- nflushed++;
- }
- atomic_load_add_store_zu(&ecs->fallback->count, nflushed);
- malloc_mutex_unlock(tsdn, &ecs->fallback->mtx);
-}
-
-void
-edata_cache_fast_put(tsdn_t *tsdn, edata_cache_fast_t *ecs, edata_t *edata) {
- witness_assert_depth_to_rank(tsdn_witness_tsdp_get(tsdn),
- WITNESS_RANK_EDATA_CACHE, 0);
-
- if (ecs->disabled) {
- assert(edata_list_inactive_first(&ecs->list) == NULL);
- edata_cache_put(tsdn, ecs->fallback, edata);
- return;
- }
-
- /*
- * Prepend rather than append, to do LIFO ordering in the hopes of some
- * cache locality.
- */
- edata_list_inactive_prepend(&ecs->list, edata);
-}
-
-void
-edata_cache_fast_disable(tsdn_t *tsdn, edata_cache_fast_t *ecs) {
- edata_cache_fast_flush_all(tsdn, ecs);
- ecs->disabled = true;
-}
diff --git a/fluent-bit/lib/jemalloc-5.3.0/src/ehooks.c b/fluent-bit/lib/jemalloc-5.3.0/src/ehooks.c
deleted file mode 100644
index 383e9de6..00000000
--- a/fluent-bit/lib/jemalloc-5.3.0/src/ehooks.c
+++ /dev/null
@@ -1,275 +0,0 @@
-#include "jemalloc/internal/jemalloc_preamble.h"
-#include "jemalloc/internal/jemalloc_internal_includes.h"
-
-#include "jemalloc/internal/ehooks.h"
-#include "jemalloc/internal/extent_mmap.h"
-
-void
-ehooks_init(ehooks_t *ehooks, extent_hooks_t *extent_hooks, unsigned ind) {
- /* All other hooks are optional; this one is not. */
- assert(extent_hooks->alloc != NULL);
- ehooks->ind = ind;
- ehooks_set_extent_hooks_ptr(ehooks, extent_hooks);
-}
-
-/*
- * If the caller specifies (!*zero), it is still possible to receive zeroed
- * memory, in which case *zero is toggled to true. arena_extent_alloc() takes
- * advantage of this to avoid demanding zeroed extents, but taking advantage of
- * them if they are returned.
- */
-static void *
-extent_alloc_core(tsdn_t *tsdn, arena_t *arena, void *new_addr, size_t size,
- size_t alignment, bool *zero, bool *commit, dss_prec_t dss_prec) {
- void *ret;
-
- assert(size != 0);
- assert(alignment != 0);
-
- /* "primary" dss. */
- if (have_dss && dss_prec == dss_prec_primary && (ret =
- extent_alloc_dss(tsdn, arena, new_addr, size, alignment, zero,
- commit)) != NULL) {
- return ret;
- }
- /* mmap. */
- if ((ret = extent_alloc_mmap(new_addr, size, alignment, zero, commit))
- != NULL) {
- return ret;
- }
- /* "secondary" dss. */
- if (have_dss && dss_prec == dss_prec_secondary && (ret =
- extent_alloc_dss(tsdn, arena, new_addr, size, alignment, zero,
- commit)) != NULL) {
- return ret;
- }
-
- /* All strategies for allocation failed. */
- return NULL;
-}
-
-void *
-ehooks_default_alloc_impl(tsdn_t *tsdn, void *new_addr, size_t size,
- size_t alignment, bool *zero, bool *commit, unsigned arena_ind) {
- arena_t *arena = arena_get(tsdn, arena_ind, false);
- /* NULL arena indicates arena_create. */
- assert(arena != NULL || alignment == HUGEPAGE);
- dss_prec_t dss = (arena == NULL) ? dss_prec_disabled :
- (dss_prec_t)atomic_load_u(&arena->dss_prec, ATOMIC_RELAXED);
- void *ret = extent_alloc_core(tsdn, arena, new_addr, size, alignment,
- zero, commit, dss);
- if (have_madvise_huge && ret) {
- pages_set_thp_state(ret, size);
- }
- return ret;
-}
-
-static void *
-ehooks_default_alloc(extent_hooks_t *extent_hooks, void *new_addr, size_t size,
- size_t alignment, bool *zero, bool *commit, unsigned arena_ind) {
- return ehooks_default_alloc_impl(tsdn_fetch(), new_addr, size,
- ALIGNMENT_CEILING(alignment, PAGE), zero, commit, arena_ind);
-}
-
-bool
-ehooks_default_dalloc_impl(void *addr, size_t size) {
- if (!have_dss || !extent_in_dss(addr)) {
- return extent_dalloc_mmap(addr, size);
- }
- return true;
-}
-
-static bool
-ehooks_default_dalloc(extent_hooks_t *extent_hooks, void *addr, size_t size,
- bool committed, unsigned arena_ind) {
- return ehooks_default_dalloc_impl(addr, size);
-}
-
-void
-ehooks_default_destroy_impl(void *addr, size_t size) {
- if (!have_dss || !extent_in_dss(addr)) {
- pages_unmap(addr, size);
- }
-}
-
-static void
-ehooks_default_destroy(extent_hooks_t *extent_hooks, void *addr, size_t size,
- bool committed, unsigned arena_ind) {
- ehooks_default_destroy_impl(addr, size);
-}
-
-bool
-ehooks_default_commit_impl(void *addr, size_t offset, size_t length) {
- return pages_commit((void *)((uintptr_t)addr + (uintptr_t)offset),
- length);
-}
-
-static bool
-ehooks_default_commit(extent_hooks_t *extent_hooks, void *addr, size_t size,
- size_t offset, size_t length, unsigned arena_ind) {
- return ehooks_default_commit_impl(addr, offset, length);
-}
-
-bool
-ehooks_default_decommit_impl(void *addr, size_t offset, size_t length) {
- return pages_decommit((void *)((uintptr_t)addr + (uintptr_t)offset),
- length);
-}
-
-static bool
-ehooks_default_decommit(extent_hooks_t *extent_hooks, void *addr, size_t size,
- size_t offset, size_t length, unsigned arena_ind) {
- return ehooks_default_decommit_impl(addr, offset, length);
-}
-
-#ifdef PAGES_CAN_PURGE_LAZY
-bool
-ehooks_default_purge_lazy_impl(void *addr, size_t offset, size_t length) {
- return pages_purge_lazy((void *)((uintptr_t)addr + (uintptr_t)offset),
- length);
-}
-
-static bool
-ehooks_default_purge_lazy(extent_hooks_t *extent_hooks, void *addr, size_t size,
- size_t offset, size_t length, unsigned arena_ind) {
- assert(addr != NULL);
- assert((offset & PAGE_MASK) == 0);
- assert(length != 0);
- assert((length & PAGE_MASK) == 0);
- return ehooks_default_purge_lazy_impl(addr, offset, length);
-}
-#endif
-
-#ifdef PAGES_CAN_PURGE_FORCED
-bool
-ehooks_default_purge_forced_impl(void *addr, size_t offset, size_t length) {
- return pages_purge_forced((void *)((uintptr_t)addr +
- (uintptr_t)offset), length);
-}
-
-static bool
-ehooks_default_purge_forced(extent_hooks_t *extent_hooks, void *addr,
- size_t size, size_t offset, size_t length, unsigned arena_ind) {
- assert(addr != NULL);
- assert((offset & PAGE_MASK) == 0);
- assert(length != 0);
- assert((length & PAGE_MASK) == 0);
- return ehooks_default_purge_forced_impl(addr, offset, length);
-}
-#endif
-
-bool
-ehooks_default_split_impl() {
- if (!maps_coalesce) {
- /*
- * Without retain, only whole regions can be purged (required by
- * MEM_RELEASE on Windows) -- therefore disallow splitting. See
- * comments in extent_head_no_merge().
- */
- return !opt_retain;
- }
-
- return false;
-}
-
-static bool
-ehooks_default_split(extent_hooks_t *extent_hooks, void *addr, size_t size,
- size_t size_a, size_t size_b, bool committed, unsigned arena_ind) {
- return ehooks_default_split_impl();
-}
-
-bool
-ehooks_default_merge_impl(tsdn_t *tsdn, void *addr_a, void *addr_b) {
- assert(addr_a < addr_b);
- /*
- * For non-DSS cases --
- * a) W/o maps_coalesce, merge is not always allowed (Windows):
- * 1) w/o retain, never merge (first branch below).
- * 2) with retain, only merge extents from the same VirtualAlloc
- * region (in which case MEM_DECOMMIT is utilized for purging).
- *
- * b) With maps_coalesce, it's always possible to merge.
- * 1) w/o retain, always allow merge (only about dirty / muzzy).
- * 2) with retain, to preserve the SN / first-fit, merge is still
- * disallowed if b is a head extent, i.e. no merging across
- * different mmap regions.
- *
- * a2) and b2) are implemented in emap_try_acquire_edata_neighbor, and
- * sanity checked in the second branch below.
- */
- if (!maps_coalesce && !opt_retain) {
- return true;
- }
- if (config_debug) {
- edata_t *a = emap_edata_lookup(tsdn, &arena_emap_global,
- addr_a);
- bool head_a = edata_is_head_get(a);
- edata_t *b = emap_edata_lookup(tsdn, &arena_emap_global,
- addr_b);
- bool head_b = edata_is_head_get(b);
- emap_assert_mapped(tsdn, &arena_emap_global, a);
- emap_assert_mapped(tsdn, &arena_emap_global, b);
- assert(extent_neighbor_head_state_mergeable(head_a, head_b,
- /* forward */ true));
- }
- if (have_dss && !extent_dss_mergeable(addr_a, addr_b)) {
- return true;
- }
-
- return false;
-}
-
-bool
-ehooks_default_merge(extent_hooks_t *extent_hooks, void *addr_a, size_t size_a,
- void *addr_b, size_t size_b, bool committed, unsigned arena_ind) {
- tsdn_t *tsdn = tsdn_fetch();
-
- return ehooks_default_merge_impl(tsdn, addr_a, addr_b);
-}
-
-void
-ehooks_default_zero_impl(void *addr, size_t size) {
- /*
- * By default, we try to zero out memory using OS-provided demand-zeroed
- * pages. If the user has specifically requested hugepages, though, we
- * don't want to purge in the middle of a hugepage (which would break it
- * up), so we act conservatively and use memset.
- */
- bool needs_memset = true;
- if (opt_thp != thp_mode_always) {
- needs_memset = pages_purge_forced(addr, size);
- }
- if (needs_memset) {
- memset(addr, 0, size);
- }
-}
-
-void
-ehooks_default_guard_impl(void *guard1, void *guard2) {
- pages_mark_guards(guard1, guard2);
-}
-
-void
-ehooks_default_unguard_impl(void *guard1, void *guard2) {
- pages_unmark_guards(guard1, guard2);
-}
-
-const extent_hooks_t ehooks_default_extent_hooks = {
- ehooks_default_alloc,
- ehooks_default_dalloc,
- ehooks_default_destroy,
- ehooks_default_commit,
- ehooks_default_decommit,
-#ifdef PAGES_CAN_PURGE_LAZY
- ehooks_default_purge_lazy,
-#else
- NULL,
-#endif
-#ifdef PAGES_CAN_PURGE_FORCED
- ehooks_default_purge_forced,
-#else
- NULL,
-#endif
- ehooks_default_split,
- ehooks_default_merge
-};
diff --git a/fluent-bit/lib/jemalloc-5.3.0/src/emap.c b/fluent-bit/lib/jemalloc-5.3.0/src/emap.c
deleted file mode 100644
index 9cc95a72..00000000
--- a/fluent-bit/lib/jemalloc-5.3.0/src/emap.c
+++ /dev/null
@@ -1,386 +0,0 @@
-#include "jemalloc/internal/jemalloc_preamble.h"
-#include "jemalloc/internal/jemalloc_internal_includes.h"
-
-#include "jemalloc/internal/emap.h"
-
-enum emap_lock_result_e {
- emap_lock_result_success,
- emap_lock_result_failure,
- emap_lock_result_no_extent
-};
-typedef enum emap_lock_result_e emap_lock_result_t;
-
-bool
-emap_init(emap_t *emap, base_t *base, bool zeroed) {
- return rtree_new(&emap->rtree, base, zeroed);
-}
-
-void
-emap_update_edata_state(tsdn_t *tsdn, emap_t *emap, edata_t *edata,
- extent_state_t state) {
- witness_assert_positive_depth_to_rank(tsdn_witness_tsdp_get(tsdn),
- WITNESS_RANK_CORE);
-
- edata_state_set(edata, state);
-
- EMAP_DECLARE_RTREE_CTX;
- rtree_leaf_elm_t *elm1 = rtree_leaf_elm_lookup(tsdn, &emap->rtree,
- rtree_ctx, (uintptr_t)edata_base_get(edata), /* dependent */ true,
- /* init_missing */ false);
- assert(elm1 != NULL);
- rtree_leaf_elm_t *elm2 = edata_size_get(edata) == PAGE ? NULL :
- rtree_leaf_elm_lookup(tsdn, &emap->rtree, rtree_ctx,
- (uintptr_t)edata_last_get(edata), /* dependent */ true,
- /* init_missing */ false);
-
- rtree_leaf_elm_state_update(tsdn, &emap->rtree, elm1, elm2, state);
-
- emap_assert_mapped(tsdn, emap, edata);
-}
-
-static inline edata_t *
-emap_try_acquire_edata_neighbor_impl(tsdn_t *tsdn, emap_t *emap, edata_t *edata,
- extent_pai_t pai, extent_state_t expected_state, bool forward,
- bool expanding) {
- witness_assert_positive_depth_to_rank(tsdn_witness_tsdp_get(tsdn),
- WITNESS_RANK_CORE);
- assert(!edata_guarded_get(edata));
- assert(!expanding || forward);
- assert(!edata_state_in_transition(expected_state));
- assert(expected_state == extent_state_dirty ||
- expected_state == extent_state_muzzy ||
- expected_state == extent_state_retained);
-
- void *neighbor_addr = forward ? edata_past_get(edata) :
- edata_before_get(edata);
- /*
- * This is subtle; the rtree code asserts that its input pointer is
- * non-NULL, and this is a useful thing to check. But it's possible
- * that edata corresponds to an address of (void *)PAGE (in practice,
- * this has only been observed on FreeBSD when address-space
- * randomization is on, but it could in principle happen anywhere). In
- * this case, edata_before_get(edata) is NULL, triggering the assert.
- */
- if (neighbor_addr == NULL) {
- return NULL;
- }
-
- EMAP_DECLARE_RTREE_CTX;
- rtree_leaf_elm_t *elm = rtree_leaf_elm_lookup(tsdn, &emap->rtree,
- rtree_ctx, (uintptr_t)neighbor_addr, /* dependent*/ false,
- /* init_missing */ false);
- if (elm == NULL) {
- return NULL;
- }
-
- rtree_contents_t neighbor_contents = rtree_leaf_elm_read(tsdn,
- &emap->rtree, elm, /* dependent */ true);
- if (!extent_can_acquire_neighbor(edata, neighbor_contents, pai,
- expected_state, forward, expanding)) {
- return NULL;
- }
-
- /* From this point, the neighbor edata can be safely acquired. */
- edata_t *neighbor = neighbor_contents.edata;
- assert(edata_state_get(neighbor) == expected_state);
- emap_update_edata_state(tsdn, emap, neighbor, extent_state_merging);
- if (expanding) {
- extent_assert_can_expand(edata, neighbor);
- } else {
- extent_assert_can_coalesce(edata, neighbor);
- }
-
- return neighbor;
-}
-
-edata_t *
-emap_try_acquire_edata_neighbor(tsdn_t *tsdn, emap_t *emap, edata_t *edata,
- extent_pai_t pai, extent_state_t expected_state, bool forward) {
- return emap_try_acquire_edata_neighbor_impl(tsdn, emap, edata, pai,
- expected_state, forward, /* expand */ false);
-}
-
-edata_t *
-emap_try_acquire_edata_neighbor_expand(tsdn_t *tsdn, emap_t *emap,
- edata_t *edata, extent_pai_t pai, extent_state_t expected_state) {
- /* Try expanding forward. */
- return emap_try_acquire_edata_neighbor_impl(tsdn, emap, edata, pai,
- expected_state, /* forward */ true, /* expand */ true);
-}
-
-void
-emap_release_edata(tsdn_t *tsdn, emap_t *emap, edata_t *edata,
- extent_state_t new_state) {
- assert(emap_edata_in_transition(tsdn, emap, edata));
- assert(emap_edata_is_acquired(tsdn, emap, edata));
-
- emap_update_edata_state(tsdn, emap, edata, new_state);
-}
-
-static bool
-emap_rtree_leaf_elms_lookup(tsdn_t *tsdn, emap_t *emap, rtree_ctx_t *rtree_ctx,
- const edata_t *edata, bool dependent, bool init_missing,
- rtree_leaf_elm_t **r_elm_a, rtree_leaf_elm_t **r_elm_b) {
- *r_elm_a = rtree_leaf_elm_lookup(tsdn, &emap->rtree, rtree_ctx,
- (uintptr_t)edata_base_get(edata), dependent, init_missing);
- if (!dependent && *r_elm_a == NULL) {
- return true;
- }
- assert(*r_elm_a != NULL);
-
- *r_elm_b = rtree_leaf_elm_lookup(tsdn, &emap->rtree, rtree_ctx,
- (uintptr_t)edata_last_get(edata), dependent, init_missing);
- if (!dependent && *r_elm_b == NULL) {
- return true;
- }
- assert(*r_elm_b != NULL);
-
- return false;
-}
-
-static void
-emap_rtree_write_acquired(tsdn_t *tsdn, emap_t *emap, rtree_leaf_elm_t *elm_a,
- rtree_leaf_elm_t *elm_b, edata_t *edata, szind_t szind, bool slab) {
- rtree_contents_t contents;
- contents.edata = edata;
- contents.metadata.szind = szind;
- contents.metadata.slab = slab;
- contents.metadata.is_head = (edata == NULL) ? false :
- edata_is_head_get(edata);
- contents.metadata.state = (edata == NULL) ? 0 : edata_state_get(edata);
- rtree_leaf_elm_write(tsdn, &emap->rtree, elm_a, contents);
- if (elm_b != NULL) {
- rtree_leaf_elm_write(tsdn, &emap->rtree, elm_b, contents);
- }
-}
-
-bool
-emap_register_boundary(tsdn_t *tsdn, emap_t *emap, edata_t *edata,
- szind_t szind, bool slab) {
- assert(edata_state_get(edata) == extent_state_active);
- EMAP_DECLARE_RTREE_CTX;
-
- rtree_leaf_elm_t *elm_a, *elm_b;
- bool err = emap_rtree_leaf_elms_lookup(tsdn, emap, rtree_ctx, edata,
- false, true, &elm_a, &elm_b);
- if (err) {
- return true;
- }
- assert(rtree_leaf_elm_read(tsdn, &emap->rtree, elm_a,
- /* dependent */ false).edata == NULL);
- assert(rtree_leaf_elm_read(tsdn, &emap->rtree, elm_b,
- /* dependent */ false).edata == NULL);
- emap_rtree_write_acquired(tsdn, emap, elm_a, elm_b, edata, szind, slab);
- return false;
-}
-
-/* Invoked *after* emap_register_boundary. */
-void
-emap_register_interior(tsdn_t *tsdn, emap_t *emap, edata_t *edata,
- szind_t szind) {
- EMAP_DECLARE_RTREE_CTX;
-
- assert(edata_slab_get(edata));
- assert(edata_state_get(edata) == extent_state_active);
-
- if (config_debug) {
- /* Making sure the boundary is registered already. */
- rtree_leaf_elm_t *elm_a, *elm_b;
- bool err = emap_rtree_leaf_elms_lookup(tsdn, emap, rtree_ctx,
- edata, /* dependent */ true, /* init_missing */ false,
- &elm_a, &elm_b);
- assert(!err);
- rtree_contents_t contents_a, contents_b;
- contents_a = rtree_leaf_elm_read(tsdn, &emap->rtree, elm_a,
- /* dependent */ true);
- contents_b = rtree_leaf_elm_read(tsdn, &emap->rtree, elm_b,
- /* dependent */ true);
- assert(contents_a.edata == edata && contents_b.edata == edata);
- assert(contents_a.metadata.slab && contents_b.metadata.slab);
- }
-
- rtree_contents_t contents;
- contents.edata = edata;
- contents.metadata.szind = szind;
- contents.metadata.slab = true;
- contents.metadata.state = extent_state_active;
- contents.metadata.is_head = false; /* Not allowed to access. */
-
- assert(edata_size_get(edata) > (2 << LG_PAGE));
- rtree_write_range(tsdn, &emap->rtree, rtree_ctx,
- (uintptr_t)edata_base_get(edata) + PAGE,
- (uintptr_t)edata_last_get(edata) - PAGE, contents);
-}
-
-void
-emap_deregister_boundary(tsdn_t *tsdn, emap_t *emap, edata_t *edata) {
- /*
- * The edata must be either in an acquired state, or protected by state
- * based locks.
- */
- if (!emap_edata_is_acquired(tsdn, emap, edata)) {
- witness_assert_positive_depth_to_rank(
- tsdn_witness_tsdp_get(tsdn), WITNESS_RANK_CORE);
- }
-
- EMAP_DECLARE_RTREE_CTX;
- rtree_leaf_elm_t *elm_a, *elm_b;
-
- emap_rtree_leaf_elms_lookup(tsdn, emap, rtree_ctx, edata,
- true, false, &elm_a, &elm_b);
- emap_rtree_write_acquired(tsdn, emap, elm_a, elm_b, NULL, SC_NSIZES,
- false);
-}
-
-void
-emap_deregister_interior(tsdn_t *tsdn, emap_t *emap, edata_t *edata) {
- EMAP_DECLARE_RTREE_CTX;
-
- assert(edata_slab_get(edata));
- if (edata_size_get(edata) > (2 << LG_PAGE)) {
- rtree_clear_range(tsdn, &emap->rtree, rtree_ctx,
- (uintptr_t)edata_base_get(edata) + PAGE,
- (uintptr_t)edata_last_get(edata) - PAGE);
- }
-}
-
-void
-emap_remap(tsdn_t *tsdn, emap_t *emap, edata_t *edata, szind_t szind,
- bool slab) {
- EMAP_DECLARE_RTREE_CTX;
-
- if (szind != SC_NSIZES) {
- rtree_contents_t contents;
- contents.edata = edata;
- contents.metadata.szind = szind;
- contents.metadata.slab = slab;
- contents.metadata.is_head = edata_is_head_get(edata);
- contents.metadata.state = edata_state_get(edata);
-
- rtree_write(tsdn, &emap->rtree, rtree_ctx,
- (uintptr_t)edata_addr_get(edata), contents);
- /*
- * Recall that this is called only for active->inactive and
- * inactive->active transitions (since only active extents have
- * meaningful values for szind and slab). Active, non-slab
- * extents only need to handle lookups at their head (on
- * deallocation), so we don't bother filling in the end
- * boundary.
- *
- * For slab extents, we do the end-mapping change. This still
- * leaves the interior unmodified; an emap_register_interior
- * call is coming in those cases, though.
- */
- if (slab && edata_size_get(edata) > PAGE) {
- uintptr_t key = (uintptr_t)edata_past_get(edata)
- - (uintptr_t)PAGE;
- rtree_write(tsdn, &emap->rtree, rtree_ctx, key,
- contents);
- }
- }
-}
-
-bool
-emap_split_prepare(tsdn_t *tsdn, emap_t *emap, emap_prepare_t *prepare,
- edata_t *edata, size_t size_a, edata_t *trail, size_t size_b) {
- EMAP_DECLARE_RTREE_CTX;
-
- /*
- * We use incorrect constants for things like arena ind, zero, ranged,
- * and commit state, and head status. This is a fake edata_t, used to
- * facilitate a lookup.
- */
- edata_t lead = {0};
- edata_init(&lead, 0U, edata_addr_get(edata), size_a, false, 0, 0,
- extent_state_active, false, false, EXTENT_PAI_PAC, EXTENT_NOT_HEAD);
-
- emap_rtree_leaf_elms_lookup(tsdn, emap, rtree_ctx, &lead, false, true,
- &prepare->lead_elm_a, &prepare->lead_elm_b);
- emap_rtree_leaf_elms_lookup(tsdn, emap, rtree_ctx, trail, false, true,
- &prepare->trail_elm_a, &prepare->trail_elm_b);
-
- if (prepare->lead_elm_a == NULL || prepare->lead_elm_b == NULL
- || prepare->trail_elm_a == NULL || prepare->trail_elm_b == NULL) {
- return true;
- }
- return false;
-}
-
-void
-emap_split_commit(tsdn_t *tsdn, emap_t *emap, emap_prepare_t *prepare,
- edata_t *lead, size_t size_a, edata_t *trail, size_t size_b) {
- /*
- * We should think about not writing to the lead leaf element. We can
- * get into situations where a racing realloc-like call can disagree
- * with a size lookup request. I think it's fine to declare that these
- * situations are race bugs, but there's an argument to be made that for
- * things like xallocx, a size lookup call should return either the old
- * size or the new size, but not anything else.
- */
- emap_rtree_write_acquired(tsdn, emap, prepare->lead_elm_a,
- prepare->lead_elm_b, lead, SC_NSIZES, /* slab */ false);
- emap_rtree_write_acquired(tsdn, emap, prepare->trail_elm_a,
- prepare->trail_elm_b, trail, SC_NSIZES, /* slab */ false);
-}
-
-void
-emap_merge_prepare(tsdn_t *tsdn, emap_t *emap, emap_prepare_t *prepare,
- edata_t *lead, edata_t *trail) {
- EMAP_DECLARE_RTREE_CTX;
- emap_rtree_leaf_elms_lookup(tsdn, emap, rtree_ctx, lead, true, false,
- &prepare->lead_elm_a, &prepare->lead_elm_b);
- emap_rtree_leaf_elms_lookup(tsdn, emap, rtree_ctx, trail, true, false,
- &prepare->trail_elm_a, &prepare->trail_elm_b);
-}
-
-void
-emap_merge_commit(tsdn_t *tsdn, emap_t *emap, emap_prepare_t *prepare,
- edata_t *lead, edata_t *trail) {
- rtree_contents_t clear_contents;
- clear_contents.edata = NULL;
- clear_contents.metadata.szind = SC_NSIZES;
- clear_contents.metadata.slab = false;
- clear_contents.metadata.is_head = false;
- clear_contents.metadata.state = (extent_state_t)0;
-
- if (prepare->lead_elm_b != NULL) {
- rtree_leaf_elm_write(tsdn, &emap->rtree,
- prepare->lead_elm_b, clear_contents);
- }
-
- rtree_leaf_elm_t *merged_b;
- if (prepare->trail_elm_b != NULL) {
- rtree_leaf_elm_write(tsdn, &emap->rtree,
- prepare->trail_elm_a, clear_contents);
- merged_b = prepare->trail_elm_b;
- } else {
- merged_b = prepare->trail_elm_a;
- }
-
- emap_rtree_write_acquired(tsdn, emap, prepare->lead_elm_a, merged_b,
- lead, SC_NSIZES, false);
-}
-
-void
-emap_do_assert_mapped(tsdn_t *tsdn, emap_t *emap, edata_t *edata) {
- EMAP_DECLARE_RTREE_CTX;
-
- rtree_contents_t contents = rtree_read(tsdn, &emap->rtree, rtree_ctx,
- (uintptr_t)edata_base_get(edata));
- assert(contents.edata == edata);
- assert(contents.metadata.is_head == edata_is_head_get(edata));
- assert(contents.metadata.state == edata_state_get(edata));
-}
-
-void
-emap_do_assert_not_mapped(tsdn_t *tsdn, emap_t *emap, edata_t *edata) {
- emap_full_alloc_ctx_t context1 = {0};
- emap_full_alloc_ctx_try_lookup(tsdn, emap, edata_base_get(edata),
- &context1);
- assert(context1.edata == NULL);
-
- emap_full_alloc_ctx_t context2 = {0};
- emap_full_alloc_ctx_try_lookup(tsdn, emap, edata_last_get(edata),
- &context2);
- assert(context2.edata == NULL);
-}
diff --git a/fluent-bit/lib/jemalloc-5.3.0/src/eset.c b/fluent-bit/lib/jemalloc-5.3.0/src/eset.c
deleted file mode 100644
index 6f8f335e..00000000
--- a/fluent-bit/lib/jemalloc-5.3.0/src/eset.c
+++ /dev/null
@@ -1,282 +0,0 @@
-#include "jemalloc/internal/jemalloc_preamble.h"
-#include "jemalloc/internal/jemalloc_internal_includes.h"
-
-#include "jemalloc/internal/eset.h"
-
-#define ESET_NPSIZES (SC_NPSIZES + 1)
-
-static void
-eset_bin_init(eset_bin_t *bin) {
- edata_heap_new(&bin->heap);
- /*
- * heap_min doesn't need initialization; it gets filled in when the bin
- * goes from non-empty to empty.
- */
-}
-
-static void
-eset_bin_stats_init(eset_bin_stats_t *bin_stats) {
- atomic_store_zu(&bin_stats->nextents, 0, ATOMIC_RELAXED);
- atomic_store_zu(&bin_stats->nbytes, 0, ATOMIC_RELAXED);
-}
-
-void
-eset_init(eset_t *eset, extent_state_t state) {
- for (unsigned i = 0; i < ESET_NPSIZES; i++) {
- eset_bin_init(&eset->bins[i]);
- eset_bin_stats_init(&eset->bin_stats[i]);
- }
- fb_init(eset->bitmap, ESET_NPSIZES);
- edata_list_inactive_init(&eset->lru);
- eset->state = state;
-}
-
-size_t
-eset_npages_get(eset_t *eset) {
- return atomic_load_zu(&eset->npages, ATOMIC_RELAXED);
-}
-
-size_t
-eset_nextents_get(eset_t *eset, pszind_t pind) {
- return atomic_load_zu(&eset->bin_stats[pind].nextents, ATOMIC_RELAXED);
-}
-
-size_t
-eset_nbytes_get(eset_t *eset, pszind_t pind) {
- return atomic_load_zu(&eset->bin_stats[pind].nbytes, ATOMIC_RELAXED);
-}
-
-static void
-eset_stats_add(eset_t *eset, pszind_t pind, size_t sz) {
- size_t cur = atomic_load_zu(&eset->bin_stats[pind].nextents,
- ATOMIC_RELAXED);
- atomic_store_zu(&eset->bin_stats[pind].nextents, cur + 1,
- ATOMIC_RELAXED);
- cur = atomic_load_zu(&eset->bin_stats[pind].nbytes, ATOMIC_RELAXED);
- atomic_store_zu(&eset->bin_stats[pind].nbytes, cur + sz,
- ATOMIC_RELAXED);
-}
-
-static void
-eset_stats_sub(eset_t *eset, pszind_t pind, size_t sz) {
- size_t cur = atomic_load_zu(&eset->bin_stats[pind].nextents,
- ATOMIC_RELAXED);
- atomic_store_zu(&eset->bin_stats[pind].nextents, cur - 1,
- ATOMIC_RELAXED);
- cur = atomic_load_zu(&eset->bin_stats[pind].nbytes, ATOMIC_RELAXED);
- atomic_store_zu(&eset->bin_stats[pind].nbytes, cur - sz,
- ATOMIC_RELAXED);
-}
-
-void
-eset_insert(eset_t *eset, edata_t *edata) {
- assert(edata_state_get(edata) == eset->state);
-
- size_t size = edata_size_get(edata);
- size_t psz = sz_psz_quantize_floor(size);
- pszind_t pind = sz_psz2ind(psz);
-
- edata_cmp_summary_t edata_cmp_summary = edata_cmp_summary_get(edata);
- if (edata_heap_empty(&eset->bins[pind].heap)) {
- fb_set(eset->bitmap, ESET_NPSIZES, (size_t)pind);
- /* Only element is automatically the min element. */
- eset->bins[pind].heap_min = edata_cmp_summary;
- } else {
- /*
- * There's already a min element; update the summary if we're
- * about to insert a lower one.
- */
- if (edata_cmp_summary_comp(edata_cmp_summary,
- eset->bins[pind].heap_min) < 0) {
- eset->bins[pind].heap_min = edata_cmp_summary;
- }
- }
- edata_heap_insert(&eset->bins[pind].heap, edata);
-
- if (config_stats) {
- eset_stats_add(eset, pind, size);
- }
-
- edata_list_inactive_append(&eset->lru, edata);
- size_t npages = size >> LG_PAGE;
- /*
- * All modifications to npages hold the mutex (as asserted above), so we
- * don't need an atomic fetch-add; we can get by with a load followed by
- * a store.
- */
- size_t cur_eset_npages =
- atomic_load_zu(&eset->npages, ATOMIC_RELAXED);
- atomic_store_zu(&eset->npages, cur_eset_npages + npages,
- ATOMIC_RELAXED);
-}
-
-void
-eset_remove(eset_t *eset, edata_t *edata) {
- assert(edata_state_get(edata) == eset->state ||
- edata_state_in_transition(edata_state_get(edata)));
-
- size_t size = edata_size_get(edata);
- size_t psz = sz_psz_quantize_floor(size);
- pszind_t pind = sz_psz2ind(psz);
- if (config_stats) {
- eset_stats_sub(eset, pind, size);
- }
-
- edata_cmp_summary_t edata_cmp_summary = edata_cmp_summary_get(edata);
- edata_heap_remove(&eset->bins[pind].heap, edata);
- if (edata_heap_empty(&eset->bins[pind].heap)) {
- fb_unset(eset->bitmap, ESET_NPSIZES, (size_t)pind);
- } else {
- /*
- * This is a little weird; we compare if the summaries are
- * equal, rather than if the edata we removed was the heap
- * minimum. The reason why is that getting the heap minimum
- * can cause a pairing heap merge operation. We can avoid this
- * if we only update the min if it's changed, in which case the
- * summaries of the removed element and the min element should
- * compare equal.
- */
- if (edata_cmp_summary_comp(edata_cmp_summary,
- eset->bins[pind].heap_min) == 0) {
- eset->bins[pind].heap_min = edata_cmp_summary_get(
- edata_heap_first(&eset->bins[pind].heap));
- }
- }
- edata_list_inactive_remove(&eset->lru, edata);
- size_t npages = size >> LG_PAGE;
- /*
- * As in eset_insert, we hold eset->mtx and so don't need atomic
- * operations for updating eset->npages.
- */
- size_t cur_extents_npages =
- atomic_load_zu(&eset->npages, ATOMIC_RELAXED);
- assert(cur_extents_npages >= npages);
- atomic_store_zu(&eset->npages,
- cur_extents_npages - (size >> LG_PAGE), ATOMIC_RELAXED);
-}
-
-/*
- * Find an extent with size [min_size, max_size) to satisfy the alignment
- * requirement. For each size, try only the first extent in the heap.
- */
-static edata_t *
-eset_fit_alignment(eset_t *eset, size_t min_size, size_t max_size,
- size_t alignment) {
- pszind_t pind = sz_psz2ind(sz_psz_quantize_ceil(min_size));
- pszind_t pind_max = sz_psz2ind(sz_psz_quantize_ceil(max_size));
-
- for (pszind_t i =
- (pszind_t)fb_ffs(eset->bitmap, ESET_NPSIZES, (size_t)pind);
- i < pind_max;
- i = (pszind_t)fb_ffs(eset->bitmap, ESET_NPSIZES, (size_t)i + 1)) {
- assert(i < SC_NPSIZES);
- assert(!edata_heap_empty(&eset->bins[i].heap));
- edata_t *edata = edata_heap_first(&eset->bins[i].heap);
- uintptr_t base = (uintptr_t)edata_base_get(edata);
- size_t candidate_size = edata_size_get(edata);
- assert(candidate_size >= min_size);
-
- uintptr_t next_align = ALIGNMENT_CEILING((uintptr_t)base,
- PAGE_CEILING(alignment));
- if (base > next_align || base + candidate_size <= next_align) {
- /* Overflow or not crossing the next alignment. */
- continue;
- }
-
- size_t leadsize = next_align - base;
- if (candidate_size - leadsize >= min_size) {
- return edata;
- }
- }
-
- return NULL;
-}
-
-/*
- * Do first-fit extent selection, i.e. select the oldest/lowest extent that is
- * large enough.
- *
- * lg_max_fit is the (log of the) maximum ratio between the requested size and
- * the returned size that we'll allow. This can reduce fragmentation by
- * avoiding reusing and splitting large extents for smaller sizes. In practice,
- * it's set to opt_lg_extent_max_active_fit for the dirty eset and SC_PTR_BITS
- * for others.
- */
-static edata_t *
-eset_first_fit(eset_t *eset, size_t size, bool exact_only,
- unsigned lg_max_fit) {
- edata_t *ret = NULL;
- edata_cmp_summary_t ret_summ JEMALLOC_CC_SILENCE_INIT({0});
-
- pszind_t pind = sz_psz2ind(sz_psz_quantize_ceil(size));
-
- if (exact_only) {
- return edata_heap_empty(&eset->bins[pind].heap) ? NULL :
- edata_heap_first(&eset->bins[pind].heap);
- }
-
- for (pszind_t i =
- (pszind_t)fb_ffs(eset->bitmap, ESET_NPSIZES, (size_t)pind);
- i < ESET_NPSIZES;
- i = (pszind_t)fb_ffs(eset->bitmap, ESET_NPSIZES, (size_t)i + 1)) {
- assert(!edata_heap_empty(&eset->bins[i].heap));
- if (lg_max_fit == SC_PTR_BITS) {
- /*
- * We'll shift by this below, and shifting out all the
- * bits is undefined. Decreasing is safe, since the
- * page size is larger than 1 byte.
- */
- lg_max_fit = SC_PTR_BITS - 1;
- }
- if ((sz_pind2sz(i) >> lg_max_fit) > size) {
- break;
- }
- if (ret == NULL || edata_cmp_summary_comp(
- eset->bins[i].heap_min, ret_summ) < 0) {
- /*
- * We grab the edata as early as possible, even though
- * we might change it later. Practically, a large
- * portion of eset_fit calls succeed at the first valid
- * index, so this doesn't cost much, and we get the
- * effect of prefetching the edata as early as possible.
- */
- edata_t *edata = edata_heap_first(&eset->bins[i].heap);
- assert(edata_size_get(edata) >= size);
- assert(ret == NULL || edata_snad_comp(edata, ret) < 0);
- assert(ret == NULL || edata_cmp_summary_comp(
- eset->bins[i].heap_min,
- edata_cmp_summary_get(edata)) == 0);
- ret = edata;
- ret_summ = eset->bins[i].heap_min;
- }
- if (i == SC_NPSIZES) {
- break;
- }
- assert(i < SC_NPSIZES);
- }
-
- return ret;
-}
-
-edata_t *
-eset_fit(eset_t *eset, size_t esize, size_t alignment, bool exact_only,
- unsigned lg_max_fit) {
- size_t max_size = esize + PAGE_CEILING(alignment) - PAGE;
- /* Beware size_t wrap-around. */
- if (max_size < esize) {
- return NULL;
- }
-
- edata_t *edata = eset_first_fit(eset, max_size, exact_only, lg_max_fit);
-
- if (alignment > PAGE && edata == NULL) {
- /*
- * max_size guarantees the alignment requirement but is rather
- * pessimistic. Next we try to satisfy the aligned allocation
- * with sizes in [esize, max_size).
- */
- edata = eset_fit_alignment(eset, esize, max_size, alignment);
- }
-
- return edata;
-}
diff --git a/fluent-bit/lib/jemalloc-5.3.0/src/exp_grow.c b/fluent-bit/lib/jemalloc-5.3.0/src/exp_grow.c
deleted file mode 100644
index 386471f4..00000000
--- a/fluent-bit/lib/jemalloc-5.3.0/src/exp_grow.c
+++ /dev/null
@@ -1,8 +0,0 @@
-#include "jemalloc/internal/jemalloc_preamble.h"
-#include "jemalloc/internal/jemalloc_internal_includes.h"
-
-void
-exp_grow_init(exp_grow_t *exp_grow) {
- exp_grow->next = sz_psz2ind(HUGEPAGE);
- exp_grow->limit = sz_psz2ind(SC_LARGE_MAXCLASS);
-}
diff --git a/fluent-bit/lib/jemalloc-5.3.0/src/extent.c b/fluent-bit/lib/jemalloc-5.3.0/src/extent.c
deleted file mode 100644
index cf3d1f31..00000000
--- a/fluent-bit/lib/jemalloc-5.3.0/src/extent.c
+++ /dev/null
@@ -1,1326 +0,0 @@
-#include "jemalloc/internal/jemalloc_preamble.h"
-#include "jemalloc/internal/jemalloc_internal_includes.h"
-
-#include "jemalloc/internal/assert.h"
-#include "jemalloc/internal/emap.h"
-#include "jemalloc/internal/extent_dss.h"
-#include "jemalloc/internal/extent_mmap.h"
-#include "jemalloc/internal/ph.h"
-#include "jemalloc/internal/mutex.h"
-
-/******************************************************************************/
-/* Data. */
-
-size_t opt_lg_extent_max_active_fit = LG_EXTENT_MAX_ACTIVE_FIT_DEFAULT;
-
-static bool extent_commit_impl(tsdn_t *tsdn, ehooks_t *ehooks, edata_t *edata,
- size_t offset, size_t length, bool growing_retained);
-static bool extent_purge_lazy_impl(tsdn_t *tsdn, ehooks_t *ehooks,
- edata_t *edata, size_t offset, size_t length, bool growing_retained);
-static bool extent_purge_forced_impl(tsdn_t *tsdn, ehooks_t *ehooks,
- edata_t *edata, size_t offset, size_t length, bool growing_retained);
-static edata_t *extent_split_impl(tsdn_t *tsdn, pac_t *pac, ehooks_t *ehooks,
- edata_t *edata, size_t size_a, size_t size_b, bool holding_core_locks);
-static bool extent_merge_impl(tsdn_t *tsdn, pac_t *pac, ehooks_t *ehooks,
- edata_t *a, edata_t *b, bool holding_core_locks);
-
-/* Used exclusively for gdump triggering. */
-static atomic_zu_t curpages;
-static atomic_zu_t highpages;
-
-/******************************************************************************/
-/*
- * Function prototypes for static functions that are referenced prior to
- * definition.
- */
-
-static void extent_deregister(tsdn_t *tsdn, pac_t *pac, edata_t *edata);
-static edata_t *extent_recycle(tsdn_t *tsdn, pac_t *pac, ehooks_t *ehooks,
- ecache_t *ecache, edata_t *expand_edata, size_t usize, size_t alignment,
- bool zero, bool *commit, bool growing_retained, bool guarded);
-static edata_t *extent_try_coalesce(tsdn_t *tsdn, pac_t *pac, ehooks_t *ehooks,
- ecache_t *ecache, edata_t *edata, bool *coalesced);
-static edata_t *extent_alloc_retained(tsdn_t *tsdn, pac_t *pac,
- ehooks_t *ehooks, edata_t *expand_edata, size_t size, size_t alignment,
- bool zero, bool *commit, bool guarded);
-
-/******************************************************************************/
-
-size_t
-extent_sn_next(pac_t *pac) {
- return atomic_fetch_add_zu(&pac->extent_sn_next, 1, ATOMIC_RELAXED);
-}
-
-static inline bool
-extent_may_force_decay(pac_t *pac) {
- return !(pac_decay_ms_get(pac, extent_state_dirty) == -1
- || pac_decay_ms_get(pac, extent_state_muzzy) == -1);
-}
-
-static bool
-extent_try_delayed_coalesce(tsdn_t *tsdn, pac_t *pac, ehooks_t *ehooks,
- ecache_t *ecache, edata_t *edata) {
- emap_update_edata_state(tsdn, pac->emap, edata, extent_state_active);
-
- bool coalesced;
- edata = extent_try_coalesce(tsdn, pac, ehooks, ecache,
- edata, &coalesced);
- emap_update_edata_state(tsdn, pac->emap, edata, ecache->state);
-
- if (!coalesced) {
- return true;
- }
- eset_insert(&ecache->eset, edata);
- return false;
-}
-
-edata_t *
-ecache_alloc(tsdn_t *tsdn, pac_t *pac, ehooks_t *ehooks, ecache_t *ecache,
- edata_t *expand_edata, size_t size, size_t alignment, bool zero,
- bool guarded) {
- assert(size != 0);
- assert(alignment != 0);
- witness_assert_depth_to_rank(tsdn_witness_tsdp_get(tsdn),
- WITNESS_RANK_CORE, 0);
-
- bool commit = true;
- edata_t *edata = extent_recycle(tsdn, pac, ehooks, ecache, expand_edata,
- size, alignment, zero, &commit, false, guarded);
- assert(edata == NULL || edata_pai_get(edata) == EXTENT_PAI_PAC);
- assert(edata == NULL || edata_guarded_get(edata) == guarded);
- return edata;
-}
-
-edata_t *
-ecache_alloc_grow(tsdn_t *tsdn, pac_t *pac, ehooks_t *ehooks, ecache_t *ecache,
- edata_t *expand_edata, size_t size, size_t alignment, bool zero,
- bool guarded) {
- assert(size != 0);
- assert(alignment != 0);
- witness_assert_depth_to_rank(tsdn_witness_tsdp_get(tsdn),
- WITNESS_RANK_CORE, 0);
-
- bool commit = true;
- edata_t *edata = extent_alloc_retained(tsdn, pac, ehooks, expand_edata,
- size, alignment, zero, &commit, guarded);
- if (edata == NULL) {
- if (opt_retain && expand_edata != NULL) {
- /*
- * When retain is enabled and trying to expand, we do
- * not attempt extent_alloc_wrapper which does mmap that
- * is very unlikely to succeed (unless it happens to be
- * at the end).
- */
- return NULL;
- }
- if (guarded) {
- /*
- * Means no cached guarded extents available (and no
- * grow_retained was attempted). The pac_alloc flow
- * will alloc regular extents to make new guarded ones.
- */
- return NULL;
- }
- void *new_addr = (expand_edata == NULL) ? NULL :
- edata_past_get(expand_edata);
- edata = extent_alloc_wrapper(tsdn, pac, ehooks, new_addr,
- size, alignment, zero, &commit,
- /* growing_retained */ false);
- }
-
- assert(edata == NULL || edata_pai_get(edata) == EXTENT_PAI_PAC);
- return edata;
-}
-
-void
-ecache_dalloc(tsdn_t *tsdn, pac_t *pac, ehooks_t *ehooks, ecache_t *ecache,
- edata_t *edata) {
- assert(edata_base_get(edata) != NULL);
- assert(edata_size_get(edata) != 0);
- assert(edata_pai_get(edata) == EXTENT_PAI_PAC);
- witness_assert_depth_to_rank(tsdn_witness_tsdp_get(tsdn),
- WITNESS_RANK_CORE, 0);
-
- edata_addr_set(edata, edata_base_get(edata));
- edata_zeroed_set(edata, false);
-
- extent_record(tsdn, pac, ehooks, ecache, edata);
-}
-
-edata_t *
-ecache_evict(tsdn_t *tsdn, pac_t *pac, ehooks_t *ehooks,
- ecache_t *ecache, size_t npages_min) {
- malloc_mutex_lock(tsdn, &ecache->mtx);
-
- /*
- * Get the LRU coalesced extent, if any. If coalescing was delayed,
- * the loop will iterate until the LRU extent is fully coalesced.
- */
- edata_t *edata;
- while (true) {
- /* Get the LRU extent, if any. */
- eset_t *eset = &ecache->eset;
- edata = edata_list_inactive_first(&eset->lru);
- if (edata == NULL) {
- /*
- * Next check if there are guarded extents. They are
- * more expensive to purge (since they are not
- * mergeable), thus in favor of caching them longer.
- */
- eset = &ecache->guarded_eset;
- edata = edata_list_inactive_first(&eset->lru);
- if (edata == NULL) {
- goto label_return;
- }
- }
- /* Check the eviction limit. */
- size_t extents_npages = ecache_npages_get(ecache);
- if (extents_npages <= npages_min) {
- edata = NULL;
- goto label_return;
- }
- eset_remove(eset, edata);
- if (!ecache->delay_coalesce || edata_guarded_get(edata)) {
- break;
- }
- /* Try to coalesce. */
- if (extent_try_delayed_coalesce(tsdn, pac, ehooks, ecache,
- edata)) {
- break;
- }
- /*
- * The LRU extent was just coalesced and the result placed in
- * the LRU at its neighbor's position. Start over.
- */
- }
-
- /*
- * Either mark the extent active or deregister it to protect against
- * concurrent operations.
- */
- switch (ecache->state) {
- case extent_state_active:
- not_reached();
- case extent_state_dirty:
- case extent_state_muzzy:
- emap_update_edata_state(tsdn, pac->emap, edata,
- extent_state_active);
- break;
- case extent_state_retained:
- extent_deregister(tsdn, pac, edata);
- break;
- default:
- not_reached();
- }
-
-label_return:
- malloc_mutex_unlock(tsdn, &ecache->mtx);
- return edata;
-}
-
-/*
- * This can only happen when we fail to allocate a new extent struct (which
- * indicates OOM), e.g. when trying to split an existing extent.
- */
-static void
-extents_abandon_vm(tsdn_t *tsdn, pac_t *pac, ehooks_t *ehooks, ecache_t *ecache,
- edata_t *edata, bool growing_retained) {
- size_t sz = edata_size_get(edata);
- if (config_stats) {
- atomic_fetch_add_zu(&pac->stats->abandoned_vm, sz,
- ATOMIC_RELAXED);
- }
- /*
- * Leak extent after making sure its pages have already been purged, so
- * that this is only a virtual memory leak.
- */
- if (ecache->state == extent_state_dirty) {
- if (extent_purge_lazy_impl(tsdn, ehooks, edata, 0, sz,
- growing_retained)) {
- extent_purge_forced_impl(tsdn, ehooks, edata, 0,
- edata_size_get(edata), growing_retained);
- }
- }
- edata_cache_put(tsdn, pac->edata_cache, edata);
-}
-
-static void
-extent_deactivate_locked_impl(tsdn_t *tsdn, pac_t *pac, ecache_t *ecache,
- edata_t *edata) {
- malloc_mutex_assert_owner(tsdn, &ecache->mtx);
- assert(edata_arena_ind_get(edata) == ecache_ind_get(ecache));
-
- emap_update_edata_state(tsdn, pac->emap, edata, ecache->state);
- eset_t *eset = edata_guarded_get(edata) ? &ecache->guarded_eset :
- &ecache->eset;
- eset_insert(eset, edata);
-}
-
-static void
-extent_deactivate_locked(tsdn_t *tsdn, pac_t *pac, ecache_t *ecache,
- edata_t *edata) {
- assert(edata_state_get(edata) == extent_state_active);
- extent_deactivate_locked_impl(tsdn, pac, ecache, edata);
-}
-
-static void
-extent_deactivate_check_state_locked(tsdn_t *tsdn, pac_t *pac, ecache_t *ecache,
- edata_t *edata, extent_state_t expected_state) {
- assert(edata_state_get(edata) == expected_state);
- extent_deactivate_locked_impl(tsdn, pac, ecache, edata);
-}
-
-static void
-extent_activate_locked(tsdn_t *tsdn, pac_t *pac, ecache_t *ecache, eset_t *eset,
- edata_t *edata) {
- assert(edata_arena_ind_get(edata) == ecache_ind_get(ecache));
- assert(edata_state_get(edata) == ecache->state ||
- edata_state_get(edata) == extent_state_merging);
-
- eset_remove(eset, edata);
- emap_update_edata_state(tsdn, pac->emap, edata, extent_state_active);
-}
-
-void
-extent_gdump_add(tsdn_t *tsdn, const edata_t *edata) {
- cassert(config_prof);
- /* prof_gdump() requirement. */
- witness_assert_depth_to_rank(tsdn_witness_tsdp_get(tsdn),
- WITNESS_RANK_CORE, 0);
-
- if (opt_prof && edata_state_get(edata) == extent_state_active) {
- size_t nadd = edata_size_get(edata) >> LG_PAGE;
- size_t cur = atomic_fetch_add_zu(&curpages, nadd,
- ATOMIC_RELAXED) + nadd;
- size_t high = atomic_load_zu(&highpages, ATOMIC_RELAXED);
- while (cur > high && !atomic_compare_exchange_weak_zu(
- &highpages, &high, cur, ATOMIC_RELAXED, ATOMIC_RELAXED)) {
- /*
- * Don't refresh cur, because it may have decreased
- * since this thread lost the highpages update race.
- * Note that high is updated in case of CAS failure.
- */
- }
- if (cur > high && prof_gdump_get_unlocked()) {
- prof_gdump(tsdn);
- }
- }
-}
-
-static void
-extent_gdump_sub(tsdn_t *tsdn, const edata_t *edata) {
- cassert(config_prof);
-
- if (opt_prof && edata_state_get(edata) == extent_state_active) {
- size_t nsub = edata_size_get(edata) >> LG_PAGE;
- assert(atomic_load_zu(&curpages, ATOMIC_RELAXED) >= nsub);
- atomic_fetch_sub_zu(&curpages, nsub, ATOMIC_RELAXED);
- }
-}
-
-static bool
-extent_register_impl(tsdn_t *tsdn, pac_t *pac, edata_t *edata, bool gdump_add) {
- assert(edata_state_get(edata) == extent_state_active);
- /*
- * No locking needed, as the edata must be in active state, which
- * prevents other threads from accessing the edata.
- */
- if (emap_register_boundary(tsdn, pac->emap, edata, SC_NSIZES,
- /* slab */ false)) {
- return true;
- }
-
- if (config_prof && gdump_add) {
- extent_gdump_add(tsdn, edata);
- }
-
- return false;
-}
-
-static bool
-extent_register(tsdn_t *tsdn, pac_t *pac, edata_t *edata) {
- return extent_register_impl(tsdn, pac, edata, true);
-}
-
-static bool
-extent_register_no_gdump_add(tsdn_t *tsdn, pac_t *pac, edata_t *edata) {
- return extent_register_impl(tsdn, pac, edata, false);
-}
-
-static void
-extent_reregister(tsdn_t *tsdn, pac_t *pac, edata_t *edata) {
- bool err = extent_register(tsdn, pac, edata);
- assert(!err);
-}
-
-/*
- * Removes all pointers to the given extent from the global rtree.
- */
-static void
-extent_deregister_impl(tsdn_t *tsdn, pac_t *pac, edata_t *edata,
- bool gdump) {
- emap_deregister_boundary(tsdn, pac->emap, edata);
-
- if (config_prof && gdump) {
- extent_gdump_sub(tsdn, edata);
- }
-}
-
-static void
-extent_deregister(tsdn_t *tsdn, pac_t *pac, edata_t *edata) {
- extent_deregister_impl(tsdn, pac, edata, true);
-}
-
-static void
-extent_deregister_no_gdump_sub(tsdn_t *tsdn, pac_t *pac,
- edata_t *edata) {
- extent_deregister_impl(tsdn, pac, edata, false);
-}
-
-/*
- * Tries to find and remove an extent from ecache that can be used for the
- * given allocation request.
- */
-static edata_t *
-extent_recycle_extract(tsdn_t *tsdn, pac_t *pac, ehooks_t *ehooks,
- ecache_t *ecache, edata_t *expand_edata, size_t size, size_t alignment,
- bool guarded) {
- malloc_mutex_assert_owner(tsdn, &ecache->mtx);
- assert(alignment > 0);
- if (config_debug && expand_edata != NULL) {
- /*
- * Non-NULL expand_edata indicates in-place expanding realloc.
- * new_addr must either refer to a non-existing extent, or to
- * the base of an extant extent, since only active slabs support
- * interior lookups (which of course cannot be recycled).
- */
- void *new_addr = edata_past_get(expand_edata);
- assert(PAGE_ADDR2BASE(new_addr) == new_addr);
- assert(alignment <= PAGE);
- }
-
- edata_t *edata;
- eset_t *eset = guarded ? &ecache->guarded_eset : &ecache->eset;
- if (expand_edata != NULL) {
- edata = emap_try_acquire_edata_neighbor_expand(tsdn, pac->emap,
- expand_edata, EXTENT_PAI_PAC, ecache->state);
- if (edata != NULL) {
- extent_assert_can_expand(expand_edata, edata);
- if (edata_size_get(edata) < size) {
- emap_release_edata(tsdn, pac->emap, edata,
- ecache->state);
- edata = NULL;
- }
- }
- } else {
- /*
- * A large extent might be broken up from its original size to
- * some small size to satisfy a small request. When that small
- * request is freed, though, it won't merge back with the larger
- * extent if delayed coalescing is on. The large extent can
- * then no longer satify a request for its original size. To
- * limit this effect, when delayed coalescing is enabled, we
- * put a cap on how big an extent we can split for a request.
- */
- unsigned lg_max_fit = ecache->delay_coalesce
- ? (unsigned)opt_lg_extent_max_active_fit : SC_PTR_BITS;
-
- /*
- * If split and merge are not allowed (Windows w/o retain), try
- * exact fit only.
- *
- * For simplicity purposes, splitting guarded extents is not
- * supported. Hence, we do only exact fit for guarded
- * allocations.
- */
- bool exact_only = (!maps_coalesce && !opt_retain) || guarded;
- edata = eset_fit(eset, size, alignment, exact_only,
- lg_max_fit);
- }
- if (edata == NULL) {
- return NULL;
- }
- assert(!guarded || edata_guarded_get(edata));
- extent_activate_locked(tsdn, pac, ecache, eset, edata);
-
- return edata;
-}
-
-/*
- * Given an allocation request and an extent guaranteed to be able to satisfy
- * it, this splits off lead and trail extents, leaving edata pointing to an
- * extent satisfying the allocation.
- * This function doesn't put lead or trail into any ecache; it's the caller's
- * job to ensure that they can be reused.
- */
-typedef enum {
- /*
- * Split successfully. lead, edata, and trail, are modified to extents
- * describing the ranges before, in, and after the given allocation.
- */
- extent_split_interior_ok,
- /*
- * The extent can't satisfy the given allocation request. None of the
- * input edata_t *s are touched.
- */
- extent_split_interior_cant_alloc,
- /*
- * In a potentially invalid state. Must leak (if *to_leak is non-NULL),
- * and salvage what's still salvageable (if *to_salvage is non-NULL).
- * None of lead, edata, or trail are valid.
- */
- extent_split_interior_error
-} extent_split_interior_result_t;
-
-static extent_split_interior_result_t
-extent_split_interior(tsdn_t *tsdn, pac_t *pac, ehooks_t *ehooks,
- /* The result of splitting, in case of success. */
- edata_t **edata, edata_t **lead, edata_t **trail,
- /* The mess to clean up, in case of error. */
- edata_t **to_leak, edata_t **to_salvage,
- edata_t *expand_edata, size_t size, size_t alignment) {
- size_t leadsize = ALIGNMENT_CEILING((uintptr_t)edata_base_get(*edata),
- PAGE_CEILING(alignment)) - (uintptr_t)edata_base_get(*edata);
- assert(expand_edata == NULL || leadsize == 0);
- if (edata_size_get(*edata) < leadsize + size) {
- return extent_split_interior_cant_alloc;
- }
- size_t trailsize = edata_size_get(*edata) - leadsize - size;
-
- *lead = NULL;
- *trail = NULL;
- *to_leak = NULL;
- *to_salvage = NULL;
-
- /* Split the lead. */
- if (leadsize != 0) {
- assert(!edata_guarded_get(*edata));
- *lead = *edata;
- *edata = extent_split_impl(tsdn, pac, ehooks, *lead, leadsize,
- size + trailsize, /* holding_core_locks*/ true);
- if (*edata == NULL) {
- *to_leak = *lead;
- *lead = NULL;
- return extent_split_interior_error;
- }
- }
-
- /* Split the trail. */
- if (trailsize != 0) {
- assert(!edata_guarded_get(*edata));
- *trail = extent_split_impl(tsdn, pac, ehooks, *edata, size,
- trailsize, /* holding_core_locks */ true);
- if (*trail == NULL) {
- *to_leak = *edata;
- *to_salvage = *lead;
- *lead = NULL;
- *edata = NULL;
- return extent_split_interior_error;
- }
- }
-
- return extent_split_interior_ok;
-}
-
-/*
- * This fulfills the indicated allocation request out of the given extent (which
- * the caller should have ensured was big enough). If there's any unused space
- * before or after the resulting allocation, that space is given its own extent
- * and put back into ecache.
- */
-static edata_t *
-extent_recycle_split(tsdn_t *tsdn, pac_t *pac, ehooks_t *ehooks,
- ecache_t *ecache, edata_t *expand_edata, size_t size, size_t alignment,
- edata_t *edata, bool growing_retained) {
- assert(!edata_guarded_get(edata) || size == edata_size_get(edata));
- malloc_mutex_assert_owner(tsdn, &ecache->mtx);
-
- edata_t *lead;
- edata_t *trail;
- edata_t *to_leak JEMALLOC_CC_SILENCE_INIT(NULL);
- edata_t *to_salvage JEMALLOC_CC_SILENCE_INIT(NULL);
-
- extent_split_interior_result_t result = extent_split_interior(
- tsdn, pac, ehooks, &edata, &lead, &trail, &to_leak, &to_salvage,
- expand_edata, size, alignment);
-
- if (!maps_coalesce && result != extent_split_interior_ok
- && !opt_retain) {
- /*
- * Split isn't supported (implies Windows w/o retain). Avoid
- * leaking the extent.
- */
- assert(to_leak != NULL && lead == NULL && trail == NULL);
- extent_deactivate_locked(tsdn, pac, ecache, to_leak);
- return NULL;
- }
-
- if (result == extent_split_interior_ok) {
- if (lead != NULL) {
- extent_deactivate_locked(tsdn, pac, ecache, lead);
- }
- if (trail != NULL) {
- extent_deactivate_locked(tsdn, pac, ecache, trail);
- }
- return edata;
- } else {
- /*
- * We should have picked an extent that was large enough to
- * fulfill our allocation request.
- */
- assert(result == extent_split_interior_error);
- if (to_salvage != NULL) {
- extent_deregister(tsdn, pac, to_salvage);
- }
- if (to_leak != NULL) {
- extent_deregister_no_gdump_sub(tsdn, pac, to_leak);
- /*
- * May go down the purge path (which assume no ecache
- * locks). Only happens with OOM caused split failures.
- */
- malloc_mutex_unlock(tsdn, &ecache->mtx);
- extents_abandon_vm(tsdn, pac, ehooks, ecache, to_leak,
- growing_retained);
- malloc_mutex_lock(tsdn, &ecache->mtx);
- }
- return NULL;
- }
- unreachable();
-}
-
-/*
- * Tries to satisfy the given allocation request by reusing one of the extents
- * in the given ecache_t.
- */
-static edata_t *
-extent_recycle(tsdn_t *tsdn, pac_t *pac, ehooks_t *ehooks, ecache_t *ecache,
- edata_t *expand_edata, size_t size, size_t alignment, bool zero,
- bool *commit, bool growing_retained, bool guarded) {
- witness_assert_depth_to_rank(tsdn_witness_tsdp_get(tsdn),
- WITNESS_RANK_CORE, growing_retained ? 1 : 0);
- assert(!guarded || expand_edata == NULL);
- assert(!guarded || alignment <= PAGE);
-
- malloc_mutex_lock(tsdn, &ecache->mtx);
-
- edata_t *edata = extent_recycle_extract(tsdn, pac, ehooks, ecache,
- expand_edata, size, alignment, guarded);
- if (edata == NULL) {
- malloc_mutex_unlock(tsdn, &ecache->mtx);
- return NULL;
- }
-
- edata = extent_recycle_split(tsdn, pac, ehooks, ecache, expand_edata,
- size, alignment, edata, growing_retained);
- malloc_mutex_unlock(tsdn, &ecache->mtx);
- if (edata == NULL) {
- return NULL;
- }
-
- assert(edata_state_get(edata) == extent_state_active);
- if (extent_commit_zero(tsdn, ehooks, edata, *commit, zero,
- growing_retained)) {
- extent_record(tsdn, pac, ehooks, ecache, edata);
- return NULL;
- }
- if (edata_committed_get(edata)) {
- /*
- * This reverses the purpose of this variable - previously it
- * was treated as an input parameter, now it turns into an
- * output parameter, reporting if the edata has actually been
- * committed.
- */
- *commit = true;
- }
- return edata;
-}
-
-/*
- * If virtual memory is retained, create increasingly larger extents from which
- * to split requested extents in order to limit the total number of disjoint
- * virtual memory ranges retained by each shard.
- */
-static edata_t *
-extent_grow_retained(tsdn_t *tsdn, pac_t *pac, ehooks_t *ehooks,
- size_t size, size_t alignment, bool zero, bool *commit) {
- malloc_mutex_assert_owner(tsdn, &pac->grow_mtx);
-
- size_t alloc_size_min = size + PAGE_CEILING(alignment) - PAGE;
- /* Beware size_t wrap-around. */
- if (alloc_size_min < size) {
- goto label_err;
- }
- /*
- * Find the next extent size in the series that would be large enough to
- * satisfy this request.
- */
- size_t alloc_size;
- pszind_t exp_grow_skip;
- bool err = exp_grow_size_prepare(&pac->exp_grow, alloc_size_min,
- &alloc_size, &exp_grow_skip);
- if (err) {
- goto label_err;
- }
-
- edata_t *edata = edata_cache_get(tsdn, pac->edata_cache);
- if (edata == NULL) {
- goto label_err;
- }
- bool zeroed = false;
- bool committed = false;
-
- void *ptr = ehooks_alloc(tsdn, ehooks, NULL, alloc_size, PAGE, &zeroed,
- &committed);
-
- if (ptr == NULL) {
- edata_cache_put(tsdn, pac->edata_cache, edata);
- goto label_err;
- }
-
- edata_init(edata, ecache_ind_get(&pac->ecache_retained), ptr,
- alloc_size, false, SC_NSIZES, extent_sn_next(pac),
- extent_state_active, zeroed, committed, EXTENT_PAI_PAC,
- EXTENT_IS_HEAD);
-
- if (extent_register_no_gdump_add(tsdn, pac, edata)) {
- edata_cache_put(tsdn, pac->edata_cache, edata);
- goto label_err;
- }
-
- if (edata_committed_get(edata)) {
- *commit = true;
- }
-
- edata_t *lead;
- edata_t *trail;
- edata_t *to_leak JEMALLOC_CC_SILENCE_INIT(NULL);
- edata_t *to_salvage JEMALLOC_CC_SILENCE_INIT(NULL);
-
- extent_split_interior_result_t result = extent_split_interior(tsdn,
- pac, ehooks, &edata, &lead, &trail, &to_leak, &to_salvage, NULL,
- size, alignment);
-
- if (result == extent_split_interior_ok) {
- if (lead != NULL) {
- extent_record(tsdn, pac, ehooks, &pac->ecache_retained,
- lead);
- }
- if (trail != NULL) {
- extent_record(tsdn, pac, ehooks, &pac->ecache_retained,
- trail);
- }
- } else {
- /*
- * We should have allocated a sufficiently large extent; the
- * cant_alloc case should not occur.
- */
- assert(result == extent_split_interior_error);
- if (to_salvage != NULL) {
- if (config_prof) {
- extent_gdump_add(tsdn, to_salvage);
- }
- extent_record(tsdn, pac, ehooks, &pac->ecache_retained,
- to_salvage);
- }
- if (to_leak != NULL) {
- extent_deregister_no_gdump_sub(tsdn, pac, to_leak);
- extents_abandon_vm(tsdn, pac, ehooks,
- &pac->ecache_retained, to_leak, true);
- }
- goto label_err;
- }
-
- if (*commit && !edata_committed_get(edata)) {
- if (extent_commit_impl(tsdn, ehooks, edata, 0,
- edata_size_get(edata), true)) {
- extent_record(tsdn, pac, ehooks,
- &pac->ecache_retained, edata);
- goto label_err;
- }
- /* A successful commit should return zeroed memory. */
- if (config_debug) {
- void *addr = edata_addr_get(edata);
- size_t *p = (size_t *)(uintptr_t)addr;
- /* Check the first page only. */
- for (size_t i = 0; i < PAGE / sizeof(size_t); i++) {
- assert(p[i] == 0);
- }
- }
- }
-
- /*
- * Increment extent_grow_next if doing so wouldn't exceed the allowed
- * range.
- */
- /* All opportunities for failure are past. */
- exp_grow_size_commit(&pac->exp_grow, exp_grow_skip);
- malloc_mutex_unlock(tsdn, &pac->grow_mtx);
-
- if (config_prof) {
- /* Adjust gdump stats now that extent is final size. */
- extent_gdump_add(tsdn, edata);
- }
- if (zero && !edata_zeroed_get(edata)) {
- ehooks_zero(tsdn, ehooks, edata_base_get(edata),
- edata_size_get(edata));
- }
- return edata;
-label_err:
- malloc_mutex_unlock(tsdn, &pac->grow_mtx);
- return NULL;
-}
-
-static edata_t *
-extent_alloc_retained(tsdn_t *tsdn, pac_t *pac, ehooks_t *ehooks,
- edata_t *expand_edata, size_t size, size_t alignment, bool zero,
- bool *commit, bool guarded) {
- assert(size != 0);
- assert(alignment != 0);
-
- malloc_mutex_lock(tsdn, &pac->grow_mtx);
-
- edata_t *edata = extent_recycle(tsdn, pac, ehooks,
- &pac->ecache_retained, expand_edata, size, alignment, zero, commit,
- /* growing_retained */ true, guarded);
- if (edata != NULL) {
- malloc_mutex_unlock(tsdn, &pac->grow_mtx);
- if (config_prof) {
- extent_gdump_add(tsdn, edata);
- }
- } else if (opt_retain && expand_edata == NULL && !guarded) {
- edata = extent_grow_retained(tsdn, pac, ehooks, size,
- alignment, zero, commit);
- /* extent_grow_retained() always releases pac->grow_mtx. */
- } else {
- malloc_mutex_unlock(tsdn, &pac->grow_mtx);
- }
- malloc_mutex_assert_not_owner(tsdn, &pac->grow_mtx);
-
- return edata;
-}
-
-static bool
-extent_coalesce(tsdn_t *tsdn, pac_t *pac, ehooks_t *ehooks, ecache_t *ecache,
- edata_t *inner, edata_t *outer, bool forward) {
- extent_assert_can_coalesce(inner, outer);
- eset_remove(&ecache->eset, outer);
-
- bool err = extent_merge_impl(tsdn, pac, ehooks,
- forward ? inner : outer, forward ? outer : inner,
- /* holding_core_locks */ true);
- if (err) {
- extent_deactivate_check_state_locked(tsdn, pac, ecache, outer,
- extent_state_merging);
- }
-
- return err;
-}
-
-static edata_t *
-extent_try_coalesce_impl(tsdn_t *tsdn, pac_t *pac, ehooks_t *ehooks,
- ecache_t *ecache, edata_t *edata, bool *coalesced) {
- assert(!edata_guarded_get(edata));
- /*
- * We avoid checking / locking inactive neighbors for large size
- * classes, since they are eagerly coalesced on deallocation which can
- * cause lock contention.
- */
- /*
- * Continue attempting to coalesce until failure, to protect against
- * races with other threads that are thwarted by this one.
- */
- bool again;
- do {
- again = false;
-
- /* Try to coalesce forward. */
- edata_t *next = emap_try_acquire_edata_neighbor(tsdn, pac->emap,
- edata, EXTENT_PAI_PAC, ecache->state, /* forward */ true);
- if (next != NULL) {
- if (!extent_coalesce(tsdn, pac, ehooks, ecache, edata,
- next, true)) {
- if (ecache->delay_coalesce) {
- /* Do minimal coalescing. */
- *coalesced = true;
- return edata;
- }
- again = true;
- }
- }
-
- /* Try to coalesce backward. */
- edata_t *prev = emap_try_acquire_edata_neighbor(tsdn, pac->emap,
- edata, EXTENT_PAI_PAC, ecache->state, /* forward */ false);
- if (prev != NULL) {
- if (!extent_coalesce(tsdn, pac, ehooks, ecache, edata,
- prev, false)) {
- edata = prev;
- if (ecache->delay_coalesce) {
- /* Do minimal coalescing. */
- *coalesced = true;
- return edata;
- }
- again = true;
- }
- }
- } while (again);
-
- if (ecache->delay_coalesce) {
- *coalesced = false;
- }
- return edata;
-}
-
-static edata_t *
-extent_try_coalesce(tsdn_t *tsdn, pac_t *pac, ehooks_t *ehooks,
- ecache_t *ecache, edata_t *edata, bool *coalesced) {
- return extent_try_coalesce_impl(tsdn, pac, ehooks, ecache, edata,
- coalesced);
-}
-
-static edata_t *
-extent_try_coalesce_large(tsdn_t *tsdn, pac_t *pac, ehooks_t *ehooks,
- ecache_t *ecache, edata_t *edata, bool *coalesced) {
- return extent_try_coalesce_impl(tsdn, pac, ehooks, ecache, edata,
- coalesced);
-}
-
-/* Purge a single extent to retained / unmapped directly. */
-static void
-extent_maximally_purge(tsdn_t *tsdn, pac_t *pac, ehooks_t *ehooks,
- edata_t *edata) {
- size_t extent_size = edata_size_get(edata);
- extent_dalloc_wrapper(tsdn, pac, ehooks, edata);
- if (config_stats) {
- /* Update stats accordingly. */
- LOCKEDINT_MTX_LOCK(tsdn, *pac->stats_mtx);
- locked_inc_u64(tsdn,
- LOCKEDINT_MTX(*pac->stats_mtx),
- &pac->stats->decay_dirty.nmadvise, 1);
- locked_inc_u64(tsdn,
- LOCKEDINT_MTX(*pac->stats_mtx),
- &pac->stats->decay_dirty.purged,
- extent_size >> LG_PAGE);
- LOCKEDINT_MTX_UNLOCK(tsdn, *pac->stats_mtx);
- atomic_fetch_sub_zu(&pac->stats->pac_mapped, extent_size,
- ATOMIC_RELAXED);
- }
-}
-
-/*
- * Does the metadata management portions of putting an unused extent into the
- * given ecache_t (coalesces and inserts into the eset).
- */
-void
-extent_record(tsdn_t *tsdn, pac_t *pac, ehooks_t *ehooks, ecache_t *ecache,
- edata_t *edata) {
- assert((ecache->state != extent_state_dirty &&
- ecache->state != extent_state_muzzy) ||
- !edata_zeroed_get(edata));
-
- malloc_mutex_lock(tsdn, &ecache->mtx);
-
- emap_assert_mapped(tsdn, pac->emap, edata);
-
- if (edata_guarded_get(edata)) {
- goto label_skip_coalesce;
- }
- if (!ecache->delay_coalesce) {
- edata = extent_try_coalesce(tsdn, pac, ehooks, ecache, edata,
- NULL);
- } else if (edata_size_get(edata) >= SC_LARGE_MINCLASS) {
- assert(ecache == &pac->ecache_dirty);
- /* Always coalesce large extents eagerly. */
- bool coalesced;
- do {
- assert(edata_state_get(edata) == extent_state_active);
- edata = extent_try_coalesce_large(tsdn, pac, ehooks,
- ecache, edata, &coalesced);
- } while (coalesced);
- if (edata_size_get(edata) >=
- atomic_load_zu(&pac->oversize_threshold, ATOMIC_RELAXED)
- && extent_may_force_decay(pac)) {
- /* Shortcut to purge the oversize extent eagerly. */
- malloc_mutex_unlock(tsdn, &ecache->mtx);
- extent_maximally_purge(tsdn, pac, ehooks, edata);
- return;
- }
- }
-label_skip_coalesce:
- extent_deactivate_locked(tsdn, pac, ecache, edata);
-
- malloc_mutex_unlock(tsdn, &ecache->mtx);
-}
-
-void
-extent_dalloc_gap(tsdn_t *tsdn, pac_t *pac, ehooks_t *ehooks,
- edata_t *edata) {
- witness_assert_depth_to_rank(tsdn_witness_tsdp_get(tsdn),
- WITNESS_RANK_CORE, 0);
-
- if (extent_register(tsdn, pac, edata)) {
- edata_cache_put(tsdn, pac->edata_cache, edata);
- return;
- }
- extent_dalloc_wrapper(tsdn, pac, ehooks, edata);
-}
-
-static bool
-extent_dalloc_wrapper_try(tsdn_t *tsdn, pac_t *pac, ehooks_t *ehooks,
- edata_t *edata) {
- bool err;
-
- assert(edata_base_get(edata) != NULL);
- assert(edata_size_get(edata) != 0);
- witness_assert_depth_to_rank(tsdn_witness_tsdp_get(tsdn),
- WITNESS_RANK_CORE, 0);
-
- edata_addr_set(edata, edata_base_get(edata));
-
- /* Try to deallocate. */
- err = ehooks_dalloc(tsdn, ehooks, edata_base_get(edata),
- edata_size_get(edata), edata_committed_get(edata));
-
- if (!err) {
- edata_cache_put(tsdn, pac->edata_cache, edata);
- }
-
- return err;
-}
-
-edata_t *
-extent_alloc_wrapper(tsdn_t *tsdn, pac_t *pac, ehooks_t *ehooks,
- void *new_addr, size_t size, size_t alignment, bool zero, bool *commit,
- bool growing_retained) {
- witness_assert_depth_to_rank(tsdn_witness_tsdp_get(tsdn),
- WITNESS_RANK_CORE, growing_retained ? 1 : 0);
-
- edata_t *edata = edata_cache_get(tsdn, pac->edata_cache);
- if (edata == NULL) {
- return NULL;
- }
- size_t palignment = ALIGNMENT_CEILING(alignment, PAGE);
- void *addr = ehooks_alloc(tsdn, ehooks, new_addr, size, palignment,
- &zero, commit);
- if (addr == NULL) {
- edata_cache_put(tsdn, pac->edata_cache, edata);
- return NULL;
- }
- edata_init(edata, ecache_ind_get(&pac->ecache_dirty), addr,
- size, /* slab */ false, SC_NSIZES, extent_sn_next(pac),
- extent_state_active, zero, *commit, EXTENT_PAI_PAC,
- opt_retain ? EXTENT_IS_HEAD : EXTENT_NOT_HEAD);
- /*
- * Retained memory is not counted towards gdump. Only if an extent is
- * allocated as a separate mapping, i.e. growing_retained is false, then
- * gdump should be updated.
- */
- bool gdump_add = !growing_retained;
- if (extent_register_impl(tsdn, pac, edata, gdump_add)) {
- edata_cache_put(tsdn, pac->edata_cache, edata);
- return NULL;
- }
-
- return edata;
-}
-
-void
-extent_dalloc_wrapper(tsdn_t *tsdn, pac_t *pac, ehooks_t *ehooks,
- edata_t *edata) {
- assert(edata_pai_get(edata) == EXTENT_PAI_PAC);
- witness_assert_depth_to_rank(tsdn_witness_tsdp_get(tsdn),
- WITNESS_RANK_CORE, 0);
-
- /* Avoid calling the default extent_dalloc unless have to. */
- if (!ehooks_dalloc_will_fail(ehooks)) {
- /* Remove guard pages for dalloc / unmap. */
- if (edata_guarded_get(edata)) {
- assert(ehooks_are_default(ehooks));
- san_unguard_pages_two_sided(tsdn, ehooks, edata,
- pac->emap);
- }
- /*
- * Deregister first to avoid a race with other allocating
- * threads, and reregister if deallocation fails.
- */
- extent_deregister(tsdn, pac, edata);
- if (!extent_dalloc_wrapper_try(tsdn, pac, ehooks, edata)) {
- return;
- }
- extent_reregister(tsdn, pac, edata);
- }
-
- /* Try to decommit; purge if that fails. */
- bool zeroed;
- if (!edata_committed_get(edata)) {
- zeroed = true;
- } else if (!extent_decommit_wrapper(tsdn, ehooks, edata, 0,
- edata_size_get(edata))) {
- zeroed = true;
- } else if (!ehooks_purge_forced(tsdn, ehooks, edata_base_get(edata),
- edata_size_get(edata), 0, edata_size_get(edata))) {
- zeroed = true;
- } else if (edata_state_get(edata) == extent_state_muzzy ||
- !ehooks_purge_lazy(tsdn, ehooks, edata_base_get(edata),
- edata_size_get(edata), 0, edata_size_get(edata))) {
- zeroed = false;
- } else {
- zeroed = false;
- }
- edata_zeroed_set(edata, zeroed);
-
- if (config_prof) {
- extent_gdump_sub(tsdn, edata);
- }
-
- extent_record(tsdn, pac, ehooks, &pac->ecache_retained, edata);
-}
-
-void
-extent_destroy_wrapper(tsdn_t *tsdn, pac_t *pac, ehooks_t *ehooks,
- edata_t *edata) {
- assert(edata_base_get(edata) != NULL);
- assert(edata_size_get(edata) != 0);
- extent_state_t state = edata_state_get(edata);
- assert(state == extent_state_retained || state == extent_state_active);
- assert(emap_edata_is_acquired(tsdn, pac->emap, edata));
- witness_assert_depth_to_rank(tsdn_witness_tsdp_get(tsdn),
- WITNESS_RANK_CORE, 0);
-
- if (edata_guarded_get(edata)) {
- assert(opt_retain);
- san_unguard_pages_pre_destroy(tsdn, ehooks, edata, pac->emap);
- }
- edata_addr_set(edata, edata_base_get(edata));
-
- /* Try to destroy; silently fail otherwise. */
- ehooks_destroy(tsdn, ehooks, edata_base_get(edata),
- edata_size_get(edata), edata_committed_get(edata));
-
- edata_cache_put(tsdn, pac->edata_cache, edata);
-}
-
-static bool
-extent_commit_impl(tsdn_t *tsdn, ehooks_t *ehooks, edata_t *edata,
- size_t offset, size_t length, bool growing_retained) {
- witness_assert_depth_to_rank(tsdn_witness_tsdp_get(tsdn),
- WITNESS_RANK_CORE, growing_retained ? 1 : 0);
- bool err = ehooks_commit(tsdn, ehooks, edata_base_get(edata),
- edata_size_get(edata), offset, length);
- edata_committed_set(edata, edata_committed_get(edata) || !err);
- return err;
-}
-
-bool
-extent_commit_wrapper(tsdn_t *tsdn, ehooks_t *ehooks, edata_t *edata,
- size_t offset, size_t length) {
- return extent_commit_impl(tsdn, ehooks, edata, offset, length,
- /* growing_retained */ false);
-}
-
-bool
-extent_decommit_wrapper(tsdn_t *tsdn, ehooks_t *ehooks, edata_t *edata,
- size_t offset, size_t length) {
- witness_assert_depth_to_rank(tsdn_witness_tsdp_get(tsdn),
- WITNESS_RANK_CORE, 0);
- bool err = ehooks_decommit(tsdn, ehooks, edata_base_get(edata),
- edata_size_get(edata), offset, length);
- edata_committed_set(edata, edata_committed_get(edata) && err);
- return err;
-}
-
-static bool
-extent_purge_lazy_impl(tsdn_t *tsdn, ehooks_t *ehooks, edata_t *edata,
- size_t offset, size_t length, bool growing_retained) {
- witness_assert_depth_to_rank(tsdn_witness_tsdp_get(tsdn),
- WITNESS_RANK_CORE, growing_retained ? 1 : 0);
- bool err = ehooks_purge_lazy(tsdn, ehooks, edata_base_get(edata),
- edata_size_get(edata), offset, length);
- return err;
-}
-
-bool
-extent_purge_lazy_wrapper(tsdn_t *tsdn, ehooks_t *ehooks, edata_t *edata,
- size_t offset, size_t length) {
- return extent_purge_lazy_impl(tsdn, ehooks, edata, offset,
- length, false);
-}
-
-static bool
-extent_purge_forced_impl(tsdn_t *tsdn, ehooks_t *ehooks, edata_t *edata,
- size_t offset, size_t length, bool growing_retained) {
- witness_assert_depth_to_rank(tsdn_witness_tsdp_get(tsdn),
- WITNESS_RANK_CORE, growing_retained ? 1 : 0);
- bool err = ehooks_purge_forced(tsdn, ehooks, edata_base_get(edata),
- edata_size_get(edata), offset, length);
- return err;
-}
-
-bool
-extent_purge_forced_wrapper(tsdn_t *tsdn, ehooks_t *ehooks, edata_t *edata,
- size_t offset, size_t length) {
- return extent_purge_forced_impl(tsdn, ehooks, edata, offset, length,
- false);
-}
-
-/*
- * Accepts the extent to split, and the characteristics of each side of the
- * split. The 'a' parameters go with the 'lead' of the resulting pair of
- * extents (the lower addressed portion of the split), and the 'b' parameters go
- * with the trail (the higher addressed portion). This makes 'extent' the lead,
- * and returns the trail (except in case of error).
- */
-static edata_t *
-extent_split_impl(tsdn_t *tsdn, pac_t *pac, ehooks_t *ehooks,
- edata_t *edata, size_t size_a, size_t size_b, bool holding_core_locks) {
- assert(edata_size_get(edata) == size_a + size_b);
- /* Only the shrink path may split w/o holding core locks. */
- if (holding_core_locks) {
- witness_assert_positive_depth_to_rank(
- tsdn_witness_tsdp_get(tsdn), WITNESS_RANK_CORE);
- } else {
- witness_assert_depth_to_rank(tsdn_witness_tsdp_get(tsdn),
- WITNESS_RANK_CORE, 0);
- }
-
- if (ehooks_split_will_fail(ehooks)) {
- return NULL;
- }
-
- edata_t *trail = edata_cache_get(tsdn, pac->edata_cache);
- if (trail == NULL) {
- goto label_error_a;
- }
-
- edata_init(trail, edata_arena_ind_get(edata),
- (void *)((uintptr_t)edata_base_get(edata) + size_a), size_b,
- /* slab */ false, SC_NSIZES, edata_sn_get(edata),
- edata_state_get(edata), edata_zeroed_get(edata),
- edata_committed_get(edata), EXTENT_PAI_PAC, EXTENT_NOT_HEAD);
- emap_prepare_t prepare;
- bool err = emap_split_prepare(tsdn, pac->emap, &prepare, edata,
- size_a, trail, size_b);
- if (err) {
- goto label_error_b;
- }
-
- /*
- * No need to acquire trail or edata, because: 1) trail was new (just
- * allocated); and 2) edata is either an active allocation (the shrink
- * path), or in an acquired state (extracted from the ecache on the
- * extent_recycle_split path).
- */
- assert(emap_edata_is_acquired(tsdn, pac->emap, edata));
- assert(emap_edata_is_acquired(tsdn, pac->emap, trail));
-
- err = ehooks_split(tsdn, ehooks, edata_base_get(edata), size_a + size_b,
- size_a, size_b, edata_committed_get(edata));
-
- if (err) {
- goto label_error_b;
- }
-
- edata_size_set(edata, size_a);
- emap_split_commit(tsdn, pac->emap, &prepare, edata, size_a, trail,
- size_b);
-
- return trail;
-label_error_b:
- edata_cache_put(tsdn, pac->edata_cache, trail);
-label_error_a:
- return NULL;
-}
-
-edata_t *
-extent_split_wrapper(tsdn_t *tsdn, pac_t *pac, ehooks_t *ehooks, edata_t *edata,
- size_t size_a, size_t size_b, bool holding_core_locks) {
- return extent_split_impl(tsdn, pac, ehooks, edata, size_a, size_b,
- holding_core_locks);
-}
-
-static bool
-extent_merge_impl(tsdn_t *tsdn, pac_t *pac, ehooks_t *ehooks, edata_t *a,
- edata_t *b, bool holding_core_locks) {
- /* Only the expanding path may merge w/o holding ecache locks. */
- if (holding_core_locks) {
- witness_assert_positive_depth_to_rank(
- tsdn_witness_tsdp_get(tsdn), WITNESS_RANK_CORE);
- } else {
- witness_assert_depth_to_rank(tsdn_witness_tsdp_get(tsdn),
- WITNESS_RANK_CORE, 0);
- }
-
- assert(edata_base_get(a) < edata_base_get(b));
- assert(edata_arena_ind_get(a) == edata_arena_ind_get(b));
- assert(edata_arena_ind_get(a) == ehooks_ind_get(ehooks));
- emap_assert_mapped(tsdn, pac->emap, a);
- emap_assert_mapped(tsdn, pac->emap, b);
-
- bool err = ehooks_merge(tsdn, ehooks, edata_base_get(a),
- edata_size_get(a), edata_base_get(b), edata_size_get(b),
- edata_committed_get(a));
-
- if (err) {
- return true;
- }
-
- /*
- * The rtree writes must happen while all the relevant elements are
- * owned, so the following code uses decomposed helper functions rather
- * than extent_{,de}register() to do things in the right order.
- */
- emap_prepare_t prepare;
- emap_merge_prepare(tsdn, pac->emap, &prepare, a, b);
-
- assert(edata_state_get(a) == extent_state_active ||
- edata_state_get(a) == extent_state_merging);
- edata_state_set(a, extent_state_active);
- edata_size_set(a, edata_size_get(a) + edata_size_get(b));
- edata_sn_set(a, (edata_sn_get(a) < edata_sn_get(b)) ?
- edata_sn_get(a) : edata_sn_get(b));
- edata_zeroed_set(a, edata_zeroed_get(a) && edata_zeroed_get(b));
-
- emap_merge_commit(tsdn, pac->emap, &prepare, a, b);
-
- edata_cache_put(tsdn, pac->edata_cache, b);
-
- return false;
-}
-
-bool
-extent_merge_wrapper(tsdn_t *tsdn, pac_t *pac, ehooks_t *ehooks,
- edata_t *a, edata_t *b) {
- return extent_merge_impl(tsdn, pac, ehooks, a, b,
- /* holding_core_locks */ false);
-}
-
-bool
-extent_commit_zero(tsdn_t *tsdn, ehooks_t *ehooks, edata_t *edata,
- bool commit, bool zero, bool growing_retained) {
- witness_assert_depth_to_rank(tsdn_witness_tsdp_get(tsdn),
- WITNESS_RANK_CORE, growing_retained ? 1 : 0);
-
- if (commit && !edata_committed_get(edata)) {
- if (extent_commit_impl(tsdn, ehooks, edata, 0,
- edata_size_get(edata), growing_retained)) {
- return true;
- }
- }
- if (zero && !edata_zeroed_get(edata)) {
- void *addr = edata_base_get(edata);
- size_t size = edata_size_get(edata);
- ehooks_zero(tsdn, ehooks, addr, size);
- }
- return false;
-}
-
-bool
-extent_boot(void) {
- assert(sizeof(slab_data_t) >= sizeof(e_prof_info_t));
-
- if (have_dss) {
- extent_dss_boot();
- }
-
- return false;
-}
diff --git a/fluent-bit/lib/jemalloc-5.3.0/src/extent_dss.c b/fluent-bit/lib/jemalloc-5.3.0/src/extent_dss.c
deleted file mode 100644
index 9a35bacf..00000000
--- a/fluent-bit/lib/jemalloc-5.3.0/src/extent_dss.c
+++ /dev/null
@@ -1,277 +0,0 @@
-#include "jemalloc/internal/jemalloc_preamble.h"
-#include "jemalloc/internal/jemalloc_internal_includes.h"
-
-#include "jemalloc/internal/assert.h"
-#include "jemalloc/internal/extent_dss.h"
-#include "jemalloc/internal/spin.h"
-
-/******************************************************************************/
-/* Data. */
-
-const char *opt_dss = DSS_DEFAULT;
-
-const char *dss_prec_names[] = {
- "disabled",
- "primary",
- "secondary",
- "N/A"
-};
-
-/*
- * Current dss precedence default, used when creating new arenas. NB: This is
- * stored as unsigned rather than dss_prec_t because in principle there's no
- * guarantee that sizeof(dss_prec_t) is the same as sizeof(unsigned), and we use
- * atomic operations to synchronize the setting.
- */
-static atomic_u_t dss_prec_default = ATOMIC_INIT(
- (unsigned)DSS_PREC_DEFAULT);
-
-/* Base address of the DSS. */
-static void *dss_base;
-/* Atomic boolean indicating whether a thread is currently extending DSS. */
-static atomic_b_t dss_extending;
-/* Atomic boolean indicating whether the DSS is exhausted. */
-static atomic_b_t dss_exhausted;
-/* Atomic current upper limit on DSS addresses. */
-static atomic_p_t dss_max;
-
-/******************************************************************************/
-
-static void *
-extent_dss_sbrk(intptr_t increment) {
-#ifdef JEMALLOC_DSS
- return sbrk(increment);
-#else
- not_implemented();
- return NULL;
-#endif
-}
-
-dss_prec_t
-extent_dss_prec_get(void) {
- dss_prec_t ret;
-
- if (!have_dss) {
- return dss_prec_disabled;
- }
- ret = (dss_prec_t)atomic_load_u(&dss_prec_default, ATOMIC_ACQUIRE);
- return ret;
-}
-
-bool
-extent_dss_prec_set(dss_prec_t dss_prec) {
- if (!have_dss) {
- return (dss_prec != dss_prec_disabled);
- }
- atomic_store_u(&dss_prec_default, (unsigned)dss_prec, ATOMIC_RELEASE);
- return false;
-}
-
-static void
-extent_dss_extending_start(void) {
- spin_t spinner = SPIN_INITIALIZER;
- while (true) {
- bool expected = false;
- if (atomic_compare_exchange_weak_b(&dss_extending, &expected,
- true, ATOMIC_ACQ_REL, ATOMIC_RELAXED)) {
- break;
- }
- spin_adaptive(&spinner);
- }
-}
-
-static void
-extent_dss_extending_finish(void) {
- assert(atomic_load_b(&dss_extending, ATOMIC_RELAXED));
-
- atomic_store_b(&dss_extending, false, ATOMIC_RELEASE);
-}
-
-static void *
-extent_dss_max_update(void *new_addr) {
- /*
- * Get the current end of the DSS as max_cur and assure that dss_max is
- * up to date.
- */
- void *max_cur = extent_dss_sbrk(0);
- if (max_cur == (void *)-1) {
- return NULL;
- }
- atomic_store_p(&dss_max, max_cur, ATOMIC_RELEASE);
- /* Fixed new_addr can only be supported if it is at the edge of DSS. */
- if (new_addr != NULL && max_cur != new_addr) {
- return NULL;
- }
- return max_cur;
-}
-
-void *
-extent_alloc_dss(tsdn_t *tsdn, arena_t *arena, void *new_addr, size_t size,
- size_t alignment, bool *zero, bool *commit) {
- edata_t *gap;
-
- cassert(have_dss);
- assert(size > 0);
- assert(alignment == ALIGNMENT_CEILING(alignment, PAGE));
-
- /*
- * sbrk() uses a signed increment argument, so take care not to
- * interpret a large allocation request as a negative increment.
- */
- if ((intptr_t)size < 0) {
- return NULL;
- }
-
- gap = edata_cache_get(tsdn, &arena->pa_shard.edata_cache);
- if (gap == NULL) {
- return NULL;
- }
-
- extent_dss_extending_start();
- if (!atomic_load_b(&dss_exhausted, ATOMIC_ACQUIRE)) {
- /*
- * The loop is necessary to recover from races with other
- * threads that are using the DSS for something other than
- * malloc.
- */
- while (true) {
- void *max_cur = extent_dss_max_update(new_addr);
- if (max_cur == NULL) {
- goto label_oom;
- }
-
- bool head_state = opt_retain ? EXTENT_IS_HEAD :
- EXTENT_NOT_HEAD;
- /*
- * Compute how much page-aligned gap space (if any) is
- * necessary to satisfy alignment. This space can be
- * recycled for later use.
- */
- void *gap_addr_page = (void *)(PAGE_CEILING(
- (uintptr_t)max_cur));
- void *ret = (void *)ALIGNMENT_CEILING(
- (uintptr_t)gap_addr_page, alignment);
- size_t gap_size_page = (uintptr_t)ret -
- (uintptr_t)gap_addr_page;
- if (gap_size_page != 0) {
- edata_init(gap, arena_ind_get(arena),
- gap_addr_page, gap_size_page, false,
- SC_NSIZES, extent_sn_next(
- &arena->pa_shard.pac),
- extent_state_active, false, true,
- EXTENT_PAI_PAC, head_state);
- }
- /*
- * Compute the address just past the end of the desired
- * allocation space.
- */
- void *dss_next = (void *)((uintptr_t)ret + size);
- if ((uintptr_t)ret < (uintptr_t)max_cur ||
- (uintptr_t)dss_next < (uintptr_t)max_cur) {
- goto label_oom; /* Wrap-around. */
- }
- /* Compute the increment, including subpage bytes. */
- void *gap_addr_subpage = max_cur;
- size_t gap_size_subpage = (uintptr_t)ret -
- (uintptr_t)gap_addr_subpage;
- intptr_t incr = gap_size_subpage + size;
-
- assert((uintptr_t)max_cur + incr == (uintptr_t)ret +
- size);
-
- /* Try to allocate. */
- void *dss_prev = extent_dss_sbrk(incr);
- if (dss_prev == max_cur) {
- /* Success. */
- atomic_store_p(&dss_max, dss_next,
- ATOMIC_RELEASE);
- extent_dss_extending_finish();
-
- if (gap_size_page != 0) {
- ehooks_t *ehooks = arena_get_ehooks(
- arena);
- extent_dalloc_gap(tsdn,
- &arena->pa_shard.pac, ehooks, gap);
- } else {
- edata_cache_put(tsdn,
- &arena->pa_shard.edata_cache, gap);
- }
- if (!*commit) {
- *commit = pages_decommit(ret, size);
- }
- if (*zero && *commit) {
- edata_t edata = {0};
- ehooks_t *ehooks = arena_get_ehooks(
- arena);
-
- edata_init(&edata,
- arena_ind_get(arena), ret, size,
- size, false, SC_NSIZES,
- extent_state_active, false, true,
- EXTENT_PAI_PAC, head_state);
- if (extent_purge_forced_wrapper(tsdn,
- ehooks, &edata, 0, size)) {
- memset(ret, 0, size);
- }
- }
- return ret;
- }
- /*
- * Failure, whether due to OOM or a race with a raw
- * sbrk() call from outside the allocator.
- */
- if (dss_prev == (void *)-1) {
- /* OOM. */
- atomic_store_b(&dss_exhausted, true,
- ATOMIC_RELEASE);
- goto label_oom;
- }
- }
- }
-label_oom:
- extent_dss_extending_finish();
- edata_cache_put(tsdn, &arena->pa_shard.edata_cache, gap);
- return NULL;
-}
-
-static bool
-extent_in_dss_helper(void *addr, void *max) {
- return ((uintptr_t)addr >= (uintptr_t)dss_base && (uintptr_t)addr <
- (uintptr_t)max);
-}
-
-bool
-extent_in_dss(void *addr) {
- cassert(have_dss);
-
- return extent_in_dss_helper(addr, atomic_load_p(&dss_max,
- ATOMIC_ACQUIRE));
-}
-
-bool
-extent_dss_mergeable(void *addr_a, void *addr_b) {
- void *max;
-
- cassert(have_dss);
-
- if ((uintptr_t)addr_a < (uintptr_t)dss_base && (uintptr_t)addr_b <
- (uintptr_t)dss_base) {
- return true;
- }
-
- max = atomic_load_p(&dss_max, ATOMIC_ACQUIRE);
- return (extent_in_dss_helper(addr_a, max) ==
- extent_in_dss_helper(addr_b, max));
-}
-
-void
-extent_dss_boot(void) {
- cassert(have_dss);
-
- dss_base = extent_dss_sbrk(0);
- atomic_store_b(&dss_extending, false, ATOMIC_RELAXED);
- atomic_store_b(&dss_exhausted, dss_base == (void *)-1, ATOMIC_RELAXED);
- atomic_store_p(&dss_max, dss_base, ATOMIC_RELAXED);
-}
-
-/******************************************************************************/
diff --git a/fluent-bit/lib/jemalloc-5.3.0/src/extent_mmap.c b/fluent-bit/lib/jemalloc-5.3.0/src/extent_mmap.c
deleted file mode 100644
index 5f0ee2d2..00000000
--- a/fluent-bit/lib/jemalloc-5.3.0/src/extent_mmap.c
+++ /dev/null
@@ -1,41 +0,0 @@
-#include "jemalloc/internal/jemalloc_preamble.h"
-#include "jemalloc/internal/jemalloc_internal_includes.h"
-
-#include "jemalloc/internal/assert.h"
-#include "jemalloc/internal/extent_mmap.h"
-
-/******************************************************************************/
-/* Data. */
-
-bool opt_retain =
-#ifdef JEMALLOC_RETAIN
- true
-#else
- false
-#endif
- ;
-
-/******************************************************************************/
-
-void *
-extent_alloc_mmap(void *new_addr, size_t size, size_t alignment, bool *zero,
- bool *commit) {
- assert(alignment == ALIGNMENT_CEILING(alignment, PAGE));
- void *ret = pages_map(new_addr, size, alignment, commit);
- if (ret == NULL) {
- return NULL;
- }
- assert(ret != NULL);
- if (*commit) {
- *zero = true;
- }
- return ret;
-}
-
-bool
-extent_dalloc_mmap(void *addr, size_t size) {
- if (!opt_retain) {
- pages_unmap(addr, size);
- }
- return opt_retain;
-}
diff --git a/fluent-bit/lib/jemalloc-5.3.0/src/fxp.c b/fluent-bit/lib/jemalloc-5.3.0/src/fxp.c
deleted file mode 100644
index 96585f0a..00000000
--- a/fluent-bit/lib/jemalloc-5.3.0/src/fxp.c
+++ /dev/null
@@ -1,124 +0,0 @@
-#include "jemalloc/internal/jemalloc_preamble.h"
-#include "jemalloc/internal/jemalloc_internal_includes.h"
-
-#include "jemalloc/internal/fxp.h"
-
-static bool
-fxp_isdigit(char c) {
- return '0' <= c && c <= '9';
-}
-
-bool
-fxp_parse(fxp_t *result, const char *str, char **end) {
- /*
- * Using malloc_strtoumax in this method isn't as handy as you might
- * expect (I tried). In the fractional part, significant leading zeros
- * mean that you still need to do your own parsing, now with trickier
- * math. In the integer part, the casting (uintmax_t to uint32_t)
- * forces more reasoning about bounds than just checking for overflow as
- * we parse.
- */
- uint32_t integer_part = 0;
-
- const char *cur = str;
-
- /* The string must start with a digit or a decimal point. */
- if (*cur != '.' && !fxp_isdigit(*cur)) {
- return true;
- }
-
- while ('0' <= *cur && *cur <= '9') {
- integer_part *= 10;
- integer_part += *cur - '0';
- if (integer_part >= (1U << 16)) {
- return true;
- }
- cur++;
- }
-
- /*
- * We've parsed all digits at the beginning of the string, without
- * overflow. Either we're done, or there's a fractional part.
- */
- if (*cur != '.') {
- *result = (integer_part << 16);
- if (end != NULL) {
- *end = (char *)cur;
- }
- return false;
- }
-
- /* There's a fractional part. */
- cur++;
- if (!fxp_isdigit(*cur)) {
- /* Shouldn't end on the decimal point. */
- return true;
- }
-
- /*
- * We use a lot of precision for the fractional part, even though we'll
- * discard most of it; this lets us get exact values for the important
- * special case where the denominator is a small power of 2 (for
- * instance, 1/512 == 0.001953125 is exactly representable even with
- * only 16 bits of fractional precision). We need to left-shift by 16
- * before dividing so we pick the number of digits to be
- * floor(log(2**48)) = 14.
- */
- uint64_t fractional_part = 0;
- uint64_t frac_div = 1;
- for (int i = 0; i < FXP_FRACTIONAL_PART_DIGITS; i++) {
- fractional_part *= 10;
- frac_div *= 10;
- if (fxp_isdigit(*cur)) {
- fractional_part += *cur - '0';
- cur++;
- }
- }
- /*
- * We only parse the first maxdigits characters, but we can still ignore
- * any digits after that.
- */
- while (fxp_isdigit(*cur)) {
- cur++;
- }
-
- assert(fractional_part < frac_div);
- uint32_t fractional_repr = (uint32_t)(
- (fractional_part << 16) / frac_div);
-
- /* Success! */
- *result = (integer_part << 16) + fractional_repr;
- if (end != NULL) {
- *end = (char *)cur;
- }
- return false;
-}
-
-void
-fxp_print(fxp_t a, char buf[FXP_BUF_SIZE]) {
- uint32_t integer_part = fxp_round_down(a);
- uint32_t fractional_part = (a & ((1U << 16) - 1));
-
- int leading_fraction_zeros = 0;
- uint64_t fraction_digits = fractional_part;
- for (int i = 0; i < FXP_FRACTIONAL_PART_DIGITS; i++) {
- if (fraction_digits < (1U << 16)
- && fraction_digits * 10 >= (1U << 16)) {
- leading_fraction_zeros = i;
- }
- fraction_digits *= 10;
- }
- fraction_digits >>= 16;
- while (fraction_digits > 0 && fraction_digits % 10 == 0) {
- fraction_digits /= 10;
- }
-
- size_t printed = malloc_snprintf(buf, FXP_BUF_SIZE, "%"FMTu32".",
- integer_part);
- for (int i = 0; i < leading_fraction_zeros; i++) {
- buf[printed] = '0';
- printed++;
- }
- malloc_snprintf(&buf[printed], FXP_BUF_SIZE - printed, "%"FMTu64,
- fraction_digits);
-}
diff --git a/fluent-bit/lib/jemalloc-5.3.0/src/hook.c b/fluent-bit/lib/jemalloc-5.3.0/src/hook.c
deleted file mode 100644
index 493edbbe..00000000
--- a/fluent-bit/lib/jemalloc-5.3.0/src/hook.c
+++ /dev/null
@@ -1,195 +0,0 @@
-#include "jemalloc/internal/jemalloc_preamble.h"
-
-#include "jemalloc/internal/hook.h"
-
-#include "jemalloc/internal/atomic.h"
-#include "jemalloc/internal/mutex.h"
-#include "jemalloc/internal/seq.h"
-
-typedef struct hooks_internal_s hooks_internal_t;
-struct hooks_internal_s {
- hooks_t hooks;
- bool in_use;
-};
-
-seq_define(hooks_internal_t, hooks)
-
-static atomic_u_t nhooks = ATOMIC_INIT(0);
-static seq_hooks_t hooks[HOOK_MAX];
-static malloc_mutex_t hooks_mu;
-
-bool
-hook_boot() {
- return malloc_mutex_init(&hooks_mu, "hooks", WITNESS_RANK_HOOK,
- malloc_mutex_rank_exclusive);
-}
-
-static void *
-hook_install_locked(hooks_t *to_install) {
- hooks_internal_t hooks_internal;
- for (int i = 0; i < HOOK_MAX; i++) {
- bool success = seq_try_load_hooks(&hooks_internal, &hooks[i]);
- /* We hold mu; no concurrent access. */
- assert(success);
- if (!hooks_internal.in_use) {
- hooks_internal.hooks = *to_install;
- hooks_internal.in_use = true;
- seq_store_hooks(&hooks[i], &hooks_internal);
- atomic_store_u(&nhooks,
- atomic_load_u(&nhooks, ATOMIC_RELAXED) + 1,
- ATOMIC_RELAXED);
- return &hooks[i];
- }
- }
- return NULL;
-}
-
-void *
-hook_install(tsdn_t *tsdn, hooks_t *to_install) {
- malloc_mutex_lock(tsdn, &hooks_mu);
- void *ret = hook_install_locked(to_install);
- if (ret != NULL) {
- tsd_global_slow_inc(tsdn);
- }
- malloc_mutex_unlock(tsdn, &hooks_mu);
- return ret;
-}
-
-static void
-hook_remove_locked(seq_hooks_t *to_remove) {
- hooks_internal_t hooks_internal;
- bool success = seq_try_load_hooks(&hooks_internal, to_remove);
- /* We hold mu; no concurrent access. */
- assert(success);
- /* Should only remove hooks that were added. */
- assert(hooks_internal.in_use);
- hooks_internal.in_use = false;
- seq_store_hooks(to_remove, &hooks_internal);
- atomic_store_u(&nhooks, atomic_load_u(&nhooks, ATOMIC_RELAXED) - 1,
- ATOMIC_RELAXED);
-}
-
-void
-hook_remove(tsdn_t *tsdn, void *opaque) {
- if (config_debug) {
- char *hooks_begin = (char *)&hooks[0];
- char *hooks_end = (char *)&hooks[HOOK_MAX];
- char *hook = (char *)opaque;
- assert(hooks_begin <= hook && hook < hooks_end
- && (hook - hooks_begin) % sizeof(seq_hooks_t) == 0);
- }
- malloc_mutex_lock(tsdn, &hooks_mu);
- hook_remove_locked((seq_hooks_t *)opaque);
- tsd_global_slow_dec(tsdn);
- malloc_mutex_unlock(tsdn, &hooks_mu);
-}
-
-#define FOR_EACH_HOOK_BEGIN(hooks_internal_ptr) \
-for (int for_each_hook_counter = 0; \
- for_each_hook_counter < HOOK_MAX; \
- for_each_hook_counter++) { \
- bool for_each_hook_success = seq_try_load_hooks( \
- (hooks_internal_ptr), &hooks[for_each_hook_counter]); \
- if (!for_each_hook_success) { \
- continue; \
- } \
- if (!(hooks_internal_ptr)->in_use) { \
- continue; \
- }
-#define FOR_EACH_HOOK_END \
-}
-
-static bool *
-hook_reentrantp() {
- /*
- * We prevent user reentrancy within hooks. This is basically just a
- * thread-local bool that triggers an early-exit.
- *
- * We don't fold in_hook into reentrancy. There are two reasons for
- * this:
- * - Right now, we turn on reentrancy during things like extent hook
- * execution. Allocating during extent hooks is not officially
- * supported, but we don't want to break it for the time being. These
- * sorts of allocations should probably still be hooked, though.
- * - If a hook allocates, we may want it to be relatively fast (after
- * all, it executes on every allocator operation). Turning on
- * reentrancy is a fairly heavyweight mode (disabling tcache,
- * redirecting to arena 0, etc.). It's possible we may one day want
- * to turn on reentrant mode here, if it proves too difficult to keep
- * this working. But that's fairly easy for us to see; OTOH, people
- * not using hooks because they're too slow is easy for us to miss.
- *
- * The tricky part is
- * that this code might get invoked even if we don't have access to tsd.
- * This function mimics getting a pointer to thread-local data, except
- * that it might secretly return a pointer to some global data if we
- * know that the caller will take the early-exit path.
- * If we return a bool that indicates that we are reentrant, then the
- * caller will go down the early exit path, leaving the global
- * untouched.
- */
- static bool in_hook_global = true;
- tsdn_t *tsdn = tsdn_fetch();
- bool *in_hook = tsdn_in_hookp_get(tsdn);
- if (in_hook!= NULL) {
- return in_hook;
- }
- return &in_hook_global;
-}
-
-#define HOOK_PROLOGUE \
- if (likely(atomic_load_u(&nhooks, ATOMIC_RELAXED) == 0)) { \
- return; \
- } \
- bool *in_hook = hook_reentrantp(); \
- if (*in_hook) { \
- return; \
- } \
- *in_hook = true;
-
-#define HOOK_EPILOGUE \
- *in_hook = false;
-
-void
-hook_invoke_alloc(hook_alloc_t type, void *result, uintptr_t result_raw,
- uintptr_t args_raw[3]) {
- HOOK_PROLOGUE
-
- hooks_internal_t hook;
- FOR_EACH_HOOK_BEGIN(&hook)
- hook_alloc h = hook.hooks.alloc_hook;
- if (h != NULL) {
- h(hook.hooks.extra, type, result, result_raw, args_raw);
- }
- FOR_EACH_HOOK_END
-
- HOOK_EPILOGUE
-}
-
-void
-hook_invoke_dalloc(hook_dalloc_t type, void *address, uintptr_t args_raw[3]) {
- HOOK_PROLOGUE
- hooks_internal_t hook;
- FOR_EACH_HOOK_BEGIN(&hook)
- hook_dalloc h = hook.hooks.dalloc_hook;
- if (h != NULL) {
- h(hook.hooks.extra, type, address, args_raw);
- }
- FOR_EACH_HOOK_END
- HOOK_EPILOGUE
-}
-
-void
-hook_invoke_expand(hook_expand_t type, void *address, size_t old_usize,
- size_t new_usize, uintptr_t result_raw, uintptr_t args_raw[4]) {
- HOOK_PROLOGUE
- hooks_internal_t hook;
- FOR_EACH_HOOK_BEGIN(&hook)
- hook_expand h = hook.hooks.expand_hook;
- if (h != NULL) {
- h(hook.hooks.extra, type, address, old_usize, new_usize,
- result_raw, args_raw);
- }
- FOR_EACH_HOOK_END
- HOOK_EPILOGUE
-}
diff --git a/fluent-bit/lib/jemalloc-5.3.0/src/hpa.c b/fluent-bit/lib/jemalloc-5.3.0/src/hpa.c
deleted file mode 100644
index 7e2aeba0..00000000
--- a/fluent-bit/lib/jemalloc-5.3.0/src/hpa.c
+++ /dev/null
@@ -1,1044 +0,0 @@
-#include "jemalloc/internal/jemalloc_preamble.h"
-#include "jemalloc/internal/jemalloc_internal_includes.h"
-
-#include "jemalloc/internal/hpa.h"
-
-#include "jemalloc/internal/fb.h"
-#include "jemalloc/internal/witness.h"
-
-#define HPA_EDEN_SIZE (128 * HUGEPAGE)
-
-static edata_t *hpa_alloc(tsdn_t *tsdn, pai_t *self, size_t size,
- size_t alignment, bool zero, bool guarded, bool frequent_reuse,
- bool *deferred_work_generated);
-static size_t hpa_alloc_batch(tsdn_t *tsdn, pai_t *self, size_t size,
- size_t nallocs, edata_list_active_t *results, bool *deferred_work_generated);
-static bool hpa_expand(tsdn_t *tsdn, pai_t *self, edata_t *edata,
- size_t old_size, size_t new_size, bool zero, bool *deferred_work_generated);
-static bool hpa_shrink(tsdn_t *tsdn, pai_t *self, edata_t *edata,
- size_t old_size, size_t new_size, bool *deferred_work_generated);
-static void hpa_dalloc(tsdn_t *tsdn, pai_t *self, edata_t *edata,
- bool *deferred_work_generated);
-static void hpa_dalloc_batch(tsdn_t *tsdn, pai_t *self,
- edata_list_active_t *list, bool *deferred_work_generated);
-static uint64_t hpa_time_until_deferred_work(tsdn_t *tsdn, pai_t *self);
-
-bool
-hpa_supported() {
-#ifdef _WIN32
- /*
- * At least until the API and implementation is somewhat settled, we
- * don't want to try to debug the VM subsystem on the hardest-to-test
- * platform.
- */
- return false;
-#endif
- if (!pages_can_hugify) {
- return false;
- }
- /*
- * We fundamentally rely on a address-space-hungry growth strategy for
- * hugepages.
- */
- if (LG_SIZEOF_PTR != 3) {
- return false;
- }
- /*
- * If we couldn't detect the value of HUGEPAGE, HUGEPAGE_PAGES becomes
- * this sentinel value -- see the comment in pages.h.
- */
- if (HUGEPAGE_PAGES == 1) {
- return false;
- }
- return true;
-}
-
-static void
-hpa_do_consistency_checks(hpa_shard_t *shard) {
- assert(shard->base != NULL);
-}
-
-bool
-hpa_central_init(hpa_central_t *central, base_t *base, const hpa_hooks_t *hooks) {
- /* malloc_conf processing should have filtered out these cases. */
- assert(hpa_supported());
- bool err;
- err = malloc_mutex_init(&central->grow_mtx, "hpa_central_grow",
- WITNESS_RANK_HPA_CENTRAL_GROW, malloc_mutex_rank_exclusive);
- if (err) {
- return true;
- }
- err = malloc_mutex_init(&central->mtx, "hpa_central",
- WITNESS_RANK_HPA_CENTRAL, malloc_mutex_rank_exclusive);
- if (err) {
- return true;
- }
- central->base = base;
- central->eden = NULL;
- central->eden_len = 0;
- central->age_counter = 0;
- central->hooks = *hooks;
- return false;
-}
-
-static hpdata_t *
-hpa_alloc_ps(tsdn_t *tsdn, hpa_central_t *central) {
- return (hpdata_t *)base_alloc(tsdn, central->base, sizeof(hpdata_t),
- CACHELINE);
-}
-
-hpdata_t *
-hpa_central_extract(tsdn_t *tsdn, hpa_central_t *central, size_t size,
- bool *oom) {
- /* Don't yet support big allocations; these should get filtered out. */
- assert(size <= HUGEPAGE);
- /*
- * Should only try to extract from the central allocator if the local
- * shard is exhausted. We should hold the grow_mtx on that shard.
- */
- witness_assert_positive_depth_to_rank(
- tsdn_witness_tsdp_get(tsdn), WITNESS_RANK_HPA_SHARD_GROW);
-
- malloc_mutex_lock(tsdn, &central->grow_mtx);
- *oom = false;
-
- hpdata_t *ps = NULL;
-
- /* Is eden a perfect fit? */
- if (central->eden != NULL && central->eden_len == HUGEPAGE) {
- ps = hpa_alloc_ps(tsdn, central);
- if (ps == NULL) {
- *oom = true;
- malloc_mutex_unlock(tsdn, &central->grow_mtx);
- return NULL;
- }
- hpdata_init(ps, central->eden, central->age_counter++);
- central->eden = NULL;
- central->eden_len = 0;
- malloc_mutex_unlock(tsdn, &central->grow_mtx);
- return ps;
- }
-
- /*
- * We're about to try to allocate from eden by splitting. If eden is
- * NULL, we have to allocate it too. Otherwise, we just have to
- * allocate an edata_t for the new psset.
- */
- if (central->eden == NULL) {
- /*
- * During development, we're primarily concerned with systems
- * with overcommit. Eventually, we should be more careful here.
- */
- bool commit = true;
- /* Allocate address space, bailing if we fail. */
- void *new_eden = pages_map(NULL, HPA_EDEN_SIZE, HUGEPAGE,
- &commit);
- if (new_eden == NULL) {
- *oom = true;
- malloc_mutex_unlock(tsdn, &central->grow_mtx);
- return NULL;
- }
- ps = hpa_alloc_ps(tsdn, central);
- if (ps == NULL) {
- pages_unmap(new_eden, HPA_EDEN_SIZE);
- *oom = true;
- malloc_mutex_unlock(tsdn, &central->grow_mtx);
- return NULL;
- }
- central->eden = new_eden;
- central->eden_len = HPA_EDEN_SIZE;
- } else {
- /* Eden is already nonempty; only need an edata for ps. */
- ps = hpa_alloc_ps(tsdn, central);
- if (ps == NULL) {
- *oom = true;
- malloc_mutex_unlock(tsdn, &central->grow_mtx);
- return NULL;
- }
- }
- assert(ps != NULL);
- assert(central->eden != NULL);
- assert(central->eden_len > HUGEPAGE);
- assert(central->eden_len % HUGEPAGE == 0);
- assert(HUGEPAGE_ADDR2BASE(central->eden) == central->eden);
-
- hpdata_init(ps, central->eden, central->age_counter++);
-
- char *eden_char = (char *)central->eden;
- eden_char += HUGEPAGE;
- central->eden = (void *)eden_char;
- central->eden_len -= HUGEPAGE;
-
- malloc_mutex_unlock(tsdn, &central->grow_mtx);
-
- return ps;
-}
-
-bool
-hpa_shard_init(hpa_shard_t *shard, hpa_central_t *central, emap_t *emap,
- base_t *base, edata_cache_t *edata_cache, unsigned ind,
- const hpa_shard_opts_t *opts) {
- /* malloc_conf processing should have filtered out these cases. */
- assert(hpa_supported());
- bool err;
- err = malloc_mutex_init(&shard->grow_mtx, "hpa_shard_grow",
- WITNESS_RANK_HPA_SHARD_GROW, malloc_mutex_rank_exclusive);
- if (err) {
- return true;
- }
- err = malloc_mutex_init(&shard->mtx, "hpa_shard",
- WITNESS_RANK_HPA_SHARD, malloc_mutex_rank_exclusive);
- if (err) {
- return true;
- }
-
- assert(edata_cache != NULL);
- shard->central = central;
- shard->base = base;
- edata_cache_fast_init(&shard->ecf, edata_cache);
- psset_init(&shard->psset);
- shard->age_counter = 0;
- shard->ind = ind;
- shard->emap = emap;
-
- shard->opts = *opts;
-
- shard->npending_purge = 0;
- nstime_init_zero(&shard->last_purge);
-
- shard->stats.npurge_passes = 0;
- shard->stats.npurges = 0;
- shard->stats.nhugifies = 0;
- shard->stats.ndehugifies = 0;
-
- /*
- * Fill these in last, so that if an hpa_shard gets used despite
- * initialization failing, we'll at least crash instead of just
- * operating on corrupted data.
- */
- shard->pai.alloc = &hpa_alloc;
- shard->pai.alloc_batch = &hpa_alloc_batch;
- shard->pai.expand = &hpa_expand;
- shard->pai.shrink = &hpa_shrink;
- shard->pai.dalloc = &hpa_dalloc;
- shard->pai.dalloc_batch = &hpa_dalloc_batch;
- shard->pai.time_until_deferred_work = &hpa_time_until_deferred_work;
-
- hpa_do_consistency_checks(shard);
-
- return false;
-}
-
-/*
- * Note that the stats functions here follow the usual stats naming conventions;
- * "merge" obtains the stats from some live object of instance, while "accum"
- * only combines the stats from one stats objet to another. Hence the lack of
- * locking here.
- */
-static void
-hpa_shard_nonderived_stats_accum(hpa_shard_nonderived_stats_t *dst,
- hpa_shard_nonderived_stats_t *src) {
- dst->npurge_passes += src->npurge_passes;
- dst->npurges += src->npurges;
- dst->nhugifies += src->nhugifies;
- dst->ndehugifies += src->ndehugifies;
-}
-
-void
-hpa_shard_stats_accum(hpa_shard_stats_t *dst, hpa_shard_stats_t *src) {
- psset_stats_accum(&dst->psset_stats, &src->psset_stats);
- hpa_shard_nonderived_stats_accum(&dst->nonderived_stats,
- &src->nonderived_stats);
-}
-
-void
-hpa_shard_stats_merge(tsdn_t *tsdn, hpa_shard_t *shard,
- hpa_shard_stats_t *dst) {
- hpa_do_consistency_checks(shard);
-
- malloc_mutex_lock(tsdn, &shard->grow_mtx);
- malloc_mutex_lock(tsdn, &shard->mtx);
- psset_stats_accum(&dst->psset_stats, &shard->psset.stats);
- hpa_shard_nonderived_stats_accum(&dst->nonderived_stats, &shard->stats);
- malloc_mutex_unlock(tsdn, &shard->mtx);
- malloc_mutex_unlock(tsdn, &shard->grow_mtx);
-}
-
-static bool
-hpa_good_hugification_candidate(hpa_shard_t *shard, hpdata_t *ps) {
- /*
- * Note that this needs to be >= rather than just >, because of the
- * important special case in which the hugification threshold is exactly
- * HUGEPAGE.
- */
- return hpdata_nactive_get(ps) * PAGE
- >= shard->opts.hugification_threshold;
-}
-
-static size_t
-hpa_adjusted_ndirty(tsdn_t *tsdn, hpa_shard_t *shard) {
- malloc_mutex_assert_owner(tsdn, &shard->mtx);
- return psset_ndirty(&shard->psset) - shard->npending_purge;
-}
-
-static size_t
-hpa_ndirty_max(tsdn_t *tsdn, hpa_shard_t *shard) {
- malloc_mutex_assert_owner(tsdn, &shard->mtx);
- if (shard->opts.dirty_mult == (fxp_t)-1) {
- return (size_t)-1;
- }
- return fxp_mul_frac(psset_nactive(&shard->psset),
- shard->opts.dirty_mult);
-}
-
-static bool
-hpa_hugify_blocked_by_ndirty(tsdn_t *tsdn, hpa_shard_t *shard) {
- malloc_mutex_assert_owner(tsdn, &shard->mtx);
- hpdata_t *to_hugify = psset_pick_hugify(&shard->psset);
- if (to_hugify == NULL) {
- return false;
- }
- return hpa_adjusted_ndirty(tsdn, shard)
- + hpdata_nretained_get(to_hugify) > hpa_ndirty_max(tsdn, shard);
-}
-
-static bool
-hpa_should_purge(tsdn_t *tsdn, hpa_shard_t *shard) {
- malloc_mutex_assert_owner(tsdn, &shard->mtx);
- if (hpa_adjusted_ndirty(tsdn, shard) > hpa_ndirty_max(tsdn, shard)) {
- return true;
- }
- if (hpa_hugify_blocked_by_ndirty(tsdn, shard)) {
- return true;
- }
- return false;
-}
-
-static void
-hpa_update_purge_hugify_eligibility(tsdn_t *tsdn, hpa_shard_t *shard,
- hpdata_t *ps) {
- malloc_mutex_assert_owner(tsdn, &shard->mtx);
- if (hpdata_changing_state_get(ps)) {
- hpdata_purge_allowed_set(ps, false);
- hpdata_disallow_hugify(ps);
- return;
- }
- /*
- * Hugepages are distinctly costly to purge, so try to avoid it unless
- * they're *particularly* full of dirty pages. Eventually, we should
- * use a smarter / more dynamic heuristic for situations where we have
- * to manually hugify.
- *
- * In situations where we don't manually hugify, this problem is
- * reduced. The "bad" situation we're trying to avoid is one's that's
- * common in some Linux configurations (where both enabled and defrag
- * are set to madvise) that can lead to long latency spikes on the first
- * access after a hugification. The ideal policy in such configurations
- * is probably time-based for both purging and hugifying; only hugify a
- * hugepage if it's met the criteria for some extended period of time,
- * and only dehugify it if it's failed to meet the criteria for an
- * extended period of time. When background threads are on, we should
- * try to take this hit on one of them, as well.
- *
- * I think the ideal setting is THP always enabled, and defrag set to
- * deferred; in that case we don't need any explicit calls on the
- * allocator's end at all; we just try to pack allocations in a
- * hugepage-friendly manner and let the OS hugify in the background.
- */
- hpdata_purge_allowed_set(ps, hpdata_ndirty_get(ps) > 0);
- if (hpa_good_hugification_candidate(shard, ps)
- && !hpdata_huge_get(ps)) {
- nstime_t now;
- shard->central->hooks.curtime(&now, /* first_reading */ true);
- hpdata_allow_hugify(ps, now);
- }
- /*
- * Once a hugepage has become eligible for hugification, we don't mark
- * it as ineligible just because it stops meeting the criteria (this
- * could lead to situations where a hugepage that spends most of its
- * time meeting the criteria never quite getting hugified if there are
- * intervening deallocations). The idea is that the hugification delay
- * will allow them to get purged, reseting their "hugify-allowed" bit.
- * If they don't get purged, then the hugification isn't hurting and
- * might help. As an exception, we don't hugify hugepages that are now
- * empty; it definitely doesn't help there until the hugepage gets
- * reused, which is likely not for a while.
- */
- if (hpdata_nactive_get(ps) == 0) {
- hpdata_disallow_hugify(ps);
- }
-}
-
-static bool
-hpa_shard_has_deferred_work(tsdn_t *tsdn, hpa_shard_t *shard) {
- malloc_mutex_assert_owner(tsdn, &shard->mtx);
- hpdata_t *to_hugify = psset_pick_hugify(&shard->psset);
- return to_hugify != NULL || hpa_should_purge(tsdn, shard);
-}
-
-/* Returns whether or not we purged anything. */
-static bool
-hpa_try_purge(tsdn_t *tsdn, hpa_shard_t *shard) {
- malloc_mutex_assert_owner(tsdn, &shard->mtx);
-
- hpdata_t *to_purge = psset_pick_purge(&shard->psset);
- if (to_purge == NULL) {
- return false;
- }
- assert(hpdata_purge_allowed_get(to_purge));
- assert(!hpdata_changing_state_get(to_purge));
-
- /*
- * Don't let anyone else purge or hugify this page while
- * we're purging it (allocations and deallocations are
- * OK).
- */
- psset_update_begin(&shard->psset, to_purge);
- assert(hpdata_alloc_allowed_get(to_purge));
- hpdata_mid_purge_set(to_purge, true);
- hpdata_purge_allowed_set(to_purge, false);
- hpdata_disallow_hugify(to_purge);
- /*
- * Unlike with hugification (where concurrent
- * allocations are allowed), concurrent allocation out
- * of a hugepage being purged is unsafe; we might hand
- * out an extent for an allocation and then purge it
- * (clearing out user data).
- */
- hpdata_alloc_allowed_set(to_purge, false);
- psset_update_end(&shard->psset, to_purge);
-
- /* Gather all the metadata we'll need during the purge. */
- bool dehugify = hpdata_huge_get(to_purge);
- hpdata_purge_state_t purge_state;
- size_t num_to_purge = hpdata_purge_begin(to_purge, &purge_state);
-
- shard->npending_purge += num_to_purge;
-
- malloc_mutex_unlock(tsdn, &shard->mtx);
-
- /* Actually do the purging, now that the lock is dropped. */
- if (dehugify) {
- shard->central->hooks.dehugify(hpdata_addr_get(to_purge),
- HUGEPAGE);
- }
- size_t total_purged = 0;
- uint64_t purges_this_pass = 0;
- void *purge_addr;
- size_t purge_size;
- while (hpdata_purge_next(to_purge, &purge_state, &purge_addr,
- &purge_size)) {
- total_purged += purge_size;
- assert(total_purged <= HUGEPAGE);
- purges_this_pass++;
- shard->central->hooks.purge(purge_addr, purge_size);
- }
-
- malloc_mutex_lock(tsdn, &shard->mtx);
- /* The shard updates */
- shard->npending_purge -= num_to_purge;
- shard->stats.npurge_passes++;
- shard->stats.npurges += purges_this_pass;
- shard->central->hooks.curtime(&shard->last_purge,
- /* first_reading */ false);
- if (dehugify) {
- shard->stats.ndehugifies++;
- }
-
- /* The hpdata updates. */
- psset_update_begin(&shard->psset, to_purge);
- if (dehugify) {
- hpdata_dehugify(to_purge);
- }
- hpdata_purge_end(to_purge, &purge_state);
- hpdata_mid_purge_set(to_purge, false);
-
- hpdata_alloc_allowed_set(to_purge, true);
- hpa_update_purge_hugify_eligibility(tsdn, shard, to_purge);
-
- psset_update_end(&shard->psset, to_purge);
-
- return true;
-}
-
-/* Returns whether or not we hugified anything. */
-static bool
-hpa_try_hugify(tsdn_t *tsdn, hpa_shard_t *shard) {
- malloc_mutex_assert_owner(tsdn, &shard->mtx);
-
- if (hpa_hugify_blocked_by_ndirty(tsdn, shard)) {
- return false;
- }
-
- hpdata_t *to_hugify = psset_pick_hugify(&shard->psset);
- if (to_hugify == NULL) {
- return false;
- }
- assert(hpdata_hugify_allowed_get(to_hugify));
- assert(!hpdata_changing_state_get(to_hugify));
-
- /* Make sure that it's been hugifiable for long enough. */
- nstime_t time_hugify_allowed = hpdata_time_hugify_allowed(to_hugify);
- uint64_t millis = shard->central->hooks.ms_since(&time_hugify_allowed);
- if (millis < shard->opts.hugify_delay_ms) {
- return false;
- }
-
- /*
- * Don't let anyone else purge or hugify this page while
- * we're hugifying it (allocations and deallocations are
- * OK).
- */
- psset_update_begin(&shard->psset, to_hugify);
- hpdata_mid_hugify_set(to_hugify, true);
- hpdata_purge_allowed_set(to_hugify, false);
- hpdata_disallow_hugify(to_hugify);
- assert(hpdata_alloc_allowed_get(to_hugify));
- psset_update_end(&shard->psset, to_hugify);
-
- malloc_mutex_unlock(tsdn, &shard->mtx);
-
- shard->central->hooks.hugify(hpdata_addr_get(to_hugify), HUGEPAGE);
-
- malloc_mutex_lock(tsdn, &shard->mtx);
- shard->stats.nhugifies++;
-
- psset_update_begin(&shard->psset, to_hugify);
- hpdata_hugify(to_hugify);
- hpdata_mid_hugify_set(to_hugify, false);
- hpa_update_purge_hugify_eligibility(tsdn, shard, to_hugify);
- psset_update_end(&shard->psset, to_hugify);
-
- return true;
-}
-
-/*
- * Execution of deferred work is forced if it's triggered by an explicit
- * hpa_shard_do_deferred_work() call.
- */
-static void
-hpa_shard_maybe_do_deferred_work(tsdn_t *tsdn, hpa_shard_t *shard,
- bool forced) {
- malloc_mutex_assert_owner(tsdn, &shard->mtx);
- if (!forced && shard->opts.deferral_allowed) {
- return;
- }
- /*
- * If we're on a background thread, do work so long as there's work to
- * be done. Otherwise, bound latency to not be *too* bad by doing at
- * most a small fixed number of operations.
- */
- bool hugified = false;
- bool purged = false;
- size_t max_ops = (forced ? (size_t)-1 : 16);
- size_t nops = 0;
- do {
- /*
- * Always purge before hugifying, to make sure we get some
- * ability to hit our quiescence targets.
- */
- purged = false;
- while (hpa_should_purge(tsdn, shard) && nops < max_ops) {
- purged = hpa_try_purge(tsdn, shard);
- if (purged) {
- nops++;
- }
- }
- hugified = hpa_try_hugify(tsdn, shard);
- if (hugified) {
- nops++;
- }
- malloc_mutex_assert_owner(tsdn, &shard->mtx);
- malloc_mutex_assert_owner(tsdn, &shard->mtx);
- } while ((hugified || purged) && nops < max_ops);
-}
-
-static edata_t *
-hpa_try_alloc_one_no_grow(tsdn_t *tsdn, hpa_shard_t *shard, size_t size,
- bool *oom) {
- bool err;
- edata_t *edata = edata_cache_fast_get(tsdn, &shard->ecf);
- if (edata == NULL) {
- *oom = true;
- return NULL;
- }
-
- hpdata_t *ps = psset_pick_alloc(&shard->psset, size);
- if (ps == NULL) {
- edata_cache_fast_put(tsdn, &shard->ecf, edata);
- return NULL;
- }
-
- psset_update_begin(&shard->psset, ps);
-
- if (hpdata_empty(ps)) {
- /*
- * If the pageslab used to be empty, treat it as though it's
- * brand new for fragmentation-avoidance purposes; what we're
- * trying to approximate is the age of the allocations *in* that
- * pageslab, and the allocations in the new pageslab are
- * definitionally the youngest in this hpa shard.
- */
- hpdata_age_set(ps, shard->age_counter++);
- }
-
- void *addr = hpdata_reserve_alloc(ps, size);
- edata_init(edata, shard->ind, addr, size, /* slab */ false,
- SC_NSIZES, /* sn */ hpdata_age_get(ps), extent_state_active,
- /* zeroed */ false, /* committed */ true, EXTENT_PAI_HPA,
- EXTENT_NOT_HEAD);
- edata_ps_set(edata, ps);
-
- /*
- * This could theoretically be moved outside of the critical section,
- * but that introduces the potential for a race. Without the lock, the
- * (initially nonempty, since this is the reuse pathway) pageslab we
- * allocated out of could become otherwise empty while the lock is
- * dropped. This would force us to deal with a pageslab eviction down
- * the error pathway, which is a pain.
- */
- err = emap_register_boundary(tsdn, shard->emap, edata,
- SC_NSIZES, /* slab */ false);
- if (err) {
- hpdata_unreserve(ps, edata_addr_get(edata),
- edata_size_get(edata));
- /*
- * We should arguably reset dirty state here, but this would
- * require some sort of prepare + commit functionality that's a
- * little much to deal with for now.
- *
- * We don't have a do_deferred_work down this pathway, on the
- * principle that we didn't *really* affect shard state (we
- * tweaked the stats, but our tweaks weren't really accurate).
- */
- psset_update_end(&shard->psset, ps);
- edata_cache_fast_put(tsdn, &shard->ecf, edata);
- *oom = true;
- return NULL;
- }
-
- hpa_update_purge_hugify_eligibility(tsdn, shard, ps);
- psset_update_end(&shard->psset, ps);
- return edata;
-}
-
-static size_t
-hpa_try_alloc_batch_no_grow(tsdn_t *tsdn, hpa_shard_t *shard, size_t size,
- bool *oom, size_t nallocs, edata_list_active_t *results,
- bool *deferred_work_generated) {
- malloc_mutex_lock(tsdn, &shard->mtx);
- size_t nsuccess = 0;
- for (; nsuccess < nallocs; nsuccess++) {
- edata_t *edata = hpa_try_alloc_one_no_grow(tsdn, shard, size,
- oom);
- if (edata == NULL) {
- break;
- }
- edata_list_active_append(results, edata);
- }
-
- hpa_shard_maybe_do_deferred_work(tsdn, shard, /* forced */ false);
- *deferred_work_generated = hpa_shard_has_deferred_work(tsdn, shard);
- malloc_mutex_unlock(tsdn, &shard->mtx);
- return nsuccess;
-}
-
-static size_t
-hpa_alloc_batch_psset(tsdn_t *tsdn, hpa_shard_t *shard, size_t size,
- size_t nallocs, edata_list_active_t *results,
- bool *deferred_work_generated) {
- assert(size <= shard->opts.slab_max_alloc);
- bool oom = false;
-
- size_t nsuccess = hpa_try_alloc_batch_no_grow(tsdn, shard, size, &oom,
- nallocs, results, deferred_work_generated);
-
- if (nsuccess == nallocs || oom) {
- return nsuccess;
- }
-
- /*
- * We didn't OOM, but weren't able to fill everything requested of us;
- * try to grow.
- */
- malloc_mutex_lock(tsdn, &shard->grow_mtx);
- /*
- * Check for grow races; maybe some earlier thread expanded the psset
- * in between when we dropped the main mutex and grabbed the grow mutex.
- */
- nsuccess += hpa_try_alloc_batch_no_grow(tsdn, shard, size, &oom,
- nallocs - nsuccess, results, deferred_work_generated);
- if (nsuccess == nallocs || oom) {
- malloc_mutex_unlock(tsdn, &shard->grow_mtx);
- return nsuccess;
- }
-
- /*
- * Note that we don't hold shard->mtx here (while growing);
- * deallocations (and allocations of smaller sizes) may still succeed
- * while we're doing this potentially expensive system call.
- */
- hpdata_t *ps = hpa_central_extract(tsdn, shard->central, size, &oom);
- if (ps == NULL) {
- malloc_mutex_unlock(tsdn, &shard->grow_mtx);
- return nsuccess;
- }
-
- /*
- * We got the pageslab; allocate from it. This does an unlock followed
- * by a lock on the same mutex, and holds the grow mutex while doing
- * deferred work, but this is an uncommon path; the simplicity is worth
- * it.
- */
- malloc_mutex_lock(tsdn, &shard->mtx);
- psset_insert(&shard->psset, ps);
- malloc_mutex_unlock(tsdn, &shard->mtx);
-
- nsuccess += hpa_try_alloc_batch_no_grow(tsdn, shard, size, &oom,
- nallocs - nsuccess, results, deferred_work_generated);
- /*
- * Drop grow_mtx before doing deferred work; other threads blocked on it
- * should be allowed to proceed while we're working.
- */
- malloc_mutex_unlock(tsdn, &shard->grow_mtx);
-
- return nsuccess;
-}
-
-static hpa_shard_t *
-hpa_from_pai(pai_t *self) {
- assert(self->alloc = &hpa_alloc);
- assert(self->expand = &hpa_expand);
- assert(self->shrink = &hpa_shrink);
- assert(self->dalloc = &hpa_dalloc);
- return (hpa_shard_t *)self;
-}
-
-static size_t
-hpa_alloc_batch(tsdn_t *tsdn, pai_t *self, size_t size, size_t nallocs,
- edata_list_active_t *results, bool *deferred_work_generated) {
- assert(nallocs > 0);
- assert((size & PAGE_MASK) == 0);
- witness_assert_depth_to_rank(tsdn_witness_tsdp_get(tsdn),
- WITNESS_RANK_CORE, 0);
- hpa_shard_t *shard = hpa_from_pai(self);
-
- if (size > shard->opts.slab_max_alloc) {
- return 0;
- }
-
- size_t nsuccess = hpa_alloc_batch_psset(tsdn, shard, size, nallocs,
- results, deferred_work_generated);
-
- witness_assert_depth_to_rank(tsdn_witness_tsdp_get(tsdn),
- WITNESS_RANK_CORE, 0);
-
- /*
- * Guard the sanity checks with config_debug because the loop cannot be
- * proven non-circular by the compiler, even if everything within the
- * loop is optimized away.
- */
- if (config_debug) {
- edata_t *edata;
- ql_foreach(edata, &results->head, ql_link_active) {
- emap_assert_mapped(tsdn, shard->emap, edata);
- assert(edata_pai_get(edata) == EXTENT_PAI_HPA);
- assert(edata_state_get(edata) == extent_state_active);
- assert(edata_arena_ind_get(edata) == shard->ind);
- assert(edata_szind_get_maybe_invalid(edata) ==
- SC_NSIZES);
- assert(!edata_slab_get(edata));
- assert(edata_committed_get(edata));
- assert(edata_base_get(edata) == edata_addr_get(edata));
- assert(edata_base_get(edata) != NULL);
- }
- }
- return nsuccess;
-}
-
-static edata_t *
-hpa_alloc(tsdn_t *tsdn, pai_t *self, size_t size, size_t alignment, bool zero,
- bool guarded, bool frequent_reuse, bool *deferred_work_generated) {
- assert((size & PAGE_MASK) == 0);
- assert(!guarded);
- witness_assert_depth_to_rank(tsdn_witness_tsdp_get(tsdn),
- WITNESS_RANK_CORE, 0);
-
- /* We don't handle alignment or zeroing for now. */
- if (alignment > PAGE || zero) {
- return NULL;
- }
- /*
- * An alloc with alignment == PAGE and zero == false is equivalent to a
- * batch alloc of 1. Just do that, so we can share code.
- */
- edata_list_active_t results;
- edata_list_active_init(&results);
- size_t nallocs = hpa_alloc_batch(tsdn, self, size, /* nallocs */ 1,
- &results, deferred_work_generated);
- assert(nallocs == 0 || nallocs == 1);
- edata_t *edata = edata_list_active_first(&results);
- return edata;
-}
-
-static bool
-hpa_expand(tsdn_t *tsdn, pai_t *self, edata_t *edata, size_t old_size,
- size_t new_size, bool zero, bool *deferred_work_generated) {
- /* Expand not yet supported. */
- return true;
-}
-
-static bool
-hpa_shrink(tsdn_t *tsdn, pai_t *self, edata_t *edata,
- size_t old_size, size_t new_size, bool *deferred_work_generated) {
- /* Shrink not yet supported. */
- return true;
-}
-
-static void
-hpa_dalloc_prepare_unlocked(tsdn_t *tsdn, hpa_shard_t *shard, edata_t *edata) {
- malloc_mutex_assert_not_owner(tsdn, &shard->mtx);
-
- assert(edata_pai_get(edata) == EXTENT_PAI_HPA);
- assert(edata_state_get(edata) == extent_state_active);
- assert(edata_arena_ind_get(edata) == shard->ind);
- assert(edata_szind_get_maybe_invalid(edata) == SC_NSIZES);
- assert(edata_committed_get(edata));
- assert(edata_base_get(edata) != NULL);
-
- /*
- * Another thread shouldn't be trying to touch the metadata of an
- * allocation being freed. The one exception is a merge attempt from a
- * lower-addressed PAC extent; in this case we have a nominal race on
- * the edata metadata bits, but in practice the fact that the PAI bits
- * are different will prevent any further access. The race is bad, but
- * benign in practice, and the long term plan is to track enough state
- * in the rtree to prevent these merge attempts in the first place.
- */
- edata_addr_set(edata, edata_base_get(edata));
- edata_zeroed_set(edata, false);
- emap_deregister_boundary(tsdn, shard->emap, edata);
-}
-
-static void
-hpa_dalloc_locked(tsdn_t *tsdn, hpa_shard_t *shard, edata_t *edata) {
- malloc_mutex_assert_owner(tsdn, &shard->mtx);
-
- /*
- * Release the metadata early, to avoid having to remember to do it
- * while we're also doing tricky purging logic. First, we need to grab
- * a few bits of metadata from it.
- *
- * Note that the shard mutex protects ps's metadata too; it wouldn't be
- * correct to try to read most information out of it without the lock.
- */
- hpdata_t *ps = edata_ps_get(edata);
- /* Currently, all edatas come from pageslabs. */
- assert(ps != NULL);
- void *unreserve_addr = edata_addr_get(edata);
- size_t unreserve_size = edata_size_get(edata);
- edata_cache_fast_put(tsdn, &shard->ecf, edata);
-
- psset_update_begin(&shard->psset, ps);
- hpdata_unreserve(ps, unreserve_addr, unreserve_size);
- hpa_update_purge_hugify_eligibility(tsdn, shard, ps);
- psset_update_end(&shard->psset, ps);
-}
-
-static void
-hpa_dalloc_batch(tsdn_t *tsdn, pai_t *self, edata_list_active_t *list,
- bool *deferred_work_generated) {
- hpa_shard_t *shard = hpa_from_pai(self);
-
- edata_t *edata;
- ql_foreach(edata, &list->head, ql_link_active) {
- hpa_dalloc_prepare_unlocked(tsdn, shard, edata);
- }
-
- malloc_mutex_lock(tsdn, &shard->mtx);
- /* Now, remove from the list. */
- while ((edata = edata_list_active_first(list)) != NULL) {
- edata_list_active_remove(list, edata);
- hpa_dalloc_locked(tsdn, shard, edata);
- }
- hpa_shard_maybe_do_deferred_work(tsdn, shard, /* forced */ false);
- *deferred_work_generated =
- hpa_shard_has_deferred_work(tsdn, shard);
-
- malloc_mutex_unlock(tsdn, &shard->mtx);
-}
-
-static void
-hpa_dalloc(tsdn_t *tsdn, pai_t *self, edata_t *edata,
- bool *deferred_work_generated) {
- assert(!edata_guarded_get(edata));
- /* Just a dalloc_batch of size 1; this lets us share logic. */
- edata_list_active_t dalloc_list;
- edata_list_active_init(&dalloc_list);
- edata_list_active_append(&dalloc_list, edata);
- hpa_dalloc_batch(tsdn, self, &dalloc_list, deferred_work_generated);
-}
-
-/*
- * Calculate time until either purging or hugification ought to happen.
- * Called by background threads.
- */
-static uint64_t
-hpa_time_until_deferred_work(tsdn_t *tsdn, pai_t *self) {
- hpa_shard_t *shard = hpa_from_pai(self);
- uint64_t time_ns = BACKGROUND_THREAD_DEFERRED_MAX;
-
- malloc_mutex_lock(tsdn, &shard->mtx);
-
- hpdata_t *to_hugify = psset_pick_hugify(&shard->psset);
- if (to_hugify != NULL) {
- nstime_t time_hugify_allowed =
- hpdata_time_hugify_allowed(to_hugify);
- uint64_t since_hugify_allowed_ms =
- shard->central->hooks.ms_since(&time_hugify_allowed);
- /*
- * If not enough time has passed since hugification was allowed,
- * sleep for the rest.
- */
- if (since_hugify_allowed_ms < shard->opts.hugify_delay_ms) {
- time_ns = shard->opts.hugify_delay_ms -
- since_hugify_allowed_ms;
- time_ns *= 1000 * 1000;
- } else {
- malloc_mutex_unlock(tsdn, &shard->mtx);
- return BACKGROUND_THREAD_DEFERRED_MIN;
- }
- }
-
- if (hpa_should_purge(tsdn, shard)) {
- /*
- * If we haven't purged before, no need to check interval
- * between purges. Simply purge as soon as possible.
- */
- if (shard->stats.npurge_passes == 0) {
- malloc_mutex_unlock(tsdn, &shard->mtx);
- return BACKGROUND_THREAD_DEFERRED_MIN;
- }
- uint64_t since_last_purge_ms = shard->central->hooks.ms_since(
- &shard->last_purge);
-
- if (since_last_purge_ms < shard->opts.min_purge_interval_ms) {
- uint64_t until_purge_ns;
- until_purge_ns = shard->opts.min_purge_interval_ms -
- since_last_purge_ms;
- until_purge_ns *= 1000 * 1000;
-
- if (until_purge_ns < time_ns) {
- time_ns = until_purge_ns;
- }
- } else {
- time_ns = BACKGROUND_THREAD_DEFERRED_MIN;
- }
- }
- malloc_mutex_unlock(tsdn, &shard->mtx);
- return time_ns;
-}
-
-void
-hpa_shard_disable(tsdn_t *tsdn, hpa_shard_t *shard) {
- hpa_do_consistency_checks(shard);
-
- malloc_mutex_lock(tsdn, &shard->mtx);
- edata_cache_fast_disable(tsdn, &shard->ecf);
- malloc_mutex_unlock(tsdn, &shard->mtx);
-}
-
-static void
-hpa_shard_assert_stats_empty(psset_bin_stats_t *bin_stats) {
- assert(bin_stats->npageslabs == 0);
- assert(bin_stats->nactive == 0);
-}
-
-static void
-hpa_assert_empty(tsdn_t *tsdn, hpa_shard_t *shard, psset_t *psset) {
- malloc_mutex_assert_owner(tsdn, &shard->mtx);
- for (int huge = 0; huge <= 1; huge++) {
- hpa_shard_assert_stats_empty(&psset->stats.full_slabs[huge]);
- for (pszind_t i = 0; i < PSSET_NPSIZES; i++) {
- hpa_shard_assert_stats_empty(
- &psset->stats.nonfull_slabs[i][huge]);
- }
- }
-}
-
-void
-hpa_shard_destroy(tsdn_t *tsdn, hpa_shard_t *shard) {
- hpa_do_consistency_checks(shard);
- /*
- * By the time we're here, the arena code should have dalloc'd all the
- * active extents, which means we should have eventually evicted
- * everything from the psset, so it shouldn't be able to serve even a
- * 1-page allocation.
- */
- if (config_debug) {
- malloc_mutex_lock(tsdn, &shard->mtx);
- hpa_assert_empty(tsdn, shard, &shard->psset);
- malloc_mutex_unlock(tsdn, &shard->mtx);
- }
- hpdata_t *ps;
- while ((ps = psset_pick_alloc(&shard->psset, PAGE)) != NULL) {
- /* There should be no allocations anywhere. */
- assert(hpdata_empty(ps));
- psset_remove(&shard->psset, ps);
- shard->central->hooks.unmap(hpdata_addr_get(ps), HUGEPAGE);
- }
-}
-
-void
-hpa_shard_set_deferral_allowed(tsdn_t *tsdn, hpa_shard_t *shard,
- bool deferral_allowed) {
- hpa_do_consistency_checks(shard);
-
- malloc_mutex_lock(tsdn, &shard->mtx);
- bool deferral_previously_allowed = shard->opts.deferral_allowed;
- shard->opts.deferral_allowed = deferral_allowed;
- if (deferral_previously_allowed && !deferral_allowed) {
- hpa_shard_maybe_do_deferred_work(tsdn, shard,
- /* forced */ true);
- }
- malloc_mutex_unlock(tsdn, &shard->mtx);
-}
-
-void
-hpa_shard_do_deferred_work(tsdn_t *tsdn, hpa_shard_t *shard) {
- hpa_do_consistency_checks(shard);
-
- malloc_mutex_lock(tsdn, &shard->mtx);
- hpa_shard_maybe_do_deferred_work(tsdn, shard, /* forced */ true);
- malloc_mutex_unlock(tsdn, &shard->mtx);
-}
-
-void
-hpa_shard_prefork3(tsdn_t *tsdn, hpa_shard_t *shard) {
- hpa_do_consistency_checks(shard);
-
- malloc_mutex_prefork(tsdn, &shard->grow_mtx);
-}
-
-void
-hpa_shard_prefork4(tsdn_t *tsdn, hpa_shard_t *shard) {
- hpa_do_consistency_checks(shard);
-
- malloc_mutex_prefork(tsdn, &shard->mtx);
-}
-
-void
-hpa_shard_postfork_parent(tsdn_t *tsdn, hpa_shard_t *shard) {
- hpa_do_consistency_checks(shard);
-
- malloc_mutex_postfork_parent(tsdn, &shard->grow_mtx);
- malloc_mutex_postfork_parent(tsdn, &shard->mtx);
-}
-
-void
-hpa_shard_postfork_child(tsdn_t *tsdn, hpa_shard_t *shard) {
- hpa_do_consistency_checks(shard);
-
- malloc_mutex_postfork_child(tsdn, &shard->grow_mtx);
- malloc_mutex_postfork_child(tsdn, &shard->mtx);
-}
diff --git a/fluent-bit/lib/jemalloc-5.3.0/src/hpa_hooks.c b/fluent-bit/lib/jemalloc-5.3.0/src/hpa_hooks.c
deleted file mode 100644
index ade581e8..00000000
--- a/fluent-bit/lib/jemalloc-5.3.0/src/hpa_hooks.c
+++ /dev/null
@@ -1,63 +0,0 @@
-#include "jemalloc/internal/jemalloc_preamble.h"
-#include "jemalloc/internal/jemalloc_internal_includes.h"
-
-#include "jemalloc/internal/hpa_hooks.h"
-
-static void *hpa_hooks_map(size_t size);
-static void hpa_hooks_unmap(void *ptr, size_t size);
-static void hpa_hooks_purge(void *ptr, size_t size);
-static void hpa_hooks_hugify(void *ptr, size_t size);
-static void hpa_hooks_dehugify(void *ptr, size_t size);
-static void hpa_hooks_curtime(nstime_t *r_nstime, bool first_reading);
-static uint64_t hpa_hooks_ms_since(nstime_t *past_nstime);
-
-hpa_hooks_t hpa_hooks_default = {
- &hpa_hooks_map,
- &hpa_hooks_unmap,
- &hpa_hooks_purge,
- &hpa_hooks_hugify,
- &hpa_hooks_dehugify,
- &hpa_hooks_curtime,
- &hpa_hooks_ms_since
-};
-
-static void *
-hpa_hooks_map(size_t size) {
- bool commit = true;
- return pages_map(NULL, size, HUGEPAGE, &commit);
-}
-
-static void
-hpa_hooks_unmap(void *ptr, size_t size) {
- pages_unmap(ptr, size);
-}
-
-static void
-hpa_hooks_purge(void *ptr, size_t size) {
- pages_purge_forced(ptr, size);
-}
-
-static void
-hpa_hooks_hugify(void *ptr, size_t size) {
- bool err = pages_huge(ptr, size);
- (void)err;
-}
-
-static void
-hpa_hooks_dehugify(void *ptr, size_t size) {
- bool err = pages_nohuge(ptr, size);
- (void)err;
-}
-
-static void
-hpa_hooks_curtime(nstime_t *r_nstime, bool first_reading) {
- if (first_reading) {
- nstime_init_zero(r_nstime);
- }
- nstime_update(r_nstime);
-}
-
-static uint64_t
-hpa_hooks_ms_since(nstime_t *past_nstime) {
- return nstime_ns_since(past_nstime) / 1000 / 1000;
-}
diff --git a/fluent-bit/lib/jemalloc-5.3.0/src/hpdata.c b/fluent-bit/lib/jemalloc-5.3.0/src/hpdata.c
deleted file mode 100644
index e7d7294c..00000000
--- a/fluent-bit/lib/jemalloc-5.3.0/src/hpdata.c
+++ /dev/null
@@ -1,325 +0,0 @@
-#include "jemalloc/internal/jemalloc_preamble.h"
-#include "jemalloc/internal/jemalloc_internal_includes.h"
-
-#include "jemalloc/internal/hpdata.h"
-
-static int
-hpdata_age_comp(const hpdata_t *a, const hpdata_t *b) {
- uint64_t a_age = hpdata_age_get(a);
- uint64_t b_age = hpdata_age_get(b);
- /*
- * hpdata ages are operation counts in the psset; no two should be the
- * same.
- */
- assert(a_age != b_age);
- return (a_age > b_age) - (a_age < b_age);
-}
-
-ph_gen(, hpdata_age_heap, hpdata_t, age_link, hpdata_age_comp)
-
-void
-hpdata_init(hpdata_t *hpdata, void *addr, uint64_t age) {
- hpdata_addr_set(hpdata, addr);
- hpdata_age_set(hpdata, age);
- hpdata->h_huge = false;
- hpdata->h_alloc_allowed = true;
- hpdata->h_in_psset_alloc_container = false;
- hpdata->h_purge_allowed = false;
- hpdata->h_hugify_allowed = false;
- hpdata->h_in_psset_hugify_container = false;
- hpdata->h_mid_purge = false;
- hpdata->h_mid_hugify = false;
- hpdata->h_updating = false;
- hpdata->h_in_psset = false;
- hpdata_longest_free_range_set(hpdata, HUGEPAGE_PAGES);
- hpdata->h_nactive = 0;
- fb_init(hpdata->active_pages, HUGEPAGE_PAGES);
- hpdata->h_ntouched = 0;
- fb_init(hpdata->touched_pages, HUGEPAGE_PAGES);
-
- hpdata_assert_consistent(hpdata);
-}
-
-void *
-hpdata_reserve_alloc(hpdata_t *hpdata, size_t sz) {
- hpdata_assert_consistent(hpdata);
- /*
- * This is a metadata change; the hpdata should therefore either not be
- * in the psset, or should have explicitly marked itself as being
- * mid-update.
- */
- assert(!hpdata->h_in_psset || hpdata->h_updating);
- assert(hpdata->h_alloc_allowed);
- assert((sz & PAGE_MASK) == 0);
- size_t npages = sz >> LG_PAGE;
- assert(npages <= hpdata_longest_free_range_get(hpdata));
-
- size_t result;
-
- size_t start = 0;
- /*
- * These are dead stores, but the compiler will issue warnings on them
- * since it can't tell statically that found is always true below.
- */
- size_t begin = 0;
- size_t len = 0;
-
- size_t largest_unchosen_range = 0;
- while (true) {
- bool found = fb_urange_iter(hpdata->active_pages,
- HUGEPAGE_PAGES, start, &begin, &len);
- /*
- * A precondition to this function is that hpdata must be able
- * to serve the allocation.
- */
- assert(found);
- assert(len <= hpdata_longest_free_range_get(hpdata));
- if (len >= npages) {
- /*
- * We use first-fit within the page slabs; this gives
- * bounded worst-case fragmentation within a slab. It's
- * not necessarily right; we could experiment with
- * various other options.
- */
- break;
- }
- if (len > largest_unchosen_range) {
- largest_unchosen_range = len;
- }
- start = begin + len;
- }
- /* We found a range; remember it. */
- result = begin;
- fb_set_range(hpdata->active_pages, HUGEPAGE_PAGES, begin, npages);
- hpdata->h_nactive += npages;
-
- /*
- * We might be about to dirty some memory for the first time; update our
- * count if so.
- */
- size_t new_dirty = fb_ucount(hpdata->touched_pages, HUGEPAGE_PAGES,
- result, npages);
- fb_set_range(hpdata->touched_pages, HUGEPAGE_PAGES, result, npages);
- hpdata->h_ntouched += new_dirty;
-
- /*
- * If we allocated out of a range that was the longest in the hpdata, it
- * might be the only one of that size and we'll have to adjust the
- * metadata.
- */
- if (len == hpdata_longest_free_range_get(hpdata)) {
- start = begin + npages;
- while (start < HUGEPAGE_PAGES) {
- bool found = fb_urange_iter(hpdata->active_pages,
- HUGEPAGE_PAGES, start, &begin, &len);
- if (!found) {
- break;
- }
- assert(len <= hpdata_longest_free_range_get(hpdata));
- if (len == hpdata_longest_free_range_get(hpdata)) {
- largest_unchosen_range = len;
- break;
- }
- if (len > largest_unchosen_range) {
- largest_unchosen_range = len;
- }
- start = begin + len;
- }
- hpdata_longest_free_range_set(hpdata, largest_unchosen_range);
- }
-
- hpdata_assert_consistent(hpdata);
- return (void *)(
- (uintptr_t)hpdata_addr_get(hpdata) + (result << LG_PAGE));
-}
-
-void
-hpdata_unreserve(hpdata_t *hpdata, void *addr, size_t sz) {
- hpdata_assert_consistent(hpdata);
- /* See the comment in reserve. */
- assert(!hpdata->h_in_psset || hpdata->h_updating);
- assert(((uintptr_t)addr & PAGE_MASK) == 0);
- assert((sz & PAGE_MASK) == 0);
- size_t begin = ((uintptr_t)addr - (uintptr_t)hpdata_addr_get(hpdata))
- >> LG_PAGE;
- assert(begin < HUGEPAGE_PAGES);
- size_t npages = sz >> LG_PAGE;
- size_t old_longest_range = hpdata_longest_free_range_get(hpdata);
-
- fb_unset_range(hpdata->active_pages, HUGEPAGE_PAGES, begin, npages);
- /* We might have just created a new, larger range. */
- size_t new_begin = (fb_fls(hpdata->active_pages, HUGEPAGE_PAGES,
- begin) + 1);
- size_t new_end = fb_ffs(hpdata->active_pages, HUGEPAGE_PAGES,
- begin + npages - 1);
- size_t new_range_len = new_end - new_begin;
-
- if (new_range_len > old_longest_range) {
- hpdata_longest_free_range_set(hpdata, new_range_len);
- }
-
- hpdata->h_nactive -= npages;
-
- hpdata_assert_consistent(hpdata);
-}
-
-size_t
-hpdata_purge_begin(hpdata_t *hpdata, hpdata_purge_state_t *purge_state) {
- hpdata_assert_consistent(hpdata);
- /*
- * See the comment below; we might purge any inactive extent, so it's
- * unsafe for any other thread to turn any inactive extent active while
- * we're operating on it.
- */
- assert(!hpdata_alloc_allowed_get(hpdata));
-
- purge_state->npurged = 0;
- purge_state->next_purge_search_begin = 0;
-
- /*
- * Initialize to_purge.
- *
- * It's possible to end up in situations where two dirty extents are
- * separated by a retained extent:
- * - 1 page allocated.
- * - 1 page allocated.
- * - 1 pages allocated.
- *
- * If the middle page is freed and purged, and then the first and third
- * pages are freed, and then another purge pass happens, the hpdata
- * looks like this:
- * - 1 page dirty.
- * - 1 page retained.
- * - 1 page dirty.
- *
- * But it's safe to do a single 3-page purge.
- *
- * We do this by first computing the dirty pages, and then filling in
- * any gaps by extending each range in the dirty bitmap to extend until
- * the next active page. This purges more pages, but the expensive part
- * of purging is the TLB shootdowns, rather than the kernel state
- * tracking; doing a little bit more of the latter is fine if it saves
- * us from doing some of the former.
- */
-
- /*
- * The dirty pages are those that are touched but not active. Note that
- * in a normal-ish case, HUGEPAGE_PAGES is something like 512 and the
- * fb_group_t is 64 bits, so this is 64 bytes, spread across 8
- * fb_group_ts.
- */
- fb_group_t dirty_pages[FB_NGROUPS(HUGEPAGE_PAGES)];
- fb_init(dirty_pages, HUGEPAGE_PAGES);
- fb_bit_not(dirty_pages, hpdata->active_pages, HUGEPAGE_PAGES);
- fb_bit_and(dirty_pages, dirty_pages, hpdata->touched_pages,
- HUGEPAGE_PAGES);
-
- fb_init(purge_state->to_purge, HUGEPAGE_PAGES);
- size_t next_bit = 0;
- while (next_bit < HUGEPAGE_PAGES) {
- size_t next_dirty = fb_ffs(dirty_pages, HUGEPAGE_PAGES,
- next_bit);
- /* Recall that fb_ffs returns nbits if no set bit is found. */
- if (next_dirty == HUGEPAGE_PAGES) {
- break;
- }
- size_t next_active = fb_ffs(hpdata->active_pages,
- HUGEPAGE_PAGES, next_dirty);
- /*
- * Don't purge past the end of the dirty extent, into retained
- * pages. This helps the kernel a tiny bit, but honestly it's
- * mostly helpful for testing (where we tend to write test cases
- * that think in terms of the dirty ranges).
- */
- ssize_t last_dirty = fb_fls(dirty_pages, HUGEPAGE_PAGES,
- next_active - 1);
- assert(last_dirty >= 0);
- assert((size_t)last_dirty >= next_dirty);
- assert((size_t)last_dirty - next_dirty + 1 <= HUGEPAGE_PAGES);
-
- fb_set_range(purge_state->to_purge, HUGEPAGE_PAGES, next_dirty,
- last_dirty - next_dirty + 1);
- next_bit = next_active + 1;
- }
-
- /* We should purge, at least, everything dirty. */
- size_t ndirty = hpdata->h_ntouched - hpdata->h_nactive;
- purge_state->ndirty_to_purge = ndirty;
- assert(ndirty <= fb_scount(
- purge_state->to_purge, HUGEPAGE_PAGES, 0, HUGEPAGE_PAGES));
- assert(ndirty == fb_scount(dirty_pages, HUGEPAGE_PAGES, 0,
- HUGEPAGE_PAGES));
-
- hpdata_assert_consistent(hpdata);
-
- return ndirty;
-}
-
-bool
-hpdata_purge_next(hpdata_t *hpdata, hpdata_purge_state_t *purge_state,
- void **r_purge_addr, size_t *r_purge_size) {
- /*
- * Note that we don't have a consistency check here; we're accessing
- * hpdata without synchronization, and therefore have no right to expect
- * a consistent state.
- */
- assert(!hpdata_alloc_allowed_get(hpdata));
-
- if (purge_state->next_purge_search_begin == HUGEPAGE_PAGES) {
- return false;
- }
- size_t purge_begin;
- size_t purge_len;
- bool found_range = fb_srange_iter(purge_state->to_purge, HUGEPAGE_PAGES,
- purge_state->next_purge_search_begin, &purge_begin, &purge_len);
- if (!found_range) {
- return false;
- }
-
- *r_purge_addr = (void *)(
- (uintptr_t)hpdata_addr_get(hpdata) + purge_begin * PAGE);
- *r_purge_size = purge_len * PAGE;
-
- purge_state->next_purge_search_begin = purge_begin + purge_len;
- purge_state->npurged += purge_len;
- assert(purge_state->npurged <= HUGEPAGE_PAGES);
-
- return true;
-}
-
-void
-hpdata_purge_end(hpdata_t *hpdata, hpdata_purge_state_t *purge_state) {
- assert(!hpdata_alloc_allowed_get(hpdata));
- hpdata_assert_consistent(hpdata);
- /* See the comment in reserve. */
- assert(!hpdata->h_in_psset || hpdata->h_updating);
-
- assert(purge_state->npurged == fb_scount(purge_state->to_purge,
- HUGEPAGE_PAGES, 0, HUGEPAGE_PAGES));
- assert(purge_state->npurged >= purge_state->ndirty_to_purge);
-
- fb_bit_not(purge_state->to_purge, purge_state->to_purge,
- HUGEPAGE_PAGES);
- fb_bit_and(hpdata->touched_pages, hpdata->touched_pages,
- purge_state->to_purge, HUGEPAGE_PAGES);
- assert(hpdata->h_ntouched >= purge_state->ndirty_to_purge);
- hpdata->h_ntouched -= purge_state->ndirty_to_purge;
-
- hpdata_assert_consistent(hpdata);
-}
-
-void
-hpdata_hugify(hpdata_t *hpdata) {
- hpdata_assert_consistent(hpdata);
- hpdata->h_huge = true;
- fb_set_range(hpdata->touched_pages, HUGEPAGE_PAGES, 0, HUGEPAGE_PAGES);
- hpdata->h_ntouched = HUGEPAGE_PAGES;
- hpdata_assert_consistent(hpdata);
-}
-
-void
-hpdata_dehugify(hpdata_t *hpdata) {
- hpdata_assert_consistent(hpdata);
- hpdata->h_huge = false;
- hpdata_assert_consistent(hpdata);
-}
diff --git a/fluent-bit/lib/jemalloc-5.3.0/src/inspect.c b/fluent-bit/lib/jemalloc-5.3.0/src/inspect.c
deleted file mode 100644
index 911b5d52..00000000
--- a/fluent-bit/lib/jemalloc-5.3.0/src/inspect.c
+++ /dev/null
@@ -1,77 +0,0 @@
-#include "jemalloc/internal/jemalloc_preamble.h"
-#include "jemalloc/internal/jemalloc_internal_includes.h"
-
-void
-inspect_extent_util_stats_get(tsdn_t *tsdn, const void *ptr, size_t *nfree,
- size_t *nregs, size_t *size) {
- assert(ptr != NULL && nfree != NULL && nregs != NULL && size != NULL);
-
- const edata_t *edata = emap_edata_lookup(tsdn, &arena_emap_global, ptr);
- if (unlikely(edata == NULL)) {
- *nfree = *nregs = *size = 0;
- return;
- }
-
- *size = edata_size_get(edata);
- if (!edata_slab_get(edata)) {
- *nfree = 0;
- *nregs = 1;
- } else {
- *nfree = edata_nfree_get(edata);
- *nregs = bin_infos[edata_szind_get(edata)].nregs;
- assert(*nfree <= *nregs);
- assert(*nfree * edata_usize_get(edata) <= *size);
- }
-}
-
-void
-inspect_extent_util_stats_verbose_get(tsdn_t *tsdn, const void *ptr,
- size_t *nfree, size_t *nregs, size_t *size, size_t *bin_nfree,
- size_t *bin_nregs, void **slabcur_addr) {
- assert(ptr != NULL && nfree != NULL && nregs != NULL && size != NULL
- && bin_nfree != NULL && bin_nregs != NULL && slabcur_addr != NULL);
-
- const edata_t *edata = emap_edata_lookup(tsdn, &arena_emap_global, ptr);
- if (unlikely(edata == NULL)) {
- *nfree = *nregs = *size = *bin_nfree = *bin_nregs = 0;
- *slabcur_addr = NULL;
- return;
- }
-
- *size = edata_size_get(edata);
- if (!edata_slab_get(edata)) {
- *nfree = *bin_nfree = *bin_nregs = 0;
- *nregs = 1;
- *slabcur_addr = NULL;
- return;
- }
-
- *nfree = edata_nfree_get(edata);
- const szind_t szind = edata_szind_get(edata);
- *nregs = bin_infos[szind].nregs;
- assert(*nfree <= *nregs);
- assert(*nfree * edata_usize_get(edata) <= *size);
-
- arena_t *arena = (arena_t *)atomic_load_p(
- &arenas[edata_arena_ind_get(edata)], ATOMIC_RELAXED);
- assert(arena != NULL);
- const unsigned binshard = edata_binshard_get(edata);
- bin_t *bin = arena_get_bin(arena, szind, binshard);
-
- malloc_mutex_lock(tsdn, &bin->lock);
- if (config_stats) {
- *bin_nregs = *nregs * bin->stats.curslabs;
- assert(*bin_nregs >= bin->stats.curregs);
- *bin_nfree = *bin_nregs - bin->stats.curregs;
- } else {
- *bin_nfree = *bin_nregs = 0;
- }
- edata_t *slab;
- if (bin->slabcur != NULL) {
- slab = bin->slabcur;
- } else {
- slab = edata_heap_first(&bin->slabs_nonfull);
- }
- *slabcur_addr = slab != NULL ? edata_addr_get(slab) : NULL;
- malloc_mutex_unlock(tsdn, &bin->lock);
-}
diff --git a/fluent-bit/lib/jemalloc-5.3.0/src/jemalloc.c b/fluent-bit/lib/jemalloc-5.3.0/src/jemalloc.c
deleted file mode 100644
index 7655de4e..00000000
--- a/fluent-bit/lib/jemalloc-5.3.0/src/jemalloc.c
+++ /dev/null
@@ -1,4476 +0,0 @@
-#define JEMALLOC_C_
-#include "jemalloc/internal/jemalloc_preamble.h"
-#include "jemalloc/internal/jemalloc_internal_includes.h"
-
-#include "jemalloc/internal/assert.h"
-#include "jemalloc/internal/atomic.h"
-#include "jemalloc/internal/buf_writer.h"
-#include "jemalloc/internal/ctl.h"
-#include "jemalloc/internal/emap.h"
-#include "jemalloc/internal/extent_dss.h"
-#include "jemalloc/internal/extent_mmap.h"
-#include "jemalloc/internal/fxp.h"
-#include "jemalloc/internal/san.h"
-#include "jemalloc/internal/hook.h"
-#include "jemalloc/internal/jemalloc_internal_types.h"
-#include "jemalloc/internal/log.h"
-#include "jemalloc/internal/malloc_io.h"
-#include "jemalloc/internal/mutex.h"
-#include "jemalloc/internal/nstime.h"
-#include "jemalloc/internal/rtree.h"
-#include "jemalloc/internal/safety_check.h"
-#include "jemalloc/internal/sc.h"
-#include "jemalloc/internal/spin.h"
-#include "jemalloc/internal/sz.h"
-#include "jemalloc/internal/ticker.h"
-#include "jemalloc/internal/thread_event.h"
-#include "jemalloc/internal/util.h"
-
-/******************************************************************************/
-/* Data. */
-
-/* Runtime configuration options. */
-const char *je_malloc_conf
-#ifndef _WIN32
- JEMALLOC_ATTR(weak)
-#endif
- ;
-/*
- * The usual rule is that the closer to runtime you are, the higher priority
- * your configuration settings are (so the jemalloc config options get lower
- * priority than the per-binary setting, which gets lower priority than the /etc
- * setting, which gets lower priority than the environment settings).
- *
- * But it's a fairly common use case in some testing environments for a user to
- * be able to control the binary, but nothing else (e.g. a performancy canary
- * uses the production OS and environment variables, but can run any binary in
- * those circumstances). For these use cases, it's handy to have an in-binary
- * mechanism for overriding environment variable settings, with the idea that if
- * the results are positive they get promoted to the official settings, and
- * moved from the binary to the environment variable.
- *
- * We don't actually want this to be widespread, so we'll give it a silly name
- * and not mention it in headers or documentation.
- */
-const char *je_malloc_conf_2_conf_harder
-#ifndef _WIN32
- JEMALLOC_ATTR(weak)
-#endif
- ;
-
-bool opt_abort =
-#ifdef JEMALLOC_DEBUG
- true
-#else
- false
-#endif
- ;
-bool opt_abort_conf =
-#ifdef JEMALLOC_DEBUG
- true
-#else
- false
-#endif
- ;
-/* Intentionally default off, even with debug builds. */
-bool opt_confirm_conf = false;
-const char *opt_junk =
-#if (defined(JEMALLOC_DEBUG) && defined(JEMALLOC_FILL))
- "true"
-#else
- "false"
-#endif
- ;
-bool opt_junk_alloc =
-#if (defined(JEMALLOC_DEBUG) && defined(JEMALLOC_FILL))
- true
-#else
- false
-#endif
- ;
-bool opt_junk_free =
-#if (defined(JEMALLOC_DEBUG) && defined(JEMALLOC_FILL))
- true
-#else
- false
-#endif
- ;
-bool opt_trust_madvise =
-#ifdef JEMALLOC_PURGE_MADVISE_DONTNEED_ZEROS
- false
-#else
- true
-#endif
- ;
-
-bool opt_cache_oblivious =
-#ifdef JEMALLOC_CACHE_OBLIVIOUS
- true
-#else
- false
-#endif
- ;
-
-zero_realloc_action_t opt_zero_realloc_action =
-#ifdef JEMALLOC_ZERO_REALLOC_DEFAULT_FREE
- zero_realloc_action_free
-#else
- zero_realloc_action_alloc
-#endif
- ;
-
-atomic_zu_t zero_realloc_count = ATOMIC_INIT(0);
-
-const char *zero_realloc_mode_names[] = {
- "alloc",
- "free",
- "abort",
-};
-
-/*
- * These are the documented values for junk fill debugging facilities -- see the
- * man page.
- */
-static const uint8_t junk_alloc_byte = 0xa5;
-static const uint8_t junk_free_byte = 0x5a;
-
-static void default_junk_alloc(void *ptr, size_t usize) {
- memset(ptr, junk_alloc_byte, usize);
-}
-
-static void default_junk_free(void *ptr, size_t usize) {
- memset(ptr, junk_free_byte, usize);
-}
-
-void (*junk_alloc_callback)(void *ptr, size_t size) = &default_junk_alloc;
-void (*junk_free_callback)(void *ptr, size_t size) = &default_junk_free;
-
-bool opt_utrace = false;
-bool opt_xmalloc = false;
-bool opt_experimental_infallible_new = false;
-bool opt_zero = false;
-unsigned opt_narenas = 0;
-fxp_t opt_narenas_ratio = FXP_INIT_INT(4);
-
-unsigned ncpus;
-
-/* Protects arenas initialization. */
-malloc_mutex_t arenas_lock;
-
-/* The global hpa, and whether it's on. */
-bool opt_hpa = false;
-hpa_shard_opts_t opt_hpa_opts = HPA_SHARD_OPTS_DEFAULT;
-sec_opts_t opt_hpa_sec_opts = SEC_OPTS_DEFAULT;
-
-/*
- * Arenas that are used to service external requests. Not all elements of the
- * arenas array are necessarily used; arenas are created lazily as needed.
- *
- * arenas[0..narenas_auto) are used for automatic multiplexing of threads and
- * arenas. arenas[narenas_auto..narenas_total) are only used if the application
- * takes some action to create them and allocate from them.
- *
- * Points to an arena_t.
- */
-JEMALLOC_ALIGNED(CACHELINE)
-atomic_p_t arenas[MALLOCX_ARENA_LIMIT];
-static atomic_u_t narenas_total; /* Use narenas_total_*(). */
-/* Below three are read-only after initialization. */
-static arena_t *a0; /* arenas[0]. */
-unsigned narenas_auto;
-unsigned manual_arena_base;
-
-malloc_init_t malloc_init_state = malloc_init_uninitialized;
-
-/* False should be the common case. Set to true to trigger initialization. */
-bool malloc_slow = true;
-
-/* When malloc_slow is true, set the corresponding bits for sanity check. */
-enum {
- flag_opt_junk_alloc = (1U),
- flag_opt_junk_free = (1U << 1),
- flag_opt_zero = (1U << 2),
- flag_opt_utrace = (1U << 3),
- flag_opt_xmalloc = (1U << 4)
-};
-static uint8_t malloc_slow_flags;
-
-#ifdef JEMALLOC_THREADED_INIT
-/* Used to let the initializing thread recursively allocate. */
-# define NO_INITIALIZER ((unsigned long)0)
-# define INITIALIZER pthread_self()
-# define IS_INITIALIZER (malloc_initializer == pthread_self())
-static pthread_t malloc_initializer = NO_INITIALIZER;
-#else
-# define NO_INITIALIZER false
-# define INITIALIZER true
-# define IS_INITIALIZER malloc_initializer
-static bool malloc_initializer = NO_INITIALIZER;
-#endif
-
-/* Used to avoid initialization races. */
-#ifdef _WIN32
-#if _WIN32_WINNT >= 0x0600
-static malloc_mutex_t init_lock = SRWLOCK_INIT;
-#else
-static malloc_mutex_t init_lock;
-static bool init_lock_initialized = false;
-
-JEMALLOC_ATTR(constructor)
-static void WINAPI
-_init_init_lock(void) {
- /*
- * If another constructor in the same binary is using mallctl to e.g.
- * set up extent hooks, it may end up running before this one, and
- * malloc_init_hard will crash trying to lock the uninitialized lock. So
- * we force an initialization of the lock in malloc_init_hard as well.
- * We don't try to care about atomicity of the accessed to the
- * init_lock_initialized boolean, since it really only matters early in
- * the process creation, before any separate thread normally starts
- * doing anything.
- */
- if (!init_lock_initialized) {
- malloc_mutex_init(&init_lock, "init", WITNESS_RANK_INIT,
- malloc_mutex_rank_exclusive);
- }
- init_lock_initialized = true;
-}
-
-#ifdef _MSC_VER
-# pragma section(".CRT$XCU", read)
-JEMALLOC_SECTION(".CRT$XCU") JEMALLOC_ATTR(used)
-static const void (WINAPI *init_init_lock)(void) = _init_init_lock;
-#endif
-#endif
-#else
-static malloc_mutex_t init_lock = MALLOC_MUTEX_INITIALIZER;
-#endif
-
-typedef struct {
- void *p; /* Input pointer (as in realloc(p, s)). */
- size_t s; /* Request size. */
- void *r; /* Result pointer. */
-} malloc_utrace_t;
-
-#ifdef JEMALLOC_UTRACE
-# define UTRACE(a, b, c) do { \
- if (unlikely(opt_utrace)) { \
- int utrace_serrno = errno; \
- malloc_utrace_t ut; \
- ut.p = (a); \
- ut.s = (b); \
- ut.r = (c); \
- UTRACE_CALL(&ut, sizeof(ut)); \
- errno = utrace_serrno; \
- } \
-} while (0)
-#else
-# define UTRACE(a, b, c)
-#endif
-
-/* Whether encountered any invalid config options. */
-static bool had_conf_error = false;
-
-/******************************************************************************/
-/*
- * Function prototypes for static functions that are referenced prior to
- * definition.
- */
-
-static bool malloc_init_hard_a0(void);
-static bool malloc_init_hard(void);
-
-/******************************************************************************/
-/*
- * Begin miscellaneous support functions.
- */
-
-JEMALLOC_ALWAYS_INLINE bool
-malloc_init_a0(void) {
- if (unlikely(malloc_init_state == malloc_init_uninitialized)) {
- return malloc_init_hard_a0();
- }
- return false;
-}
-
-JEMALLOC_ALWAYS_INLINE bool
-malloc_init(void) {
- if (unlikely(!malloc_initialized()) && malloc_init_hard()) {
- return true;
- }
- return false;
-}
-
-/*
- * The a0*() functions are used instead of i{d,}alloc() in situations that
- * cannot tolerate TLS variable access.
- */
-
-static void *
-a0ialloc(size_t size, bool zero, bool is_internal) {
- if (unlikely(malloc_init_a0())) {
- return NULL;
- }
-
- return iallocztm(TSDN_NULL, size, sz_size2index(size), zero, NULL,
- is_internal, arena_get(TSDN_NULL, 0, true), true);
-}
-
-static void
-a0idalloc(void *ptr, bool is_internal) {
- idalloctm(TSDN_NULL, ptr, NULL, NULL, is_internal, true);
-}
-
-void *
-a0malloc(size_t size) {
- return a0ialloc(size, false, true);
-}
-
-void
-a0dalloc(void *ptr) {
- a0idalloc(ptr, true);
-}
-
-/*
- * FreeBSD's libc uses the bootstrap_*() functions in bootstrap-sensitive
- * situations that cannot tolerate TLS variable access (TLS allocation and very
- * early internal data structure initialization).
- */
-
-void *
-bootstrap_malloc(size_t size) {
- if (unlikely(size == 0)) {
- size = 1;
- }
-
- return a0ialloc(size, false, false);
-}
-
-void *
-bootstrap_calloc(size_t num, size_t size) {
- size_t num_size;
-
- num_size = num * size;
- if (unlikely(num_size == 0)) {
- assert(num == 0 || size == 0);
- num_size = 1;
- }
-
- return a0ialloc(num_size, true, false);
-}
-
-void
-bootstrap_free(void *ptr) {
- if (unlikely(ptr == NULL)) {
- return;
- }
-
- a0idalloc(ptr, false);
-}
-
-void
-arena_set(unsigned ind, arena_t *arena) {
- atomic_store_p(&arenas[ind], arena, ATOMIC_RELEASE);
-}
-
-static void
-narenas_total_set(unsigned narenas) {
- atomic_store_u(&narenas_total, narenas, ATOMIC_RELEASE);
-}
-
-static void
-narenas_total_inc(void) {
- atomic_fetch_add_u(&narenas_total, 1, ATOMIC_RELEASE);
-}
-
-unsigned
-narenas_total_get(void) {
- return atomic_load_u(&narenas_total, ATOMIC_ACQUIRE);
-}
-
-/* Create a new arena and insert it into the arenas array at index ind. */
-static arena_t *
-arena_init_locked(tsdn_t *tsdn, unsigned ind, const arena_config_t *config) {
- arena_t *arena;
-
- assert(ind <= narenas_total_get());
- if (ind >= MALLOCX_ARENA_LIMIT) {
- return NULL;
- }
- if (ind == narenas_total_get()) {
- narenas_total_inc();
- }
-
- /*
- * Another thread may have already initialized arenas[ind] if it's an
- * auto arena.
- */
- arena = arena_get(tsdn, ind, false);
- if (arena != NULL) {
- assert(arena_is_auto(arena));
- return arena;
- }
-
- /* Actually initialize the arena. */
- arena = arena_new(tsdn, ind, config);
-
- return arena;
-}
-
-static void
-arena_new_create_background_thread(tsdn_t *tsdn, unsigned ind) {
- if (ind == 0) {
- return;
- }
- /*
- * Avoid creating a new background thread just for the huge arena, which
- * purges eagerly by default.
- */
- if (have_background_thread && !arena_is_huge(ind)) {
- if (background_thread_create(tsdn_tsd(tsdn), ind)) {
- malloc_printf("<jemalloc>: error in background thread "
- "creation for arena %u. Abort.\n", ind);
- abort();
- }
- }
-}
-
-arena_t *
-arena_init(tsdn_t *tsdn, unsigned ind, const arena_config_t *config) {
- arena_t *arena;
-
- malloc_mutex_lock(tsdn, &arenas_lock);
- arena = arena_init_locked(tsdn, ind, config);
- malloc_mutex_unlock(tsdn, &arenas_lock);
-
- arena_new_create_background_thread(tsdn, ind);
-
- return arena;
-}
-
-static void
-arena_bind(tsd_t *tsd, unsigned ind, bool internal) {
- arena_t *arena = arena_get(tsd_tsdn(tsd), ind, false);
- arena_nthreads_inc(arena, internal);
-
- if (internal) {
- tsd_iarena_set(tsd, arena);
- } else {
- tsd_arena_set(tsd, arena);
- unsigned shard = atomic_fetch_add_u(&arena->binshard_next, 1,
- ATOMIC_RELAXED);
- tsd_binshards_t *bins = tsd_binshardsp_get(tsd);
- for (unsigned i = 0; i < SC_NBINS; i++) {
- assert(bin_infos[i].n_shards > 0 &&
- bin_infos[i].n_shards <= BIN_SHARDS_MAX);
- bins->binshard[i] = shard % bin_infos[i].n_shards;
- }
- }
-}
-
-void
-arena_migrate(tsd_t *tsd, arena_t *oldarena, arena_t *newarena) {
- assert(oldarena != NULL);
- assert(newarena != NULL);
-
- arena_nthreads_dec(oldarena, false);
- arena_nthreads_inc(newarena, false);
- tsd_arena_set(tsd, newarena);
-
- if (arena_nthreads_get(oldarena, false) == 0) {
- /* Purge if the old arena has no associated threads anymore. */
- arena_decay(tsd_tsdn(tsd), oldarena,
- /* is_background_thread */ false, /* all */ true);
- }
-}
-
-static void
-arena_unbind(tsd_t *tsd, unsigned ind, bool internal) {
- arena_t *arena;
-
- arena = arena_get(tsd_tsdn(tsd), ind, false);
- arena_nthreads_dec(arena, internal);
-
- if (internal) {
- tsd_iarena_set(tsd, NULL);
- } else {
- tsd_arena_set(tsd, NULL);
- }
-}
-
-/* Slow path, called only by arena_choose(). */
-arena_t *
-arena_choose_hard(tsd_t *tsd, bool internal) {
- arena_t *ret JEMALLOC_CC_SILENCE_INIT(NULL);
-
- if (have_percpu_arena && PERCPU_ARENA_ENABLED(opt_percpu_arena)) {
- unsigned choose = percpu_arena_choose();
- ret = arena_get(tsd_tsdn(tsd), choose, true);
- assert(ret != NULL);
- arena_bind(tsd, arena_ind_get(ret), false);
- arena_bind(tsd, arena_ind_get(ret), true);
-
- return ret;
- }
-
- if (narenas_auto > 1) {
- unsigned i, j, choose[2], first_null;
- bool is_new_arena[2];
-
- /*
- * Determine binding for both non-internal and internal
- * allocation.
- *
- * choose[0]: For application allocation.
- * choose[1]: For internal metadata allocation.
- */
-
- for (j = 0; j < 2; j++) {
- choose[j] = 0;
- is_new_arena[j] = false;
- }
-
- first_null = narenas_auto;
- malloc_mutex_lock(tsd_tsdn(tsd), &arenas_lock);
- assert(arena_get(tsd_tsdn(tsd), 0, false) != NULL);
- for (i = 1; i < narenas_auto; i++) {
- if (arena_get(tsd_tsdn(tsd), i, false) != NULL) {
- /*
- * Choose the first arena that has the lowest
- * number of threads assigned to it.
- */
- for (j = 0; j < 2; j++) {
- if (arena_nthreads_get(arena_get(
- tsd_tsdn(tsd), i, false), !!j) <
- arena_nthreads_get(arena_get(
- tsd_tsdn(tsd), choose[j], false),
- !!j)) {
- choose[j] = i;
- }
- }
- } else if (first_null == narenas_auto) {
- /*
- * Record the index of the first uninitialized
- * arena, in case all extant arenas are in use.
- *
- * NB: It is possible for there to be
- * discontinuities in terms of initialized
- * versus uninitialized arenas, due to the
- * "thread.arena" mallctl.
- */
- first_null = i;
- }
- }
-
- for (j = 0; j < 2; j++) {
- if (arena_nthreads_get(arena_get(tsd_tsdn(tsd),
- choose[j], false), !!j) == 0 || first_null ==
- narenas_auto) {
- /*
- * Use an unloaded arena, or the least loaded
- * arena if all arenas are already initialized.
- */
- if (!!j == internal) {
- ret = arena_get(tsd_tsdn(tsd),
- choose[j], false);
- }
- } else {
- arena_t *arena;
-
- /* Initialize a new arena. */
- choose[j] = first_null;
- arena = arena_init_locked(tsd_tsdn(tsd),
- choose[j], &arena_config_default);
- if (arena == NULL) {
- malloc_mutex_unlock(tsd_tsdn(tsd),
- &arenas_lock);
- return NULL;
- }
- is_new_arena[j] = true;
- if (!!j == internal) {
- ret = arena;
- }
- }
- arena_bind(tsd, choose[j], !!j);
- }
- malloc_mutex_unlock(tsd_tsdn(tsd), &arenas_lock);
-
- for (j = 0; j < 2; j++) {
- if (is_new_arena[j]) {
- assert(choose[j] > 0);
- arena_new_create_background_thread(
- tsd_tsdn(tsd), choose[j]);
- }
- }
-
- } else {
- ret = arena_get(tsd_tsdn(tsd), 0, false);
- arena_bind(tsd, 0, false);
- arena_bind(tsd, 0, true);
- }
-
- return ret;
-}
-
-void
-iarena_cleanup(tsd_t *tsd) {
- arena_t *iarena;
-
- iarena = tsd_iarena_get(tsd);
- if (iarena != NULL) {
- arena_unbind(tsd, arena_ind_get(iarena), true);
- }
-}
-
-void
-arena_cleanup(tsd_t *tsd) {
- arena_t *arena;
-
- arena = tsd_arena_get(tsd);
- if (arena != NULL) {
- arena_unbind(tsd, arena_ind_get(arena), false);
- }
-}
-
-static void
-stats_print_atexit(void) {
- if (config_stats) {
- tsdn_t *tsdn;
- unsigned narenas, i;
-
- tsdn = tsdn_fetch();
-
- /*
- * Merge stats from extant threads. This is racy, since
- * individual threads do not lock when recording tcache stats
- * events. As a consequence, the final stats may be slightly
- * out of date by the time they are reported, if other threads
- * continue to allocate.
- */
- for (i = 0, narenas = narenas_total_get(); i < narenas; i++) {
- arena_t *arena = arena_get(tsdn, i, false);
- if (arena != NULL) {
- tcache_slow_t *tcache_slow;
-
- malloc_mutex_lock(tsdn, &arena->tcache_ql_mtx);
- ql_foreach(tcache_slow, &arena->tcache_ql,
- link) {
- tcache_stats_merge(tsdn,
- tcache_slow->tcache, arena);
- }
- malloc_mutex_unlock(tsdn,
- &arena->tcache_ql_mtx);
- }
- }
- }
- je_malloc_stats_print(NULL, NULL, opt_stats_print_opts);
-}
-
-/*
- * Ensure that we don't hold any locks upon entry to or exit from allocator
- * code (in a "broad" sense that doesn't count a reentrant allocation as an
- * entrance or exit).
- */
-JEMALLOC_ALWAYS_INLINE void
-check_entry_exit_locking(tsdn_t *tsdn) {
- if (!config_debug) {
- return;
- }
- if (tsdn_null(tsdn)) {
- return;
- }
- tsd_t *tsd = tsdn_tsd(tsdn);
- /*
- * It's possible we hold locks at entry/exit if we're in a nested
- * allocation.
- */
- int8_t reentrancy_level = tsd_reentrancy_level_get(tsd);
- if (reentrancy_level != 0) {
- return;
- }
- witness_assert_lockless(tsdn_witness_tsdp_get(tsdn));
-}
-
-/*
- * End miscellaneous support functions.
- */
-/******************************************************************************/
-/*
- * Begin initialization functions.
- */
-
-static char *
-jemalloc_secure_getenv(const char *name) {
-#ifdef JEMALLOC_HAVE_SECURE_GETENV
- return secure_getenv(name);
-#else
-# ifdef JEMALLOC_HAVE_ISSETUGID
- if (issetugid() != 0) {
- return NULL;
- }
-# endif
- return getenv(name);
-#endif
-}
-
-static unsigned
-malloc_ncpus(void) {
- long result;
-
-#ifdef _WIN32
- SYSTEM_INFO si;
- GetSystemInfo(&si);
- result = si.dwNumberOfProcessors;
-#elif defined(CPU_COUNT)
- /*
- * glibc >= 2.6 has the CPU_COUNT macro.
- *
- * glibc's sysconf() uses isspace(). glibc allocates for the first time
- * *before* setting up the isspace tables. Therefore we need a
- * different method to get the number of CPUs.
- *
- * The getaffinity approach is also preferred when only a subset of CPUs
- * is available, to avoid using more arenas than necessary.
- */
- {
-# if defined(__FreeBSD__) || defined(__DragonFly__)
- cpuset_t set;
-# else
- cpu_set_t set;
-# endif
-# if defined(JEMALLOC_HAVE_SCHED_SETAFFINITY)
- sched_getaffinity(0, sizeof(set), &set);
-# else
- pthread_getaffinity_np(pthread_self(), sizeof(set), &set);
-# endif
- result = CPU_COUNT(&set);
- }
-#else
- result = sysconf(_SC_NPROCESSORS_ONLN);
-#endif
- return ((result == -1) ? 1 : (unsigned)result);
-}
-
-/*
- * Ensure that number of CPUs is determistinc, i.e. it is the same based on:
- * - sched_getaffinity()
- * - _SC_NPROCESSORS_ONLN
- * - _SC_NPROCESSORS_CONF
- * Since otherwise tricky things is possible with percpu arenas in use.
- */
-static bool
-malloc_cpu_count_is_deterministic()
-{
-#ifdef _WIN32
- return true;
-#else
- long cpu_onln = sysconf(_SC_NPROCESSORS_ONLN);
- long cpu_conf = sysconf(_SC_NPROCESSORS_CONF);
- if (cpu_onln != cpu_conf) {
- return false;
- }
-# if defined(CPU_COUNT)
-# if defined(__FreeBSD__) || defined(__DragonFly__)
- cpuset_t set;
-# else
- cpu_set_t set;
-# endif /* __FreeBSD__ */
-# if defined(JEMALLOC_HAVE_SCHED_SETAFFINITY)
- sched_getaffinity(0, sizeof(set), &set);
-# else /* !JEMALLOC_HAVE_SCHED_SETAFFINITY */
- pthread_getaffinity_np(pthread_self(), sizeof(set), &set);
-# endif /* JEMALLOC_HAVE_SCHED_SETAFFINITY */
- long cpu_affinity = CPU_COUNT(&set);
- if (cpu_affinity != cpu_conf) {
- return false;
- }
-# endif /* CPU_COUNT */
- return true;
-#endif
-}
-
-static void
-init_opt_stats_opts(const char *v, size_t vlen, char *dest) {
- size_t opts_len = strlen(dest);
- assert(opts_len <= stats_print_tot_num_options);
-
- for (size_t i = 0; i < vlen; i++) {
- switch (v[i]) {
-#define OPTION(o, v, d, s) case o: break;
- STATS_PRINT_OPTIONS
-#undef OPTION
- default: continue;
- }
-
- if (strchr(dest, v[i]) != NULL) {
- /* Ignore repeated. */
- continue;
- }
-
- dest[opts_len++] = v[i];
- dest[opts_len] = '\0';
- assert(opts_len <= stats_print_tot_num_options);
- }
- assert(opts_len == strlen(dest));
-}
-
-/* Reads the next size pair in a multi-sized option. */
-static bool
-malloc_conf_multi_sizes_next(const char **slab_size_segment_cur,
- size_t *vlen_left, size_t *slab_start, size_t *slab_end, size_t *new_size) {
- const char *cur = *slab_size_segment_cur;
- char *end;
- uintmax_t um;
-
- set_errno(0);
-
- /* First number, then '-' */
- um = malloc_strtoumax(cur, &end, 0);
- if (get_errno() != 0 || *end != '-') {
- return true;
- }
- *slab_start = (size_t)um;
- cur = end + 1;
-
- /* Second number, then ':' */
- um = malloc_strtoumax(cur, &end, 0);
- if (get_errno() != 0 || *end != ':') {
- return true;
- }
- *slab_end = (size_t)um;
- cur = end + 1;
-
- /* Last number */
- um = malloc_strtoumax(cur, &end, 0);
- if (get_errno() != 0) {
- return true;
- }
- *new_size = (size_t)um;
-
- /* Consume the separator if there is one. */
- if (*end == '|') {
- end++;
- }
-
- *vlen_left -= end - *slab_size_segment_cur;
- *slab_size_segment_cur = end;
-
- return false;
-}
-
-static bool
-malloc_conf_next(char const **opts_p, char const **k_p, size_t *klen_p,
- char const **v_p, size_t *vlen_p) {
- bool accept;
- const char *opts = *opts_p;
-
- *k_p = opts;
-
- for (accept = false; !accept;) {
- switch (*opts) {
- case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
- case 'G': case 'H': case 'I': case 'J': case 'K': case 'L':
- case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R':
- case 'S': case 'T': case 'U': case 'V': case 'W': case 'X':
- case 'Y': case 'Z':
- case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
- case 'g': case 'h': case 'i': case 'j': case 'k': case 'l':
- case 'm': case 'n': case 'o': case 'p': case 'q': case 'r':
- case 's': case 't': case 'u': case 'v': case 'w': case 'x':
- case 'y': case 'z':
- case '0': case '1': case '2': case '3': case '4': case '5':
- case '6': case '7': case '8': case '9':
- case '_':
- opts++;
- break;
- case ':':
- opts++;
- *klen_p = (uintptr_t)opts - 1 - (uintptr_t)*k_p;
- *v_p = opts;
- accept = true;
- break;
- case '\0':
- if (opts != *opts_p) {
- malloc_write("<jemalloc>: Conf string ends "
- "with key\n");
- had_conf_error = true;
- }
- return true;
- default:
- malloc_write("<jemalloc>: Malformed conf string\n");
- had_conf_error = true;
- return true;
- }
- }
-
- for (accept = false; !accept;) {
- switch (*opts) {
- case ',':
- opts++;
- /*
- * Look ahead one character here, because the next time
- * this function is called, it will assume that end of
- * input has been cleanly reached if no input remains,
- * but we have optimistically already consumed the
- * comma if one exists.
- */
- if (*opts == '\0') {
- malloc_write("<jemalloc>: Conf string ends "
- "with comma\n");
- had_conf_error = true;
- }
- *vlen_p = (uintptr_t)opts - 1 - (uintptr_t)*v_p;
- accept = true;
- break;
- case '\0':
- *vlen_p = (uintptr_t)opts - (uintptr_t)*v_p;
- accept = true;
- break;
- default:
- opts++;
- break;
- }
- }
-
- *opts_p = opts;
- return false;
-}
-
-static void
-malloc_abort_invalid_conf(void) {
- assert(opt_abort_conf);
- malloc_printf("<jemalloc>: Abort (abort_conf:true) on invalid conf "
- "value (see above).\n");
- abort();
-}
-
-static void
-malloc_conf_error(const char *msg, const char *k, size_t klen, const char *v,
- size_t vlen) {
- malloc_printf("<jemalloc>: %s: %.*s:%.*s\n", msg, (int)klen, k,
- (int)vlen, v);
- /* If abort_conf is set, error out after processing all options. */
- const char *experimental = "experimental_";
- if (strncmp(k, experimental, strlen(experimental)) == 0) {
- /* However, tolerate experimental features. */
- return;
- }
- had_conf_error = true;
-}
-
-static void
-malloc_slow_flag_init(void) {
- /*
- * Combine the runtime options into malloc_slow for fast path. Called
- * after processing all the options.
- */
- malloc_slow_flags |= (opt_junk_alloc ? flag_opt_junk_alloc : 0)
- | (opt_junk_free ? flag_opt_junk_free : 0)
- | (opt_zero ? flag_opt_zero : 0)
- | (opt_utrace ? flag_opt_utrace : 0)
- | (opt_xmalloc ? flag_opt_xmalloc : 0);
-
- malloc_slow = (malloc_slow_flags != 0);
-}
-
-/* Number of sources for initializing malloc_conf */
-#define MALLOC_CONF_NSOURCES 5
-
-static const char *
-obtain_malloc_conf(unsigned which_source, char buf[PATH_MAX + 1]) {
- if (config_debug) {
- static unsigned read_source = 0;
- /*
- * Each source should only be read once, to minimize # of
- * syscalls on init.
- */
- assert(read_source++ == which_source);
- }
- assert(which_source < MALLOC_CONF_NSOURCES);
-
- const char *ret;
- switch (which_source) {
- case 0:
- ret = config_malloc_conf;
- break;
- case 1:
- if (je_malloc_conf != NULL) {
- /* Use options that were compiled into the program. */
- ret = je_malloc_conf;
- } else {
- /* No configuration specified. */
- ret = NULL;
- }
- break;
- case 2: {
- ssize_t linklen = 0;
-#ifndef _WIN32
- int saved_errno = errno;
- const char *linkname =
-# ifdef JEMALLOC_PREFIX
- "/etc/"JEMALLOC_PREFIX"malloc.conf"
-# else
- "/etc/malloc.conf"
-# endif
- ;
-
- /*
- * Try to use the contents of the "/etc/malloc.conf" symbolic
- * link's name.
- */
-#ifndef JEMALLOC_READLINKAT
- linklen = readlink(linkname, buf, PATH_MAX);
-#else
- linklen = readlinkat(AT_FDCWD, linkname, buf, PATH_MAX);
-#endif
- if (linklen == -1) {
- /* No configuration specified. */
- linklen = 0;
- /* Restore errno. */
- set_errno(saved_errno);
- }
-#endif
- buf[linklen] = '\0';
- ret = buf;
- break;
- } case 3: {
- const char *envname =
-#ifdef JEMALLOC_PREFIX
- JEMALLOC_CPREFIX"MALLOC_CONF"
-#else
- "MALLOC_CONF"
-#endif
- ;
-
- if ((ret = jemalloc_secure_getenv(envname)) != NULL) {
- /*
- * Do nothing; opts is already initialized to the value
- * of the MALLOC_CONF environment variable.
- */
- } else {
- /* No configuration specified. */
- ret = NULL;
- }
- break;
- } case 4: {
- ret = je_malloc_conf_2_conf_harder;
- break;
- } default:
- not_reached();
- ret = NULL;
- }
- return ret;
-}
-
-static void
-malloc_conf_init_helper(sc_data_t *sc_data, unsigned bin_shard_sizes[SC_NBINS],
- bool initial_call, const char *opts_cache[MALLOC_CONF_NSOURCES],
- char buf[PATH_MAX + 1]) {
- static const char *opts_explain[MALLOC_CONF_NSOURCES] = {
- "string specified via --with-malloc-conf",
- "string pointed to by the global variable malloc_conf",
- "\"name\" of the file referenced by the symbolic link named "
- "/etc/malloc.conf",
- "value of the environment variable MALLOC_CONF",
- "string pointed to by the global variable "
- "malloc_conf_2_conf_harder",
- };
- unsigned i;
- const char *opts, *k, *v;
- size_t klen, vlen;
-
- for (i = 0; i < MALLOC_CONF_NSOURCES; i++) {
- /* Get runtime configuration. */
- if (initial_call) {
- opts_cache[i] = obtain_malloc_conf(i, buf);
- }
- opts = opts_cache[i];
- if (!initial_call && opt_confirm_conf) {
- malloc_printf(
- "<jemalloc>: malloc_conf #%u (%s): \"%s\"\n",
- i + 1, opts_explain[i], opts != NULL ? opts : "");
- }
- if (opts == NULL) {
- continue;
- }
-
- while (*opts != '\0' && !malloc_conf_next(&opts, &k, &klen, &v,
- &vlen)) {
-
-#define CONF_ERROR(msg, k, klen, v, vlen) \
- if (!initial_call) { \
- malloc_conf_error( \
- msg, k, klen, v, vlen); \
- cur_opt_valid = false; \
- }
-#define CONF_CONTINUE { \
- if (!initial_call && opt_confirm_conf \
- && cur_opt_valid) { \
- malloc_printf("<jemalloc>: -- " \
- "Set conf value: %.*s:%.*s" \
- "\n", (int)klen, k, \
- (int)vlen, v); \
- } \
- continue; \
- }
-#define CONF_MATCH(n) \
- (sizeof(n)-1 == klen && strncmp(n, k, klen) == 0)
-#define CONF_MATCH_VALUE(n) \
- (sizeof(n)-1 == vlen && strncmp(n, v, vlen) == 0)
-#define CONF_HANDLE_BOOL(o, n) \
- if (CONF_MATCH(n)) { \
- if (CONF_MATCH_VALUE("true")) { \
- o = true; \
- } else if (CONF_MATCH_VALUE("false")) { \
- o = false; \
- } else { \
- CONF_ERROR("Invalid conf value",\
- k, klen, v, vlen); \
- } \
- CONF_CONTINUE; \
- }
- /*
- * One of the CONF_MIN macros below expands, in one of the use points,
- * to "unsigned integer < 0", which is always false, triggering the
- * GCC -Wtype-limits warning, which we disable here and re-enable below.
- */
- JEMALLOC_DIAGNOSTIC_PUSH
- JEMALLOC_DIAGNOSTIC_IGNORE_TYPE_LIMITS
-
-#define CONF_DONT_CHECK_MIN(um, min) false
-#define CONF_CHECK_MIN(um, min) ((um) < (min))
-#define CONF_DONT_CHECK_MAX(um, max) false
-#define CONF_CHECK_MAX(um, max) ((um) > (max))
-
-#define CONF_VALUE_READ(max_t, result) \
- char *end; \
- set_errno(0); \
- result = (max_t)malloc_strtoumax(v, &end, 0);
-#define CONF_VALUE_READ_FAIL() \
- (get_errno() != 0 || (uintptr_t)end - (uintptr_t)v != vlen)
-
-#define CONF_HANDLE_T(t, max_t, o, n, min, max, check_min, check_max, clip) \
- if (CONF_MATCH(n)) { \
- max_t mv; \
- CONF_VALUE_READ(max_t, mv) \
- if (CONF_VALUE_READ_FAIL()) { \
- CONF_ERROR("Invalid conf value",\
- k, klen, v, vlen); \
- } else if (clip) { \
- if (check_min(mv, (t)(min))) { \
- o = (t)(min); \
- } else if ( \
- check_max(mv, (t)(max))) { \
- o = (t)(max); \
- } else { \
- o = (t)mv; \
- } \
- } else { \
- if (check_min(mv, (t)(min)) || \
- check_max(mv, (t)(max))) { \
- CONF_ERROR( \
- "Out-of-range " \
- "conf value", \
- k, klen, v, vlen); \
- } else { \
- o = (t)mv; \
- } \
- } \
- CONF_CONTINUE; \
- }
-#define CONF_HANDLE_T_U(t, o, n, min, max, check_min, check_max, clip) \
- CONF_HANDLE_T(t, uintmax_t, o, n, min, max, check_min, \
- check_max, clip)
-#define CONF_HANDLE_T_SIGNED(t, o, n, min, max, check_min, check_max, clip)\
- CONF_HANDLE_T(t, intmax_t, o, n, min, max, check_min, \
- check_max, clip)
-
-#define CONF_HANDLE_UNSIGNED(o, n, min, max, check_min, check_max, \
- clip) \
- CONF_HANDLE_T_U(unsigned, o, n, min, max, \
- check_min, check_max, clip)
-#define CONF_HANDLE_SIZE_T(o, n, min, max, check_min, check_max, clip) \
- CONF_HANDLE_T_U(size_t, o, n, min, max, \
- check_min, check_max, clip)
-#define CONF_HANDLE_INT64_T(o, n, min, max, check_min, check_max, clip) \
- CONF_HANDLE_T_SIGNED(int64_t, o, n, min, max, \
- check_min, check_max, clip)
-#define CONF_HANDLE_UINT64_T(o, n, min, max, check_min, check_max, clip)\
- CONF_HANDLE_T_U(uint64_t, o, n, min, max, \
- check_min, check_max, clip)
-#define CONF_HANDLE_SSIZE_T(o, n, min, max) \
- CONF_HANDLE_T_SIGNED(ssize_t, o, n, min, max, \
- CONF_CHECK_MIN, CONF_CHECK_MAX, false)
-#define CONF_HANDLE_CHAR_P(o, n, d) \
- if (CONF_MATCH(n)) { \
- size_t cpylen = (vlen <= \
- sizeof(o)-1) ? vlen : \
- sizeof(o)-1; \
- strncpy(o, v, cpylen); \
- o[cpylen] = '\0'; \
- CONF_CONTINUE; \
- }
-
- bool cur_opt_valid = true;
-
- CONF_HANDLE_BOOL(opt_confirm_conf, "confirm_conf")
- if (initial_call) {
- continue;
- }
-
- CONF_HANDLE_BOOL(opt_abort, "abort")
- CONF_HANDLE_BOOL(opt_abort_conf, "abort_conf")
- CONF_HANDLE_BOOL(opt_trust_madvise, "trust_madvise")
- if (strncmp("metadata_thp", k, klen) == 0) {
- int m;
- bool match = false;
- for (m = 0; m < metadata_thp_mode_limit; m++) {
- if (strncmp(metadata_thp_mode_names[m],
- v, vlen) == 0) {
- opt_metadata_thp = m;
- match = true;
- break;
- }
- }
- if (!match) {
- CONF_ERROR("Invalid conf value",
- k, klen, v, vlen);
- }
- CONF_CONTINUE;
- }
- CONF_HANDLE_BOOL(opt_retain, "retain")
- if (strncmp("dss", k, klen) == 0) {
- int m;
- bool match = false;
- for (m = 0; m < dss_prec_limit; m++) {
- if (strncmp(dss_prec_names[m], v, vlen)
- == 0) {
- if (extent_dss_prec_set(m)) {
- CONF_ERROR(
- "Error setting dss",
- k, klen, v, vlen);
- } else {
- opt_dss =
- dss_prec_names[m];
- match = true;
- break;
- }
- }
- }
- if (!match) {
- CONF_ERROR("Invalid conf value",
- k, klen, v, vlen);
- }
- CONF_CONTINUE;
- }
- if (CONF_MATCH("narenas")) {
- if (CONF_MATCH_VALUE("default")) {
- opt_narenas = 0;
- CONF_CONTINUE;
- } else {
- CONF_HANDLE_UNSIGNED(opt_narenas,
- "narenas", 1, UINT_MAX,
- CONF_CHECK_MIN, CONF_DONT_CHECK_MAX,
- /* clip */ false)
- }
- }
- if (CONF_MATCH("narenas_ratio")) {
- char *end;
- bool err = fxp_parse(&opt_narenas_ratio, v,
- &end);
- if (err || (size_t)(end - v) != vlen) {
- CONF_ERROR("Invalid conf value",
- k, klen, v, vlen);
- }
- CONF_CONTINUE;
- }
- if (CONF_MATCH("bin_shards")) {
- const char *bin_shards_segment_cur = v;
- size_t vlen_left = vlen;
- do {
- size_t size_start;
- size_t size_end;
- size_t nshards;
- bool err = malloc_conf_multi_sizes_next(
- &bin_shards_segment_cur, &vlen_left,
- &size_start, &size_end, &nshards);
- if (err || bin_update_shard_size(
- bin_shard_sizes, size_start,
- size_end, nshards)) {
- CONF_ERROR(
- "Invalid settings for "
- "bin_shards", k, klen, v,
- vlen);
- break;
- }
- } while (vlen_left > 0);
- CONF_CONTINUE;
- }
- CONF_HANDLE_INT64_T(opt_mutex_max_spin,
- "mutex_max_spin", -1, INT64_MAX, CONF_CHECK_MIN,
- CONF_DONT_CHECK_MAX, false);
- CONF_HANDLE_SSIZE_T(opt_dirty_decay_ms,
- "dirty_decay_ms", -1, NSTIME_SEC_MAX * KQU(1000) <
- QU(SSIZE_MAX) ? NSTIME_SEC_MAX * KQU(1000) :
- SSIZE_MAX);
- CONF_HANDLE_SSIZE_T(opt_muzzy_decay_ms,
- "muzzy_decay_ms", -1, NSTIME_SEC_MAX * KQU(1000) <
- QU(SSIZE_MAX) ? NSTIME_SEC_MAX * KQU(1000) :
- SSIZE_MAX);
- CONF_HANDLE_BOOL(opt_stats_print, "stats_print")
- if (CONF_MATCH("stats_print_opts")) {
- init_opt_stats_opts(v, vlen,
- opt_stats_print_opts);
- CONF_CONTINUE;
- }
- CONF_HANDLE_INT64_T(opt_stats_interval,
- "stats_interval", -1, INT64_MAX,
- CONF_CHECK_MIN, CONF_DONT_CHECK_MAX, false)
- if (CONF_MATCH("stats_interval_opts")) {
- init_opt_stats_opts(v, vlen,
- opt_stats_interval_opts);
- CONF_CONTINUE;
- }
- if (config_fill) {
- if (CONF_MATCH("junk")) {
- if (CONF_MATCH_VALUE("true")) {
- opt_junk = "true";
- opt_junk_alloc = opt_junk_free =
- true;
- } else if (CONF_MATCH_VALUE("false")) {
- opt_junk = "false";
- opt_junk_alloc = opt_junk_free =
- false;
- } else if (CONF_MATCH_VALUE("alloc")) {
- opt_junk = "alloc";
- opt_junk_alloc = true;
- opt_junk_free = false;
- } else if (CONF_MATCH_VALUE("free")) {
- opt_junk = "free";
- opt_junk_alloc = false;
- opt_junk_free = true;
- } else {
- CONF_ERROR(
- "Invalid conf value",
- k, klen, v, vlen);
- }
- CONF_CONTINUE;
- }
- CONF_HANDLE_BOOL(opt_zero, "zero")
- }
- if (config_utrace) {
- CONF_HANDLE_BOOL(opt_utrace, "utrace")
- }
- if (config_xmalloc) {
- CONF_HANDLE_BOOL(opt_xmalloc, "xmalloc")
- }
- if (config_enable_cxx) {
- CONF_HANDLE_BOOL(
- opt_experimental_infallible_new,
- "experimental_infallible_new")
- }
-
- CONF_HANDLE_BOOL(opt_tcache, "tcache")
- CONF_HANDLE_SIZE_T(opt_tcache_max, "tcache_max",
- 0, TCACHE_MAXCLASS_LIMIT, CONF_DONT_CHECK_MIN,
- CONF_CHECK_MAX, /* clip */ true)
- if (CONF_MATCH("lg_tcache_max")) {
- size_t m;
- CONF_VALUE_READ(size_t, m)
- if (CONF_VALUE_READ_FAIL()) {
- CONF_ERROR("Invalid conf value",
- k, klen, v, vlen);
- } else {
- /* clip if necessary */
- if (m > TCACHE_LG_MAXCLASS_LIMIT) {
- m = TCACHE_LG_MAXCLASS_LIMIT;
- }
- opt_tcache_max = (size_t)1 << m;
- }
- CONF_CONTINUE;
- }
- /*
- * Anyone trying to set a value outside -16 to 16 is
- * deeply confused.
- */
- CONF_HANDLE_SSIZE_T(opt_lg_tcache_nslots_mul,
- "lg_tcache_nslots_mul", -16, 16)
- /* Ditto with values past 2048. */
- CONF_HANDLE_UNSIGNED(opt_tcache_nslots_small_min,
- "tcache_nslots_small_min", 1, 2048,
- CONF_CHECK_MIN, CONF_CHECK_MAX, /* clip */ true)
- CONF_HANDLE_UNSIGNED(opt_tcache_nslots_small_max,
- "tcache_nslots_small_max", 1, 2048,
- CONF_CHECK_MIN, CONF_CHECK_MAX, /* clip */ true)
- CONF_HANDLE_UNSIGNED(opt_tcache_nslots_large,
- "tcache_nslots_large", 1, 2048,
- CONF_CHECK_MIN, CONF_CHECK_MAX, /* clip */ true)
- CONF_HANDLE_SIZE_T(opt_tcache_gc_incr_bytes,
- "tcache_gc_incr_bytes", 1024, SIZE_T_MAX,
- CONF_CHECK_MIN, CONF_DONT_CHECK_MAX,
- /* clip */ true)
- CONF_HANDLE_SIZE_T(opt_tcache_gc_delay_bytes,
- "tcache_gc_delay_bytes", 0, SIZE_T_MAX,
- CONF_DONT_CHECK_MIN, CONF_DONT_CHECK_MAX,
- /* clip */ false)
- CONF_HANDLE_UNSIGNED(opt_lg_tcache_flush_small_div,
- "lg_tcache_flush_small_div", 1, 16,
- CONF_CHECK_MIN, CONF_CHECK_MAX, /* clip */ true)
- CONF_HANDLE_UNSIGNED(opt_lg_tcache_flush_large_div,
- "lg_tcache_flush_large_div", 1, 16,
- CONF_CHECK_MIN, CONF_CHECK_MAX, /* clip */ true)
-
- /*
- * The runtime option of oversize_threshold remains
- * undocumented. It may be tweaked in the next major
- * release (6.0). The default value 8M is rather
- * conservative / safe. Tuning it further down may
- * improve fragmentation a bit more, but may also cause
- * contention on the huge arena.
- */
- CONF_HANDLE_SIZE_T(opt_oversize_threshold,
- "oversize_threshold", 0, SC_LARGE_MAXCLASS,
- CONF_DONT_CHECK_MIN, CONF_CHECK_MAX, false)
- CONF_HANDLE_SIZE_T(opt_lg_extent_max_active_fit,
- "lg_extent_max_active_fit", 0,
- (sizeof(size_t) << 3), CONF_DONT_CHECK_MIN,
- CONF_CHECK_MAX, false)
-
- if (strncmp("percpu_arena", k, klen) == 0) {
- bool match = false;
- for (int m = percpu_arena_mode_names_base; m <
- percpu_arena_mode_names_limit; m++) {
- if (strncmp(percpu_arena_mode_names[m],
- v, vlen) == 0) {
- if (!have_percpu_arena) {
- CONF_ERROR(
- "No getcpu support",
- k, klen, v, vlen);
- }
- opt_percpu_arena = m;
- match = true;
- break;
- }
- }
- if (!match) {
- CONF_ERROR("Invalid conf value",
- k, klen, v, vlen);
- }
- CONF_CONTINUE;
- }
- CONF_HANDLE_BOOL(opt_background_thread,
- "background_thread");
- CONF_HANDLE_SIZE_T(opt_max_background_threads,
- "max_background_threads", 1,
- opt_max_background_threads,
- CONF_CHECK_MIN, CONF_CHECK_MAX,
- true);
- CONF_HANDLE_BOOL(opt_hpa, "hpa")
- CONF_HANDLE_SIZE_T(opt_hpa_opts.slab_max_alloc,
- "hpa_slab_max_alloc", PAGE, HUGEPAGE,
- CONF_CHECK_MIN, CONF_CHECK_MAX, true);
-
- /*
- * Accept either a ratio-based or an exact hugification
- * threshold.
- */
- CONF_HANDLE_SIZE_T(opt_hpa_opts.hugification_threshold,
- "hpa_hugification_threshold", PAGE, HUGEPAGE,
- CONF_CHECK_MIN, CONF_CHECK_MAX, true);
- if (CONF_MATCH("hpa_hugification_threshold_ratio")) {
- fxp_t ratio;
- char *end;
- bool err = fxp_parse(&ratio, v,
- &end);
- if (err || (size_t)(end - v) != vlen
- || ratio > FXP_INIT_INT(1)) {
- CONF_ERROR("Invalid conf value",
- k, klen, v, vlen);
- } else {
- opt_hpa_opts.hugification_threshold =
- fxp_mul_frac(HUGEPAGE, ratio);
- }
- CONF_CONTINUE;
- }
-
- CONF_HANDLE_UINT64_T(
- opt_hpa_opts.hugify_delay_ms, "hpa_hugify_delay_ms",
- 0, 0, CONF_DONT_CHECK_MIN, CONF_DONT_CHECK_MAX,
- false);
-
- CONF_HANDLE_UINT64_T(
- opt_hpa_opts.min_purge_interval_ms,
- "hpa_min_purge_interval_ms", 0, 0,
- CONF_DONT_CHECK_MIN, CONF_DONT_CHECK_MAX, false);
-
- if (CONF_MATCH("hpa_dirty_mult")) {
- if (CONF_MATCH_VALUE("-1")) {
- opt_hpa_opts.dirty_mult = (fxp_t)-1;
- CONF_CONTINUE;
- }
- fxp_t ratio;
- char *end;
- bool err = fxp_parse(&ratio, v,
- &end);
- if (err || (size_t)(end - v) != vlen) {
- CONF_ERROR("Invalid conf value",
- k, klen, v, vlen);
- } else {
- opt_hpa_opts.dirty_mult = ratio;
- }
- CONF_CONTINUE;
- }
-
- CONF_HANDLE_SIZE_T(opt_hpa_sec_opts.nshards,
- "hpa_sec_nshards", 0, 0, CONF_CHECK_MIN,
- CONF_DONT_CHECK_MAX, true);
- CONF_HANDLE_SIZE_T(opt_hpa_sec_opts.max_alloc,
- "hpa_sec_max_alloc", PAGE, 0, CONF_CHECK_MIN,
- CONF_DONT_CHECK_MAX, true);
- CONF_HANDLE_SIZE_T(opt_hpa_sec_opts.max_bytes,
- "hpa_sec_max_bytes", PAGE, 0, CONF_CHECK_MIN,
- CONF_DONT_CHECK_MAX, true);
- CONF_HANDLE_SIZE_T(opt_hpa_sec_opts.bytes_after_flush,
- "hpa_sec_bytes_after_flush", PAGE, 0,
- CONF_CHECK_MIN, CONF_DONT_CHECK_MAX, true);
- CONF_HANDLE_SIZE_T(opt_hpa_sec_opts.batch_fill_extra,
- "hpa_sec_batch_fill_extra", 0, HUGEPAGE_PAGES,
- CONF_CHECK_MIN, CONF_CHECK_MAX, true);
-
- if (CONF_MATCH("slab_sizes")) {
- if (CONF_MATCH_VALUE("default")) {
- sc_data_init(sc_data);
- CONF_CONTINUE;
- }
- bool err;
- const char *slab_size_segment_cur = v;
- size_t vlen_left = vlen;
- do {
- size_t slab_start;
- size_t slab_end;
- size_t pgs;
- err = malloc_conf_multi_sizes_next(
- &slab_size_segment_cur,
- &vlen_left, &slab_start, &slab_end,
- &pgs);
- if (!err) {
- sc_data_update_slab_size(
- sc_data, slab_start,
- slab_end, (int)pgs);
- } else {
- CONF_ERROR("Invalid settings "
- "for slab_sizes",
- k, klen, v, vlen);
- }
- } while (!err && vlen_left > 0);
- CONF_CONTINUE;
- }
- if (config_prof) {
- CONF_HANDLE_BOOL(opt_prof, "prof")
- CONF_HANDLE_CHAR_P(opt_prof_prefix,
- "prof_prefix", "jeprof")
- CONF_HANDLE_BOOL(opt_prof_active, "prof_active")
- CONF_HANDLE_BOOL(opt_prof_thread_active_init,
- "prof_thread_active_init")
- CONF_HANDLE_SIZE_T(opt_lg_prof_sample,
- "lg_prof_sample", 0, (sizeof(uint64_t) << 3)
- - 1, CONF_DONT_CHECK_MIN, CONF_CHECK_MAX,
- true)
- CONF_HANDLE_BOOL(opt_prof_accum, "prof_accum")
- CONF_HANDLE_SSIZE_T(opt_lg_prof_interval,
- "lg_prof_interval", -1,
- (sizeof(uint64_t) << 3) - 1)
- CONF_HANDLE_BOOL(opt_prof_gdump, "prof_gdump")
- CONF_HANDLE_BOOL(opt_prof_final, "prof_final")
- CONF_HANDLE_BOOL(opt_prof_leak, "prof_leak")
- CONF_HANDLE_BOOL(opt_prof_leak_error,
- "prof_leak_error")
- CONF_HANDLE_BOOL(opt_prof_log, "prof_log")
- CONF_HANDLE_SSIZE_T(opt_prof_recent_alloc_max,
- "prof_recent_alloc_max", -1, SSIZE_MAX)
- CONF_HANDLE_BOOL(opt_prof_stats, "prof_stats")
- CONF_HANDLE_BOOL(opt_prof_sys_thread_name,
- "prof_sys_thread_name")
- if (CONF_MATCH("prof_time_resolution")) {
- if (CONF_MATCH_VALUE("default")) {
- opt_prof_time_res =
- prof_time_res_default;
- } else if (CONF_MATCH_VALUE("high")) {
- if (!config_high_res_timer) {
- CONF_ERROR(
- "No high resolution"
- " timer support",
- k, klen, v, vlen);
- } else {
- opt_prof_time_res =
- prof_time_res_high;
- }
- } else {
- CONF_ERROR("Invalid conf value",
- k, klen, v, vlen);
- }
- CONF_CONTINUE;
- }
- /*
- * Undocumented. When set to false, don't
- * correct for an unbiasing bug in jeprof
- * attribution. This can be handy if you want
- * to get consistent numbers from your binary
- * across different jemalloc versions, even if
- * those numbers are incorrect. The default is
- * true.
- */
- CONF_HANDLE_BOOL(opt_prof_unbias, "prof_unbias")
- }
- if (config_log) {
- if (CONF_MATCH("log")) {
- size_t cpylen = (
- vlen <= sizeof(log_var_names) ?
- vlen : sizeof(log_var_names) - 1);
- strncpy(log_var_names, v, cpylen);
- log_var_names[cpylen] = '\0';
- CONF_CONTINUE;
- }
- }
- if (CONF_MATCH("thp")) {
- bool match = false;
- for (int m = 0; m < thp_mode_names_limit; m++) {
- if (strncmp(thp_mode_names[m],v, vlen)
- == 0) {
- if (!have_madvise_huge && !have_memcntl) {
- CONF_ERROR(
- "No THP support",
- k, klen, v, vlen);
- }
- opt_thp = m;
- match = true;
- break;
- }
- }
- if (!match) {
- CONF_ERROR("Invalid conf value",
- k, klen, v, vlen);
- }
- CONF_CONTINUE;
- }
- if (CONF_MATCH("zero_realloc")) {
- if (CONF_MATCH_VALUE("alloc")) {
- opt_zero_realloc_action
- = zero_realloc_action_alloc;
- } else if (CONF_MATCH_VALUE("free")) {
- opt_zero_realloc_action
- = zero_realloc_action_free;
- } else if (CONF_MATCH_VALUE("abort")) {
- opt_zero_realloc_action
- = zero_realloc_action_abort;
- } else {
- CONF_ERROR("Invalid conf value",
- k, klen, v, vlen);
- }
- CONF_CONTINUE;
- }
- if (config_uaf_detection &&
- CONF_MATCH("lg_san_uaf_align")) {
- ssize_t a;
- CONF_VALUE_READ(ssize_t, a)
- if (CONF_VALUE_READ_FAIL() || a < -1) {
- CONF_ERROR("Invalid conf value",
- k, klen, v, vlen);
- }
- if (a == -1) {
- opt_lg_san_uaf_align = -1;
- CONF_CONTINUE;
- }
-
- /* clip if necessary */
- ssize_t max_allowed = (sizeof(size_t) << 3) - 1;
- ssize_t min_allowed = LG_PAGE;
- if (a > max_allowed) {
- a = max_allowed;
- } else if (a < min_allowed) {
- a = min_allowed;
- }
-
- opt_lg_san_uaf_align = a;
- CONF_CONTINUE;
- }
-
- CONF_HANDLE_SIZE_T(opt_san_guard_small,
- "san_guard_small", 0, SIZE_T_MAX,
- CONF_DONT_CHECK_MIN, CONF_DONT_CHECK_MAX, false)
- CONF_HANDLE_SIZE_T(opt_san_guard_large,
- "san_guard_large", 0, SIZE_T_MAX,
- CONF_DONT_CHECK_MIN, CONF_DONT_CHECK_MAX, false)
-
- CONF_ERROR("Invalid conf pair", k, klen, v, vlen);
-#undef CONF_ERROR
-#undef CONF_CONTINUE
-#undef CONF_MATCH
-#undef CONF_MATCH_VALUE
-#undef CONF_HANDLE_BOOL
-#undef CONF_DONT_CHECK_MIN
-#undef CONF_CHECK_MIN
-#undef CONF_DONT_CHECK_MAX
-#undef CONF_CHECK_MAX
-#undef CONF_HANDLE_T
-#undef CONF_HANDLE_T_U
-#undef CONF_HANDLE_T_SIGNED
-#undef CONF_HANDLE_UNSIGNED
-#undef CONF_HANDLE_SIZE_T
-#undef CONF_HANDLE_SSIZE_T
-#undef CONF_HANDLE_CHAR_P
- /* Re-enable diagnostic "-Wtype-limits" */
- JEMALLOC_DIAGNOSTIC_POP
- }
- if (opt_abort_conf && had_conf_error) {
- malloc_abort_invalid_conf();
- }
- }
- atomic_store_b(&log_init_done, true, ATOMIC_RELEASE);
-}
-
-static bool
-malloc_conf_init_check_deps(void) {
- if (opt_prof_leak_error && !opt_prof_final) {
- malloc_printf("<jemalloc>: prof_leak_error is set w/o "
- "prof_final.\n");
- return true;
- }
-
- return false;
-}
-
-static void
-malloc_conf_init(sc_data_t *sc_data, unsigned bin_shard_sizes[SC_NBINS]) {
- const char *opts_cache[MALLOC_CONF_NSOURCES] = {NULL, NULL, NULL, NULL,
- NULL};
- char buf[PATH_MAX + 1];
-
- /* The first call only set the confirm_conf option and opts_cache */
- malloc_conf_init_helper(NULL, NULL, true, opts_cache, buf);
- malloc_conf_init_helper(sc_data, bin_shard_sizes, false, opts_cache,
- NULL);
- if (malloc_conf_init_check_deps()) {
- /* check_deps does warning msg only; abort below if needed. */
- if (opt_abort_conf) {
- malloc_abort_invalid_conf();
- }
- }
-}
-
-#undef MALLOC_CONF_NSOURCES
-
-static bool
-malloc_init_hard_needed(void) {
- if (malloc_initialized() || (IS_INITIALIZER && malloc_init_state ==
- malloc_init_recursible)) {
- /*
- * Another thread initialized the allocator before this one
- * acquired init_lock, or this thread is the initializing
- * thread, and it is recursively allocating.
- */
- return false;
- }
-#ifdef JEMALLOC_THREADED_INIT
- if (malloc_initializer != NO_INITIALIZER && !IS_INITIALIZER) {
- /* Busy-wait until the initializing thread completes. */
- spin_t spinner = SPIN_INITIALIZER;
- do {
- malloc_mutex_unlock(TSDN_NULL, &init_lock);
- spin_adaptive(&spinner);
- malloc_mutex_lock(TSDN_NULL, &init_lock);
- } while (!malloc_initialized());
- return false;
- }
-#endif
- return true;
-}
-
-static bool
-malloc_init_hard_a0_locked() {
- malloc_initializer = INITIALIZER;
-
- JEMALLOC_DIAGNOSTIC_PUSH
- JEMALLOC_DIAGNOSTIC_IGNORE_MISSING_STRUCT_FIELD_INITIALIZERS
- sc_data_t sc_data = {0};
- JEMALLOC_DIAGNOSTIC_POP
-
- /*
- * Ordering here is somewhat tricky; we need sc_boot() first, since that
- * determines what the size classes will be, and then
- * malloc_conf_init(), since any slab size tweaking will need to be done
- * before sz_boot and bin_info_boot, which assume that the values they
- * read out of sc_data_global are final.
- */
- sc_boot(&sc_data);
- unsigned bin_shard_sizes[SC_NBINS];
- bin_shard_sizes_boot(bin_shard_sizes);
- /*
- * prof_boot0 only initializes opt_prof_prefix. We need to do it before
- * we parse malloc_conf options, in case malloc_conf parsing overwrites
- * it.
- */
- if (config_prof) {
- prof_boot0();
- }
- malloc_conf_init(&sc_data, bin_shard_sizes);
- san_init(opt_lg_san_uaf_align);
- sz_boot(&sc_data, opt_cache_oblivious);
- bin_info_boot(&sc_data, bin_shard_sizes);
-
- if (opt_stats_print) {
- /* Print statistics at exit. */
- if (atexit(stats_print_atexit) != 0) {
- malloc_write("<jemalloc>: Error in atexit()\n");
- if (opt_abort) {
- abort();
- }
- }
- }
-
- if (stats_boot()) {
- return true;
- }
- if (pages_boot()) {
- return true;
- }
- if (base_boot(TSDN_NULL)) {
- return true;
- }
- /* emap_global is static, hence zeroed. */
- if (emap_init(&arena_emap_global, b0get(), /* zeroed */ true)) {
- return true;
- }
- if (extent_boot()) {
- return true;
- }
- if (ctl_boot()) {
- return true;
- }
- if (config_prof) {
- prof_boot1();
- }
- if (opt_hpa && !hpa_supported()) {
- malloc_printf("<jemalloc>: HPA not supported in the current "
- "configuration; %s.",
- opt_abort_conf ? "aborting" : "disabling");
- if (opt_abort_conf) {
- malloc_abort_invalid_conf();
- } else {
- opt_hpa = false;
- }
- }
- if (arena_boot(&sc_data, b0get(), opt_hpa)) {
- return true;
- }
- if (tcache_boot(TSDN_NULL, b0get())) {
- return true;
- }
- if (malloc_mutex_init(&arenas_lock, "arenas", WITNESS_RANK_ARENAS,
- malloc_mutex_rank_exclusive)) {
- return true;
- }
- hook_boot();
- /*
- * Create enough scaffolding to allow recursive allocation in
- * malloc_ncpus().
- */
- narenas_auto = 1;
- manual_arena_base = narenas_auto + 1;
- memset(arenas, 0, sizeof(arena_t *) * narenas_auto);
- /*
- * Initialize one arena here. The rest are lazily created in
- * arena_choose_hard().
- */
- if (arena_init(TSDN_NULL, 0, &arena_config_default) == NULL) {
- return true;
- }
- a0 = arena_get(TSDN_NULL, 0, false);
-
- if (opt_hpa && !hpa_supported()) {
- malloc_printf("<jemalloc>: HPA not supported in the current "
- "configuration; %s.",
- opt_abort_conf ? "aborting" : "disabling");
- if (opt_abort_conf) {
- malloc_abort_invalid_conf();
- } else {
- opt_hpa = false;
- }
- } else if (opt_hpa) {
- hpa_shard_opts_t hpa_shard_opts = opt_hpa_opts;
- hpa_shard_opts.deferral_allowed = background_thread_enabled();
- if (pa_shard_enable_hpa(TSDN_NULL, &a0->pa_shard,
- &hpa_shard_opts, &opt_hpa_sec_opts)) {
- return true;
- }
- }
-
- malloc_init_state = malloc_init_a0_initialized;
-
- return false;
-}
-
-static bool
-malloc_init_hard_a0(void) {
- bool ret;
-
- malloc_mutex_lock(TSDN_NULL, &init_lock);
- ret = malloc_init_hard_a0_locked();
- malloc_mutex_unlock(TSDN_NULL, &init_lock);
- return ret;
-}
-
-/* Initialize data structures which may trigger recursive allocation. */
-static bool
-malloc_init_hard_recursible(void) {
- malloc_init_state = malloc_init_recursible;
-
- ncpus = malloc_ncpus();
- if (opt_percpu_arena != percpu_arena_disabled) {
- bool cpu_count_is_deterministic =
- malloc_cpu_count_is_deterministic();
- if (!cpu_count_is_deterministic) {
- /*
- * If # of CPU is not deterministic, and narenas not
- * specified, disables per cpu arena since it may not
- * detect CPU IDs properly.
- */
- if (opt_narenas == 0) {
- opt_percpu_arena = percpu_arena_disabled;
- malloc_write("<jemalloc>: Number of CPUs "
- "detected is not deterministic. Per-CPU "
- "arena disabled.\n");
- if (opt_abort_conf) {
- malloc_abort_invalid_conf();
- }
- if (opt_abort) {
- abort();
- }
- }
- }
- }
-
-#if (defined(JEMALLOC_HAVE_PTHREAD_ATFORK) && !defined(JEMALLOC_MUTEX_INIT_CB) \
- && !defined(JEMALLOC_ZONE) && !defined(_WIN32) && \
- !defined(__native_client__))
- /* LinuxThreads' pthread_atfork() allocates. */
- if (pthread_atfork(jemalloc_prefork, jemalloc_postfork_parent,
- jemalloc_postfork_child) != 0) {
- malloc_write("<jemalloc>: Error in pthread_atfork()\n");
- if (opt_abort) {
- abort();
- }
- return true;
- }
-#endif
-
- if (background_thread_boot0()) {
- return true;
- }
-
- return false;
-}
-
-static unsigned
-malloc_narenas_default(void) {
- assert(ncpus > 0);
- /*
- * For SMP systems, create more than one arena per CPU by
- * default.
- */
- if (ncpus > 1) {
- fxp_t fxp_ncpus = FXP_INIT_INT(ncpus);
- fxp_t goal = fxp_mul(fxp_ncpus, opt_narenas_ratio);
- uint32_t int_goal = fxp_round_nearest(goal);
- if (int_goal == 0) {
- return 1;
- }
- return int_goal;
- } else {
- return 1;
- }
-}
-
-static percpu_arena_mode_t
-percpu_arena_as_initialized(percpu_arena_mode_t mode) {
- assert(!malloc_initialized());
- assert(mode <= percpu_arena_disabled);
-
- if (mode != percpu_arena_disabled) {
- mode += percpu_arena_mode_enabled_base;
- }
-
- return mode;
-}
-
-static bool
-malloc_init_narenas(void) {
- assert(ncpus > 0);
-
- if (opt_percpu_arena != percpu_arena_disabled) {
- if (!have_percpu_arena || malloc_getcpu() < 0) {
- opt_percpu_arena = percpu_arena_disabled;
- malloc_printf("<jemalloc>: perCPU arena getcpu() not "
- "available. Setting narenas to %u.\n", opt_narenas ?
- opt_narenas : malloc_narenas_default());
- if (opt_abort) {
- abort();
- }
- } else {
- if (ncpus >= MALLOCX_ARENA_LIMIT) {
- malloc_printf("<jemalloc>: narenas w/ percpu"
- "arena beyond limit (%d)\n", ncpus);
- if (opt_abort) {
- abort();
- }
- return true;
- }
- /* NB: opt_percpu_arena isn't fully initialized yet. */
- if (percpu_arena_as_initialized(opt_percpu_arena) ==
- per_phycpu_arena && ncpus % 2 != 0) {
- malloc_printf("<jemalloc>: invalid "
- "configuration -- per physical CPU arena "
- "with odd number (%u) of CPUs (no hyper "
- "threading?).\n", ncpus);
- if (opt_abort)
- abort();
- }
- unsigned n = percpu_arena_ind_limit(
- percpu_arena_as_initialized(opt_percpu_arena));
- if (opt_narenas < n) {
- /*
- * If narenas is specified with percpu_arena
- * enabled, actual narenas is set as the greater
- * of the two. percpu_arena_choose will be free
- * to use any of the arenas based on CPU
- * id. This is conservative (at a small cost)
- * but ensures correctness.
- *
- * If for some reason the ncpus determined at
- * boot is not the actual number (e.g. because
- * of affinity setting from numactl), reserving
- * narenas this way provides a workaround for
- * percpu_arena.
- */
- opt_narenas = n;
- }
- }
- }
- if (opt_narenas == 0) {
- opt_narenas = malloc_narenas_default();
- }
- assert(opt_narenas > 0);
-
- narenas_auto = opt_narenas;
- /*
- * Limit the number of arenas to the indexing range of MALLOCX_ARENA().
- */
- if (narenas_auto >= MALLOCX_ARENA_LIMIT) {
- narenas_auto = MALLOCX_ARENA_LIMIT - 1;
- malloc_printf("<jemalloc>: Reducing narenas to limit (%d)\n",
- narenas_auto);
- }
- narenas_total_set(narenas_auto);
- if (arena_init_huge()) {
- narenas_total_inc();
- }
- manual_arena_base = narenas_total_get();
-
- return false;
-}
-
-static void
-malloc_init_percpu(void) {
- opt_percpu_arena = percpu_arena_as_initialized(opt_percpu_arena);
-}
-
-static bool
-malloc_init_hard_finish(void) {
- if (malloc_mutex_boot()) {
- return true;
- }
-
- malloc_init_state = malloc_init_initialized;
- malloc_slow_flag_init();
-
- return false;
-}
-
-static void
-malloc_init_hard_cleanup(tsdn_t *tsdn, bool reentrancy_set) {
- malloc_mutex_assert_owner(tsdn, &init_lock);
- malloc_mutex_unlock(tsdn, &init_lock);
- if (reentrancy_set) {
- assert(!tsdn_null(tsdn));
- tsd_t *tsd = tsdn_tsd(tsdn);
- assert(tsd_reentrancy_level_get(tsd) > 0);
- post_reentrancy(tsd);
- }
-}
-
-static bool
-malloc_init_hard(void) {
- tsd_t *tsd;
-
-#if defined(_WIN32) && _WIN32_WINNT < 0x0600
- _init_init_lock();
-#endif
- malloc_mutex_lock(TSDN_NULL, &init_lock);
-
-#define UNLOCK_RETURN(tsdn, ret, reentrancy) \
- malloc_init_hard_cleanup(tsdn, reentrancy); \
- return ret;
-
- if (!malloc_init_hard_needed()) {
- UNLOCK_RETURN(TSDN_NULL, false, false)
- }
-
- if (malloc_init_state != malloc_init_a0_initialized &&
- malloc_init_hard_a0_locked()) {
- UNLOCK_RETURN(TSDN_NULL, true, false)
- }
-
- malloc_mutex_unlock(TSDN_NULL, &init_lock);
- /* Recursive allocation relies on functional tsd. */
- tsd = malloc_tsd_boot0();
- if (tsd == NULL) {
- return true;
- }
- if (malloc_init_hard_recursible()) {
- return true;
- }
-
- malloc_mutex_lock(tsd_tsdn(tsd), &init_lock);
- /* Set reentrancy level to 1 during init. */
- pre_reentrancy(tsd, NULL);
- /* Initialize narenas before prof_boot2 (for allocation). */
- if (malloc_init_narenas()
- || background_thread_boot1(tsd_tsdn(tsd), b0get())) {
- UNLOCK_RETURN(tsd_tsdn(tsd), true, true)
- }
- if (config_prof && prof_boot2(tsd, b0get())) {
- UNLOCK_RETURN(tsd_tsdn(tsd), true, true)
- }
-
- malloc_init_percpu();
-
- if (malloc_init_hard_finish()) {
- UNLOCK_RETURN(tsd_tsdn(tsd), true, true)
- }
- post_reentrancy(tsd);
- malloc_mutex_unlock(tsd_tsdn(tsd), &init_lock);
-
- witness_assert_lockless(witness_tsd_tsdn(
- tsd_witness_tsdp_get_unsafe(tsd)));
- malloc_tsd_boot1();
- /* Update TSD after tsd_boot1. */
- tsd = tsd_fetch();
- if (opt_background_thread) {
- assert(have_background_thread);
- /*
- * Need to finish init & unlock first before creating background
- * threads (pthread_create depends on malloc). ctl_init (which
- * sets isthreaded) needs to be called without holding any lock.
- */
- background_thread_ctl_init(tsd_tsdn(tsd));
- if (background_thread_create(tsd, 0)) {
- return true;
- }
- }
-#undef UNLOCK_RETURN
- return false;
-}
-
-/*
- * End initialization functions.
- */
-/******************************************************************************/
-/*
- * Begin allocation-path internal functions and data structures.
- */
-
-/*
- * Settings determined by the documented behavior of the allocation functions.
- */
-typedef struct static_opts_s static_opts_t;
-struct static_opts_s {
- /* Whether or not allocation size may overflow. */
- bool may_overflow;
-
- /*
- * Whether or not allocations (with alignment) of size 0 should be
- * treated as size 1.
- */
- bool bump_empty_aligned_alloc;
- /*
- * Whether to assert that allocations are not of size 0 (after any
- * bumping).
- */
- bool assert_nonempty_alloc;
-
- /*
- * Whether or not to modify the 'result' argument to malloc in case of
- * error.
- */
- bool null_out_result_on_error;
- /* Whether to set errno when we encounter an error condition. */
- bool set_errno_on_error;
-
- /*
- * The minimum valid alignment for functions requesting aligned storage.
- */
- size_t min_alignment;
-
- /* The error string to use if we oom. */
- const char *oom_string;
- /* The error string to use if the passed-in alignment is invalid. */
- const char *invalid_alignment_string;
-
- /*
- * False if we're configured to skip some time-consuming operations.
- *
- * This isn't really a malloc "behavior", but it acts as a useful
- * summary of several other static (or at least, static after program
- * initialization) options.
- */
- bool slow;
- /*
- * Return size.
- */
- bool usize;
-};
-
-JEMALLOC_ALWAYS_INLINE void
-static_opts_init(static_opts_t *static_opts) {
- static_opts->may_overflow = false;
- static_opts->bump_empty_aligned_alloc = false;
- static_opts->assert_nonempty_alloc = false;
- static_opts->null_out_result_on_error = false;
- static_opts->set_errno_on_error = false;
- static_opts->min_alignment = 0;
- static_opts->oom_string = "";
- static_opts->invalid_alignment_string = "";
- static_opts->slow = false;
- static_opts->usize = false;
-}
-
-/*
- * These correspond to the macros in jemalloc/jemalloc_macros.h. Broadly, we
- * should have one constant here per magic value there. Note however that the
- * representations need not be related.
- */
-#define TCACHE_IND_NONE ((unsigned)-1)
-#define TCACHE_IND_AUTOMATIC ((unsigned)-2)
-#define ARENA_IND_AUTOMATIC ((unsigned)-1)
-
-typedef struct dynamic_opts_s dynamic_opts_t;
-struct dynamic_opts_s {
- void **result;
- size_t usize;
- size_t num_items;
- size_t item_size;
- size_t alignment;
- bool zero;
- unsigned tcache_ind;
- unsigned arena_ind;
-};
-
-JEMALLOC_ALWAYS_INLINE void
-dynamic_opts_init(dynamic_opts_t *dynamic_opts) {
- dynamic_opts->result = NULL;
- dynamic_opts->usize = 0;
- dynamic_opts->num_items = 0;
- dynamic_opts->item_size = 0;
- dynamic_opts->alignment = 0;
- dynamic_opts->zero = false;
- dynamic_opts->tcache_ind = TCACHE_IND_AUTOMATIC;
- dynamic_opts->arena_ind = ARENA_IND_AUTOMATIC;
-}
-
-/*
- * ind parameter is optional and is only checked and filled if alignment == 0;
- * return true if result is out of range.
- */
-JEMALLOC_ALWAYS_INLINE bool
-aligned_usize_get(size_t size, size_t alignment, size_t *usize, szind_t *ind,
- bool bump_empty_aligned_alloc) {
- assert(usize != NULL);
- if (alignment == 0) {
- if (ind != NULL) {
- *ind = sz_size2index(size);
- if (unlikely(*ind >= SC_NSIZES)) {
- return true;
- }
- *usize = sz_index2size(*ind);
- assert(*usize > 0 && *usize <= SC_LARGE_MAXCLASS);
- return false;
- }
- *usize = sz_s2u(size);
- } else {
- if (bump_empty_aligned_alloc && unlikely(size == 0)) {
- size = 1;
- }
- *usize = sz_sa2u(size, alignment);
- }
- if (unlikely(*usize == 0 || *usize > SC_LARGE_MAXCLASS)) {
- return true;
- }
- return false;
-}
-
-JEMALLOC_ALWAYS_INLINE bool
-zero_get(bool guarantee, bool slow) {
- if (config_fill && slow && unlikely(opt_zero)) {
- return true;
- } else {
- return guarantee;
- }
-}
-
-JEMALLOC_ALWAYS_INLINE tcache_t *
-tcache_get_from_ind(tsd_t *tsd, unsigned tcache_ind, bool slow, bool is_alloc) {
- tcache_t *tcache;
- if (tcache_ind == TCACHE_IND_AUTOMATIC) {
- if (likely(!slow)) {
- /* Getting tcache ptr unconditionally. */
- tcache = tsd_tcachep_get(tsd);
- assert(tcache == tcache_get(tsd));
- } else if (is_alloc ||
- likely(tsd_reentrancy_level_get(tsd) == 0)) {
- tcache = tcache_get(tsd);
- } else {
- tcache = NULL;
- }
- } else {
- /*
- * Should not specify tcache on deallocation path when being
- * reentrant.
- */
- assert(is_alloc || tsd_reentrancy_level_get(tsd) == 0 ||
- tsd_state_nocleanup(tsd));
- if (tcache_ind == TCACHE_IND_NONE) {
- tcache = NULL;
- } else {
- tcache = tcaches_get(tsd, tcache_ind);
- }
- }
- return tcache;
-}
-
-/* Return true if a manual arena is specified and arena_get() OOMs. */
-JEMALLOC_ALWAYS_INLINE bool
-arena_get_from_ind(tsd_t *tsd, unsigned arena_ind, arena_t **arena_p) {
- if (arena_ind == ARENA_IND_AUTOMATIC) {
- /*
- * In case of automatic arena management, we defer arena
- * computation until as late as we can, hoping to fill the
- * allocation out of the tcache.
- */
- *arena_p = NULL;
- } else {
- *arena_p = arena_get(tsd_tsdn(tsd), arena_ind, true);
- if (unlikely(*arena_p == NULL) && arena_ind >= narenas_auto) {
- return true;
- }
- }
- return false;
-}
-
-/* ind is ignored if dopts->alignment > 0. */
-JEMALLOC_ALWAYS_INLINE void *
-imalloc_no_sample(static_opts_t *sopts, dynamic_opts_t *dopts, tsd_t *tsd,
- size_t size, size_t usize, szind_t ind) {
- /* Fill in the tcache. */
- tcache_t *tcache = tcache_get_from_ind(tsd, dopts->tcache_ind,
- sopts->slow, /* is_alloc */ true);
-
- /* Fill in the arena. */
- arena_t *arena;
- if (arena_get_from_ind(tsd, dopts->arena_ind, &arena)) {
- return NULL;
- }
-
- if (unlikely(dopts->alignment != 0)) {
- return ipalloct(tsd_tsdn(tsd), usize, dopts->alignment,
- dopts->zero, tcache, arena);
- }
-
- return iallocztm(tsd_tsdn(tsd), size, ind, dopts->zero, tcache, false,
- arena, sopts->slow);
-}
-
-JEMALLOC_ALWAYS_INLINE void *
-imalloc_sample(static_opts_t *sopts, dynamic_opts_t *dopts, tsd_t *tsd,
- size_t usize, szind_t ind) {
- void *ret;
-
- /*
- * For small allocations, sampling bumps the usize. If so, we allocate
- * from the ind_large bucket.
- */
- szind_t ind_large;
- size_t bumped_usize = usize;
-
- dopts->alignment = prof_sample_align(dopts->alignment);
- if (usize <= SC_SMALL_MAXCLASS) {
- assert(((dopts->alignment == 0) ?
- sz_s2u(SC_LARGE_MINCLASS) :
- sz_sa2u(SC_LARGE_MINCLASS, dopts->alignment))
- == SC_LARGE_MINCLASS);
- ind_large = sz_size2index(SC_LARGE_MINCLASS);
- bumped_usize = sz_s2u(SC_LARGE_MINCLASS);
- ret = imalloc_no_sample(sopts, dopts, tsd, bumped_usize,
- bumped_usize, ind_large);
- if (unlikely(ret == NULL)) {
- return NULL;
- }
- arena_prof_promote(tsd_tsdn(tsd), ret, usize);
- } else {
- ret = imalloc_no_sample(sopts, dopts, tsd, usize, usize, ind);
- }
- assert(prof_sample_aligned(ret));
-
- return ret;
-}
-
-/*
- * Returns true if the allocation will overflow, and false otherwise. Sets
- * *size to the product either way.
- */
-JEMALLOC_ALWAYS_INLINE bool
-compute_size_with_overflow(bool may_overflow, dynamic_opts_t *dopts,
- size_t *size) {
- /*
- * This function is just num_items * item_size, except that we may have
- * to check for overflow.
- */
-
- if (!may_overflow) {
- assert(dopts->num_items == 1);
- *size = dopts->item_size;
- return false;
- }
-
- /* A size_t with its high-half bits all set to 1. */
- static const size_t high_bits = SIZE_T_MAX << (sizeof(size_t) * 8 / 2);
-
- *size = dopts->item_size * dopts->num_items;
-
- if (unlikely(*size == 0)) {
- return (dopts->num_items != 0 && dopts->item_size != 0);
- }
-
- /*
- * We got a non-zero size, but we don't know if we overflowed to get
- * there. To avoid having to do a divide, we'll be clever and note that
- * if both A and B can be represented in N/2 bits, then their product
- * can be represented in N bits (without the possibility of overflow).
- */
- if (likely((high_bits & (dopts->num_items | dopts->item_size)) == 0)) {
- return false;
- }
- if (likely(*size / dopts->item_size == dopts->num_items)) {
- return false;
- }
- return true;
-}
-
-JEMALLOC_ALWAYS_INLINE int
-imalloc_body(static_opts_t *sopts, dynamic_opts_t *dopts, tsd_t *tsd) {
- /* Where the actual allocated memory will live. */
- void *allocation = NULL;
- /* Filled in by compute_size_with_overflow below. */
- size_t size = 0;
- /*
- * The zero initialization for ind is actually dead store, in that its
- * value is reset before any branch on its value is taken. Sometimes
- * though, it's convenient to pass it as arguments before this point.
- * To avoid undefined behavior then, we initialize it with dummy stores.
- */
- szind_t ind = 0;
- /* usize will always be properly initialized. */
- size_t usize;
-
- /* Reentrancy is only checked on slow path. */
- int8_t reentrancy_level;
-
- /* Compute the amount of memory the user wants. */
- if (unlikely(compute_size_with_overflow(sopts->may_overflow, dopts,
- &size))) {
- goto label_oom;
- }
-
- if (unlikely(dopts->alignment < sopts->min_alignment
- || (dopts->alignment & (dopts->alignment - 1)) != 0)) {
- goto label_invalid_alignment;
- }
-
- /* This is the beginning of the "core" algorithm. */
- dopts->zero = zero_get(dopts->zero, sopts->slow);
- if (aligned_usize_get(size, dopts->alignment, &usize, &ind,
- sopts->bump_empty_aligned_alloc)) {
- goto label_oom;
- }
- dopts->usize = usize;
- /* Validate the user input. */
- if (sopts->assert_nonempty_alloc) {
- assert (size != 0);
- }
-
- check_entry_exit_locking(tsd_tsdn(tsd));
-
- /*
- * If we need to handle reentrancy, we can do it out of a
- * known-initialized arena (i.e. arena 0).
- */
- reentrancy_level = tsd_reentrancy_level_get(tsd);
- if (sopts->slow && unlikely(reentrancy_level > 0)) {
- /*
- * We should never specify particular arenas or tcaches from
- * within our internal allocations.
- */
- assert(dopts->tcache_ind == TCACHE_IND_AUTOMATIC ||
- dopts->tcache_ind == TCACHE_IND_NONE);
- assert(dopts->arena_ind == ARENA_IND_AUTOMATIC);
- dopts->tcache_ind = TCACHE_IND_NONE;
- /* We know that arena 0 has already been initialized. */
- dopts->arena_ind = 0;
- }
-
- /*
- * If dopts->alignment > 0, then ind is still 0, but usize was computed
- * in the previous if statement. Down the positive alignment path,
- * imalloc_no_sample and imalloc_sample will ignore ind.
- */
-
- /* If profiling is on, get our profiling context. */
- if (config_prof && opt_prof) {
- bool prof_active = prof_active_get_unlocked();
- bool sample_event = te_prof_sample_event_lookahead(tsd, usize);
- prof_tctx_t *tctx = prof_alloc_prep(tsd, prof_active,
- sample_event);
-
- emap_alloc_ctx_t alloc_ctx;
- if (likely((uintptr_t)tctx == (uintptr_t)1U)) {
- alloc_ctx.slab = (usize <= SC_SMALL_MAXCLASS);
- allocation = imalloc_no_sample(
- sopts, dopts, tsd, usize, usize, ind);
- } else if ((uintptr_t)tctx > (uintptr_t)1U) {
- allocation = imalloc_sample(
- sopts, dopts, tsd, usize, ind);
- alloc_ctx.slab = false;
- } else {
- allocation = NULL;
- }
-
- if (unlikely(allocation == NULL)) {
- prof_alloc_rollback(tsd, tctx);
- goto label_oom;
- }
- prof_malloc(tsd, allocation, size, usize, &alloc_ctx, tctx);
- } else {
- assert(!opt_prof);
- allocation = imalloc_no_sample(sopts, dopts, tsd, size, usize,
- ind);
- if (unlikely(allocation == NULL)) {
- goto label_oom;
- }
- }
-
- /*
- * Allocation has been done at this point. We still have some
- * post-allocation work to do though.
- */
-
- thread_alloc_event(tsd, usize);
-
- assert(dopts->alignment == 0
- || ((uintptr_t)allocation & (dopts->alignment - 1)) == ZU(0));
-
- assert(usize == isalloc(tsd_tsdn(tsd), allocation));
-
- if (config_fill && sopts->slow && !dopts->zero
- && unlikely(opt_junk_alloc)) {
- junk_alloc_callback(allocation, usize);
- }
-
- if (sopts->slow) {
- UTRACE(0, size, allocation);
- }
-
- /* Success! */
- check_entry_exit_locking(tsd_tsdn(tsd));
- *dopts->result = allocation;
- return 0;
-
-label_oom:
- if (unlikely(sopts->slow) && config_xmalloc && unlikely(opt_xmalloc)) {
- malloc_write(sopts->oom_string);
- abort();
- }
-
- if (sopts->slow) {
- UTRACE(NULL, size, NULL);
- }
-
- check_entry_exit_locking(tsd_tsdn(tsd));
-
- if (sopts->set_errno_on_error) {
- set_errno(ENOMEM);
- }
-
- if (sopts->null_out_result_on_error) {
- *dopts->result = NULL;
- }
-
- return ENOMEM;
-
- /*
- * This label is only jumped to by one goto; we move it out of line
- * anyways to avoid obscuring the non-error paths, and for symmetry with
- * the oom case.
- */
-label_invalid_alignment:
- if (config_xmalloc && unlikely(opt_xmalloc)) {
- malloc_write(sopts->invalid_alignment_string);
- abort();
- }
-
- if (sopts->set_errno_on_error) {
- set_errno(EINVAL);
- }
-
- if (sopts->slow) {
- UTRACE(NULL, size, NULL);
- }
-
- check_entry_exit_locking(tsd_tsdn(tsd));
-
- if (sopts->null_out_result_on_error) {
- *dopts->result = NULL;
- }
-
- return EINVAL;
-}
-
-JEMALLOC_ALWAYS_INLINE bool
-imalloc_init_check(static_opts_t *sopts, dynamic_opts_t *dopts) {
- if (unlikely(!malloc_initialized()) && unlikely(malloc_init())) {
- if (config_xmalloc && unlikely(opt_xmalloc)) {
- malloc_write(sopts->oom_string);
- abort();
- }
- UTRACE(NULL, dopts->num_items * dopts->item_size, NULL);
- set_errno(ENOMEM);
- *dopts->result = NULL;
-
- return false;
- }
-
- return true;
-}
-
-/* Returns the errno-style error code of the allocation. */
-JEMALLOC_ALWAYS_INLINE int
-imalloc(static_opts_t *sopts, dynamic_opts_t *dopts) {
- if (tsd_get_allocates() && !imalloc_init_check(sopts, dopts)) {
- return ENOMEM;
- }
-
- /* We always need the tsd. Let's grab it right away. */
- tsd_t *tsd = tsd_fetch();
- assert(tsd);
- if (likely(tsd_fast(tsd))) {
- /* Fast and common path. */
- tsd_assert_fast(tsd);
- sopts->slow = false;
- return imalloc_body(sopts, dopts, tsd);
- } else {
- if (!tsd_get_allocates() && !imalloc_init_check(sopts, dopts)) {
- return ENOMEM;
- }
-
- sopts->slow = true;
- return imalloc_body(sopts, dopts, tsd);
- }
-}
-
-JEMALLOC_NOINLINE
-void *
-malloc_default(size_t size) {
- void *ret;
- static_opts_t sopts;
- dynamic_opts_t dopts;
-
- /*
- * This variant has logging hook on exit but not on entry. It's callled
- * only by je_malloc, below, which emits the entry one for us (and, if
- * it calls us, does so only via tail call).
- */
-
- static_opts_init(&sopts);
- dynamic_opts_init(&dopts);
-
- sopts.null_out_result_on_error = true;
- sopts.set_errno_on_error = true;
- sopts.oom_string = "<jemalloc>: Error in malloc(): out of memory\n";
-
- dopts.result = &ret;
- dopts.num_items = 1;
- dopts.item_size = size;
-
- imalloc(&sopts, &dopts);
- /*
- * Note that this branch gets optimized away -- it immediately follows
- * the check on tsd_fast that sets sopts.slow.
- */
- if (sopts.slow) {
- uintptr_t args[3] = {size};
- hook_invoke_alloc(hook_alloc_malloc, ret, (uintptr_t)ret, args);
- }
-
- LOG("core.malloc.exit", "result: %p", ret);
-
- return ret;
-}
-
-/******************************************************************************/
-/*
- * Begin malloc(3)-compatible functions.
- */
-
-JEMALLOC_EXPORT JEMALLOC_ALLOCATOR JEMALLOC_RESTRICT_RETURN
-void JEMALLOC_NOTHROW *
-JEMALLOC_ATTR(malloc) JEMALLOC_ALLOC_SIZE(1)
-je_malloc(size_t size) {
- return imalloc_fastpath(size, &malloc_default);
-}
-
-JEMALLOC_EXPORT int JEMALLOC_NOTHROW
-JEMALLOC_ATTR(nonnull(1))
-je_posix_memalign(void **memptr, size_t alignment, size_t size) {
- int ret;
- static_opts_t sopts;
- dynamic_opts_t dopts;
-
- LOG("core.posix_memalign.entry", "mem ptr: %p, alignment: %zu, "
- "size: %zu", memptr, alignment, size);
-
- static_opts_init(&sopts);
- dynamic_opts_init(&dopts);
-
- sopts.bump_empty_aligned_alloc = true;
- sopts.min_alignment = sizeof(void *);
- sopts.oom_string =
- "<jemalloc>: Error allocating aligned memory: out of memory\n";
- sopts.invalid_alignment_string =
- "<jemalloc>: Error allocating aligned memory: invalid alignment\n";
-
- dopts.result = memptr;
- dopts.num_items = 1;
- dopts.item_size = size;
- dopts.alignment = alignment;
-
- ret = imalloc(&sopts, &dopts);
- if (sopts.slow) {
- uintptr_t args[3] = {(uintptr_t)memptr, (uintptr_t)alignment,
- (uintptr_t)size};
- hook_invoke_alloc(hook_alloc_posix_memalign, *memptr,
- (uintptr_t)ret, args);
- }
-
- LOG("core.posix_memalign.exit", "result: %d, alloc ptr: %p", ret,
- *memptr);
-
- return ret;
-}
-
-JEMALLOC_EXPORT JEMALLOC_ALLOCATOR JEMALLOC_RESTRICT_RETURN
-void JEMALLOC_NOTHROW *
-JEMALLOC_ATTR(malloc) JEMALLOC_ALLOC_SIZE(2)
-je_aligned_alloc(size_t alignment, size_t size) {
- void *ret;
-
- static_opts_t sopts;
- dynamic_opts_t dopts;
-
- LOG("core.aligned_alloc.entry", "alignment: %zu, size: %zu\n",
- alignment, size);
-
- static_opts_init(&sopts);
- dynamic_opts_init(&dopts);
-
- sopts.bump_empty_aligned_alloc = true;
- sopts.null_out_result_on_error = true;
- sopts.set_errno_on_error = true;
- sopts.min_alignment = 1;
- sopts.oom_string =
- "<jemalloc>: Error allocating aligned memory: out of memory\n";
- sopts.invalid_alignment_string =
- "<jemalloc>: Error allocating aligned memory: invalid alignment\n";
-
- dopts.result = &ret;
- dopts.num_items = 1;
- dopts.item_size = size;
- dopts.alignment = alignment;
-
- imalloc(&sopts, &dopts);
- if (sopts.slow) {
- uintptr_t args[3] = {(uintptr_t)alignment, (uintptr_t)size};
- hook_invoke_alloc(hook_alloc_aligned_alloc, ret,
- (uintptr_t)ret, args);
- }
-
- LOG("core.aligned_alloc.exit", "result: %p", ret);
-
- return ret;
-}
-
-JEMALLOC_EXPORT JEMALLOC_ALLOCATOR JEMALLOC_RESTRICT_RETURN
-void JEMALLOC_NOTHROW *
-JEMALLOC_ATTR(malloc) JEMALLOC_ALLOC_SIZE2(1, 2)
-je_calloc(size_t num, size_t size) {
- void *ret;
- static_opts_t sopts;
- dynamic_opts_t dopts;
-
- LOG("core.calloc.entry", "num: %zu, size: %zu\n", num, size);
-
- static_opts_init(&sopts);
- dynamic_opts_init(&dopts);
-
- sopts.may_overflow = true;
- sopts.null_out_result_on_error = true;
- sopts.set_errno_on_error = true;
- sopts.oom_string = "<jemalloc>: Error in calloc(): out of memory\n";
-
- dopts.result = &ret;
- dopts.num_items = num;
- dopts.item_size = size;
- dopts.zero = true;
-
- imalloc(&sopts, &dopts);
- if (sopts.slow) {
- uintptr_t args[3] = {(uintptr_t)num, (uintptr_t)size};
- hook_invoke_alloc(hook_alloc_calloc, ret, (uintptr_t)ret, args);
- }
-
- LOG("core.calloc.exit", "result: %p", ret);
-
- return ret;
-}
-
-JEMALLOC_ALWAYS_INLINE void
-ifree(tsd_t *tsd, void *ptr, tcache_t *tcache, bool slow_path) {
- if (!slow_path) {
- tsd_assert_fast(tsd);
- }
- check_entry_exit_locking(tsd_tsdn(tsd));
- if (tsd_reentrancy_level_get(tsd) != 0) {
- assert(slow_path);
- }
-
- assert(ptr != NULL);
- assert(malloc_initialized() || IS_INITIALIZER);
-
- emap_alloc_ctx_t alloc_ctx;
- emap_alloc_ctx_lookup(tsd_tsdn(tsd), &arena_emap_global, ptr,
- &alloc_ctx);
- assert(alloc_ctx.szind != SC_NSIZES);
-
- size_t usize = sz_index2size(alloc_ctx.szind);
- if (config_prof && opt_prof) {
- prof_free(tsd, ptr, usize, &alloc_ctx);
- }
-
- if (likely(!slow_path)) {
- idalloctm(tsd_tsdn(tsd), ptr, tcache, &alloc_ctx, false,
- false);
- } else {
- if (config_fill && slow_path && opt_junk_free) {
- junk_free_callback(ptr, usize);
- }
- idalloctm(tsd_tsdn(tsd), ptr, tcache, &alloc_ctx, false,
- true);
- }
- thread_dalloc_event(tsd, usize);
-}
-
-JEMALLOC_ALWAYS_INLINE bool
-maybe_check_alloc_ctx(tsd_t *tsd, void *ptr, emap_alloc_ctx_t *alloc_ctx) {
- if (config_opt_size_checks) {
- emap_alloc_ctx_t dbg_ctx;
- emap_alloc_ctx_lookup(tsd_tsdn(tsd), &arena_emap_global, ptr,
- &dbg_ctx);
- if (alloc_ctx->szind != dbg_ctx.szind) {
- safety_check_fail_sized_dealloc(
- /* current_dealloc */ true, ptr,
- /* true_size */ sz_size2index(dbg_ctx.szind),
- /* input_size */ sz_size2index(alloc_ctx->szind));
- return true;
- }
- if (alloc_ctx->slab != dbg_ctx.slab) {
- safety_check_fail(
- "Internal heap corruption detected: "
- "mismatch in slab bit");
- return true;
- }
- }
- return false;
-}
-
-JEMALLOC_ALWAYS_INLINE void
-isfree(tsd_t *tsd, void *ptr, size_t usize, tcache_t *tcache, bool slow_path) {
- if (!slow_path) {
- tsd_assert_fast(tsd);
- }
- check_entry_exit_locking(tsd_tsdn(tsd));
- if (tsd_reentrancy_level_get(tsd) != 0) {
- assert(slow_path);
- }
-
- assert(ptr != NULL);
- assert(malloc_initialized() || IS_INITIALIZER);
-
- emap_alloc_ctx_t alloc_ctx;
- if (!config_prof) {
- alloc_ctx.szind = sz_size2index(usize);
- alloc_ctx.slab = (alloc_ctx.szind < SC_NBINS);
- } else {
- if (likely(!prof_sample_aligned(ptr))) {
- /*
- * When the ptr is not page aligned, it was not sampled.
- * usize can be trusted to determine szind and slab.
- */
- alloc_ctx.szind = sz_size2index(usize);
- alloc_ctx.slab = (alloc_ctx.szind < SC_NBINS);
- } else if (opt_prof) {
- emap_alloc_ctx_lookup(tsd_tsdn(tsd), &arena_emap_global,
- ptr, &alloc_ctx);
-
- if (config_opt_safety_checks) {
- /* Small alloc may have !slab (sampled). */
- if (unlikely(alloc_ctx.szind !=
- sz_size2index(usize))) {
- safety_check_fail_sized_dealloc(
- /* current_dealloc */ true, ptr,
- /* true_size */ sz_index2size(
- alloc_ctx.szind),
- /* input_size */ usize);
- }
- }
- } else {
- alloc_ctx.szind = sz_size2index(usize);
- alloc_ctx.slab = (alloc_ctx.szind < SC_NBINS);
- }
- }
- bool fail = maybe_check_alloc_ctx(tsd, ptr, &alloc_ctx);
- if (fail) {
- /*
- * This is a heap corruption bug. In real life we'll crash; for
- * the unit test we just want to avoid breaking anything too
- * badly to get a test result out. Let's leak instead of trying
- * to free.
- */
- return;
- }
-
- if (config_prof && opt_prof) {
- prof_free(tsd, ptr, usize, &alloc_ctx);
- }
- if (likely(!slow_path)) {
- isdalloct(tsd_tsdn(tsd), ptr, usize, tcache, &alloc_ctx,
- false);
- } else {
- if (config_fill && slow_path && opt_junk_free) {
- junk_free_callback(ptr, usize);
- }
- isdalloct(tsd_tsdn(tsd), ptr, usize, tcache, &alloc_ctx,
- true);
- }
- thread_dalloc_event(tsd, usize);
-}
-
-JEMALLOC_NOINLINE
-void
-free_default(void *ptr) {
- UTRACE(ptr, 0, 0);
- if (likely(ptr != NULL)) {
- /*
- * We avoid setting up tsd fully (e.g. tcache, arena binding)
- * based on only free() calls -- other activities trigger the
- * minimal to full transition. This is because free() may
- * happen during thread shutdown after tls deallocation: if a
- * thread never had any malloc activities until then, a
- * fully-setup tsd won't be destructed properly.
- */
- tsd_t *tsd = tsd_fetch_min();
- check_entry_exit_locking(tsd_tsdn(tsd));
-
- if (likely(tsd_fast(tsd))) {
- tcache_t *tcache = tcache_get_from_ind(tsd,
- TCACHE_IND_AUTOMATIC, /* slow */ false,
- /* is_alloc */ false);
- ifree(tsd, ptr, tcache, /* slow */ false);
- } else {
- tcache_t *tcache = tcache_get_from_ind(tsd,
- TCACHE_IND_AUTOMATIC, /* slow */ true,
- /* is_alloc */ false);
- uintptr_t args_raw[3] = {(uintptr_t)ptr};
- hook_invoke_dalloc(hook_dalloc_free, ptr, args_raw);
- ifree(tsd, ptr, tcache, /* slow */ true);
- }
-
- check_entry_exit_locking(tsd_tsdn(tsd));
- }
-}
-
-JEMALLOC_ALWAYS_INLINE bool
-free_fastpath_nonfast_aligned(void *ptr, bool check_prof) {
- /*
- * free_fastpath do not handle two uncommon cases: 1) sampled profiled
- * objects and 2) sampled junk & stash for use-after-free detection.
- * Both have special alignments which are used to escape the fastpath.
- *
- * prof_sample is page-aligned, which covers the UAF check when both
- * are enabled (the assertion below). Avoiding redundant checks since
- * this is on the fastpath -- at most one runtime branch from this.
- */
- if (config_debug && cache_bin_nonfast_aligned(ptr)) {
- assert(prof_sample_aligned(ptr));
- }
-
- if (config_prof && check_prof) {
- /* When prof is enabled, the prof_sample alignment is enough. */
- if (prof_sample_aligned(ptr)) {
- return true;
- } else {
- return false;
- }
- }
-
- if (config_uaf_detection) {
- if (cache_bin_nonfast_aligned(ptr)) {
- return true;
- } else {
- return false;
- }
- }
-
- return false;
-}
-
-/* Returns whether or not the free attempt was successful. */
-JEMALLOC_ALWAYS_INLINE
-bool free_fastpath(void *ptr, size_t size, bool size_hint) {
- tsd_t *tsd = tsd_get(false);
- /* The branch gets optimized away unless tsd_get_allocates(). */
- if (unlikely(tsd == NULL)) {
- return false;
- }
- /*
- * The tsd_fast() / initialized checks are folded into the branch
- * testing (deallocated_after >= threshold) later in this function.
- * The threshold will be set to 0 when !tsd_fast.
- */
- assert(tsd_fast(tsd) ||
- *tsd_thread_deallocated_next_event_fastp_get_unsafe(tsd) == 0);
-
- emap_alloc_ctx_t alloc_ctx;
- if (!size_hint) {
- bool err = emap_alloc_ctx_try_lookup_fast(tsd,
- &arena_emap_global, ptr, &alloc_ctx);
-
- /* Note: profiled objects will have alloc_ctx.slab set */
- if (unlikely(err || !alloc_ctx.slab ||
- free_fastpath_nonfast_aligned(ptr,
- /* check_prof */ false))) {
- return false;
- }
- assert(alloc_ctx.szind != SC_NSIZES);
- } else {
- /*
- * Check for both sizes that are too large, and for sampled /
- * special aligned objects. The alignment check will also check
- * for null ptr.
- */
- if (unlikely(size > SC_LOOKUP_MAXCLASS ||
- free_fastpath_nonfast_aligned(ptr,
- /* check_prof */ true))) {
- return false;
- }
- alloc_ctx.szind = sz_size2index_lookup(size);
- /* Max lookup class must be small. */
- assert(alloc_ctx.szind < SC_NBINS);
- /* This is a dead store, except when opt size checking is on. */
- alloc_ctx.slab = true;
- }
- /*
- * Currently the fastpath only handles small sizes. The branch on
- * SC_LOOKUP_MAXCLASS makes sure of it. This lets us avoid checking
- * tcache szind upper limit (i.e. tcache_maxclass) as well.
- */
- assert(alloc_ctx.slab);
-
- uint64_t deallocated, threshold;
- te_free_fastpath_ctx(tsd, &deallocated, &threshold);
-
- size_t usize = sz_index2size(alloc_ctx.szind);
- uint64_t deallocated_after = deallocated + usize;
- /*
- * Check for events and tsd non-nominal (fast_threshold will be set to
- * 0) in a single branch. Note that this handles the uninitialized case
- * as well (TSD init will be triggered on the non-fastpath). Therefore
- * anything depends on a functional TSD (e.g. the alloc_ctx sanity check
- * below) needs to be after this branch.
- */
- if (unlikely(deallocated_after >= threshold)) {
- return false;
- }
- assert(tsd_fast(tsd));
- bool fail = maybe_check_alloc_ctx(tsd, ptr, &alloc_ctx);
- if (fail) {
- /* See the comment in isfree. */
- return true;
- }
-
- tcache_t *tcache = tcache_get_from_ind(tsd, TCACHE_IND_AUTOMATIC,
- /* slow */ false, /* is_alloc */ false);
- cache_bin_t *bin = &tcache->bins[alloc_ctx.szind];
-
- /*
- * If junking were enabled, this is where we would do it. It's not
- * though, since we ensured above that we're on the fast path. Assert
- * that to double-check.
- */
- assert(!opt_junk_free);
-
- if (!cache_bin_dalloc_easy(bin, ptr)) {
- return false;
- }
-
- *tsd_thread_deallocatedp_get(tsd) = deallocated_after;
-
- return true;
-}
-
-JEMALLOC_EXPORT void JEMALLOC_NOTHROW
-je_free(void *ptr) {
- LOG("core.free.entry", "ptr: %p", ptr);
-
- if (!free_fastpath(ptr, 0, false)) {
- free_default(ptr);
- }
-
- LOG("core.free.exit", "");
-}
-
-/*
- * End malloc(3)-compatible functions.
- */
-/******************************************************************************/
-/*
- * Begin non-standard override functions.
- */
-
-#ifdef JEMALLOC_OVERRIDE_MEMALIGN
-JEMALLOC_EXPORT JEMALLOC_ALLOCATOR JEMALLOC_RESTRICT_RETURN
-void JEMALLOC_NOTHROW *
-JEMALLOC_ATTR(malloc)
-je_memalign(size_t alignment, size_t size) {
- void *ret;
- static_opts_t sopts;
- dynamic_opts_t dopts;
-
- LOG("core.memalign.entry", "alignment: %zu, size: %zu\n", alignment,
- size);
-
- static_opts_init(&sopts);
- dynamic_opts_init(&dopts);
-
- sopts.min_alignment = 1;
- sopts.oom_string =
- "<jemalloc>: Error allocating aligned memory: out of memory\n";
- sopts.invalid_alignment_string =
- "<jemalloc>: Error allocating aligned memory: invalid alignment\n";
- sopts.null_out_result_on_error = true;
-
- dopts.result = &ret;
- dopts.num_items = 1;
- dopts.item_size = size;
- dopts.alignment = alignment;
-
- imalloc(&sopts, &dopts);
- if (sopts.slow) {
- uintptr_t args[3] = {alignment, size};
- hook_invoke_alloc(hook_alloc_memalign, ret, (uintptr_t)ret,
- args);
- }
-
- LOG("core.memalign.exit", "result: %p", ret);
- return ret;
-}
-#endif
-
-#ifdef JEMALLOC_OVERRIDE_VALLOC
-JEMALLOC_EXPORT JEMALLOC_ALLOCATOR JEMALLOC_RESTRICT_RETURN
-void JEMALLOC_NOTHROW *
-JEMALLOC_ATTR(malloc)
-je_valloc(size_t size) {
- void *ret;
-
- static_opts_t sopts;
- dynamic_opts_t dopts;
-
- LOG("core.valloc.entry", "size: %zu\n", size);
-
- static_opts_init(&sopts);
- dynamic_opts_init(&dopts);
-
- sopts.null_out_result_on_error = true;
- sopts.min_alignment = PAGE;
- sopts.oom_string =
- "<jemalloc>: Error allocating aligned memory: out of memory\n";
- sopts.invalid_alignment_string =
- "<jemalloc>: Error allocating aligned memory: invalid alignment\n";
-
- dopts.result = &ret;
- dopts.num_items = 1;
- dopts.item_size = size;
- dopts.alignment = PAGE;
-
- imalloc(&sopts, &dopts);
- if (sopts.slow) {
- uintptr_t args[3] = {size};
- hook_invoke_alloc(hook_alloc_valloc, ret, (uintptr_t)ret, args);
- }
-
- LOG("core.valloc.exit", "result: %p\n", ret);
- return ret;
-}
-#endif
-
-#if defined(JEMALLOC_IS_MALLOC) && defined(JEMALLOC_GLIBC_MALLOC_HOOK)
-/*
- * glibc provides the RTLD_DEEPBIND flag for dlopen which can make it possible
- * to inconsistently reference libc's malloc(3)-compatible functions
- * (https://bugzilla.mozilla.org/show_bug.cgi?id=493541).
- *
- * These definitions interpose hooks in glibc. The functions are actually
- * passed an extra argument for the caller return address, which will be
- * ignored.
- */
-#include <features.h> // defines __GLIBC__ if we are compiling against glibc
-
-JEMALLOC_EXPORT void (*__free_hook)(void *ptr) = je_free;
-JEMALLOC_EXPORT void *(*__malloc_hook)(size_t size) = je_malloc;
-JEMALLOC_EXPORT void *(*__realloc_hook)(void *ptr, size_t size) = je_realloc;
-# ifdef JEMALLOC_GLIBC_MEMALIGN_HOOK
-JEMALLOC_EXPORT void *(*__memalign_hook)(size_t alignment, size_t size) =
- je_memalign;
-# endif
-
-# ifdef __GLIBC__
-/*
- * To enable static linking with glibc, the libc specific malloc interface must
- * be implemented also, so none of glibc's malloc.o functions are added to the
- * link.
- */
-# define ALIAS(je_fn) __attribute__((alias (#je_fn), used))
-/* To force macro expansion of je_ prefix before stringification. */
-# define PREALIAS(je_fn) ALIAS(je_fn)
-# ifdef JEMALLOC_OVERRIDE___LIBC_CALLOC
-void *__libc_calloc(size_t n, size_t size) PREALIAS(je_calloc);
-# endif
-# ifdef JEMALLOC_OVERRIDE___LIBC_FREE
-void __libc_free(void* ptr) PREALIAS(je_free);
-# endif
-# ifdef JEMALLOC_OVERRIDE___LIBC_MALLOC
-void *__libc_malloc(size_t size) PREALIAS(je_malloc);
-# endif
-# ifdef JEMALLOC_OVERRIDE___LIBC_MEMALIGN
-void *__libc_memalign(size_t align, size_t s) PREALIAS(je_memalign);
-# endif
-# ifdef JEMALLOC_OVERRIDE___LIBC_REALLOC
-void *__libc_realloc(void* ptr, size_t size) PREALIAS(je_realloc);
-# endif
-# ifdef JEMALLOC_OVERRIDE___LIBC_VALLOC
-void *__libc_valloc(size_t size) PREALIAS(je_valloc);
-# endif
-# ifdef JEMALLOC_OVERRIDE___POSIX_MEMALIGN
-int __posix_memalign(void** r, size_t a, size_t s) PREALIAS(je_posix_memalign);
-# endif
-# undef PREALIAS
-# undef ALIAS
-# endif
-#endif
-
-/*
- * End non-standard override functions.
- */
-/******************************************************************************/
-/*
- * Begin non-standard functions.
- */
-
-JEMALLOC_ALWAYS_INLINE unsigned
-mallocx_tcache_get(int flags) {
- if (likely((flags & MALLOCX_TCACHE_MASK) == 0)) {
- return TCACHE_IND_AUTOMATIC;
- } else if ((flags & MALLOCX_TCACHE_MASK) == MALLOCX_TCACHE_NONE) {
- return TCACHE_IND_NONE;
- } else {
- return MALLOCX_TCACHE_GET(flags);
- }
-}
-
-JEMALLOC_ALWAYS_INLINE unsigned
-mallocx_arena_get(int flags) {
- if (unlikely((flags & MALLOCX_ARENA_MASK) != 0)) {
- return MALLOCX_ARENA_GET(flags);
- } else {
- return ARENA_IND_AUTOMATIC;
- }
-}
-
-#ifdef JEMALLOC_EXPERIMENTAL_SMALLOCX_API
-
-#define JEMALLOC_SMALLOCX_CONCAT_HELPER(x, y) x ## y
-#define JEMALLOC_SMALLOCX_CONCAT_HELPER2(x, y) \
- JEMALLOC_SMALLOCX_CONCAT_HELPER(x, y)
-
-typedef struct {
- void *ptr;
- size_t size;
-} smallocx_return_t;
-
-JEMALLOC_EXPORT JEMALLOC_ALLOCATOR JEMALLOC_RESTRICT_RETURN
-smallocx_return_t JEMALLOC_NOTHROW
-/*
- * The attribute JEMALLOC_ATTR(malloc) cannot be used due to:
- * - https://gcc.gnu.org/bugzilla/show_bug.cgi?id=86488
- */
-JEMALLOC_SMALLOCX_CONCAT_HELPER2(je_smallocx_, JEMALLOC_VERSION_GID_IDENT)
- (size_t size, int flags) {
- /*
- * Note: the attribute JEMALLOC_ALLOC_SIZE(1) cannot be
- * used here because it makes writing beyond the `size`
- * of the `ptr` undefined behavior, but the objective
- * of this function is to allow writing beyond `size`
- * up to `smallocx_return_t::size`.
- */
- smallocx_return_t ret;
- static_opts_t sopts;
- dynamic_opts_t dopts;
-
- LOG("core.smallocx.entry", "size: %zu, flags: %d", size, flags);
-
- static_opts_init(&sopts);
- dynamic_opts_init(&dopts);
-
- sopts.assert_nonempty_alloc = true;
- sopts.null_out_result_on_error = true;
- sopts.oom_string = "<jemalloc>: Error in mallocx(): out of memory\n";
- sopts.usize = true;
-
- dopts.result = &ret.ptr;
- dopts.num_items = 1;
- dopts.item_size = size;
- if (unlikely(flags != 0)) {
- dopts.alignment = MALLOCX_ALIGN_GET(flags);
- dopts.zero = MALLOCX_ZERO_GET(flags);
- dopts.tcache_ind = mallocx_tcache_get(flags);
- dopts.arena_ind = mallocx_arena_get(flags);
- }
-
- imalloc(&sopts, &dopts);
- assert(dopts.usize == je_nallocx(size, flags));
- ret.size = dopts.usize;
-
- LOG("core.smallocx.exit", "result: %p, size: %zu", ret.ptr, ret.size);
- return ret;
-}
-#undef JEMALLOC_SMALLOCX_CONCAT_HELPER
-#undef JEMALLOC_SMALLOCX_CONCAT_HELPER2
-#endif
-
-JEMALLOC_EXPORT JEMALLOC_ALLOCATOR JEMALLOC_RESTRICT_RETURN
-void JEMALLOC_NOTHROW *
-JEMALLOC_ATTR(malloc) JEMALLOC_ALLOC_SIZE(1)
-je_mallocx(size_t size, int flags) {
- void *ret;
- static_opts_t sopts;
- dynamic_opts_t dopts;
-
- LOG("core.mallocx.entry", "size: %zu, flags: %d", size, flags);
-
- static_opts_init(&sopts);
- dynamic_opts_init(&dopts);
-
- sopts.assert_nonempty_alloc = true;
- sopts.null_out_result_on_error = true;
- sopts.oom_string = "<jemalloc>: Error in mallocx(): out of memory\n";
-
- dopts.result = &ret;
- dopts.num_items = 1;
- dopts.item_size = size;
- if (unlikely(flags != 0)) {
- dopts.alignment = MALLOCX_ALIGN_GET(flags);
- dopts.zero = MALLOCX_ZERO_GET(flags);
- dopts.tcache_ind = mallocx_tcache_get(flags);
- dopts.arena_ind = mallocx_arena_get(flags);
- }
-
- imalloc(&sopts, &dopts);
- if (sopts.slow) {
- uintptr_t args[3] = {size, flags};
- hook_invoke_alloc(hook_alloc_mallocx, ret, (uintptr_t)ret,
- args);
- }
-
- LOG("core.mallocx.exit", "result: %p", ret);
- return ret;
-}
-
-static void *
-irallocx_prof_sample(tsdn_t *tsdn, void *old_ptr, size_t old_usize,
- size_t usize, size_t alignment, bool zero, tcache_t *tcache, arena_t *arena,
- prof_tctx_t *tctx, hook_ralloc_args_t *hook_args) {
- void *p;
-
- if (tctx == NULL) {
- return NULL;
- }
-
- alignment = prof_sample_align(alignment);
- if (usize <= SC_SMALL_MAXCLASS) {
- p = iralloct(tsdn, old_ptr, old_usize,
- SC_LARGE_MINCLASS, alignment, zero, tcache,
- arena, hook_args);
- if (p == NULL) {
- return NULL;
- }
- arena_prof_promote(tsdn, p, usize);
- } else {
- p = iralloct(tsdn, old_ptr, old_usize, usize, alignment, zero,
- tcache, arena, hook_args);
- }
- assert(prof_sample_aligned(p));
-
- return p;
-}
-
-JEMALLOC_ALWAYS_INLINE void *
-irallocx_prof(tsd_t *tsd, void *old_ptr, size_t old_usize, size_t size,
- size_t alignment, size_t usize, bool zero, tcache_t *tcache,
- arena_t *arena, emap_alloc_ctx_t *alloc_ctx,
- hook_ralloc_args_t *hook_args) {
- prof_info_t old_prof_info;
- prof_info_get_and_reset_recent(tsd, old_ptr, alloc_ctx, &old_prof_info);
- bool prof_active = prof_active_get_unlocked();
- bool sample_event = te_prof_sample_event_lookahead(tsd, usize);
- prof_tctx_t *tctx = prof_alloc_prep(tsd, prof_active, sample_event);
- void *p;
- if (unlikely((uintptr_t)tctx != (uintptr_t)1U)) {
- p = irallocx_prof_sample(tsd_tsdn(tsd), old_ptr, old_usize,
- usize, alignment, zero, tcache, arena, tctx, hook_args);
- } else {
- p = iralloct(tsd_tsdn(tsd), old_ptr, old_usize, size, alignment,
- zero, tcache, arena, hook_args);
- }
- if (unlikely(p == NULL)) {
- prof_alloc_rollback(tsd, tctx);
- return NULL;
- }
- assert(usize == isalloc(tsd_tsdn(tsd), p));
- prof_realloc(tsd, p, size, usize, tctx, prof_active, old_ptr,
- old_usize, &old_prof_info, sample_event);
-
- return p;
-}
-
-static void *
-do_rallocx(void *ptr, size_t size, int flags, bool is_realloc) {
- void *p;
- tsd_t *tsd;
- size_t usize;
- size_t old_usize;
- size_t alignment = MALLOCX_ALIGN_GET(flags);
- arena_t *arena;
-
- assert(ptr != NULL);
- assert(size != 0);
- assert(malloc_initialized() || IS_INITIALIZER);
- tsd = tsd_fetch();
- check_entry_exit_locking(tsd_tsdn(tsd));
-
- bool zero = zero_get(MALLOCX_ZERO_GET(flags), /* slow */ true);
-
- unsigned arena_ind = mallocx_arena_get(flags);
- if (arena_get_from_ind(tsd, arena_ind, &arena)) {
- goto label_oom;
- }
-
- unsigned tcache_ind = mallocx_tcache_get(flags);
- tcache_t *tcache = tcache_get_from_ind(tsd, tcache_ind,
- /* slow */ true, /* is_alloc */ true);
-
- emap_alloc_ctx_t alloc_ctx;
- emap_alloc_ctx_lookup(tsd_tsdn(tsd), &arena_emap_global, ptr,
- &alloc_ctx);
- assert(alloc_ctx.szind != SC_NSIZES);
- old_usize = sz_index2size(alloc_ctx.szind);
- assert(old_usize == isalloc(tsd_tsdn(tsd), ptr));
- if (aligned_usize_get(size, alignment, &usize, NULL, false)) {
- goto label_oom;
- }
-
- hook_ralloc_args_t hook_args = {is_realloc, {(uintptr_t)ptr, size,
- flags, 0}};
- if (config_prof && opt_prof) {
- p = irallocx_prof(tsd, ptr, old_usize, size, alignment, usize,
- zero, tcache, arena, &alloc_ctx, &hook_args);
- if (unlikely(p == NULL)) {
- goto label_oom;
- }
- } else {
- p = iralloct(tsd_tsdn(tsd), ptr, old_usize, size, alignment,
- zero, tcache, arena, &hook_args);
- if (unlikely(p == NULL)) {
- goto label_oom;
- }
- assert(usize == isalloc(tsd_tsdn(tsd), p));
- }
- assert(alignment == 0 || ((uintptr_t)p & (alignment - 1)) == ZU(0));
- thread_alloc_event(tsd, usize);
- thread_dalloc_event(tsd, old_usize);
-
- UTRACE(ptr, size, p);
- check_entry_exit_locking(tsd_tsdn(tsd));
-
- if (config_fill && unlikely(opt_junk_alloc) && usize > old_usize
- && !zero) {
- size_t excess_len = usize - old_usize;
- void *excess_start = (void *)((uintptr_t)p + old_usize);
- junk_alloc_callback(excess_start, excess_len);
- }
-
- return p;
-label_oom:
- if (config_xmalloc && unlikely(opt_xmalloc)) {
- malloc_write("<jemalloc>: Error in rallocx(): out of memory\n");
- abort();
- }
- UTRACE(ptr, size, 0);
- check_entry_exit_locking(tsd_tsdn(tsd));
-
- return NULL;
-}
-
-JEMALLOC_EXPORT JEMALLOC_ALLOCATOR JEMALLOC_RESTRICT_RETURN
-void JEMALLOC_NOTHROW *
-JEMALLOC_ALLOC_SIZE(2)
-je_rallocx(void *ptr, size_t size, int flags) {
- LOG("core.rallocx.entry", "ptr: %p, size: %zu, flags: %d", ptr,
- size, flags);
- void *ret = do_rallocx(ptr, size, flags, false);
- LOG("core.rallocx.exit", "result: %p", ret);
- return ret;
-}
-
-static void *
-do_realloc_nonnull_zero(void *ptr) {
- if (config_stats) {
- atomic_fetch_add_zu(&zero_realloc_count, 1, ATOMIC_RELAXED);
- }
- if (opt_zero_realloc_action == zero_realloc_action_alloc) {
- /*
- * The user might have gotten an alloc setting while expecting a
- * free setting. If that's the case, we at least try to
- * reduce the harm, and turn off the tcache while allocating, so
- * that we'll get a true first fit.
- */
- return do_rallocx(ptr, 1, MALLOCX_TCACHE_NONE, true);
- } else if (opt_zero_realloc_action == zero_realloc_action_free) {
- UTRACE(ptr, 0, 0);
- tsd_t *tsd = tsd_fetch();
- check_entry_exit_locking(tsd_tsdn(tsd));
-
- tcache_t *tcache = tcache_get_from_ind(tsd,
- TCACHE_IND_AUTOMATIC, /* slow */ true,
- /* is_alloc */ false);
- uintptr_t args[3] = {(uintptr_t)ptr, 0};
- hook_invoke_dalloc(hook_dalloc_realloc, ptr, args);
- ifree(tsd, ptr, tcache, true);
-
- check_entry_exit_locking(tsd_tsdn(tsd));
- return NULL;
- } else {
- safety_check_fail("Called realloc(non-null-ptr, 0) with "
- "zero_realloc:abort set\n");
- /* In real code, this will never run; the safety check failure
- * will call abort. In the unit test, we just want to bail out
- * without corrupting internal state that the test needs to
- * finish.
- */
- return NULL;
- }
-}
-
-JEMALLOC_EXPORT JEMALLOC_ALLOCATOR JEMALLOC_RESTRICT_RETURN
-void JEMALLOC_NOTHROW *
-JEMALLOC_ALLOC_SIZE(2)
-je_realloc(void *ptr, size_t size) {
- LOG("core.realloc.entry", "ptr: %p, size: %zu\n", ptr, size);
-
- if (likely(ptr != NULL && size != 0)) {
- void *ret = do_rallocx(ptr, size, 0, true);
- LOG("core.realloc.exit", "result: %p", ret);
- return ret;
- } else if (ptr != NULL && size == 0) {
- void *ret = do_realloc_nonnull_zero(ptr);
- LOG("core.realloc.exit", "result: %p", ret);
- return ret;
- } else {
- /* realloc(NULL, size) is equivalent to malloc(size). */
- void *ret;
-
- static_opts_t sopts;
- dynamic_opts_t dopts;
-
- static_opts_init(&sopts);
- dynamic_opts_init(&dopts);
-
- sopts.null_out_result_on_error = true;
- sopts.set_errno_on_error = true;
- sopts.oom_string =
- "<jemalloc>: Error in realloc(): out of memory\n";
-
- dopts.result = &ret;
- dopts.num_items = 1;
- dopts.item_size = size;
-
- imalloc(&sopts, &dopts);
- if (sopts.slow) {
- uintptr_t args[3] = {(uintptr_t)ptr, size};
- hook_invoke_alloc(hook_alloc_realloc, ret,
- (uintptr_t)ret, args);
- }
- LOG("core.realloc.exit", "result: %p", ret);
- return ret;
- }
-}
-
-JEMALLOC_ALWAYS_INLINE size_t
-ixallocx_helper(tsdn_t *tsdn, void *ptr, size_t old_usize, size_t size,
- size_t extra, size_t alignment, bool zero) {
- size_t newsize;
-
- if (ixalloc(tsdn, ptr, old_usize, size, extra, alignment, zero,
- &newsize)) {
- return old_usize;
- }
-
- return newsize;
-}
-
-static size_t
-ixallocx_prof_sample(tsdn_t *tsdn, void *ptr, size_t old_usize, size_t size,
- size_t extra, size_t alignment, bool zero, prof_tctx_t *tctx) {
- /* Sampled allocation needs to be page aligned. */
- if (tctx == NULL || !prof_sample_aligned(ptr)) {
- return old_usize;
- }
-
- return ixallocx_helper(tsdn, ptr, old_usize, size, extra, alignment,
- zero);
-}
-
-JEMALLOC_ALWAYS_INLINE size_t
-ixallocx_prof(tsd_t *tsd, void *ptr, size_t old_usize, size_t size,
- size_t extra, size_t alignment, bool zero, emap_alloc_ctx_t *alloc_ctx) {
- /*
- * old_prof_info is only used for asserting that the profiling info
- * isn't changed by the ixalloc() call.
- */
- prof_info_t old_prof_info;
- prof_info_get(tsd, ptr, alloc_ctx, &old_prof_info);
-
- /*
- * usize isn't knowable before ixalloc() returns when extra is non-zero.
- * Therefore, compute its maximum possible value and use that in
- * prof_alloc_prep() to decide whether to capture a backtrace.
- * prof_realloc() will use the actual usize to decide whether to sample.
- */
- size_t usize_max;
- if (aligned_usize_get(size + extra, alignment, &usize_max, NULL,
- false)) {
- /*
- * usize_max is out of range, and chances are that allocation
- * will fail, but use the maximum possible value and carry on
- * with prof_alloc_prep(), just in case allocation succeeds.
- */
- usize_max = SC_LARGE_MAXCLASS;
- }
- bool prof_active = prof_active_get_unlocked();
- bool sample_event = te_prof_sample_event_lookahead(tsd, usize_max);
- prof_tctx_t *tctx = prof_alloc_prep(tsd, prof_active, sample_event);
-
- size_t usize;
- if (unlikely((uintptr_t)tctx != (uintptr_t)1U)) {
- usize = ixallocx_prof_sample(tsd_tsdn(tsd), ptr, old_usize,
- size, extra, alignment, zero, tctx);
- } else {
- usize = ixallocx_helper(tsd_tsdn(tsd), ptr, old_usize, size,
- extra, alignment, zero);
- }
-
- /*
- * At this point we can still safely get the original profiling
- * information associated with the ptr, because (a) the edata_t object
- * associated with the ptr still lives and (b) the profiling info
- * fields are not touched. "(a)" is asserted in the outer je_xallocx()
- * function, and "(b)" is indirectly verified below by checking that
- * the alloc_tctx field is unchanged.
- */
- prof_info_t prof_info;
- if (usize == old_usize) {
- prof_info_get(tsd, ptr, alloc_ctx, &prof_info);
- prof_alloc_rollback(tsd, tctx);
- } else {
- prof_info_get_and_reset_recent(tsd, ptr, alloc_ctx, &prof_info);
- assert(usize <= usize_max);
- sample_event = te_prof_sample_event_lookahead(tsd, usize);
- prof_realloc(tsd, ptr, size, usize, tctx, prof_active, ptr,
- old_usize, &prof_info, sample_event);
- }
-
- assert(old_prof_info.alloc_tctx == prof_info.alloc_tctx);
- return usize;
-}
-
-JEMALLOC_EXPORT size_t JEMALLOC_NOTHROW
-je_xallocx(void *ptr, size_t size, size_t extra, int flags) {
- tsd_t *tsd;
- size_t usize, old_usize;
- size_t alignment = MALLOCX_ALIGN_GET(flags);
- bool zero = zero_get(MALLOCX_ZERO_GET(flags), /* slow */ true);
-
- LOG("core.xallocx.entry", "ptr: %p, size: %zu, extra: %zu, "
- "flags: %d", ptr, size, extra, flags);
-
- assert(ptr != NULL);
- assert(size != 0);
- assert(SIZE_T_MAX - size >= extra);
- assert(malloc_initialized() || IS_INITIALIZER);
- tsd = tsd_fetch();
- check_entry_exit_locking(tsd_tsdn(tsd));
-
- /*
- * old_edata is only for verifying that xallocx() keeps the edata_t
- * object associated with the ptr (though the content of the edata_t
- * object can be changed).
- */
- edata_t *old_edata = emap_edata_lookup(tsd_tsdn(tsd),
- &arena_emap_global, ptr);
-
- emap_alloc_ctx_t alloc_ctx;
- emap_alloc_ctx_lookup(tsd_tsdn(tsd), &arena_emap_global, ptr,
- &alloc_ctx);
- assert(alloc_ctx.szind != SC_NSIZES);
- old_usize = sz_index2size(alloc_ctx.szind);
- assert(old_usize == isalloc(tsd_tsdn(tsd), ptr));
- /*
- * The API explicitly absolves itself of protecting against (size +
- * extra) numerical overflow, but we may need to clamp extra to avoid
- * exceeding SC_LARGE_MAXCLASS.
- *
- * Ordinarily, size limit checking is handled deeper down, but here we
- * have to check as part of (size + extra) clamping, since we need the
- * clamped value in the above helper functions.
- */
- if (unlikely(size > SC_LARGE_MAXCLASS)) {
- usize = old_usize;
- goto label_not_resized;
- }
- if (unlikely(SC_LARGE_MAXCLASS - size < extra)) {
- extra = SC_LARGE_MAXCLASS - size;
- }
-
- if (config_prof && opt_prof) {
- usize = ixallocx_prof(tsd, ptr, old_usize, size, extra,
- alignment, zero, &alloc_ctx);
- } else {
- usize = ixallocx_helper(tsd_tsdn(tsd), ptr, old_usize, size,
- extra, alignment, zero);
- }
-
- /*
- * xallocx() should keep using the same edata_t object (though its
- * content can be changed).
- */
- assert(emap_edata_lookup(tsd_tsdn(tsd), &arena_emap_global, ptr)
- == old_edata);
-
- if (unlikely(usize == old_usize)) {
- goto label_not_resized;
- }
- thread_alloc_event(tsd, usize);
- thread_dalloc_event(tsd, old_usize);
-
- if (config_fill && unlikely(opt_junk_alloc) && usize > old_usize &&
- !zero) {
- size_t excess_len = usize - old_usize;
- void *excess_start = (void *)((uintptr_t)ptr + old_usize);
- junk_alloc_callback(excess_start, excess_len);
- }
-label_not_resized:
- if (unlikely(!tsd_fast(tsd))) {
- uintptr_t args[4] = {(uintptr_t)ptr, size, extra, flags};
- hook_invoke_expand(hook_expand_xallocx, ptr, old_usize,
- usize, (uintptr_t)usize, args);
- }
-
- UTRACE(ptr, size, ptr);
- check_entry_exit_locking(tsd_tsdn(tsd));
-
- LOG("core.xallocx.exit", "result: %zu", usize);
- return usize;
-}
-
-JEMALLOC_EXPORT size_t JEMALLOC_NOTHROW
-JEMALLOC_ATTR(pure)
-je_sallocx(const void *ptr, int flags) {
- size_t usize;
- tsdn_t *tsdn;
-
- LOG("core.sallocx.entry", "ptr: %p, flags: %d", ptr, flags);
-
- assert(malloc_initialized() || IS_INITIALIZER);
- assert(ptr != NULL);
-
- tsdn = tsdn_fetch();
- check_entry_exit_locking(tsdn);
-
- if (config_debug || force_ivsalloc) {
- usize = ivsalloc(tsdn, ptr);
- assert(force_ivsalloc || usize != 0);
- } else {
- usize = isalloc(tsdn, ptr);
- }
-
- check_entry_exit_locking(tsdn);
-
- LOG("core.sallocx.exit", "result: %zu", usize);
- return usize;
-}
-
-JEMALLOC_EXPORT void JEMALLOC_NOTHROW
-je_dallocx(void *ptr, int flags) {
- LOG("core.dallocx.entry", "ptr: %p, flags: %d", ptr, flags);
-
- assert(ptr != NULL);
- assert(malloc_initialized() || IS_INITIALIZER);
-
- tsd_t *tsd = tsd_fetch_min();
- bool fast = tsd_fast(tsd);
- check_entry_exit_locking(tsd_tsdn(tsd));
-
- unsigned tcache_ind = mallocx_tcache_get(flags);
- tcache_t *tcache = tcache_get_from_ind(tsd, tcache_ind, !fast,
- /* is_alloc */ false);
-
- UTRACE(ptr, 0, 0);
- if (likely(fast)) {
- tsd_assert_fast(tsd);
- ifree(tsd, ptr, tcache, false);
- } else {
- uintptr_t args_raw[3] = {(uintptr_t)ptr, flags};
- hook_invoke_dalloc(hook_dalloc_dallocx, ptr, args_raw);
- ifree(tsd, ptr, tcache, true);
- }
- check_entry_exit_locking(tsd_tsdn(tsd));
-
- LOG("core.dallocx.exit", "");
-}
-
-JEMALLOC_ALWAYS_INLINE size_t
-inallocx(tsdn_t *tsdn, size_t size, int flags) {
- check_entry_exit_locking(tsdn);
- size_t usize;
- /* In case of out of range, let the user see it rather than fail. */
- aligned_usize_get(size, MALLOCX_ALIGN_GET(flags), &usize, NULL, false);
- check_entry_exit_locking(tsdn);
- return usize;
-}
-
-JEMALLOC_NOINLINE void
-sdallocx_default(void *ptr, size_t size, int flags) {
- assert(ptr != NULL);
- assert(malloc_initialized() || IS_INITIALIZER);
-
- tsd_t *tsd = tsd_fetch_min();
- bool fast = tsd_fast(tsd);
- size_t usize = inallocx(tsd_tsdn(tsd), size, flags);
- check_entry_exit_locking(tsd_tsdn(tsd));
-
- unsigned tcache_ind = mallocx_tcache_get(flags);
- tcache_t *tcache = tcache_get_from_ind(tsd, tcache_ind, !fast,
- /* is_alloc */ false);
-
- UTRACE(ptr, 0, 0);
- if (likely(fast)) {
- tsd_assert_fast(tsd);
- isfree(tsd, ptr, usize, tcache, false);
- } else {
- uintptr_t args_raw[3] = {(uintptr_t)ptr, size, flags};
- hook_invoke_dalloc(hook_dalloc_sdallocx, ptr, args_raw);
- isfree(tsd, ptr, usize, tcache, true);
- }
- check_entry_exit_locking(tsd_tsdn(tsd));
-}
-
-JEMALLOC_EXPORT void JEMALLOC_NOTHROW
-je_sdallocx(void *ptr, size_t size, int flags) {
- LOG("core.sdallocx.entry", "ptr: %p, size: %zu, flags: %d", ptr,
- size, flags);
-
- if (flags != 0 || !free_fastpath(ptr, size, true)) {
- sdallocx_default(ptr, size, flags);
- }
-
- LOG("core.sdallocx.exit", "");
-}
-
-void JEMALLOC_NOTHROW
-je_sdallocx_noflags(void *ptr, size_t size) {
- LOG("core.sdallocx.entry", "ptr: %p, size: %zu, flags: 0", ptr,
- size);
-
- if (!free_fastpath(ptr, size, true)) {
- sdallocx_default(ptr, size, 0);
- }
-
- LOG("core.sdallocx.exit", "");
-}
-
-JEMALLOC_EXPORT size_t JEMALLOC_NOTHROW
-JEMALLOC_ATTR(pure)
-je_nallocx(size_t size, int flags) {
- size_t usize;
- tsdn_t *tsdn;
-
- assert(size != 0);
-
- if (unlikely(malloc_init())) {
- LOG("core.nallocx.exit", "result: %zu", ZU(0));
- return 0;
- }
-
- tsdn = tsdn_fetch();
- check_entry_exit_locking(tsdn);
-
- usize = inallocx(tsdn, size, flags);
- if (unlikely(usize > SC_LARGE_MAXCLASS)) {
- LOG("core.nallocx.exit", "result: %zu", ZU(0));
- return 0;
- }
-
- check_entry_exit_locking(tsdn);
- LOG("core.nallocx.exit", "result: %zu", usize);
- return usize;
-}
-
-JEMALLOC_EXPORT int JEMALLOC_NOTHROW
-je_mallctl(const char *name, void *oldp, size_t *oldlenp, void *newp,
- size_t newlen) {
- int ret;
- tsd_t *tsd;
-
- LOG("core.mallctl.entry", "name: %s", name);
-
- if (unlikely(malloc_init())) {
- LOG("core.mallctl.exit", "result: %d", EAGAIN);
- return EAGAIN;
- }
-
- tsd = tsd_fetch();
- check_entry_exit_locking(tsd_tsdn(tsd));
- ret = ctl_byname(tsd, name, oldp, oldlenp, newp, newlen);
- check_entry_exit_locking(tsd_tsdn(tsd));
-
- LOG("core.mallctl.exit", "result: %d", ret);
- return ret;
-}
-
-JEMALLOC_EXPORT int JEMALLOC_NOTHROW
-je_mallctlnametomib(const char *name, size_t *mibp, size_t *miblenp) {
- int ret;
-
- LOG("core.mallctlnametomib.entry", "name: %s", name);
-
- if (unlikely(malloc_init())) {
- LOG("core.mallctlnametomib.exit", "result: %d", EAGAIN);
- return EAGAIN;
- }
-
- tsd_t *tsd = tsd_fetch();
- check_entry_exit_locking(tsd_tsdn(tsd));
- ret = ctl_nametomib(tsd, name, mibp, miblenp);
- check_entry_exit_locking(tsd_tsdn(tsd));
-
- LOG("core.mallctlnametomib.exit", "result: %d", ret);
- return ret;
-}
-
-JEMALLOC_EXPORT int JEMALLOC_NOTHROW
-je_mallctlbymib(const size_t *mib, size_t miblen, void *oldp, size_t *oldlenp,
- void *newp, size_t newlen) {
- int ret;
- tsd_t *tsd;
-
- LOG("core.mallctlbymib.entry", "");
-
- if (unlikely(malloc_init())) {
- LOG("core.mallctlbymib.exit", "result: %d", EAGAIN);
- return EAGAIN;
- }
-
- tsd = tsd_fetch();
- check_entry_exit_locking(tsd_tsdn(tsd));
- ret = ctl_bymib(tsd, mib, miblen, oldp, oldlenp, newp, newlen);
- check_entry_exit_locking(tsd_tsdn(tsd));
- LOG("core.mallctlbymib.exit", "result: %d", ret);
- return ret;
-}
-
-#define STATS_PRINT_BUFSIZE 65536
-JEMALLOC_EXPORT void JEMALLOC_NOTHROW
-je_malloc_stats_print(void (*write_cb)(void *, const char *), void *cbopaque,
- const char *opts) {
- tsdn_t *tsdn;
-
- LOG("core.malloc_stats_print.entry", "");
-
- tsdn = tsdn_fetch();
- check_entry_exit_locking(tsdn);
-
- if (config_debug) {
- stats_print(write_cb, cbopaque, opts);
- } else {
- buf_writer_t buf_writer;
- buf_writer_init(tsdn, &buf_writer, write_cb, cbopaque, NULL,
- STATS_PRINT_BUFSIZE);
- stats_print(buf_writer_cb, &buf_writer, opts);
- buf_writer_terminate(tsdn, &buf_writer);
- }
-
- check_entry_exit_locking(tsdn);
- LOG("core.malloc_stats_print.exit", "");
-}
-#undef STATS_PRINT_BUFSIZE
-
-JEMALLOC_ALWAYS_INLINE size_t
-je_malloc_usable_size_impl(JEMALLOC_USABLE_SIZE_CONST void *ptr) {
- assert(malloc_initialized() || IS_INITIALIZER);
-
- tsdn_t *tsdn = tsdn_fetch();
- check_entry_exit_locking(tsdn);
-
- size_t ret;
- if (unlikely(ptr == NULL)) {
- ret = 0;
- } else {
- if (config_debug || force_ivsalloc) {
- ret = ivsalloc(tsdn, ptr);
- assert(force_ivsalloc || ret != 0);
- } else {
- ret = isalloc(tsdn, ptr);
- }
- }
- check_entry_exit_locking(tsdn);
-
- return ret;
-}
-
-JEMALLOC_EXPORT size_t JEMALLOC_NOTHROW
-je_malloc_usable_size(JEMALLOC_USABLE_SIZE_CONST void *ptr) {
- LOG("core.malloc_usable_size.entry", "ptr: %p", ptr);
-
- size_t ret = je_malloc_usable_size_impl(ptr);
-
- LOG("core.malloc_usable_size.exit", "result: %zu", ret);
- return ret;
-}
-
-#ifdef JEMALLOC_HAVE_MALLOC_SIZE
-JEMALLOC_EXPORT size_t JEMALLOC_NOTHROW
-je_malloc_size(const void *ptr) {
- LOG("core.malloc_size.entry", "ptr: %p", ptr);
-
- size_t ret = je_malloc_usable_size_impl(ptr);
-
- LOG("core.malloc_size.exit", "result: %zu", ret);
- return ret;
-}
-#endif
-
-static void
-batch_alloc_prof_sample_assert(tsd_t *tsd, size_t batch, size_t usize) {
- assert(config_prof && opt_prof);
- bool prof_sample_event = te_prof_sample_event_lookahead(tsd,
- batch * usize);
- assert(!prof_sample_event);
- size_t surplus;
- prof_sample_event = te_prof_sample_event_lookahead_surplus(tsd,
- (batch + 1) * usize, &surplus);
- assert(prof_sample_event);
- assert(surplus < usize);
-}
-
-size_t
-batch_alloc(void **ptrs, size_t num, size_t size, int flags) {
- LOG("core.batch_alloc.entry",
- "ptrs: %p, num: %zu, size: %zu, flags: %d", ptrs, num, size, flags);
-
- tsd_t *tsd = tsd_fetch();
- check_entry_exit_locking(tsd_tsdn(tsd));
-
- size_t filled = 0;
-
- if (unlikely(tsd == NULL || tsd_reentrancy_level_get(tsd) > 0)) {
- goto label_done;
- }
-
- size_t alignment = MALLOCX_ALIGN_GET(flags);
- size_t usize;
- if (aligned_usize_get(size, alignment, &usize, NULL, false)) {
- goto label_done;
- }
- szind_t ind = sz_size2index(usize);
- bool zero = zero_get(MALLOCX_ZERO_GET(flags), /* slow */ true);
-
- /*
- * The cache bin and arena will be lazily initialized; it's hard to
- * know in advance whether each of them needs to be initialized.
- */
- cache_bin_t *bin = NULL;
- arena_t *arena = NULL;
-
- size_t nregs = 0;
- if (likely(ind < SC_NBINS)) {
- nregs = bin_infos[ind].nregs;
- assert(nregs > 0);
- }
-
- while (filled < num) {
- size_t batch = num - filled;
- size_t surplus = SIZE_MAX; /* Dead store. */
- bool prof_sample_event = config_prof && opt_prof
- && prof_active_get_unlocked()
- && te_prof_sample_event_lookahead_surplus(tsd,
- batch * usize, &surplus);
-
- if (prof_sample_event) {
- /*
- * Adjust so that the batch does not trigger prof
- * sampling.
- */
- batch -= surplus / usize + 1;
- batch_alloc_prof_sample_assert(tsd, batch, usize);
- }
-
- size_t progress = 0;
-
- if (likely(ind < SC_NBINS) && batch >= nregs) {
- if (arena == NULL) {
- unsigned arena_ind = mallocx_arena_get(flags);
- if (arena_get_from_ind(tsd, arena_ind,
- &arena)) {
- goto label_done;
- }
- if (arena == NULL) {
- arena = arena_choose(tsd, NULL);
- }
- if (unlikely(arena == NULL)) {
- goto label_done;
- }
- }
- size_t arena_batch = batch - batch % nregs;
- size_t n = arena_fill_small_fresh(tsd_tsdn(tsd), arena,
- ind, ptrs + filled, arena_batch, zero);
- progress += n;
- filled += n;
- }
-
- if (likely(ind < nhbins) && progress < batch) {
- if (bin == NULL) {
- unsigned tcache_ind = mallocx_tcache_get(flags);
- tcache_t *tcache = tcache_get_from_ind(tsd,
- tcache_ind, /* slow */ true,
- /* is_alloc */ true);
- if (tcache != NULL) {
- bin = &tcache->bins[ind];
- }
- }
- /*
- * If we don't have a tcache bin, we don't want to
- * immediately give up, because there's the possibility
- * that the user explicitly requested to bypass the
- * tcache, or that the user explicitly turned off the
- * tcache; in such cases, we go through the slow path,
- * i.e. the mallocx() call at the end of the while loop.
- */
- if (bin != NULL) {
- size_t bin_batch = batch - progress;
- /*
- * n can be less than bin_batch, meaning that
- * the cache bin does not have enough memory.
- * In such cases, we rely on the slow path,
- * i.e. the mallocx() call at the end of the
- * while loop, to fill in the cache, and in the
- * next iteration of the while loop, the tcache
- * will contain a lot of memory, and we can
- * harvest them here. Compared to the
- * alternative approach where we directly go to
- * the arena bins here, the overhead of our
- * current approach should usually be minimal,
- * since we never try to fetch more memory than
- * what a slab contains via the tcache. An
- * additional benefit is that the tcache will
- * not be empty for the next allocation request.
- */
- size_t n = cache_bin_alloc_batch(bin, bin_batch,
- ptrs + filled);
- if (config_stats) {
- bin->tstats.nrequests += n;
- }
- if (zero) {
- for (size_t i = 0; i < n; ++i) {
- memset(ptrs[filled + i], 0,
- usize);
- }
- }
- if (config_prof && opt_prof
- && unlikely(ind >= SC_NBINS)) {
- for (size_t i = 0; i < n; ++i) {
- prof_tctx_reset_sampled(tsd,
- ptrs[filled + i]);
- }
- }
- progress += n;
- filled += n;
- }
- }
-
- /*
- * For thread events other than prof sampling, trigger them as
- * if there's a single allocation of size (n * usize). This is
- * fine because:
- * (a) these events do not alter the allocation itself, and
- * (b) it's possible that some event would have been triggered
- * multiple times, instead of only once, if the allocations
- * were handled individually, but it would do no harm (or
- * even be beneficial) to coalesce the triggerings.
- */
- thread_alloc_event(tsd, progress * usize);
-
- if (progress < batch || prof_sample_event) {
- void *p = je_mallocx(size, flags);
- if (p == NULL) { /* OOM */
- break;
- }
- if (progress == batch) {
- assert(prof_sampled(tsd, p));
- }
- ptrs[filled++] = p;
- }
- }
-
-label_done:
- check_entry_exit_locking(tsd_tsdn(tsd));
- LOG("core.batch_alloc.exit", "result: %zu", filled);
- return filled;
-}
-
-/*
- * End non-standard functions.
- */
-/******************************************************************************/
-/*
- * The following functions are used by threading libraries for protection of
- * malloc during fork().
- */
-
-/*
- * If an application creates a thread before doing any allocation in the main
- * thread, then calls fork(2) in the main thread followed by memory allocation
- * in the child process, a race can occur that results in deadlock within the
- * child: the main thread may have forked while the created thread had
- * partially initialized the allocator. Ordinarily jemalloc prevents
- * fork/malloc races via the following functions it registers during
- * initialization using pthread_atfork(), but of course that does no good if
- * the allocator isn't fully initialized at fork time. The following library
- * constructor is a partial solution to this problem. It may still be possible
- * to trigger the deadlock described above, but doing so would involve forking
- * via a library constructor that runs before jemalloc's runs.
- */
-#ifndef JEMALLOC_JET
-JEMALLOC_ATTR(constructor)
-static void
-jemalloc_constructor(void) {
- malloc_init();
-}
-#endif
-
-#ifndef JEMALLOC_MUTEX_INIT_CB
-void
-jemalloc_prefork(void)
-#else
-JEMALLOC_EXPORT void
-_malloc_prefork(void)
-#endif
-{
- tsd_t *tsd;
- unsigned i, j, narenas;
- arena_t *arena;
-
-#ifdef JEMALLOC_MUTEX_INIT_CB
- if (!malloc_initialized()) {
- return;
- }
-#endif
- assert(malloc_initialized());
-
- tsd = tsd_fetch();
-
- narenas = narenas_total_get();
-
- witness_prefork(tsd_witness_tsdp_get(tsd));
- /* Acquire all mutexes in a safe order. */
- ctl_prefork(tsd_tsdn(tsd));
- tcache_prefork(tsd_tsdn(tsd));
- malloc_mutex_prefork(tsd_tsdn(tsd), &arenas_lock);
- if (have_background_thread) {
- background_thread_prefork0(tsd_tsdn(tsd));
- }
- prof_prefork0(tsd_tsdn(tsd));
- if (have_background_thread) {
- background_thread_prefork1(tsd_tsdn(tsd));
- }
- /* Break arena prefork into stages to preserve lock order. */
- for (i = 0; i < 9; i++) {
- for (j = 0; j < narenas; j++) {
- if ((arena = arena_get(tsd_tsdn(tsd), j, false)) !=
- NULL) {
- switch (i) {
- case 0:
- arena_prefork0(tsd_tsdn(tsd), arena);
- break;
- case 1:
- arena_prefork1(tsd_tsdn(tsd), arena);
- break;
- case 2:
- arena_prefork2(tsd_tsdn(tsd), arena);
- break;
- case 3:
- arena_prefork3(tsd_tsdn(tsd), arena);
- break;
- case 4:
- arena_prefork4(tsd_tsdn(tsd), arena);
- break;
- case 5:
- arena_prefork5(tsd_tsdn(tsd), arena);
- break;
- case 6:
- arena_prefork6(tsd_tsdn(tsd), arena);
- break;
- case 7:
- arena_prefork7(tsd_tsdn(tsd), arena);
- break;
- case 8:
- arena_prefork8(tsd_tsdn(tsd), arena);
- break;
- default: not_reached();
- }
- }
- }
-
- }
- prof_prefork1(tsd_tsdn(tsd));
- stats_prefork(tsd_tsdn(tsd));
- tsd_prefork(tsd);
-}
-
-#ifndef JEMALLOC_MUTEX_INIT_CB
-void
-jemalloc_postfork_parent(void)
-#else
-JEMALLOC_EXPORT void
-_malloc_postfork(void)
-#endif
-{
- tsd_t *tsd;
- unsigned i, narenas;
-
-#ifdef JEMALLOC_MUTEX_INIT_CB
- if (!malloc_initialized()) {
- return;
- }
-#endif
- assert(malloc_initialized());
-
- tsd = tsd_fetch();
-
- tsd_postfork_parent(tsd);
-
- witness_postfork_parent(tsd_witness_tsdp_get(tsd));
- /* Release all mutexes, now that fork() has completed. */
- stats_postfork_parent(tsd_tsdn(tsd));
- for (i = 0, narenas = narenas_total_get(); i < narenas; i++) {
- arena_t *arena;
-
- if ((arena = arena_get(tsd_tsdn(tsd), i, false)) != NULL) {
- arena_postfork_parent(tsd_tsdn(tsd), arena);
- }
- }
- prof_postfork_parent(tsd_tsdn(tsd));
- if (have_background_thread) {
- background_thread_postfork_parent(tsd_tsdn(tsd));
- }
- malloc_mutex_postfork_parent(tsd_tsdn(tsd), &arenas_lock);
- tcache_postfork_parent(tsd_tsdn(tsd));
- ctl_postfork_parent(tsd_tsdn(tsd));
-}
-
-void
-jemalloc_postfork_child(void) {
- tsd_t *tsd;
- unsigned i, narenas;
-
- assert(malloc_initialized());
-
- tsd = tsd_fetch();
-
- tsd_postfork_child(tsd);
-
- witness_postfork_child(tsd_witness_tsdp_get(tsd));
- /* Release all mutexes, now that fork() has completed. */
- stats_postfork_child(tsd_tsdn(tsd));
- for (i = 0, narenas = narenas_total_get(); i < narenas; i++) {
- arena_t *arena;
-
- if ((arena = arena_get(tsd_tsdn(tsd), i, false)) != NULL) {
- arena_postfork_child(tsd_tsdn(tsd), arena);
- }
- }
- prof_postfork_child(tsd_tsdn(tsd));
- if (have_background_thread) {
- background_thread_postfork_child(tsd_tsdn(tsd));
- }
- malloc_mutex_postfork_child(tsd_tsdn(tsd), &arenas_lock);
- tcache_postfork_child(tsd_tsdn(tsd));
- ctl_postfork_child(tsd_tsdn(tsd));
-}
-
-/******************************************************************************/
diff --git a/fluent-bit/lib/jemalloc-5.3.0/src/jemalloc_cpp.cpp b/fluent-bit/lib/jemalloc-5.3.0/src/jemalloc_cpp.cpp
deleted file mode 100644
index 451655f1..00000000
--- a/fluent-bit/lib/jemalloc-5.3.0/src/jemalloc_cpp.cpp
+++ /dev/null
@@ -1,254 +0,0 @@
-#include <mutex>
-#include <new>
-
-#define JEMALLOC_CPP_CPP_
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#include "jemalloc/internal/jemalloc_preamble.h"
-#include "jemalloc/internal/jemalloc_internal_includes.h"
-
-#ifdef __cplusplus
-}
-#endif
-
-// All operators in this file are exported.
-
-// Possibly alias hidden versions of malloc and sdallocx to avoid an extra plt
-// thunk?
-//
-// extern __typeof (sdallocx) sdallocx_int
-// __attribute ((alias ("sdallocx"),
-// visibility ("hidden")));
-//
-// ... but it needs to work with jemalloc namespaces.
-
-void *operator new(std::size_t size);
-void *operator new[](std::size_t size);
-void *operator new(std::size_t size, const std::nothrow_t &) noexcept;
-void *operator new[](std::size_t size, const std::nothrow_t &) noexcept;
-void operator delete(void *ptr) noexcept;
-void operator delete[](void *ptr) noexcept;
-void operator delete(void *ptr, const std::nothrow_t &) noexcept;
-void operator delete[](void *ptr, const std::nothrow_t &) noexcept;
-
-#if __cpp_sized_deallocation >= 201309
-/* C++14's sized-delete operators. */
-void operator delete(void *ptr, std::size_t size) noexcept;
-void operator delete[](void *ptr, std::size_t size) noexcept;
-#endif
-
-#if __cpp_aligned_new >= 201606
-/* C++17's over-aligned operators. */
-void *operator new(std::size_t size, std::align_val_t);
-void *operator new(std::size_t size, std::align_val_t, const std::nothrow_t &) noexcept;
-void *operator new[](std::size_t size, std::align_val_t);
-void *operator new[](std::size_t size, std::align_val_t, const std::nothrow_t &) noexcept;
-void operator delete(void* ptr, std::align_val_t) noexcept;
-void operator delete(void* ptr, std::align_val_t, const std::nothrow_t &) noexcept;
-void operator delete(void* ptr, std::size_t size, std::align_val_t al) noexcept;
-void operator delete[](void* ptr, std::align_val_t) noexcept;
-void operator delete[](void* ptr, std::align_val_t, const std::nothrow_t &) noexcept;
-void operator delete[](void* ptr, std::size_t size, std::align_val_t al) noexcept;
-#endif
-
-JEMALLOC_NOINLINE
-static void *
-handleOOM(std::size_t size, bool nothrow) {
- if (opt_experimental_infallible_new) {
- safety_check_fail("<jemalloc>: Allocation failed and "
- "opt.experimental_infallible_new is true. Aborting.\n");
- return nullptr;
- }
-
- void *ptr = nullptr;
-
- while (ptr == nullptr) {
- std::new_handler handler;
- // GCC-4.8 and clang 4.0 do not have std::get_new_handler.
- {
- static std::mutex mtx;
- std::lock_guard<std::mutex> lock(mtx);
-
- handler = std::set_new_handler(nullptr);
- std::set_new_handler(handler);
- }
- if (handler == nullptr)
- break;
-
- try {
- handler();
- } catch (const std::bad_alloc &) {
- break;
- }
-
- ptr = je_malloc(size);
- }
-
- if (ptr == nullptr && !nothrow)
- std::__throw_bad_alloc();
- return ptr;
-}
-
-template <bool IsNoExcept>
-JEMALLOC_NOINLINE
-static void *
-fallback_impl(std::size_t size) noexcept(IsNoExcept) {
- void *ptr = malloc_default(size);
- if (likely(ptr != nullptr)) {
- return ptr;
- }
- return handleOOM(size, IsNoExcept);
-}
-
-template <bool IsNoExcept>
-JEMALLOC_ALWAYS_INLINE
-void *
-newImpl(std::size_t size) noexcept(IsNoExcept) {
- return imalloc_fastpath(size, &fallback_impl<IsNoExcept>);
-}
-
-void *
-operator new(std::size_t size) {
- return newImpl<false>(size);
-}
-
-void *
-operator new[](std::size_t size) {
- return newImpl<false>(size);
-}
-
-void *
-operator new(std::size_t size, const std::nothrow_t &) noexcept {
- return newImpl<true>(size);
-}
-
-void *
-operator new[](std::size_t size, const std::nothrow_t &) noexcept {
- return newImpl<true>(size);
-}
-
-#if __cpp_aligned_new >= 201606
-
-template <bool IsNoExcept>
-JEMALLOC_ALWAYS_INLINE
-void *
-alignedNewImpl(std::size_t size, std::align_val_t alignment) noexcept(IsNoExcept) {
- void *ptr = je_aligned_alloc(static_cast<std::size_t>(alignment), size);
- if (likely(ptr != nullptr)) {
- return ptr;
- }
-
- return handleOOM(size, IsNoExcept);
-}
-
-void *
-operator new(std::size_t size, std::align_val_t alignment) {
- return alignedNewImpl<false>(size, alignment);
-}
-
-void *
-operator new[](std::size_t size, std::align_val_t alignment) {
- return alignedNewImpl<false>(size, alignment);
-}
-
-void *
-operator new(std::size_t size, std::align_val_t alignment, const std::nothrow_t &) noexcept {
- return alignedNewImpl<true>(size, alignment);
-}
-
-void *
-operator new[](std::size_t size, std::align_val_t alignment, const std::nothrow_t &) noexcept {
- return alignedNewImpl<true>(size, alignment);
-}
-
-#endif // __cpp_aligned_new
-
-void
-operator delete(void *ptr) noexcept {
- je_free(ptr);
-}
-
-void
-operator delete[](void *ptr) noexcept {
- je_free(ptr);
-}
-
-void
-operator delete(void *ptr, const std::nothrow_t &) noexcept {
- je_free(ptr);
-}
-
-void operator delete[](void *ptr, const std::nothrow_t &) noexcept {
- je_free(ptr);
-}
-
-#if __cpp_sized_deallocation >= 201309
-
-JEMALLOC_ALWAYS_INLINE
-void
-sizedDeleteImpl(void* ptr, std::size_t size) noexcept {
- if (unlikely(ptr == nullptr)) {
- return;
- }
- je_sdallocx_noflags(ptr, size);
-}
-
-void
-operator delete(void *ptr, std::size_t size) noexcept {
- sizedDeleteImpl(ptr, size);
-}
-
-void
-operator delete[](void *ptr, std::size_t size) noexcept {
- sizedDeleteImpl(ptr, size);
-}
-
-#endif // __cpp_sized_deallocation
-
-#if __cpp_aligned_new >= 201606
-
-JEMALLOC_ALWAYS_INLINE
-void
-alignedSizedDeleteImpl(void* ptr, std::size_t size, std::align_val_t alignment) noexcept {
- if (config_debug) {
- assert(((size_t)alignment & ((size_t)alignment - 1)) == 0);
- }
- if (unlikely(ptr == nullptr)) {
- return;
- }
- je_sdallocx(ptr, size, MALLOCX_ALIGN(alignment));
-}
-
-void
-operator delete(void* ptr, std::align_val_t) noexcept {
- je_free(ptr);
-}
-
-void
-operator delete[](void* ptr, std::align_val_t) noexcept {
- je_free(ptr);
-}
-
-void
-operator delete(void* ptr, std::align_val_t, const std::nothrow_t&) noexcept {
- je_free(ptr);
-}
-
-void
-operator delete[](void* ptr, std::align_val_t, const std::nothrow_t&) noexcept {
- je_free(ptr);
-}
-
-void
-operator delete(void* ptr, std::size_t size, std::align_val_t alignment) noexcept {
- alignedSizedDeleteImpl(ptr, size, alignment);
-}
-
-void
-operator delete[](void* ptr, std::size_t size, std::align_val_t alignment) noexcept {
- alignedSizedDeleteImpl(ptr, size, alignment);
-}
-
-#endif // __cpp_aligned_new
diff --git a/fluent-bit/lib/jemalloc-5.3.0/src/large.c b/fluent-bit/lib/jemalloc-5.3.0/src/large.c
deleted file mode 100644
index 5fc4bf58..00000000
--- a/fluent-bit/lib/jemalloc-5.3.0/src/large.c
+++ /dev/null
@@ -1,322 +0,0 @@
-#include "jemalloc/internal/jemalloc_preamble.h"
-#include "jemalloc/internal/jemalloc_internal_includes.h"
-
-#include "jemalloc/internal/assert.h"
-#include "jemalloc/internal/emap.h"
-#include "jemalloc/internal/extent_mmap.h"
-#include "jemalloc/internal/mutex.h"
-#include "jemalloc/internal/prof_recent.h"
-#include "jemalloc/internal/util.h"
-
-/******************************************************************************/
-
-void *
-large_malloc(tsdn_t *tsdn, arena_t *arena, size_t usize, bool zero) {
- assert(usize == sz_s2u(usize));
-
- return large_palloc(tsdn, arena, usize, CACHELINE, zero);
-}
-
-void *
-large_palloc(tsdn_t *tsdn, arena_t *arena, size_t usize, size_t alignment,
- bool zero) {
- size_t ausize;
- edata_t *edata;
- UNUSED bool idump JEMALLOC_CC_SILENCE_INIT(false);
-
- assert(!tsdn_null(tsdn) || arena != NULL);
-
- ausize = sz_sa2u(usize, alignment);
- if (unlikely(ausize == 0 || ausize > SC_LARGE_MAXCLASS)) {
- return NULL;
- }
-
- if (likely(!tsdn_null(tsdn))) {
- arena = arena_choose_maybe_huge(tsdn_tsd(tsdn), arena, usize);
- }
- if (unlikely(arena == NULL) || (edata = arena_extent_alloc_large(tsdn,
- arena, usize, alignment, zero)) == NULL) {
- return NULL;
- }
-
- /* See comments in arena_bin_slabs_full_insert(). */
- if (!arena_is_auto(arena)) {
- /* Insert edata into large. */
- malloc_mutex_lock(tsdn, &arena->large_mtx);
- edata_list_active_append(&arena->large, edata);
- malloc_mutex_unlock(tsdn, &arena->large_mtx);
- }
-
- arena_decay_tick(tsdn, arena);
- return edata_addr_get(edata);
-}
-
-static bool
-large_ralloc_no_move_shrink(tsdn_t *tsdn, edata_t *edata, size_t usize) {
- arena_t *arena = arena_get_from_edata(edata);
- ehooks_t *ehooks = arena_get_ehooks(arena);
- size_t old_size = edata_size_get(edata);
- size_t old_usize = edata_usize_get(edata);
-
- assert(old_usize > usize);
-
- if (ehooks_split_will_fail(ehooks)) {
- return true;
- }
-
- bool deferred_work_generated = false;
- bool err = pa_shrink(tsdn, &arena->pa_shard, edata, old_size,
- usize + sz_large_pad, sz_size2index(usize),
- &deferred_work_generated);
- if (err) {
- return true;
- }
- if (deferred_work_generated) {
- arena_handle_deferred_work(tsdn, arena);
- }
- arena_extent_ralloc_large_shrink(tsdn, arena, edata, old_usize);
-
- return false;
-}
-
-static bool
-large_ralloc_no_move_expand(tsdn_t *tsdn, edata_t *edata, size_t usize,
- bool zero) {
- arena_t *arena = arena_get_from_edata(edata);
-
- size_t old_size = edata_size_get(edata);
- size_t old_usize = edata_usize_get(edata);
- size_t new_size = usize + sz_large_pad;
-
- szind_t szind = sz_size2index(usize);
-
- bool deferred_work_generated = false;
- bool err = pa_expand(tsdn, &arena->pa_shard, edata, old_size, new_size,
- szind, zero, &deferred_work_generated);
-
- if (deferred_work_generated) {
- arena_handle_deferred_work(tsdn, arena);
- }
-
- if (err) {
- return true;
- }
-
- if (zero) {
- if (opt_cache_oblivious) {
- assert(sz_large_pad == PAGE);
- /*
- * Zero the trailing bytes of the original allocation's
- * last page, since they are in an indeterminate state.
- * There will always be trailing bytes, because ptr's
- * offset from the beginning of the extent is a multiple
- * of CACHELINE in [0 .. PAGE).
- */
- void *zbase = (void *)
- ((uintptr_t)edata_addr_get(edata) + old_usize);
- void *zpast = PAGE_ADDR2BASE((void *)((uintptr_t)zbase +
- PAGE));
- size_t nzero = (uintptr_t)zpast - (uintptr_t)zbase;
- assert(nzero > 0);
- memset(zbase, 0, nzero);
- }
- }
- arena_extent_ralloc_large_expand(tsdn, arena, edata, old_usize);
-
- return false;
-}
-
-bool
-large_ralloc_no_move(tsdn_t *tsdn, edata_t *edata, size_t usize_min,
- size_t usize_max, bool zero) {
- size_t oldusize = edata_usize_get(edata);
-
- /* The following should have been caught by callers. */
- assert(usize_min > 0 && usize_max <= SC_LARGE_MAXCLASS);
- /* Both allocation sizes must be large to avoid a move. */
- assert(oldusize >= SC_LARGE_MINCLASS
- && usize_max >= SC_LARGE_MINCLASS);
-
- if (usize_max > oldusize) {
- /* Attempt to expand the allocation in-place. */
- if (!large_ralloc_no_move_expand(tsdn, edata, usize_max,
- zero)) {
- arena_decay_tick(tsdn, arena_get_from_edata(edata));
- return false;
- }
- /* Try again, this time with usize_min. */
- if (usize_min < usize_max && usize_min > oldusize &&
- large_ralloc_no_move_expand(tsdn, edata, usize_min, zero)) {
- arena_decay_tick(tsdn, arena_get_from_edata(edata));
- return false;
- }
- }
-
- /*
- * Avoid moving the allocation if the existing extent size accommodates
- * the new size.
- */
- if (oldusize >= usize_min && oldusize <= usize_max) {
- arena_decay_tick(tsdn, arena_get_from_edata(edata));
- return false;
- }
-
- /* Attempt to shrink the allocation in-place. */
- if (oldusize > usize_max) {
- if (!large_ralloc_no_move_shrink(tsdn, edata, usize_max)) {
- arena_decay_tick(tsdn, arena_get_from_edata(edata));
- return false;
- }
- }
- return true;
-}
-
-static void *
-large_ralloc_move_helper(tsdn_t *tsdn, arena_t *arena, size_t usize,
- size_t alignment, bool zero) {
- if (alignment <= CACHELINE) {
- return large_malloc(tsdn, arena, usize, zero);
- }
- return large_palloc(tsdn, arena, usize, alignment, zero);
-}
-
-void *
-large_ralloc(tsdn_t *tsdn, arena_t *arena, void *ptr, size_t usize,
- size_t alignment, bool zero, tcache_t *tcache,
- hook_ralloc_args_t *hook_args) {
- edata_t *edata = emap_edata_lookup(tsdn, &arena_emap_global, ptr);
-
- size_t oldusize = edata_usize_get(edata);
- /* The following should have been caught by callers. */
- assert(usize > 0 && usize <= SC_LARGE_MAXCLASS);
- /* Both allocation sizes must be large to avoid a move. */
- assert(oldusize >= SC_LARGE_MINCLASS
- && usize >= SC_LARGE_MINCLASS);
-
- /* Try to avoid moving the allocation. */
- if (!large_ralloc_no_move(tsdn, edata, usize, usize, zero)) {
- hook_invoke_expand(hook_args->is_realloc
- ? hook_expand_realloc : hook_expand_rallocx, ptr, oldusize,
- usize, (uintptr_t)ptr, hook_args->args);
- return edata_addr_get(edata);
- }
-
- /*
- * usize and old size are different enough that we need to use a
- * different size class. In that case, fall back to allocating new
- * space and copying.
- */
- void *ret = large_ralloc_move_helper(tsdn, arena, usize, alignment,
- zero);
- if (ret == NULL) {
- return NULL;
- }
-
- hook_invoke_alloc(hook_args->is_realloc
- ? hook_alloc_realloc : hook_alloc_rallocx, ret, (uintptr_t)ret,
- hook_args->args);
- hook_invoke_dalloc(hook_args->is_realloc
- ? hook_dalloc_realloc : hook_dalloc_rallocx, ptr, hook_args->args);
-
- size_t copysize = (usize < oldusize) ? usize : oldusize;
- memcpy(ret, edata_addr_get(edata), copysize);
- isdalloct(tsdn, edata_addr_get(edata), oldusize, tcache, NULL, true);
- return ret;
-}
-
-/*
- * locked indicates whether the arena's large_mtx is currently held.
- */
-static void
-large_dalloc_prep_impl(tsdn_t *tsdn, arena_t *arena, edata_t *edata,
- bool locked) {
- if (!locked) {
- /* See comments in arena_bin_slabs_full_insert(). */
- if (!arena_is_auto(arena)) {
- malloc_mutex_lock(tsdn, &arena->large_mtx);
- edata_list_active_remove(&arena->large, edata);
- malloc_mutex_unlock(tsdn, &arena->large_mtx);
- }
- } else {
- /* Only hold the large_mtx if necessary. */
- if (!arena_is_auto(arena)) {
- malloc_mutex_assert_owner(tsdn, &arena->large_mtx);
- edata_list_active_remove(&arena->large, edata);
- }
- }
- arena_extent_dalloc_large_prep(tsdn, arena, edata);
-}
-
-static void
-large_dalloc_finish_impl(tsdn_t *tsdn, arena_t *arena, edata_t *edata) {
- bool deferred_work_generated = false;
- pa_dalloc(tsdn, &arena->pa_shard, edata, &deferred_work_generated);
- if (deferred_work_generated) {
- arena_handle_deferred_work(tsdn, arena);
- }
-}
-
-void
-large_dalloc_prep_locked(tsdn_t *tsdn, edata_t *edata) {
- large_dalloc_prep_impl(tsdn, arena_get_from_edata(edata), edata, true);
-}
-
-void
-large_dalloc_finish(tsdn_t *tsdn, edata_t *edata) {
- large_dalloc_finish_impl(tsdn, arena_get_from_edata(edata), edata);
-}
-
-void
-large_dalloc(tsdn_t *tsdn, edata_t *edata) {
- arena_t *arena = arena_get_from_edata(edata);
- large_dalloc_prep_impl(tsdn, arena, edata, false);
- large_dalloc_finish_impl(tsdn, arena, edata);
- arena_decay_tick(tsdn, arena);
-}
-
-size_t
-large_salloc(tsdn_t *tsdn, const edata_t *edata) {
- return edata_usize_get(edata);
-}
-
-void
-large_prof_info_get(tsd_t *tsd, edata_t *edata, prof_info_t *prof_info,
- bool reset_recent) {
- assert(prof_info != NULL);
-
- prof_tctx_t *alloc_tctx = edata_prof_tctx_get(edata);
- prof_info->alloc_tctx = alloc_tctx;
-
- if ((uintptr_t)alloc_tctx > (uintptr_t)1U) {
- nstime_copy(&prof_info->alloc_time,
- edata_prof_alloc_time_get(edata));
- prof_info->alloc_size = edata_prof_alloc_size_get(edata);
- if (reset_recent) {
- /*
- * Reset the pointer on the recent allocation record,
- * so that this allocation is recorded as released.
- */
- prof_recent_alloc_reset(tsd, edata);
- }
- }
-}
-
-static void
-large_prof_tctx_set(edata_t *edata, prof_tctx_t *tctx) {
- edata_prof_tctx_set(edata, tctx);
-}
-
-void
-large_prof_tctx_reset(edata_t *edata) {
- large_prof_tctx_set(edata, (prof_tctx_t *)(uintptr_t)1U);
-}
-
-void
-large_prof_info_set(edata_t *edata, prof_tctx_t *tctx, size_t size) {
- nstime_t t;
- nstime_prof_init_update(&t);
- edata_prof_alloc_time_set(edata, &t);
- edata_prof_alloc_size_set(edata, size);
- edata_prof_recent_alloc_init(edata);
- large_prof_tctx_set(edata, tctx);
-}
diff --git a/fluent-bit/lib/jemalloc-5.3.0/src/log.c b/fluent-bit/lib/jemalloc-5.3.0/src/log.c
deleted file mode 100644
index 778902fb..00000000
--- a/fluent-bit/lib/jemalloc-5.3.0/src/log.c
+++ /dev/null
@@ -1,78 +0,0 @@
-#include "jemalloc/internal/jemalloc_preamble.h"
-#include "jemalloc/internal/jemalloc_internal_includes.h"
-
-#include "jemalloc/internal/log.h"
-
-char log_var_names[JEMALLOC_LOG_VAR_BUFSIZE];
-atomic_b_t log_init_done = ATOMIC_INIT(false);
-
-/*
- * Returns true if we were able to pick out a segment. Fills in r_segment_end
- * with a pointer to the first character after the end of the string.
- */
-static const char *
-log_var_extract_segment(const char* segment_begin) {
- const char *end;
- for (end = segment_begin; *end != '\0' && *end != '|'; end++) {
- }
- return end;
-}
-
-static bool
-log_var_matches_segment(const char *segment_begin, const char *segment_end,
- const char *log_var_begin, const char *log_var_end) {
- assert(segment_begin <= segment_end);
- assert(log_var_begin < log_var_end);
-
- ptrdiff_t segment_len = segment_end - segment_begin;
- ptrdiff_t log_var_len = log_var_end - log_var_begin;
- /* The special '.' segment matches everything. */
- if (segment_len == 1 && *segment_begin == '.') {
- return true;
- }
- if (segment_len == log_var_len) {
- return strncmp(segment_begin, log_var_begin, segment_len) == 0;
- } else if (segment_len < log_var_len) {
- return strncmp(segment_begin, log_var_begin, segment_len) == 0
- && log_var_begin[segment_len] == '.';
- } else {
- return false;
- }
-}
-
-unsigned
-log_var_update_state(log_var_t *log_var) {
- const char *log_var_begin = log_var->name;
- const char *log_var_end = log_var->name + strlen(log_var->name);
-
- /* Pointer to one before the beginning of the current segment. */
- const char *segment_begin = log_var_names;
-
- /*
- * If log_init done is false, we haven't parsed the malloc conf yet. To
- * avoid log-spew, we default to not displaying anything.
- */
- if (!atomic_load_b(&log_init_done, ATOMIC_ACQUIRE)) {
- return LOG_INITIALIZED_NOT_ENABLED;
- }
-
- while (true) {
- const char *segment_end = log_var_extract_segment(
- segment_begin);
- assert(segment_end < log_var_names + JEMALLOC_LOG_VAR_BUFSIZE);
- if (log_var_matches_segment(segment_begin, segment_end,
- log_var_begin, log_var_end)) {
- atomic_store_u(&log_var->state, LOG_ENABLED,
- ATOMIC_RELAXED);
- return LOG_ENABLED;
- }
- if (*segment_end == '\0') {
- /* Hit the end of the segment string with no match. */
- atomic_store_u(&log_var->state,
- LOG_INITIALIZED_NOT_ENABLED, ATOMIC_RELAXED);
- return LOG_INITIALIZED_NOT_ENABLED;
- }
- /* Otherwise, skip the delimiter and continue. */
- segment_begin = segment_end + 1;
- }
-}
diff --git a/fluent-bit/lib/jemalloc-5.3.0/src/malloc_io.c b/fluent-bit/lib/jemalloc-5.3.0/src/malloc_io.c
deleted file mode 100644
index b76885cb..00000000
--- a/fluent-bit/lib/jemalloc-5.3.0/src/malloc_io.c
+++ /dev/null
@@ -1,697 +0,0 @@
-#include "jemalloc/internal/jemalloc_preamble.h"
-#include "jemalloc/internal/jemalloc_internal_includes.h"
-
-#include "jemalloc/internal/malloc_io.h"
-#include "jemalloc/internal/util.h"
-
-#ifdef assert
-# undef assert
-#endif
-#ifdef not_reached
-# undef not_reached
-#endif
-#ifdef not_implemented
-# undef not_implemented
-#endif
-#ifdef assert_not_implemented
-# undef assert_not_implemented
-#endif
-
-/*
- * Define simple versions of assertion macros that won't recurse in case
- * of assertion failures in malloc_*printf().
- */
-#define assert(e) do { \
- if (config_debug && !(e)) { \
- malloc_write("<jemalloc>: Failed assertion\n"); \
- abort(); \
- } \
-} while (0)
-
-#define not_reached() do { \
- if (config_debug) { \
- malloc_write("<jemalloc>: Unreachable code reached\n"); \
- abort(); \
- } \
- unreachable(); \
-} while (0)
-
-#define not_implemented() do { \
- if (config_debug) { \
- malloc_write("<jemalloc>: Not implemented\n"); \
- abort(); \
- } \
-} while (0)
-
-#define assert_not_implemented(e) do { \
- if (unlikely(config_debug && !(e))) { \
- not_implemented(); \
- } \
-} while (0)
-
-/******************************************************************************/
-/* Function prototypes for non-inline static functions. */
-
-#define U2S_BUFSIZE ((1U << (LG_SIZEOF_INTMAX_T + 3)) + 1)
-static char *u2s(uintmax_t x, unsigned base, bool uppercase, char *s,
- size_t *slen_p);
-#define D2S_BUFSIZE (1 + U2S_BUFSIZE)
-static char *d2s(intmax_t x, char sign, char *s, size_t *slen_p);
-#define O2S_BUFSIZE (1 + U2S_BUFSIZE)
-static char *o2s(uintmax_t x, bool alt_form, char *s, size_t *slen_p);
-#define X2S_BUFSIZE (2 + U2S_BUFSIZE)
-static char *x2s(uintmax_t x, bool alt_form, bool uppercase, char *s,
- size_t *slen_p);
-
-/******************************************************************************/
-
-/* malloc_message() setup. */
-void
-wrtmessage(void *cbopaque, const char *s) {
- malloc_write_fd(STDERR_FILENO, s, strlen(s));
-}
-
-JEMALLOC_EXPORT void (*je_malloc_message)(void *, const char *s);
-
-/*
- * Wrapper around malloc_message() that avoids the need for
- * je_malloc_message(...) throughout the code.
- */
-void
-malloc_write(const char *s) {
- if (je_malloc_message != NULL) {
- je_malloc_message(NULL, s);
- } else {
- wrtmessage(NULL, s);
- }
-}
-
-/*
- * glibc provides a non-standard strerror_r() when _GNU_SOURCE is defined, so
- * provide a wrapper.
- */
-int
-buferror(int err, char *buf, size_t buflen) {
-#ifdef _WIN32
- FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM, NULL, err, 0,
- (LPSTR)buf, (DWORD)buflen, NULL);
- return 0;
-#elif defined(JEMALLOC_STRERROR_R_RETURNS_CHAR_WITH_GNU_SOURCE) && defined(_GNU_SOURCE)
- char *b = strerror_r(err, buf, buflen);
- if (b != buf) {
- strncpy(buf, b, buflen);
- buf[buflen-1] = '\0';
- }
- return 0;
-#else
- return strerror_r(err, buf, buflen);
-#endif
-}
-
-uintmax_t
-malloc_strtoumax(const char *restrict nptr, char **restrict endptr, int base) {
- uintmax_t ret, digit;
- unsigned b;
- bool neg;
- const char *p, *ns;
-
- p = nptr;
- if (base < 0 || base == 1 || base > 36) {
- ns = p;
- set_errno(EINVAL);
- ret = UINTMAX_MAX;
- goto label_return;
- }
- b = base;
-
- /* Swallow leading whitespace and get sign, if any. */
- neg = false;
- while (true) {
- switch (*p) {
- case '\t': case '\n': case '\v': case '\f': case '\r': case ' ':
- p++;
- break;
- case '-':
- neg = true;
- JEMALLOC_FALLTHROUGH;
- case '+':
- p++;
- JEMALLOC_FALLTHROUGH;
- default:
- goto label_prefix;
- }
- }
-
- /* Get prefix, if any. */
- label_prefix:
- /*
- * Note where the first non-whitespace/sign character is so that it is
- * possible to tell whether any digits are consumed (e.g., " 0" vs.
- * " -x").
- */
- ns = p;
- if (*p == '0') {
- switch (p[1]) {
- case '0': case '1': case '2': case '3': case '4': case '5':
- case '6': case '7':
- if (b == 0) {
- b = 8;
- }
- if (b == 8) {
- p++;
- }
- break;
- case 'X': case 'x':
- switch (p[2]) {
- case '0': case '1': case '2': case '3': case '4':
- case '5': case '6': case '7': case '8': case '9':
- case 'A': case 'B': case 'C': case 'D': case 'E':
- case 'F':
- case 'a': case 'b': case 'c': case 'd': case 'e':
- case 'f':
- if (b == 0) {
- b = 16;
- }
- if (b == 16) {
- p += 2;
- }
- break;
- default:
- break;
- }
- break;
- default:
- p++;
- ret = 0;
- goto label_return;
- }
- }
- if (b == 0) {
- b = 10;
- }
-
- /* Convert. */
- ret = 0;
- while ((*p >= '0' && *p <= '9' && (digit = *p - '0') < b)
- || (*p >= 'A' && *p <= 'Z' && (digit = 10 + *p - 'A') < b)
- || (*p >= 'a' && *p <= 'z' && (digit = 10 + *p - 'a') < b)) {
- uintmax_t pret = ret;
- ret *= b;
- ret += digit;
- if (ret < pret) {
- /* Overflow. */
- set_errno(ERANGE);
- ret = UINTMAX_MAX;
- goto label_return;
- }
- p++;
- }
- if (neg) {
- ret = (uintmax_t)(-((intmax_t)ret));
- }
-
- if (p == ns) {
- /* No conversion performed. */
- set_errno(EINVAL);
- ret = UINTMAX_MAX;
- goto label_return;
- }
-
-label_return:
- if (endptr != NULL) {
- if (p == ns) {
- /* No characters were converted. */
- *endptr = (char *)nptr;
- } else {
- *endptr = (char *)p;
- }
- }
- return ret;
-}
-
-static char *
-u2s(uintmax_t x, unsigned base, bool uppercase, char *s, size_t *slen_p) {
- unsigned i;
-
- i = U2S_BUFSIZE - 1;
- s[i] = '\0';
- switch (base) {
- case 10:
- do {
- i--;
- s[i] = "0123456789"[x % (uint64_t)10];
- x /= (uint64_t)10;
- } while (x > 0);
- break;
- case 16: {
- const char *digits = (uppercase)
- ? "0123456789ABCDEF"
- : "0123456789abcdef";
-
- do {
- i--;
- s[i] = digits[x & 0xf];
- x >>= 4;
- } while (x > 0);
- break;
- } default: {
- const char *digits = (uppercase)
- ? "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
- : "0123456789abcdefghijklmnopqrstuvwxyz";
-
- assert(base >= 2 && base <= 36);
- do {
- i--;
- s[i] = digits[x % (uint64_t)base];
- x /= (uint64_t)base;
- } while (x > 0);
- }}
-
- *slen_p = U2S_BUFSIZE - 1 - i;
- return &s[i];
-}
-
-static char *
-d2s(intmax_t x, char sign, char *s, size_t *slen_p) {
- bool neg;
-
- if ((neg = (x < 0))) {
- x = -x;
- }
- s = u2s(x, 10, false, s, slen_p);
- if (neg) {
- sign = '-';
- }
- switch (sign) {
- case '-':
- if (!neg) {
- break;
- }
- JEMALLOC_FALLTHROUGH;
- case ' ':
- case '+':
- s--;
- (*slen_p)++;
- *s = sign;
- break;
- default: not_reached();
- }
- return s;
-}
-
-static char *
-o2s(uintmax_t x, bool alt_form, char *s, size_t *slen_p) {
- s = u2s(x, 8, false, s, slen_p);
- if (alt_form && *s != '0') {
- s--;
- (*slen_p)++;
- *s = '0';
- }
- return s;
-}
-
-static char *
-x2s(uintmax_t x, bool alt_form, bool uppercase, char *s, size_t *slen_p) {
- s = u2s(x, 16, uppercase, s, slen_p);
- if (alt_form) {
- s -= 2;
- (*slen_p) += 2;
- memcpy(s, uppercase ? "0X" : "0x", 2);
- }
- return s;
-}
-
-JEMALLOC_COLD
-size_t
-malloc_vsnprintf(char *str, size_t size, const char *format, va_list ap) {
- size_t i;
- const char *f;
-
-#define APPEND_C(c) do { \
- if (i < size) { \
- str[i] = (c); \
- } \
- i++; \
-} while (0)
-#define APPEND_S(s, slen) do { \
- if (i < size) { \
- size_t cpylen = (slen <= size - i) ? slen : size - i; \
- memcpy(&str[i], s, cpylen); \
- } \
- i += slen; \
-} while (0)
-#define APPEND_PADDED_S(s, slen, width, left_justify) do { \
- /* Left padding. */ \
- size_t pad_len = (width == -1) ? 0 : ((slen < (size_t)width) ? \
- (size_t)width - slen : 0); \
- if (!left_justify && pad_len != 0) { \
- size_t j; \
- for (j = 0; j < pad_len; j++) { \
- if (pad_zero) { \
- APPEND_C('0'); \
- } else { \
- APPEND_C(' '); \
- } \
- } \
- } \
- /* Value. */ \
- APPEND_S(s, slen); \
- /* Right padding. */ \
- if (left_justify && pad_len != 0) { \
- size_t j; \
- for (j = 0; j < pad_len; j++) { \
- APPEND_C(' '); \
- } \
- } \
-} while (0)
-#define GET_ARG_NUMERIC(val, len) do { \
- switch ((unsigned char)len) { \
- case '?': \
- val = va_arg(ap, int); \
- break; \
- case '?' | 0x80: \
- val = va_arg(ap, unsigned int); \
- break; \
- case 'l': \
- val = va_arg(ap, long); \
- break; \
- case 'l' | 0x80: \
- val = va_arg(ap, unsigned long); \
- break; \
- case 'q': \
- val = va_arg(ap, long long); \
- break; \
- case 'q' | 0x80: \
- val = va_arg(ap, unsigned long long); \
- break; \
- case 'j': \
- val = va_arg(ap, intmax_t); \
- break; \
- case 'j' | 0x80: \
- val = va_arg(ap, uintmax_t); \
- break; \
- case 't': \
- val = va_arg(ap, ptrdiff_t); \
- break; \
- case 'z': \
- val = va_arg(ap, ssize_t); \
- break; \
- case 'z' | 0x80: \
- val = va_arg(ap, size_t); \
- break; \
- case 'p': /* Synthetic; used for %p. */ \
- val = va_arg(ap, uintptr_t); \
- break; \
- default: \
- not_reached(); \
- val = 0; \
- } \
-} while (0)
-
- i = 0;
- f = format;
- while (true) {
- switch (*f) {
- case '\0': goto label_out;
- case '%': {
- bool alt_form = false;
- bool left_justify = false;
- bool plus_space = false;
- bool plus_plus = false;
- int prec = -1;
- int width = -1;
- unsigned char len = '?';
- char *s;
- size_t slen;
- bool first_width_digit = true;
- bool pad_zero = false;
-
- f++;
- /* Flags. */
- while (true) {
- switch (*f) {
- case '#':
- assert(!alt_form);
- alt_form = true;
- break;
- case '-':
- assert(!left_justify);
- left_justify = true;
- break;
- case ' ':
- assert(!plus_space);
- plus_space = true;
- break;
- case '+':
- assert(!plus_plus);
- plus_plus = true;
- break;
- default: goto label_width;
- }
- f++;
- }
- /* Width. */
- label_width:
- switch (*f) {
- case '*':
- width = va_arg(ap, int);
- f++;
- if (width < 0) {
- left_justify = true;
- width = -width;
- }
- break;
- case '0':
- if (first_width_digit) {
- pad_zero = true;
- }
- JEMALLOC_FALLTHROUGH;
- case '1': case '2': case '3': case '4':
- case '5': case '6': case '7': case '8': case '9': {
- uintmax_t uwidth;
- set_errno(0);
- uwidth = malloc_strtoumax(f, (char **)&f, 10);
- assert(uwidth != UINTMAX_MAX || get_errno() !=
- ERANGE);
- width = (int)uwidth;
- first_width_digit = false;
- break;
- } default:
- break;
- }
- /* Width/precision separator. */
- if (*f == '.') {
- f++;
- } else {
- goto label_length;
- }
- /* Precision. */
- switch (*f) {
- case '*':
- prec = va_arg(ap, int);
- f++;
- break;
- case '0': case '1': case '2': case '3': case '4':
- case '5': case '6': case '7': case '8': case '9': {
- uintmax_t uprec;
- set_errno(0);
- uprec = malloc_strtoumax(f, (char **)&f, 10);
- assert(uprec != UINTMAX_MAX || get_errno() !=
- ERANGE);
- prec = (int)uprec;
- break;
- }
- default: break;
- }
- /* Length. */
- label_length:
- switch (*f) {
- case 'l':
- f++;
- if (*f == 'l') {
- len = 'q';
- f++;
- } else {
- len = 'l';
- }
- break;
- case 'q': case 'j': case 't': case 'z':
- len = *f;
- f++;
- break;
- default: break;
- }
- /* Conversion specifier. */
- switch (*f) {
- case '%':
- /* %% */
- APPEND_C(*f);
- f++;
- break;
- case 'd': case 'i': {
- intmax_t val JEMALLOC_CC_SILENCE_INIT(0);
- char buf[D2S_BUFSIZE];
-
- /*
- * Outputting negative, zero-padded numbers
- * would require a nontrivial rework of the
- * interaction between the width and padding
- * (since 0 padding goes between the '-' and the
- * number, while ' ' padding goes either before
- * the - or after the number. Since we
- * currently don't ever need 0-padded negative
- * numbers, just don't bother supporting it.
- */
- assert(!pad_zero);
-
- GET_ARG_NUMERIC(val, len);
- s = d2s(val, (plus_plus ? '+' : (plus_space ?
- ' ' : '-')), buf, &slen);
- APPEND_PADDED_S(s, slen, width, left_justify);
- f++;
- break;
- } case 'o': {
- uintmax_t val JEMALLOC_CC_SILENCE_INIT(0);
- char buf[O2S_BUFSIZE];
-
- GET_ARG_NUMERIC(val, len | 0x80);
- s = o2s(val, alt_form, buf, &slen);
- APPEND_PADDED_S(s, slen, width, left_justify);
- f++;
- break;
- } case 'u': {
- uintmax_t val JEMALLOC_CC_SILENCE_INIT(0);
- char buf[U2S_BUFSIZE];
-
- GET_ARG_NUMERIC(val, len | 0x80);
- s = u2s(val, 10, false, buf, &slen);
- APPEND_PADDED_S(s, slen, width, left_justify);
- f++;
- break;
- } case 'x': case 'X': {
- uintmax_t val JEMALLOC_CC_SILENCE_INIT(0);
- char buf[X2S_BUFSIZE];
-
- GET_ARG_NUMERIC(val, len | 0x80);
- s = x2s(val, alt_form, *f == 'X', buf, &slen);
- APPEND_PADDED_S(s, slen, width, left_justify);
- f++;
- break;
- } case 'c': {
- unsigned char val;
- char buf[2];
-
- assert(len == '?' || len == 'l');
- assert_not_implemented(len != 'l');
- val = va_arg(ap, int);
- buf[0] = val;
- buf[1] = '\0';
- APPEND_PADDED_S(buf, 1, width, left_justify);
- f++;
- break;
- } case 's':
- assert(len == '?' || len == 'l');
- assert_not_implemented(len != 'l');
- s = va_arg(ap, char *);
- slen = (prec < 0) ? strlen(s) : (size_t)prec;
- APPEND_PADDED_S(s, slen, width, left_justify);
- f++;
- break;
- case 'p': {
- uintmax_t val;
- char buf[X2S_BUFSIZE];
-
- GET_ARG_NUMERIC(val, 'p');
- s = x2s(val, true, false, buf, &slen);
- APPEND_PADDED_S(s, slen, width, left_justify);
- f++;
- break;
- } default: not_reached();
- }
- break;
- } default: {
- APPEND_C(*f);
- f++;
- break;
- }}
- }
- label_out:
- if (i < size) {
- str[i] = '\0';
- } else {
- str[size - 1] = '\0';
- }
-
-#undef APPEND_C
-#undef APPEND_S
-#undef APPEND_PADDED_S
-#undef GET_ARG_NUMERIC
- return i;
-}
-
-JEMALLOC_FORMAT_PRINTF(3, 4)
-size_t
-malloc_snprintf(char *str, size_t size, const char *format, ...) {
- size_t ret;
- va_list ap;
-
- va_start(ap, format);
- ret = malloc_vsnprintf(str, size, format, ap);
- va_end(ap);
-
- return ret;
-}
-
-void
-malloc_vcprintf(write_cb_t *write_cb, void *cbopaque, const char *format,
- va_list ap) {
- char buf[MALLOC_PRINTF_BUFSIZE];
-
- if (write_cb == NULL) {
- /*
- * The caller did not provide an alternate write_cb callback
- * function, so use the default one. malloc_write() is an
- * inline function, so use malloc_message() directly here.
- */
- write_cb = (je_malloc_message != NULL) ? je_malloc_message :
- wrtmessage;
- }
-
- malloc_vsnprintf(buf, sizeof(buf), format, ap);
- write_cb(cbopaque, buf);
-}
-
-/*
- * Print to a callback function in such a way as to (hopefully) avoid memory
- * allocation.
- */
-JEMALLOC_FORMAT_PRINTF(3, 4)
-void
-malloc_cprintf(write_cb_t *write_cb, void *cbopaque, const char *format, ...) {
- va_list ap;
-
- va_start(ap, format);
- malloc_vcprintf(write_cb, cbopaque, format, ap);
- va_end(ap);
-}
-
-/* Print to stderr in such a way as to avoid memory allocation. */
-JEMALLOC_FORMAT_PRINTF(1, 2)
-void
-malloc_printf(const char *format, ...) {
- va_list ap;
-
- va_start(ap, format);
- malloc_vcprintf(NULL, NULL, format, ap);
- va_end(ap);
-}
-
-/*
- * Restore normal assertion macros, in order to make it possible to compile all
- * C files as a single concatenation.
- */
-#undef assert
-#undef not_reached
-#undef not_implemented
-#undef assert_not_implemented
-#include "jemalloc/internal/assert.h"
diff --git a/fluent-bit/lib/jemalloc-5.3.0/src/mutex.c b/fluent-bit/lib/jemalloc-5.3.0/src/mutex.c
deleted file mode 100644
index 0b3547a8..00000000
--- a/fluent-bit/lib/jemalloc-5.3.0/src/mutex.c
+++ /dev/null
@@ -1,228 +0,0 @@
-#include "jemalloc/internal/jemalloc_preamble.h"
-#include "jemalloc/internal/jemalloc_internal_includes.h"
-
-#include "jemalloc/internal/assert.h"
-#include "jemalloc/internal/malloc_io.h"
-#include "jemalloc/internal/spin.h"
-
-#ifndef _CRT_SPINCOUNT
-#define _CRT_SPINCOUNT 4000
-#endif
-
-/*
- * Based on benchmark results, a fixed spin with this amount of retries works
- * well for our critical sections.
- */
-int64_t opt_mutex_max_spin = 600;
-
-/******************************************************************************/
-/* Data. */
-
-#ifdef JEMALLOC_LAZY_LOCK
-bool isthreaded = false;
-#endif
-#ifdef JEMALLOC_MUTEX_INIT_CB
-static bool postpone_init = true;
-static malloc_mutex_t *postponed_mutexes = NULL;
-#endif
-
-/******************************************************************************/
-/*
- * We intercept pthread_create() calls in order to toggle isthreaded if the
- * process goes multi-threaded.
- */
-
-#if defined(JEMALLOC_LAZY_LOCK) && !defined(_WIN32)
-JEMALLOC_EXPORT int
-pthread_create(pthread_t *__restrict thread,
- const pthread_attr_t *__restrict attr, void *(*start_routine)(void *),
- void *__restrict arg) {
- return pthread_create_wrapper(thread, attr, start_routine, arg);
-}
-#endif
-
-/******************************************************************************/
-
-#ifdef JEMALLOC_MUTEX_INIT_CB
-JEMALLOC_EXPORT int _pthread_mutex_init_calloc_cb(pthread_mutex_t *mutex,
- void *(calloc_cb)(size_t, size_t));
-#endif
-
-void
-malloc_mutex_lock_slow(malloc_mutex_t *mutex) {
- mutex_prof_data_t *data = &mutex->prof_data;
- nstime_t before;
-
- if (ncpus == 1) {
- goto label_spin_done;
- }
-
- int cnt = 0;
- do {
- spin_cpu_spinwait();
- if (!atomic_load_b(&mutex->locked, ATOMIC_RELAXED)
- && !malloc_mutex_trylock_final(mutex)) {
- data->n_spin_acquired++;
- return;
- }
- } while (cnt++ < opt_mutex_max_spin || opt_mutex_max_spin == -1);
-
- if (!config_stats) {
- /* Only spin is useful when stats is off. */
- malloc_mutex_lock_final(mutex);
- return;
- }
-label_spin_done:
- nstime_init_update(&before);
- /* Copy before to after to avoid clock skews. */
- nstime_t after;
- nstime_copy(&after, &before);
- uint32_t n_thds = atomic_fetch_add_u32(&data->n_waiting_thds, 1,
- ATOMIC_RELAXED) + 1;
- /* One last try as above two calls may take quite some cycles. */
- if (!malloc_mutex_trylock_final(mutex)) {
- atomic_fetch_sub_u32(&data->n_waiting_thds, 1, ATOMIC_RELAXED);
- data->n_spin_acquired++;
- return;
- }
-
- /* True slow path. */
- malloc_mutex_lock_final(mutex);
- /* Update more slow-path only counters. */
- atomic_fetch_sub_u32(&data->n_waiting_thds, 1, ATOMIC_RELAXED);
- nstime_update(&after);
-
- nstime_t delta;
- nstime_copy(&delta, &after);
- nstime_subtract(&delta, &before);
-
- data->n_wait_times++;
- nstime_add(&data->tot_wait_time, &delta);
- if (nstime_compare(&data->max_wait_time, &delta) < 0) {
- nstime_copy(&data->max_wait_time, &delta);
- }
- if (n_thds > data->max_n_thds) {
- data->max_n_thds = n_thds;
- }
-}
-
-static void
-mutex_prof_data_init(mutex_prof_data_t *data) {
- memset(data, 0, sizeof(mutex_prof_data_t));
- nstime_init_zero(&data->max_wait_time);
- nstime_init_zero(&data->tot_wait_time);
- data->prev_owner = NULL;
-}
-
-void
-malloc_mutex_prof_data_reset(tsdn_t *tsdn, malloc_mutex_t *mutex) {
- malloc_mutex_assert_owner(tsdn, mutex);
- mutex_prof_data_init(&mutex->prof_data);
-}
-
-static int
-mutex_addr_comp(const witness_t *witness1, void *mutex1,
- const witness_t *witness2, void *mutex2) {
- assert(mutex1 != NULL);
- assert(mutex2 != NULL);
- uintptr_t mu1int = (uintptr_t)mutex1;
- uintptr_t mu2int = (uintptr_t)mutex2;
- if (mu1int < mu2int) {
- return -1;
- } else if (mu1int == mu2int) {
- return 0;
- } else {
- return 1;
- }
-}
-
-bool
-malloc_mutex_init(malloc_mutex_t *mutex, const char *name,
- witness_rank_t rank, malloc_mutex_lock_order_t lock_order) {
- mutex_prof_data_init(&mutex->prof_data);
-#ifdef _WIN32
-# if _WIN32_WINNT >= 0x0600
- InitializeSRWLock(&mutex->lock);
-# else
- if (!InitializeCriticalSectionAndSpinCount(&mutex->lock,
- _CRT_SPINCOUNT)) {
- return true;
- }
-# endif
-#elif (defined(JEMALLOC_OS_UNFAIR_LOCK))
- mutex->lock = OS_UNFAIR_LOCK_INIT;
-#elif (defined(JEMALLOC_MUTEX_INIT_CB))
- if (postpone_init) {
- mutex->postponed_next = postponed_mutexes;
- postponed_mutexes = mutex;
- } else {
- if (_pthread_mutex_init_calloc_cb(&mutex->lock,
- bootstrap_calloc) != 0) {
- return true;
- }
- }
-#else
- pthread_mutexattr_t attr;
-
- if (pthread_mutexattr_init(&attr) != 0) {
- return true;
- }
- pthread_mutexattr_settype(&attr, MALLOC_MUTEX_TYPE);
- if (pthread_mutex_init(&mutex->lock, &attr) != 0) {
- pthread_mutexattr_destroy(&attr);
- return true;
- }
- pthread_mutexattr_destroy(&attr);
-#endif
- if (config_debug) {
- mutex->lock_order = lock_order;
- if (lock_order == malloc_mutex_address_ordered) {
- witness_init(&mutex->witness, name, rank,
- mutex_addr_comp, mutex);
- } else {
- witness_init(&mutex->witness, name, rank, NULL, NULL);
- }
- }
- return false;
-}
-
-void
-malloc_mutex_prefork(tsdn_t *tsdn, malloc_mutex_t *mutex) {
- malloc_mutex_lock(tsdn, mutex);
-}
-
-void
-malloc_mutex_postfork_parent(tsdn_t *tsdn, malloc_mutex_t *mutex) {
- malloc_mutex_unlock(tsdn, mutex);
-}
-
-void
-malloc_mutex_postfork_child(tsdn_t *tsdn, malloc_mutex_t *mutex) {
-#ifdef JEMALLOC_MUTEX_INIT_CB
- malloc_mutex_unlock(tsdn, mutex);
-#else
- if (malloc_mutex_init(mutex, mutex->witness.name,
- mutex->witness.rank, mutex->lock_order)) {
- malloc_printf("<jemalloc>: Error re-initializing mutex in "
- "child\n");
- if (opt_abort) {
- abort();
- }
- }
-#endif
-}
-
-bool
-malloc_mutex_boot(void) {
-#ifdef JEMALLOC_MUTEX_INIT_CB
- postpone_init = false;
- while (postponed_mutexes != NULL) {
- if (_pthread_mutex_init_calloc_cb(&postponed_mutexes->lock,
- bootstrap_calloc) != 0) {
- return true;
- }
- postponed_mutexes = postponed_mutexes->postponed_next;
- }
-#endif
- return false;
-}
diff --git a/fluent-bit/lib/jemalloc-5.3.0/src/nstime.c b/fluent-bit/lib/jemalloc-5.3.0/src/nstime.c
deleted file mode 100644
index a1a53777..00000000
--- a/fluent-bit/lib/jemalloc-5.3.0/src/nstime.c
+++ /dev/null
@@ -1,289 +0,0 @@
-#include "jemalloc/internal/jemalloc_preamble.h"
-#include "jemalloc/internal/jemalloc_internal_includes.h"
-
-#include "jemalloc/internal/nstime.h"
-
-#include "jemalloc/internal/assert.h"
-
-#define BILLION UINT64_C(1000000000)
-#define MILLION UINT64_C(1000000)
-
-static void
-nstime_set_initialized(nstime_t *time) {
-#ifdef JEMALLOC_DEBUG
- time->magic = NSTIME_MAGIC;
-#endif
-}
-
-static void
-nstime_assert_initialized(const nstime_t *time) {
-#ifdef JEMALLOC_DEBUG
- /*
- * Some parts (e.g. stats) rely on memset to zero initialize. Treat
- * these as valid initialization.
- */
- assert(time->magic == NSTIME_MAGIC ||
- (time->magic == 0 && time->ns == 0));
-#endif
-}
-
-static void
-nstime_pair_assert_initialized(const nstime_t *t1, const nstime_t *t2) {
- nstime_assert_initialized(t1);
- nstime_assert_initialized(t2);
-}
-
-static void
-nstime_initialize_operand(nstime_t *time) {
- /*
- * Operations like nstime_add may have the initial operand being zero
- * initialized (covered by the assert below). Full-initialize needed
- * before changing it to non-zero.
- */
- nstime_assert_initialized(time);
- nstime_set_initialized(time);
-}
-
-void
-nstime_init(nstime_t *time, uint64_t ns) {
- nstime_set_initialized(time);
- time->ns = ns;
-}
-
-void
-nstime_init2(nstime_t *time, uint64_t sec, uint64_t nsec) {
- nstime_set_initialized(time);
- time->ns = sec * BILLION + nsec;
-}
-
-uint64_t
-nstime_ns(const nstime_t *time) {
- nstime_assert_initialized(time);
- return time->ns;
-}
-
-uint64_t
-nstime_msec(const nstime_t *time) {
- nstime_assert_initialized(time);
- return time->ns / MILLION;
-}
-
-uint64_t
-nstime_sec(const nstime_t *time) {
- nstime_assert_initialized(time);
- return time->ns / BILLION;
-}
-
-uint64_t
-nstime_nsec(const nstime_t *time) {
- nstime_assert_initialized(time);
- return time->ns % BILLION;
-}
-
-void
-nstime_copy(nstime_t *time, const nstime_t *source) {
- /* Source is required to be initialized. */
- nstime_assert_initialized(source);
- *time = *source;
- nstime_assert_initialized(time);
-}
-
-int
-nstime_compare(const nstime_t *a, const nstime_t *b) {
- nstime_pair_assert_initialized(a, b);
- return (a->ns > b->ns) - (a->ns < b->ns);
-}
-
-void
-nstime_add(nstime_t *time, const nstime_t *addend) {
- nstime_pair_assert_initialized(time, addend);
- assert(UINT64_MAX - time->ns >= addend->ns);
-
- nstime_initialize_operand(time);
- time->ns += addend->ns;
-}
-
-void
-nstime_iadd(nstime_t *time, uint64_t addend) {
- nstime_assert_initialized(time);
- assert(UINT64_MAX - time->ns >= addend);
-
- nstime_initialize_operand(time);
- time->ns += addend;
-}
-
-void
-nstime_subtract(nstime_t *time, const nstime_t *subtrahend) {
- nstime_pair_assert_initialized(time, subtrahend);
- assert(nstime_compare(time, subtrahend) >= 0);
-
- /* No initialize operand -- subtraction must be initialized. */
- time->ns -= subtrahend->ns;
-}
-
-void
-nstime_isubtract(nstime_t *time, uint64_t subtrahend) {
- nstime_assert_initialized(time);
- assert(time->ns >= subtrahend);
-
- /* No initialize operand -- subtraction must be initialized. */
- time->ns -= subtrahend;
-}
-
-void
-nstime_imultiply(nstime_t *time, uint64_t multiplier) {
- nstime_assert_initialized(time);
- assert((((time->ns | multiplier) & (UINT64_MAX << (sizeof(uint64_t) <<
- 2))) == 0) || ((time->ns * multiplier) / multiplier == time->ns));
-
- nstime_initialize_operand(time);
- time->ns *= multiplier;
-}
-
-void
-nstime_idivide(nstime_t *time, uint64_t divisor) {
- nstime_assert_initialized(time);
- assert(divisor != 0);
-
- nstime_initialize_operand(time);
- time->ns /= divisor;
-}
-
-uint64_t
-nstime_divide(const nstime_t *time, const nstime_t *divisor) {
- nstime_pair_assert_initialized(time, divisor);
- assert(divisor->ns != 0);
-
- /* No initialize operand -- *time itself remains unchanged. */
- return time->ns / divisor->ns;
-}
-
-/* Returns time since *past, w/o updating *past. */
-uint64_t
-nstime_ns_since(const nstime_t *past) {
- nstime_assert_initialized(past);
-
- nstime_t now;
- nstime_copy(&now, past);
- nstime_update(&now);
-
- assert(nstime_compare(&now, past) >= 0);
- return now.ns - past->ns;
-}
-
-#ifdef _WIN32
-# define NSTIME_MONOTONIC true
-static void
-nstime_get(nstime_t *time) {
- FILETIME ft;
- uint64_t ticks_100ns;
-
- GetSystemTimeAsFileTime(&ft);
- ticks_100ns = (((uint64_t)ft.dwHighDateTime) << 32) | ft.dwLowDateTime;
-
- nstime_init(time, ticks_100ns * 100);
-}
-#elif defined(JEMALLOC_HAVE_CLOCK_MONOTONIC_COARSE)
-# define NSTIME_MONOTONIC true
-static void
-nstime_get(nstime_t *time) {
- struct timespec ts;
-
- clock_gettime(CLOCK_MONOTONIC_COARSE, &ts);
- nstime_init2(time, ts.tv_sec, ts.tv_nsec);
-}
-#elif defined(JEMALLOC_HAVE_CLOCK_MONOTONIC)
-# define NSTIME_MONOTONIC true
-static void
-nstime_get(nstime_t *time) {
- struct timespec ts;
-
- clock_gettime(CLOCK_MONOTONIC, &ts);
- nstime_init2(time, ts.tv_sec, ts.tv_nsec);
-}
-#elif defined(JEMALLOC_HAVE_MACH_ABSOLUTE_TIME)
-# define NSTIME_MONOTONIC true
-static void
-nstime_get(nstime_t *time) {
- nstime_init(time, mach_absolute_time());
-}
-#else
-# define NSTIME_MONOTONIC false
-static void
-nstime_get(nstime_t *time) {
- struct timeval tv;
-
- gettimeofday(&tv, NULL);
- nstime_init2(time, tv.tv_sec, tv.tv_usec * 1000);
-}
-#endif
-
-static bool
-nstime_monotonic_impl(void) {
- return NSTIME_MONOTONIC;
-#undef NSTIME_MONOTONIC
-}
-nstime_monotonic_t *JET_MUTABLE nstime_monotonic = nstime_monotonic_impl;
-
-prof_time_res_t opt_prof_time_res =
- prof_time_res_default;
-
-const char *prof_time_res_mode_names[] = {
- "default",
- "high",
-};
-
-
-static void
-nstime_get_realtime(nstime_t *time) {
-#if defined(JEMALLOC_HAVE_CLOCK_REALTIME) && !defined(_WIN32)
- struct timespec ts;
-
- clock_gettime(CLOCK_REALTIME, &ts);
- nstime_init2(time, ts.tv_sec, ts.tv_nsec);
-#else
- unreachable();
-#endif
-}
-
-static void
-nstime_prof_update_impl(nstime_t *time) {
- nstime_t old_time;
-
- nstime_copy(&old_time, time);
-
- if (opt_prof_time_res == prof_time_res_high) {
- nstime_get_realtime(time);
- } else {
- nstime_get(time);
- }
-}
-nstime_prof_update_t *JET_MUTABLE nstime_prof_update = nstime_prof_update_impl;
-
-static void
-nstime_update_impl(nstime_t *time) {
- nstime_t old_time;
-
- nstime_copy(&old_time, time);
- nstime_get(time);
-
- /* Handle non-monotonic clocks. */
- if (unlikely(nstime_compare(&old_time, time) > 0)) {
- nstime_copy(time, &old_time);
- }
-}
-nstime_update_t *JET_MUTABLE nstime_update = nstime_update_impl;
-
-void
-nstime_init_update(nstime_t *time) {
- nstime_init_zero(time);
- nstime_update(time);
-}
-
-void
-nstime_prof_init_update(nstime_t *time) {
- nstime_init_zero(time);
- nstime_prof_update(time);
-}
-
-
diff --git a/fluent-bit/lib/jemalloc-5.3.0/src/pa.c b/fluent-bit/lib/jemalloc-5.3.0/src/pa.c
deleted file mode 100644
index eb7e4620..00000000
--- a/fluent-bit/lib/jemalloc-5.3.0/src/pa.c
+++ /dev/null
@@ -1,277 +0,0 @@
-#include "jemalloc/internal/jemalloc_preamble.h"
-#include "jemalloc/internal/jemalloc_internal_includes.h"
-
-#include "jemalloc/internal/san.h"
-#include "jemalloc/internal/hpa.h"
-
-static void
-pa_nactive_add(pa_shard_t *shard, size_t add_pages) {
- atomic_fetch_add_zu(&shard->nactive, add_pages, ATOMIC_RELAXED);
-}
-
-static void
-pa_nactive_sub(pa_shard_t *shard, size_t sub_pages) {
- assert(atomic_load_zu(&shard->nactive, ATOMIC_RELAXED) >= sub_pages);
- atomic_fetch_sub_zu(&shard->nactive, sub_pages, ATOMIC_RELAXED);
-}
-
-bool
-pa_central_init(pa_central_t *central, base_t *base, bool hpa,
- hpa_hooks_t *hpa_hooks) {
- bool err;
- if (hpa) {
- err = hpa_central_init(&central->hpa, base, hpa_hooks);
- if (err) {
- return true;
- }
- }
- return false;
-}
-
-bool
-pa_shard_init(tsdn_t *tsdn, pa_shard_t *shard, pa_central_t *central,
- emap_t *emap, base_t *base, unsigned ind, pa_shard_stats_t *stats,
- malloc_mutex_t *stats_mtx, nstime_t *cur_time,
- size_t pac_oversize_threshold, ssize_t dirty_decay_ms,
- ssize_t muzzy_decay_ms) {
- /* This will change eventually, but for now it should hold. */
- assert(base_ind_get(base) == ind);
- if (edata_cache_init(&shard->edata_cache, base)) {
- return true;
- }
-
- if (pac_init(tsdn, &shard->pac, base, emap, &shard->edata_cache,
- cur_time, pac_oversize_threshold, dirty_decay_ms, muzzy_decay_ms,
- &stats->pac_stats, stats_mtx)) {
- return true;
- }
-
- shard->ind = ind;
-
- shard->ever_used_hpa = false;
- atomic_store_b(&shard->use_hpa, false, ATOMIC_RELAXED);
-
- atomic_store_zu(&shard->nactive, 0, ATOMIC_RELAXED);
-
- shard->stats_mtx = stats_mtx;
- shard->stats = stats;
- memset(shard->stats, 0, sizeof(*shard->stats));
-
- shard->central = central;
- shard->emap = emap;
- shard->base = base;
-
- return false;
-}
-
-bool
-pa_shard_enable_hpa(tsdn_t *tsdn, pa_shard_t *shard,
- const hpa_shard_opts_t *hpa_opts, const sec_opts_t *hpa_sec_opts) {
- if (hpa_shard_init(&shard->hpa_shard, &shard->central->hpa, shard->emap,
- shard->base, &shard->edata_cache, shard->ind, hpa_opts)) {
- return true;
- }
- if (sec_init(tsdn, &shard->hpa_sec, shard->base, &shard->hpa_shard.pai,
- hpa_sec_opts)) {
- return true;
- }
- shard->ever_used_hpa = true;
- atomic_store_b(&shard->use_hpa, true, ATOMIC_RELAXED);
-
- return false;
-}
-
-void
-pa_shard_disable_hpa(tsdn_t *tsdn, pa_shard_t *shard) {
- atomic_store_b(&shard->use_hpa, false, ATOMIC_RELAXED);
- if (shard->ever_used_hpa) {
- sec_disable(tsdn, &shard->hpa_sec);
- hpa_shard_disable(tsdn, &shard->hpa_shard);
- }
-}
-
-void
-pa_shard_reset(tsdn_t *tsdn, pa_shard_t *shard) {
- atomic_store_zu(&shard->nactive, 0, ATOMIC_RELAXED);
- if (shard->ever_used_hpa) {
- sec_flush(tsdn, &shard->hpa_sec);
- }
-}
-
-static bool
-pa_shard_uses_hpa(pa_shard_t *shard) {
- return atomic_load_b(&shard->use_hpa, ATOMIC_RELAXED);
-}
-
-void
-pa_shard_destroy(tsdn_t *tsdn, pa_shard_t *shard) {
- pac_destroy(tsdn, &shard->pac);
- if (shard->ever_used_hpa) {
- sec_flush(tsdn, &shard->hpa_sec);
- hpa_shard_disable(tsdn, &shard->hpa_shard);
- }
-}
-
-static pai_t *
-pa_get_pai(pa_shard_t *shard, edata_t *edata) {
- return (edata_pai_get(edata) == EXTENT_PAI_PAC
- ? &shard->pac.pai : &shard->hpa_sec.pai);
-}
-
-edata_t *
-pa_alloc(tsdn_t *tsdn, pa_shard_t *shard, size_t size, size_t alignment,
- bool slab, szind_t szind, bool zero, bool guarded,
- bool *deferred_work_generated) {
- witness_assert_depth_to_rank(tsdn_witness_tsdp_get(tsdn),
- WITNESS_RANK_CORE, 0);
- assert(!guarded || alignment <= PAGE);
-
- edata_t *edata = NULL;
- if (!guarded && pa_shard_uses_hpa(shard)) {
- edata = pai_alloc(tsdn, &shard->hpa_sec.pai, size, alignment,
- zero, /* guarded */ false, slab, deferred_work_generated);
- }
- /*
- * Fall back to the PAC if the HPA is off or couldn't serve the given
- * allocation request.
- */
- if (edata == NULL) {
- edata = pai_alloc(tsdn, &shard->pac.pai, size, alignment, zero,
- guarded, slab, deferred_work_generated);
- }
- if (edata != NULL) {
- assert(edata_size_get(edata) == size);
- pa_nactive_add(shard, size >> LG_PAGE);
- emap_remap(tsdn, shard->emap, edata, szind, slab);
- edata_szind_set(edata, szind);
- edata_slab_set(edata, slab);
- if (slab && (size > 2 * PAGE)) {
- emap_register_interior(tsdn, shard->emap, edata, szind);
- }
- assert(edata_arena_ind_get(edata) == shard->ind);
- }
- return edata;
-}
-
-bool
-pa_expand(tsdn_t *tsdn, pa_shard_t *shard, edata_t *edata, size_t old_size,
- size_t new_size, szind_t szind, bool zero, bool *deferred_work_generated) {
- assert(new_size > old_size);
- assert(edata_size_get(edata) == old_size);
- assert((new_size & PAGE_MASK) == 0);
- if (edata_guarded_get(edata)) {
- return true;
- }
- size_t expand_amount = new_size - old_size;
-
- pai_t *pai = pa_get_pai(shard, edata);
-
- bool error = pai_expand(tsdn, pai, edata, old_size, new_size, zero,
- deferred_work_generated);
- if (error) {
- return true;
- }
-
- pa_nactive_add(shard, expand_amount >> LG_PAGE);
- edata_szind_set(edata, szind);
- emap_remap(tsdn, shard->emap, edata, szind, /* slab */ false);
- return false;
-}
-
-bool
-pa_shrink(tsdn_t *tsdn, pa_shard_t *shard, edata_t *edata, size_t old_size,
- size_t new_size, szind_t szind, bool *deferred_work_generated) {
- assert(new_size < old_size);
- assert(edata_size_get(edata) == old_size);
- assert((new_size & PAGE_MASK) == 0);
- if (edata_guarded_get(edata)) {
- return true;
- }
- size_t shrink_amount = old_size - new_size;
-
- pai_t *pai = pa_get_pai(shard, edata);
- bool error = pai_shrink(tsdn, pai, edata, old_size, new_size,
- deferred_work_generated);
- if (error) {
- return true;
- }
- pa_nactive_sub(shard, shrink_amount >> LG_PAGE);
-
- edata_szind_set(edata, szind);
- emap_remap(tsdn, shard->emap, edata, szind, /* slab */ false);
- return false;
-}
-
-void
-pa_dalloc(tsdn_t *tsdn, pa_shard_t *shard, edata_t *edata,
- bool *deferred_work_generated) {
- emap_remap(tsdn, shard->emap, edata, SC_NSIZES, /* slab */ false);
- if (edata_slab_get(edata)) {
- emap_deregister_interior(tsdn, shard->emap, edata);
- /*
- * The slab state of the extent isn't cleared. It may be used
- * by the pai implementation, e.g. to make caching decisions.
- */
- }
- edata_addr_set(edata, edata_base_get(edata));
- edata_szind_set(edata, SC_NSIZES);
- pa_nactive_sub(shard, edata_size_get(edata) >> LG_PAGE);
- pai_t *pai = pa_get_pai(shard, edata);
- pai_dalloc(tsdn, pai, edata, deferred_work_generated);
-}
-
-bool
-pa_shard_retain_grow_limit_get_set(tsdn_t *tsdn, pa_shard_t *shard,
- size_t *old_limit, size_t *new_limit) {
- return pac_retain_grow_limit_get_set(tsdn, &shard->pac, old_limit,
- new_limit);
-}
-
-bool
-pa_decay_ms_set(tsdn_t *tsdn, pa_shard_t *shard, extent_state_t state,
- ssize_t decay_ms, pac_purge_eagerness_t eagerness) {
- return pac_decay_ms_set(tsdn, &shard->pac, state, decay_ms, eagerness);
-}
-
-ssize_t
-pa_decay_ms_get(pa_shard_t *shard, extent_state_t state) {
- return pac_decay_ms_get(&shard->pac, state);
-}
-
-void
-pa_shard_set_deferral_allowed(tsdn_t *tsdn, pa_shard_t *shard,
- bool deferral_allowed) {
- if (pa_shard_uses_hpa(shard)) {
- hpa_shard_set_deferral_allowed(tsdn, &shard->hpa_shard,
- deferral_allowed);
- }
-}
-
-void
-pa_shard_do_deferred_work(tsdn_t *tsdn, pa_shard_t *shard) {
- if (pa_shard_uses_hpa(shard)) {
- hpa_shard_do_deferred_work(tsdn, &shard->hpa_shard);
- }
-}
-
-/*
- * Get time until next deferred work ought to happen. If there are multiple
- * things that have been deferred, this function calculates the time until
- * the soonest of those things.
- */
-uint64_t
-pa_shard_time_until_deferred_work(tsdn_t *tsdn, pa_shard_t *shard) {
- uint64_t time = pai_time_until_deferred_work(tsdn, &shard->pac.pai);
- if (time == BACKGROUND_THREAD_DEFERRED_MIN) {
- return time;
- }
-
- if (pa_shard_uses_hpa(shard)) {
- uint64_t hpa =
- pai_time_until_deferred_work(tsdn, &shard->hpa_shard.pai);
- if (hpa < time) {
- time = hpa;
- }
- }
- return time;
-}
diff --git a/fluent-bit/lib/jemalloc-5.3.0/src/pa_extra.c b/fluent-bit/lib/jemalloc-5.3.0/src/pa_extra.c
deleted file mode 100644
index 0f488be6..00000000
--- a/fluent-bit/lib/jemalloc-5.3.0/src/pa_extra.c
+++ /dev/null
@@ -1,191 +0,0 @@
-#include "jemalloc/internal/jemalloc_preamble.h"
-#include "jemalloc/internal/jemalloc_internal_includes.h"
-
-/*
- * This file is logically part of the PA module. While pa.c contains the core
- * allocator functionality, this file contains boring integration functionality;
- * things like the pre- and post- fork handlers, and stats merging for CTL
- * refreshes.
- */
-
-void
-pa_shard_prefork0(tsdn_t *tsdn, pa_shard_t *shard) {
- malloc_mutex_prefork(tsdn, &shard->pac.decay_dirty.mtx);
- malloc_mutex_prefork(tsdn, &shard->pac.decay_muzzy.mtx);
-}
-
-void
-pa_shard_prefork2(tsdn_t *tsdn, pa_shard_t *shard) {
- if (shard->ever_used_hpa) {
- sec_prefork2(tsdn, &shard->hpa_sec);
- }
-}
-
-void
-pa_shard_prefork3(tsdn_t *tsdn, pa_shard_t *shard) {
- malloc_mutex_prefork(tsdn, &shard->pac.grow_mtx);
- if (shard->ever_used_hpa) {
- hpa_shard_prefork3(tsdn, &shard->hpa_shard);
- }
-}
-
-void
-pa_shard_prefork4(tsdn_t *tsdn, pa_shard_t *shard) {
- ecache_prefork(tsdn, &shard->pac.ecache_dirty);
- ecache_prefork(tsdn, &shard->pac.ecache_muzzy);
- ecache_prefork(tsdn, &shard->pac.ecache_retained);
- if (shard->ever_used_hpa) {
- hpa_shard_prefork4(tsdn, &shard->hpa_shard);
- }
-}
-
-void
-pa_shard_prefork5(tsdn_t *tsdn, pa_shard_t *shard) {
- edata_cache_prefork(tsdn, &shard->edata_cache);
-}
-
-void
-pa_shard_postfork_parent(tsdn_t *tsdn, pa_shard_t *shard) {
- edata_cache_postfork_parent(tsdn, &shard->edata_cache);
- ecache_postfork_parent(tsdn, &shard->pac.ecache_dirty);
- ecache_postfork_parent(tsdn, &shard->pac.ecache_muzzy);
- ecache_postfork_parent(tsdn, &shard->pac.ecache_retained);
- malloc_mutex_postfork_parent(tsdn, &shard->pac.grow_mtx);
- malloc_mutex_postfork_parent(tsdn, &shard->pac.decay_dirty.mtx);
- malloc_mutex_postfork_parent(tsdn, &shard->pac.decay_muzzy.mtx);
- if (shard->ever_used_hpa) {
- sec_postfork_parent(tsdn, &shard->hpa_sec);
- hpa_shard_postfork_parent(tsdn, &shard->hpa_shard);
- }
-}
-
-void
-pa_shard_postfork_child(tsdn_t *tsdn, pa_shard_t *shard) {
- edata_cache_postfork_child(tsdn, &shard->edata_cache);
- ecache_postfork_child(tsdn, &shard->pac.ecache_dirty);
- ecache_postfork_child(tsdn, &shard->pac.ecache_muzzy);
- ecache_postfork_child(tsdn, &shard->pac.ecache_retained);
- malloc_mutex_postfork_child(tsdn, &shard->pac.grow_mtx);
- malloc_mutex_postfork_child(tsdn, &shard->pac.decay_dirty.mtx);
- malloc_mutex_postfork_child(tsdn, &shard->pac.decay_muzzy.mtx);
- if (shard->ever_used_hpa) {
- sec_postfork_child(tsdn, &shard->hpa_sec);
- hpa_shard_postfork_child(tsdn, &shard->hpa_shard);
- }
-}
-
-void
-pa_shard_basic_stats_merge(pa_shard_t *shard, size_t *nactive, size_t *ndirty,
- size_t *nmuzzy) {
- *nactive += atomic_load_zu(&shard->nactive, ATOMIC_RELAXED);
- *ndirty += ecache_npages_get(&shard->pac.ecache_dirty);
- *nmuzzy += ecache_npages_get(&shard->pac.ecache_muzzy);
-}
-
-void
-pa_shard_stats_merge(tsdn_t *tsdn, pa_shard_t *shard,
- pa_shard_stats_t *pa_shard_stats_out, pac_estats_t *estats_out,
- hpa_shard_stats_t *hpa_stats_out, sec_stats_t *sec_stats_out,
- size_t *resident) {
- cassert(config_stats);
-
- pa_shard_stats_out->pac_stats.retained +=
- ecache_npages_get(&shard->pac.ecache_retained) << LG_PAGE;
- pa_shard_stats_out->edata_avail += atomic_load_zu(
- &shard->edata_cache.count, ATOMIC_RELAXED);
-
- size_t resident_pgs = 0;
- resident_pgs += atomic_load_zu(&shard->nactive, ATOMIC_RELAXED);
- resident_pgs += ecache_npages_get(&shard->pac.ecache_dirty);
- *resident += (resident_pgs << LG_PAGE);
-
- /* Dirty decay stats */
- locked_inc_u64_unsynchronized(
- &pa_shard_stats_out->pac_stats.decay_dirty.npurge,
- locked_read_u64(tsdn, LOCKEDINT_MTX(*shard->stats_mtx),
- &shard->pac.stats->decay_dirty.npurge));
- locked_inc_u64_unsynchronized(
- &pa_shard_stats_out->pac_stats.decay_dirty.nmadvise,
- locked_read_u64(tsdn, LOCKEDINT_MTX(*shard->stats_mtx),
- &shard->pac.stats->decay_dirty.nmadvise));
- locked_inc_u64_unsynchronized(
- &pa_shard_stats_out->pac_stats.decay_dirty.purged,
- locked_read_u64(tsdn, LOCKEDINT_MTX(*shard->stats_mtx),
- &shard->pac.stats->decay_dirty.purged));
-
- /* Muzzy decay stats */
- locked_inc_u64_unsynchronized(
- &pa_shard_stats_out->pac_stats.decay_muzzy.npurge,
- locked_read_u64(tsdn, LOCKEDINT_MTX(*shard->stats_mtx),
- &shard->pac.stats->decay_muzzy.npurge));
- locked_inc_u64_unsynchronized(
- &pa_shard_stats_out->pac_stats.decay_muzzy.nmadvise,
- locked_read_u64(tsdn, LOCKEDINT_MTX(*shard->stats_mtx),
- &shard->pac.stats->decay_muzzy.nmadvise));
- locked_inc_u64_unsynchronized(
- &pa_shard_stats_out->pac_stats.decay_muzzy.purged,
- locked_read_u64(tsdn, LOCKEDINT_MTX(*shard->stats_mtx),
- &shard->pac.stats->decay_muzzy.purged));
-
- atomic_load_add_store_zu(&pa_shard_stats_out->pac_stats.abandoned_vm,
- atomic_load_zu(&shard->pac.stats->abandoned_vm, ATOMIC_RELAXED));
-
- for (pszind_t i = 0; i < SC_NPSIZES; i++) {
- size_t dirty, muzzy, retained, dirty_bytes, muzzy_bytes,
- retained_bytes;
- dirty = ecache_nextents_get(&shard->pac.ecache_dirty, i);
- muzzy = ecache_nextents_get(&shard->pac.ecache_muzzy, i);
- retained = ecache_nextents_get(&shard->pac.ecache_retained, i);
- dirty_bytes = ecache_nbytes_get(&shard->pac.ecache_dirty, i);
- muzzy_bytes = ecache_nbytes_get(&shard->pac.ecache_muzzy, i);
- retained_bytes = ecache_nbytes_get(&shard->pac.ecache_retained,
- i);
-
- estats_out[i].ndirty = dirty;
- estats_out[i].nmuzzy = muzzy;
- estats_out[i].nretained = retained;
- estats_out[i].dirty_bytes = dirty_bytes;
- estats_out[i].muzzy_bytes = muzzy_bytes;
- estats_out[i].retained_bytes = retained_bytes;
- }
-
- if (shard->ever_used_hpa) {
- hpa_shard_stats_merge(tsdn, &shard->hpa_shard, hpa_stats_out);
- sec_stats_merge(tsdn, &shard->hpa_sec, sec_stats_out);
- }
-}
-
-static void
-pa_shard_mtx_stats_read_single(tsdn_t *tsdn, mutex_prof_data_t *mutex_prof_data,
- malloc_mutex_t *mtx, int ind) {
- malloc_mutex_lock(tsdn, mtx);
- malloc_mutex_prof_read(tsdn, &mutex_prof_data[ind], mtx);
- malloc_mutex_unlock(tsdn, mtx);
-}
-
-void
-pa_shard_mtx_stats_read(tsdn_t *tsdn, pa_shard_t *shard,
- mutex_prof_data_t mutex_prof_data[mutex_prof_num_arena_mutexes]) {
- pa_shard_mtx_stats_read_single(tsdn, mutex_prof_data,
- &shard->edata_cache.mtx, arena_prof_mutex_extent_avail);
- pa_shard_mtx_stats_read_single(tsdn, mutex_prof_data,
- &shard->pac.ecache_dirty.mtx, arena_prof_mutex_extents_dirty);
- pa_shard_mtx_stats_read_single(tsdn, mutex_prof_data,
- &shard->pac.ecache_muzzy.mtx, arena_prof_mutex_extents_muzzy);
- pa_shard_mtx_stats_read_single(tsdn, mutex_prof_data,
- &shard->pac.ecache_retained.mtx, arena_prof_mutex_extents_retained);
- pa_shard_mtx_stats_read_single(tsdn, mutex_prof_data,
- &shard->pac.decay_dirty.mtx, arena_prof_mutex_decay_dirty);
- pa_shard_mtx_stats_read_single(tsdn, mutex_prof_data,
- &shard->pac.decay_muzzy.mtx, arena_prof_mutex_decay_muzzy);
-
- if (shard->ever_used_hpa) {
- pa_shard_mtx_stats_read_single(tsdn, mutex_prof_data,
- &shard->hpa_shard.mtx, arena_prof_mutex_hpa_shard);
- pa_shard_mtx_stats_read_single(tsdn, mutex_prof_data,
- &shard->hpa_shard.grow_mtx,
- arena_prof_mutex_hpa_shard_grow);
- sec_mutex_stats_read(tsdn, &shard->hpa_sec,
- &mutex_prof_data[arena_prof_mutex_hpa_sec]);
- }
-}
diff --git a/fluent-bit/lib/jemalloc-5.3.0/src/pac.c b/fluent-bit/lib/jemalloc-5.3.0/src/pac.c
deleted file mode 100644
index 53e3d823..00000000
--- a/fluent-bit/lib/jemalloc-5.3.0/src/pac.c
+++ /dev/null
@@ -1,587 +0,0 @@
-#include "jemalloc/internal/jemalloc_preamble.h"
-#include "jemalloc/internal/jemalloc_internal_includes.h"
-
-#include "jemalloc/internal/pac.h"
-#include "jemalloc/internal/san.h"
-
-static edata_t *pac_alloc_impl(tsdn_t *tsdn, pai_t *self, size_t size,
- size_t alignment, bool zero, bool guarded, bool frequent_reuse,
- bool *deferred_work_generated);
-static bool pac_expand_impl(tsdn_t *tsdn, pai_t *self, edata_t *edata,
- size_t old_size, size_t new_size, bool zero, bool *deferred_work_generated);
-static bool pac_shrink_impl(tsdn_t *tsdn, pai_t *self, edata_t *edata,
- size_t old_size, size_t new_size, bool *deferred_work_generated);
-static void pac_dalloc_impl(tsdn_t *tsdn, pai_t *self, edata_t *edata,
- bool *deferred_work_generated);
-static uint64_t pac_time_until_deferred_work(tsdn_t *tsdn, pai_t *self);
-
-static inline void
-pac_decay_data_get(pac_t *pac, extent_state_t state,
- decay_t **r_decay, pac_decay_stats_t **r_decay_stats, ecache_t **r_ecache) {
- switch(state) {
- case extent_state_dirty:
- *r_decay = &pac->decay_dirty;
- *r_decay_stats = &pac->stats->decay_dirty;
- *r_ecache = &pac->ecache_dirty;
- return;
- case extent_state_muzzy:
- *r_decay = &pac->decay_muzzy;
- *r_decay_stats = &pac->stats->decay_muzzy;
- *r_ecache = &pac->ecache_muzzy;
- return;
- default:
- unreachable();
- }
-}
-
-bool
-pac_init(tsdn_t *tsdn, pac_t *pac, base_t *base, emap_t *emap,
- edata_cache_t *edata_cache, nstime_t *cur_time,
- size_t pac_oversize_threshold, ssize_t dirty_decay_ms,
- ssize_t muzzy_decay_ms, pac_stats_t *pac_stats, malloc_mutex_t *stats_mtx) {
- unsigned ind = base_ind_get(base);
- /*
- * Delay coalescing for dirty extents despite the disruptive effect on
- * memory layout for best-fit extent allocation, since cached extents
- * are likely to be reused soon after deallocation, and the cost of
- * merging/splitting extents is non-trivial.
- */
- if (ecache_init(tsdn, &pac->ecache_dirty, extent_state_dirty, ind,
- /* delay_coalesce */ true)) {
- return true;
- }
- /*
- * Coalesce muzzy extents immediately, because operations on them are in
- * the critical path much less often than for dirty extents.
- */
- if (ecache_init(tsdn, &pac->ecache_muzzy, extent_state_muzzy, ind,
- /* delay_coalesce */ false)) {
- return true;
- }
- /*
- * Coalesce retained extents immediately, in part because they will
- * never be evicted (and therefore there's no opportunity for delayed
- * coalescing), but also because operations on retained extents are not
- * in the critical path.
- */
- if (ecache_init(tsdn, &pac->ecache_retained, extent_state_retained,
- ind, /* delay_coalesce */ false)) {
- return true;
- }
- exp_grow_init(&pac->exp_grow);
- if (malloc_mutex_init(&pac->grow_mtx, "extent_grow",
- WITNESS_RANK_EXTENT_GROW, malloc_mutex_rank_exclusive)) {
- return true;
- }
- atomic_store_zu(&pac->oversize_threshold, pac_oversize_threshold,
- ATOMIC_RELAXED);
- if (decay_init(&pac->decay_dirty, cur_time, dirty_decay_ms)) {
- return true;
- }
- if (decay_init(&pac->decay_muzzy, cur_time, muzzy_decay_ms)) {
- return true;
- }
- if (san_bump_alloc_init(&pac->sba)) {
- return true;
- }
-
- pac->base = base;
- pac->emap = emap;
- pac->edata_cache = edata_cache;
- pac->stats = pac_stats;
- pac->stats_mtx = stats_mtx;
- atomic_store_zu(&pac->extent_sn_next, 0, ATOMIC_RELAXED);
-
- pac->pai.alloc = &pac_alloc_impl;
- pac->pai.alloc_batch = &pai_alloc_batch_default;
- pac->pai.expand = &pac_expand_impl;
- pac->pai.shrink = &pac_shrink_impl;
- pac->pai.dalloc = &pac_dalloc_impl;
- pac->pai.dalloc_batch = &pai_dalloc_batch_default;
- pac->pai.time_until_deferred_work = &pac_time_until_deferred_work;
-
- return false;
-}
-
-static inline bool
-pac_may_have_muzzy(pac_t *pac) {
- return pac_decay_ms_get(pac, extent_state_muzzy) != 0;
-}
-
-static edata_t *
-pac_alloc_real(tsdn_t *tsdn, pac_t *pac, ehooks_t *ehooks, size_t size,
- size_t alignment, bool zero, bool guarded) {
- assert(!guarded || alignment <= PAGE);
-
- edata_t *edata = ecache_alloc(tsdn, pac, ehooks, &pac->ecache_dirty,
- NULL, size, alignment, zero, guarded);
-
- if (edata == NULL && pac_may_have_muzzy(pac)) {
- edata = ecache_alloc(tsdn, pac, ehooks, &pac->ecache_muzzy,
- NULL, size, alignment, zero, guarded);
- }
- if (edata == NULL) {
- edata = ecache_alloc_grow(tsdn, pac, ehooks,
- &pac->ecache_retained, NULL, size, alignment, zero,
- guarded);
- if (config_stats && edata != NULL) {
- atomic_fetch_add_zu(&pac->stats->pac_mapped, size,
- ATOMIC_RELAXED);
- }
- }
-
- return edata;
-}
-
-static edata_t *
-pac_alloc_new_guarded(tsdn_t *tsdn, pac_t *pac, ehooks_t *ehooks, size_t size,
- size_t alignment, bool zero, bool frequent_reuse) {
- assert(alignment <= PAGE);
-
- edata_t *edata;
- if (san_bump_enabled() && frequent_reuse) {
- edata = san_bump_alloc(tsdn, &pac->sba, pac, ehooks, size,
- zero);
- } else {
- size_t size_with_guards = san_two_side_guarded_sz(size);
- /* Alloc a non-guarded extent first.*/
- edata = pac_alloc_real(tsdn, pac, ehooks, size_with_guards,
- /* alignment */ PAGE, zero, /* guarded */ false);
- if (edata != NULL) {
- /* Add guards around it. */
- assert(edata_size_get(edata) == size_with_guards);
- san_guard_pages_two_sided(tsdn, ehooks, edata,
- pac->emap, true);
- }
- }
- assert(edata == NULL || (edata_guarded_get(edata) &&
- edata_size_get(edata) == size));
-
- return edata;
-}
-
-static edata_t *
-pac_alloc_impl(tsdn_t *tsdn, pai_t *self, size_t size, size_t alignment,
- bool zero, bool guarded, bool frequent_reuse,
- bool *deferred_work_generated) {
- pac_t *pac = (pac_t *)self;
- ehooks_t *ehooks = pac_ehooks_get(pac);
-
- edata_t *edata = NULL;
- /*
- * The condition is an optimization - not frequently reused guarded
- * allocations are never put in the ecache. pac_alloc_real also
- * doesn't grow retained for guarded allocations. So pac_alloc_real
- * for such allocations would always return NULL.
- * */
- if (!guarded || frequent_reuse) {
- edata = pac_alloc_real(tsdn, pac, ehooks, size, alignment,
- zero, guarded);
- }
- if (edata == NULL && guarded) {
- /* No cached guarded extents; creating a new one. */
- edata = pac_alloc_new_guarded(tsdn, pac, ehooks, size,
- alignment, zero, frequent_reuse);
- }
-
- return edata;
-}
-
-static bool
-pac_expand_impl(tsdn_t *tsdn, pai_t *self, edata_t *edata, size_t old_size,
- size_t new_size, bool zero, bool *deferred_work_generated) {
- pac_t *pac = (pac_t *)self;
- ehooks_t *ehooks = pac_ehooks_get(pac);
-
- size_t mapped_add = 0;
- size_t expand_amount = new_size - old_size;
-
- if (ehooks_merge_will_fail(ehooks)) {
- return true;
- }
- edata_t *trail = ecache_alloc(tsdn, pac, ehooks, &pac->ecache_dirty,
- edata, expand_amount, PAGE, zero, /* guarded*/ false);
- if (trail == NULL) {
- trail = ecache_alloc(tsdn, pac, ehooks, &pac->ecache_muzzy,
- edata, expand_amount, PAGE, zero, /* guarded*/ false);
- }
- if (trail == NULL) {
- trail = ecache_alloc_grow(tsdn, pac, ehooks,
- &pac->ecache_retained, edata, expand_amount, PAGE, zero,
- /* guarded */ false);
- mapped_add = expand_amount;
- }
- if (trail == NULL) {
- return true;
- }
- if (extent_merge_wrapper(tsdn, pac, ehooks, edata, trail)) {
- extent_dalloc_wrapper(tsdn, pac, ehooks, trail);
- return true;
- }
- if (config_stats && mapped_add > 0) {
- atomic_fetch_add_zu(&pac->stats->pac_mapped, mapped_add,
- ATOMIC_RELAXED);
- }
- return false;
-}
-
-static bool
-pac_shrink_impl(tsdn_t *tsdn, pai_t *self, edata_t *edata, size_t old_size,
- size_t new_size, bool *deferred_work_generated) {
- pac_t *pac = (pac_t *)self;
- ehooks_t *ehooks = pac_ehooks_get(pac);
-
- size_t shrink_amount = old_size - new_size;
-
- if (ehooks_split_will_fail(ehooks)) {
- return true;
- }
-
- edata_t *trail = extent_split_wrapper(tsdn, pac, ehooks, edata,
- new_size, shrink_amount, /* holding_core_locks */ false);
- if (trail == NULL) {
- return true;
- }
- ecache_dalloc(tsdn, pac, ehooks, &pac->ecache_dirty, trail);
- *deferred_work_generated = true;
- return false;
-}
-
-static void
-pac_dalloc_impl(tsdn_t *tsdn, pai_t *self, edata_t *edata,
- bool *deferred_work_generated) {
- pac_t *pac = (pac_t *)self;
- ehooks_t *ehooks = pac_ehooks_get(pac);
-
- if (edata_guarded_get(edata)) {
- /*
- * Because cached guarded extents do exact fit only, large
- * guarded extents are restored on dalloc eagerly (otherwise
- * they will not be reused efficiently). Slab sizes have a
- * limited number of size classes, and tend to cycle faster.
- *
- * In the case where coalesce is restrained (VirtualFree on
- * Windows), guarded extents are also not cached -- otherwise
- * during arena destroy / reset, the retained extents would not
- * be whole regions (i.e. they are split between regular and
- * guarded).
- */
- if (!edata_slab_get(edata) || !maps_coalesce) {
- assert(edata_size_get(edata) >= SC_LARGE_MINCLASS ||
- !maps_coalesce);
- san_unguard_pages_two_sided(tsdn, ehooks, edata,
- pac->emap);
- }
- }
-
- ecache_dalloc(tsdn, pac, ehooks, &pac->ecache_dirty, edata);
- /* Purging of deallocated pages is deferred */
- *deferred_work_generated = true;
-}
-
-static inline uint64_t
-pac_ns_until_purge(tsdn_t *tsdn, decay_t *decay, size_t npages) {
- if (malloc_mutex_trylock(tsdn, &decay->mtx)) {
- /* Use minimal interval if decay is contended. */
- return BACKGROUND_THREAD_DEFERRED_MIN;
- }
- uint64_t result = decay_ns_until_purge(decay, npages,
- ARENA_DEFERRED_PURGE_NPAGES_THRESHOLD);
-
- malloc_mutex_unlock(tsdn, &decay->mtx);
- return result;
-}
-
-static uint64_t
-pac_time_until_deferred_work(tsdn_t *tsdn, pai_t *self) {
- uint64_t time;
- pac_t *pac = (pac_t *)self;
-
- time = pac_ns_until_purge(tsdn,
- &pac->decay_dirty,
- ecache_npages_get(&pac->ecache_dirty));
- if (time == BACKGROUND_THREAD_DEFERRED_MIN) {
- return time;
- }
-
- uint64_t muzzy = pac_ns_until_purge(tsdn,
- &pac->decay_muzzy,
- ecache_npages_get(&pac->ecache_muzzy));
- if (muzzy < time) {
- time = muzzy;
- }
- return time;
-}
-
-bool
-pac_retain_grow_limit_get_set(tsdn_t *tsdn, pac_t *pac, size_t *old_limit,
- size_t *new_limit) {
- pszind_t new_ind JEMALLOC_CC_SILENCE_INIT(0);
- if (new_limit != NULL) {
- size_t limit = *new_limit;
- /* Grow no more than the new limit. */
- if ((new_ind = sz_psz2ind(limit + 1) - 1) >= SC_NPSIZES) {
- return true;
- }
- }
-
- malloc_mutex_lock(tsdn, &pac->grow_mtx);
- if (old_limit != NULL) {
- *old_limit = sz_pind2sz(pac->exp_grow.limit);
- }
- if (new_limit != NULL) {
- pac->exp_grow.limit = new_ind;
- }
- malloc_mutex_unlock(tsdn, &pac->grow_mtx);
-
- return false;
-}
-
-static size_t
-pac_stash_decayed(tsdn_t *tsdn, pac_t *pac, ecache_t *ecache,
- size_t npages_limit, size_t npages_decay_max,
- edata_list_inactive_t *result) {
- witness_assert_depth_to_rank(tsdn_witness_tsdp_get(tsdn),
- WITNESS_RANK_CORE, 0);
- ehooks_t *ehooks = pac_ehooks_get(pac);
-
- /* Stash extents according to npages_limit. */
- size_t nstashed = 0;
- while (nstashed < npages_decay_max) {
- edata_t *edata = ecache_evict(tsdn, pac, ehooks, ecache,
- npages_limit);
- if (edata == NULL) {
- break;
- }
- edata_list_inactive_append(result, edata);
- nstashed += edata_size_get(edata) >> LG_PAGE;
- }
- return nstashed;
-}
-
-static size_t
-pac_decay_stashed(tsdn_t *tsdn, pac_t *pac, decay_t *decay,
- pac_decay_stats_t *decay_stats, ecache_t *ecache, bool fully_decay,
- edata_list_inactive_t *decay_extents) {
- bool err;
-
- size_t nmadvise = 0;
- size_t nunmapped = 0;
- size_t npurged = 0;
-
- ehooks_t *ehooks = pac_ehooks_get(pac);
-
- bool try_muzzy = !fully_decay
- && pac_decay_ms_get(pac, extent_state_muzzy) != 0;
-
- for (edata_t *edata = edata_list_inactive_first(decay_extents); edata !=
- NULL; edata = edata_list_inactive_first(decay_extents)) {
- edata_list_inactive_remove(decay_extents, edata);
-
- size_t size = edata_size_get(edata);
- size_t npages = size >> LG_PAGE;
-
- nmadvise++;
- npurged += npages;
-
- switch (ecache->state) {
- case extent_state_active:
- not_reached();
- case extent_state_dirty:
- if (try_muzzy) {
- err = extent_purge_lazy_wrapper(tsdn, ehooks,
- edata, /* offset */ 0, size);
- if (!err) {
- ecache_dalloc(tsdn, pac, ehooks,
- &pac->ecache_muzzy, edata);
- break;
- }
- }
- JEMALLOC_FALLTHROUGH;
- case extent_state_muzzy:
- extent_dalloc_wrapper(tsdn, pac, ehooks, edata);
- nunmapped += npages;
- break;
- case extent_state_retained:
- default:
- not_reached();
- }
- }
-
- if (config_stats) {
- LOCKEDINT_MTX_LOCK(tsdn, *pac->stats_mtx);
- locked_inc_u64(tsdn, LOCKEDINT_MTX(*pac->stats_mtx),
- &decay_stats->npurge, 1);
- locked_inc_u64(tsdn, LOCKEDINT_MTX(*pac->stats_mtx),
- &decay_stats->nmadvise, nmadvise);
- locked_inc_u64(tsdn, LOCKEDINT_MTX(*pac->stats_mtx),
- &decay_stats->purged, npurged);
- LOCKEDINT_MTX_UNLOCK(tsdn, *pac->stats_mtx);
- atomic_fetch_sub_zu(&pac->stats->pac_mapped,
- nunmapped << LG_PAGE, ATOMIC_RELAXED);
- }
-
- return npurged;
-}
-
-/*
- * npages_limit: Decay at most npages_decay_max pages without violating the
- * invariant: (ecache_npages_get(ecache) >= npages_limit). We need an upper
- * bound on number of pages in order to prevent unbounded growth (namely in
- * stashed), otherwise unbounded new pages could be added to extents during the
- * current decay run, so that the purging thread never finishes.
- */
-static void
-pac_decay_to_limit(tsdn_t *tsdn, pac_t *pac, decay_t *decay,
- pac_decay_stats_t *decay_stats, ecache_t *ecache, bool fully_decay,
- size_t npages_limit, size_t npages_decay_max) {
- witness_assert_depth_to_rank(tsdn_witness_tsdp_get(tsdn),
- WITNESS_RANK_CORE, 1);
-
- if (decay->purging || npages_decay_max == 0) {
- return;
- }
- decay->purging = true;
- malloc_mutex_unlock(tsdn, &decay->mtx);
-
- edata_list_inactive_t decay_extents;
- edata_list_inactive_init(&decay_extents);
- size_t npurge = pac_stash_decayed(tsdn, pac, ecache, npages_limit,
- npages_decay_max, &decay_extents);
- if (npurge != 0) {
- size_t npurged = pac_decay_stashed(tsdn, pac, decay,
- decay_stats, ecache, fully_decay, &decay_extents);
- assert(npurged == npurge);
- }
-
- malloc_mutex_lock(tsdn, &decay->mtx);
- decay->purging = false;
-}
-
-void
-pac_decay_all(tsdn_t *tsdn, pac_t *pac, decay_t *decay,
- pac_decay_stats_t *decay_stats, ecache_t *ecache, bool fully_decay) {
- malloc_mutex_assert_owner(tsdn, &decay->mtx);
- pac_decay_to_limit(tsdn, pac, decay, decay_stats, ecache, fully_decay,
- /* npages_limit */ 0, ecache_npages_get(ecache));
-}
-
-static void
-pac_decay_try_purge(tsdn_t *tsdn, pac_t *pac, decay_t *decay,
- pac_decay_stats_t *decay_stats, ecache_t *ecache,
- size_t current_npages, size_t npages_limit) {
- if (current_npages > npages_limit) {
- pac_decay_to_limit(tsdn, pac, decay, decay_stats, ecache,
- /* fully_decay */ false, npages_limit,
- current_npages - npages_limit);
- }
-}
-
-bool
-pac_maybe_decay_purge(tsdn_t *tsdn, pac_t *pac, decay_t *decay,
- pac_decay_stats_t *decay_stats, ecache_t *ecache,
- pac_purge_eagerness_t eagerness) {
- malloc_mutex_assert_owner(tsdn, &decay->mtx);
-
- /* Purge all or nothing if the option is disabled. */
- ssize_t decay_ms = decay_ms_read(decay);
- if (decay_ms <= 0) {
- if (decay_ms == 0) {
- pac_decay_to_limit(tsdn, pac, decay, decay_stats,
- ecache, /* fully_decay */ false,
- /* npages_limit */ 0, ecache_npages_get(ecache));
- }
- return false;
- }
-
- /*
- * If the deadline has been reached, advance to the current epoch and
- * purge to the new limit if necessary. Note that dirty pages created
- * during the current epoch are not subject to purge until a future
- * epoch, so as a result purging only happens during epoch advances, or
- * being triggered by background threads (scheduled event).
- */
- nstime_t time;
- nstime_init_update(&time);
- size_t npages_current = ecache_npages_get(ecache);
- bool epoch_advanced = decay_maybe_advance_epoch(decay, &time,
- npages_current);
- if (eagerness == PAC_PURGE_ALWAYS
- || (epoch_advanced && eagerness == PAC_PURGE_ON_EPOCH_ADVANCE)) {
- size_t npages_limit = decay_npages_limit_get(decay);
- pac_decay_try_purge(tsdn, pac, decay, decay_stats, ecache,
- npages_current, npages_limit);
- }
-
- return epoch_advanced;
-}
-
-bool
-pac_decay_ms_set(tsdn_t *tsdn, pac_t *pac, extent_state_t state,
- ssize_t decay_ms, pac_purge_eagerness_t eagerness) {
- decay_t *decay;
- pac_decay_stats_t *decay_stats;
- ecache_t *ecache;
- pac_decay_data_get(pac, state, &decay, &decay_stats, &ecache);
-
- if (!decay_ms_valid(decay_ms)) {
- return true;
- }
-
- malloc_mutex_lock(tsdn, &decay->mtx);
- /*
- * Restart decay backlog from scratch, which may cause many dirty pages
- * to be immediately purged. It would conceptually be possible to map
- * the old backlog onto the new backlog, but there is no justification
- * for such complexity since decay_ms changes are intended to be
- * infrequent, either between the {-1, 0, >0} states, or a one-time
- * arbitrary change during initial arena configuration.
- */
- nstime_t cur_time;
- nstime_init_update(&cur_time);
- decay_reinit(decay, &cur_time, decay_ms);
- pac_maybe_decay_purge(tsdn, pac, decay, decay_stats, ecache, eagerness);
- malloc_mutex_unlock(tsdn, &decay->mtx);
-
- return false;
-}
-
-ssize_t
-pac_decay_ms_get(pac_t *pac, extent_state_t state) {
- decay_t *decay;
- pac_decay_stats_t *decay_stats;
- ecache_t *ecache;
- pac_decay_data_get(pac, state, &decay, &decay_stats, &ecache);
- return decay_ms_read(decay);
-}
-
-void
-pac_reset(tsdn_t *tsdn, pac_t *pac) {
- /*
- * No-op for now; purging is still done at the arena-level. It should
- * get moved in here, though.
- */
- (void)tsdn;
- (void)pac;
-}
-
-void
-pac_destroy(tsdn_t *tsdn, pac_t *pac) {
- assert(ecache_npages_get(&pac->ecache_dirty) == 0);
- assert(ecache_npages_get(&pac->ecache_muzzy) == 0);
- /*
- * Iterate over the retained extents and destroy them. This gives the
- * extent allocator underlying the extent hooks an opportunity to unmap
- * all retained memory without having to keep its own metadata
- * structures. In practice, virtual memory for dss-allocated extents is
- * leaked here, so best practice is to avoid dss for arenas to be
- * destroyed, or provide custom extent hooks that track retained
- * dss-based extents for later reuse.
- */
- ehooks_t *ehooks = pac_ehooks_get(pac);
- edata_t *edata;
- while ((edata = ecache_evict(tsdn, pac, ehooks,
- &pac->ecache_retained, 0)) != NULL) {
- extent_destroy_wrapper(tsdn, pac, ehooks, edata);
- }
-}
diff --git a/fluent-bit/lib/jemalloc-5.3.0/src/pages.c b/fluent-bit/lib/jemalloc-5.3.0/src/pages.c
deleted file mode 100644
index 8c83a7de..00000000
--- a/fluent-bit/lib/jemalloc-5.3.0/src/pages.c
+++ /dev/null
@@ -1,824 +0,0 @@
-#include "jemalloc/internal/jemalloc_preamble.h"
-
-#include "jemalloc/internal/pages.h"
-
-#include "jemalloc/internal/jemalloc_internal_includes.h"
-
-#include "jemalloc/internal/assert.h"
-#include "jemalloc/internal/malloc_io.h"
-
-#ifdef JEMALLOC_SYSCTL_VM_OVERCOMMIT
-#include <sys/sysctl.h>
-#ifdef __FreeBSD__
-#include <vm/vm_param.h>
-#endif
-#endif
-#ifdef __NetBSD__
-#include <sys/bitops.h> /* ilog2 */
-#endif
-#ifdef JEMALLOC_HAVE_VM_MAKE_TAG
-#define PAGES_FD_TAG VM_MAKE_TAG(101U)
-#else
-#define PAGES_FD_TAG -1
-#endif
-
-/******************************************************************************/
-/* Data. */
-
-/* Actual operating system page size, detected during bootstrap, <= PAGE. */
-static size_t os_page;
-
-#ifndef _WIN32
-# define PAGES_PROT_COMMIT (PROT_READ | PROT_WRITE)
-# define PAGES_PROT_DECOMMIT (PROT_NONE)
-static int mmap_flags;
-#endif
-static bool os_overcommits;
-
-const char *thp_mode_names[] = {
- "default",
- "always",
- "never",
- "not supported"
-};
-thp_mode_t opt_thp = THP_MODE_DEFAULT;
-thp_mode_t init_system_thp_mode;
-
-/* Runtime support for lazy purge. Irrelevant when !pages_can_purge_lazy. */
-static bool pages_can_purge_lazy_runtime = true;
-
-#ifdef JEMALLOC_PURGE_MADVISE_DONTNEED_ZEROS
-static int madvise_dont_need_zeros_is_faulty = -1;
-/**
- * Check that MADV_DONTNEED will actually zero pages on subsequent access.
- *
- * Since qemu does not support this, yet [1], and you can get very tricky
- * assert if you will run program with jemalloc in use under qemu:
- *
- * <jemalloc>: ../contrib/jemalloc/src/extent.c:1195: Failed assertion: "p[i] == 0"
- *
- * [1]: https://patchwork.kernel.org/patch/10576637/
- */
-static int madvise_MADV_DONTNEED_zeroes_pages()
-{
- int works = -1;
- size_t size = PAGE;
-
- void * addr = mmap(NULL, size, PROT_READ|PROT_WRITE,
- MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
-
- if (addr == MAP_FAILED) {
- malloc_write("<jemalloc>: Cannot allocate memory for "
- "MADV_DONTNEED check\n");
- if (opt_abort) {
- abort();
- }
- }
-
- memset(addr, 'A', size);
- if (madvise(addr, size, MADV_DONTNEED) == 0) {
- works = memchr(addr, 'A', size) == NULL;
- } else {
- /*
- * If madvise() does not support MADV_DONTNEED, then we can
- * call it anyway, and use it's return code.
- */
- works = 1;
- }
-
- if (munmap(addr, size) != 0) {
- malloc_write("<jemalloc>: Cannot deallocate memory for "
- "MADV_DONTNEED check\n");
- if (opt_abort) {
- abort();
- }
- }
-
- return works;
-}
-#endif
-
-/******************************************************************************/
-/*
- * Function prototypes for static functions that are referenced prior to
- * definition.
- */
-
-static void os_pages_unmap(void *addr, size_t size);
-
-/******************************************************************************/
-
-static void *
-os_pages_map(void *addr, size_t size, size_t alignment, bool *commit) {
- assert(ALIGNMENT_ADDR2BASE(addr, os_page) == addr);
- assert(ALIGNMENT_CEILING(size, os_page) == size);
- assert(size != 0);
-
- if (os_overcommits) {
- *commit = true;
- }
-
- void *ret;
-#ifdef _WIN32
- /*
- * If VirtualAlloc can't allocate at the given address when one is
- * given, it fails and returns NULL.
- */
- ret = VirtualAlloc(addr, size, MEM_RESERVE | (*commit ? MEM_COMMIT : 0),
- PAGE_READWRITE);
-#else
- /*
- * We don't use MAP_FIXED here, because it can cause the *replacement*
- * of existing mappings, and we only want to create new mappings.
- */
- {
-#ifdef __NetBSD__
- /*
- * On NetBSD PAGE for a platform is defined to the
- * maximum page size of all machine architectures
- * for that platform, so that we can use the same
- * binaries across all machine architectures.
- */
- if (alignment > os_page || PAGE > os_page) {
- unsigned int a = ilog2(MAX(alignment, PAGE));
- mmap_flags |= MAP_ALIGNED(a);
- }
-#endif
- int prot = *commit ? PAGES_PROT_COMMIT : PAGES_PROT_DECOMMIT;
-
- ret = mmap(addr, size, prot, mmap_flags, PAGES_FD_TAG, 0);
- }
- assert(ret != NULL);
-
- if (ret == MAP_FAILED) {
- ret = NULL;
- } else if (addr != NULL && ret != addr) {
- /*
- * We succeeded in mapping memory, but not in the right place.
- */
- os_pages_unmap(ret, size);
- ret = NULL;
- }
-#endif
- assert(ret == NULL || (addr == NULL && ret != addr) || (addr != NULL &&
- ret == addr));
- return ret;
-}
-
-static void *
-os_pages_trim(void *addr, size_t alloc_size, size_t leadsize, size_t size,
- bool *commit) {
- void *ret = (void *)((uintptr_t)addr + leadsize);
-
- assert(alloc_size >= leadsize + size);
-#ifdef _WIN32
- os_pages_unmap(addr, alloc_size);
- void *new_addr = os_pages_map(ret, size, PAGE, commit);
- if (new_addr == ret) {
- return ret;
- }
- if (new_addr != NULL) {
- os_pages_unmap(new_addr, size);
- }
- return NULL;
-#else
- size_t trailsize = alloc_size - leadsize - size;
-
- if (leadsize != 0) {
- os_pages_unmap(addr, leadsize);
- }
- if (trailsize != 0) {
- os_pages_unmap((void *)((uintptr_t)ret + size), trailsize);
- }
- return ret;
-#endif
-}
-
-static void
-os_pages_unmap(void *addr, size_t size) {
- assert(ALIGNMENT_ADDR2BASE(addr, os_page) == addr);
- assert(ALIGNMENT_CEILING(size, os_page) == size);
-
-#ifdef _WIN32
- if (VirtualFree(addr, 0, MEM_RELEASE) == 0)
-#else
- if (munmap(addr, size) == -1)
-#endif
- {
- char buf[BUFERROR_BUF];
-
- buferror(get_errno(), buf, sizeof(buf));
- malloc_printf("<jemalloc>: Error in "
-#ifdef _WIN32
- "VirtualFree"
-#else
- "munmap"
-#endif
- "(): %s\n", buf);
- if (opt_abort) {
- abort();
- }
- }
-}
-
-static void *
-pages_map_slow(size_t size, size_t alignment, bool *commit) {
- size_t alloc_size = size + alignment - os_page;
- /* Beware size_t wrap-around. */
- if (alloc_size < size) {
- return NULL;
- }
-
- void *ret;
- do {
- void *pages = os_pages_map(NULL, alloc_size, alignment, commit);
- if (pages == NULL) {
- return NULL;
- }
- size_t leadsize = ALIGNMENT_CEILING((uintptr_t)pages, alignment)
- - (uintptr_t)pages;
- ret = os_pages_trim(pages, alloc_size, leadsize, size, commit);
- } while (ret == NULL);
-
- assert(ret != NULL);
- assert(PAGE_ADDR2BASE(ret) == ret);
- return ret;
-}
-
-void *
-pages_map(void *addr, size_t size, size_t alignment, bool *commit) {
- assert(alignment >= PAGE);
- assert(ALIGNMENT_ADDR2BASE(addr, alignment) == addr);
-
-#if defined(__FreeBSD__) && defined(MAP_EXCL)
- /*
- * FreeBSD has mechanisms both to mmap at specific address without
- * touching existing mappings, and to mmap with specific alignment.
- */
- {
- if (os_overcommits) {
- *commit = true;
- }
-
- int prot = *commit ? PAGES_PROT_COMMIT : PAGES_PROT_DECOMMIT;
- int flags = mmap_flags;
-
- if (addr != NULL) {
- flags |= MAP_FIXED | MAP_EXCL;
- } else {
- unsigned alignment_bits = ffs_zu(alignment);
- assert(alignment_bits > 0);
- flags |= MAP_ALIGNED(alignment_bits);
- }
-
- void *ret = mmap(addr, size, prot, flags, -1, 0);
- if (ret == MAP_FAILED) {
- ret = NULL;
- }
-
- return ret;
- }
-#endif
- /*
- * Ideally, there would be a way to specify alignment to mmap() (like
- * NetBSD has), but in the absence of such a feature, we have to work
- * hard to efficiently create aligned mappings. The reliable, but
- * slow method is to create a mapping that is over-sized, then trim the
- * excess. However, that always results in one or two calls to
- * os_pages_unmap(), and it can leave holes in the process's virtual
- * memory map if memory grows downward.
- *
- * Optimistically try mapping precisely the right amount before falling
- * back to the slow method, with the expectation that the optimistic
- * approach works most of the time.
- */
-
- void *ret = os_pages_map(addr, size, os_page, commit);
- if (ret == NULL || ret == addr) {
- return ret;
- }
- assert(addr == NULL);
- if (ALIGNMENT_ADDR2OFFSET(ret, alignment) != 0) {
- os_pages_unmap(ret, size);
- return pages_map_slow(size, alignment, commit);
- }
-
- assert(PAGE_ADDR2BASE(ret) == ret);
- return ret;
-}
-
-void
-pages_unmap(void *addr, size_t size) {
- assert(PAGE_ADDR2BASE(addr) == addr);
- assert(PAGE_CEILING(size) == size);
-
- os_pages_unmap(addr, size);
-}
-
-static bool
-os_pages_commit(void *addr, size_t size, bool commit) {
- assert(PAGE_ADDR2BASE(addr) == addr);
- assert(PAGE_CEILING(size) == size);
-
-#ifdef _WIN32
- return (commit ? (addr != VirtualAlloc(addr, size, MEM_COMMIT,
- PAGE_READWRITE)) : (!VirtualFree(addr, size, MEM_DECOMMIT)));
-#else
- {
- int prot = commit ? PAGES_PROT_COMMIT : PAGES_PROT_DECOMMIT;
- void *result = mmap(addr, size, prot, mmap_flags | MAP_FIXED,
- PAGES_FD_TAG, 0);
- if (result == MAP_FAILED) {
- return true;
- }
- if (result != addr) {
- /*
- * We succeeded in mapping memory, but not in the right
- * place.
- */
- os_pages_unmap(result, size);
- return true;
- }
- return false;
- }
-#endif
-}
-
-static bool
-pages_commit_impl(void *addr, size_t size, bool commit) {
- if (os_overcommits) {
- return true;
- }
-
- return os_pages_commit(addr, size, commit);
-}
-
-bool
-pages_commit(void *addr, size_t size) {
- return pages_commit_impl(addr, size, true);
-}
-
-bool
-pages_decommit(void *addr, size_t size) {
- return pages_commit_impl(addr, size, false);
-}
-
-void
-pages_mark_guards(void *head, void *tail) {
- assert(head != NULL || tail != NULL);
- assert(head == NULL || tail == NULL ||
- (uintptr_t)head < (uintptr_t)tail);
-#ifdef JEMALLOC_HAVE_MPROTECT
- if (head != NULL) {
- mprotect(head, PAGE, PROT_NONE);
- }
- if (tail != NULL) {
- mprotect(tail, PAGE, PROT_NONE);
- }
-#else
- /* Decommit sets to PROT_NONE / MEM_DECOMMIT. */
- if (head != NULL) {
- os_pages_commit(head, PAGE, false);
- }
- if (tail != NULL) {
- os_pages_commit(tail, PAGE, false);
- }
-#endif
-}
-
-void
-pages_unmark_guards(void *head, void *tail) {
- assert(head != NULL || tail != NULL);
- assert(head == NULL || tail == NULL ||
- (uintptr_t)head < (uintptr_t)tail);
-#ifdef JEMALLOC_HAVE_MPROTECT
- bool head_and_tail = (head != NULL) && (tail != NULL);
- size_t range = head_and_tail ?
- (uintptr_t)tail - (uintptr_t)head + PAGE :
- SIZE_T_MAX;
- /*
- * The amount of work that the kernel does in mprotect depends on the
- * range argument. SC_LARGE_MINCLASS is an arbitrary threshold chosen
- * to prevent kernel from doing too much work that would outweigh the
- * savings of performing one less system call.
- */
- bool ranged_mprotect = head_and_tail && range <= SC_LARGE_MINCLASS;
- if (ranged_mprotect) {
- mprotect(head, range, PROT_READ | PROT_WRITE);
- } else {
- if (head != NULL) {
- mprotect(head, PAGE, PROT_READ | PROT_WRITE);
- }
- if (tail != NULL) {
- mprotect(tail, PAGE, PROT_READ | PROT_WRITE);
- }
- }
-#else
- if (head != NULL) {
- os_pages_commit(head, PAGE, true);
- }
- if (tail != NULL) {
- os_pages_commit(tail, PAGE, true);
- }
-#endif
-}
-
-bool
-pages_purge_lazy(void *addr, size_t size) {
- assert(ALIGNMENT_ADDR2BASE(addr, os_page) == addr);
- assert(PAGE_CEILING(size) == size);
-
- if (!pages_can_purge_lazy) {
- return true;
- }
- if (!pages_can_purge_lazy_runtime) {
- /*
- * Built with lazy purge enabled, but detected it was not
- * supported on the current system.
- */
- return true;
- }
-
-#ifdef _WIN32
- VirtualAlloc(addr, size, MEM_RESET, PAGE_READWRITE);
- return false;
-#elif defined(JEMALLOC_PURGE_MADVISE_FREE)
- return (madvise(addr, size,
-# ifdef MADV_FREE
- MADV_FREE
-# else
- JEMALLOC_MADV_FREE
-# endif
- ) != 0);
-#elif defined(JEMALLOC_PURGE_MADVISE_DONTNEED) && \
- !defined(JEMALLOC_PURGE_MADVISE_DONTNEED_ZEROS)
- return (madvise(addr, size, MADV_DONTNEED) != 0);
-#elif defined(JEMALLOC_PURGE_POSIX_MADVISE_DONTNEED) && \
- !defined(JEMALLOC_PURGE_POSIX_MADVISE_DONTNEED_ZEROS)
- return (posix_madvise(addr, size, POSIX_MADV_DONTNEED) != 0);
-#else
- not_reached();
-#endif
-}
-
-bool
-pages_purge_forced(void *addr, size_t size) {
- assert(PAGE_ADDR2BASE(addr) == addr);
- assert(PAGE_CEILING(size) == size);
-
- if (!pages_can_purge_forced) {
- return true;
- }
-
-#if defined(JEMALLOC_PURGE_MADVISE_DONTNEED) && \
- defined(JEMALLOC_PURGE_MADVISE_DONTNEED_ZEROS)
- return (unlikely(madvise_dont_need_zeros_is_faulty) ||
- madvise(addr, size, MADV_DONTNEED) != 0);
-#elif defined(JEMALLOC_PURGE_POSIX_MADVISE_DONTNEED) && \
- defined(JEMALLOC_PURGE_POSIX_MADVISE_DONTNEED_ZEROS)
- return (unlikely(madvise_dont_need_zeros_is_faulty) ||
- posix_madvise(addr, size, POSIX_MADV_DONTNEED) != 0);
-#elif defined(JEMALLOC_MAPS_COALESCE)
- /* Try to overlay a new demand-zeroed mapping. */
- return pages_commit(addr, size);
-#else
- not_reached();
-#endif
-}
-
-static bool
-pages_huge_impl(void *addr, size_t size, bool aligned) {
- if (aligned) {
- assert(HUGEPAGE_ADDR2BASE(addr) == addr);
- assert(HUGEPAGE_CEILING(size) == size);
- }
-#if defined(JEMALLOC_HAVE_MADVISE_HUGE)
- return (madvise(addr, size, MADV_HUGEPAGE) != 0);
-#elif defined(JEMALLOC_HAVE_MEMCNTL)
- struct memcntl_mha m = {0};
- m.mha_cmd = MHA_MAPSIZE_VA;
- m.mha_pagesize = HUGEPAGE;
- return (memcntl(addr, size, MC_HAT_ADVISE, (caddr_t)&m, 0, 0) == 0);
-#else
- return true;
-#endif
-}
-
-bool
-pages_huge(void *addr, size_t size) {
- return pages_huge_impl(addr, size, true);
-}
-
-static bool
-pages_huge_unaligned(void *addr, size_t size) {
- return pages_huge_impl(addr, size, false);
-}
-
-static bool
-pages_nohuge_impl(void *addr, size_t size, bool aligned) {
- if (aligned) {
- assert(HUGEPAGE_ADDR2BASE(addr) == addr);
- assert(HUGEPAGE_CEILING(size) == size);
- }
-
-#ifdef JEMALLOC_HAVE_MADVISE_HUGE
- return (madvise(addr, size, MADV_NOHUGEPAGE) != 0);
-#else
- return false;
-#endif
-}
-
-bool
-pages_nohuge(void *addr, size_t size) {
- return pages_nohuge_impl(addr, size, true);
-}
-
-static bool
-pages_nohuge_unaligned(void *addr, size_t size) {
- return pages_nohuge_impl(addr, size, false);
-}
-
-bool
-pages_dontdump(void *addr, size_t size) {
- assert(PAGE_ADDR2BASE(addr) == addr);
- assert(PAGE_CEILING(size) == size);
-#if defined(JEMALLOC_MADVISE_DONTDUMP)
- return madvise(addr, size, MADV_DONTDUMP) != 0;
-#elif defined(JEMALLOC_MADVISE_NOCORE)
- return madvise(addr, size, MADV_NOCORE) != 0;
-#else
- return false;
-#endif
-}
-
-bool
-pages_dodump(void *addr, size_t size) {
- assert(PAGE_ADDR2BASE(addr) == addr);
- assert(PAGE_CEILING(size) == size);
-#if defined(JEMALLOC_MADVISE_DONTDUMP)
- return madvise(addr, size, MADV_DODUMP) != 0;
-#elif defined(JEMALLOC_MADVISE_NOCORE)
- return madvise(addr, size, MADV_CORE) != 0;
-#else
- return false;
-#endif
-}
-
-
-static size_t
-os_page_detect(void) {
-#ifdef _WIN32
- SYSTEM_INFO si;
- GetSystemInfo(&si);
- return si.dwPageSize;
-#elif defined(__FreeBSD__)
- /*
- * This returns the value obtained from
- * the auxv vector, avoiding a syscall.
- */
- return getpagesize();
-#else
- long result = sysconf(_SC_PAGESIZE);
- if (result == -1) {
- return LG_PAGE;
- }
- return (size_t)result;
-#endif
-}
-
-#ifdef JEMALLOC_SYSCTL_VM_OVERCOMMIT
-static bool
-os_overcommits_sysctl(void) {
- int vm_overcommit;
- size_t sz;
-
- sz = sizeof(vm_overcommit);
-#if defined(__FreeBSD__) && defined(VM_OVERCOMMIT)
- int mib[2];
-
- mib[0] = CTL_VM;
- mib[1] = VM_OVERCOMMIT;
- if (sysctl(mib, 2, &vm_overcommit, &sz, NULL, 0) != 0) {
- return false; /* Error. */
- }
-#else
- if (sysctlbyname("vm.overcommit", &vm_overcommit, &sz, NULL, 0) != 0) {
- return false; /* Error. */
- }
-#endif
-
- return ((vm_overcommit & 0x3) == 0);
-}
-#endif
-
-#ifdef JEMALLOC_PROC_SYS_VM_OVERCOMMIT_MEMORY
-/*
- * Use syscall(2) rather than {open,read,close}(2) when possible to avoid
- * reentry during bootstrapping if another library has interposed system call
- * wrappers.
- */
-static bool
-os_overcommits_proc(void) {
- int fd;
- char buf[1];
-
-#if defined(JEMALLOC_USE_SYSCALL) && defined(SYS_open)
- #if defined(O_CLOEXEC)
- fd = (int)syscall(SYS_open, "/proc/sys/vm/overcommit_memory", O_RDONLY |
- O_CLOEXEC);
- #else
- fd = (int)syscall(SYS_open, "/proc/sys/vm/overcommit_memory", O_RDONLY);
- if (fd != -1) {
- fcntl(fd, F_SETFD, fcntl(fd, F_GETFD) | FD_CLOEXEC);
- }
- #endif
-#elif defined(JEMALLOC_USE_SYSCALL) && defined(SYS_openat)
- #if defined(O_CLOEXEC)
- fd = (int)syscall(SYS_openat,
- AT_FDCWD, "/proc/sys/vm/overcommit_memory", O_RDONLY | O_CLOEXEC);
- #else
- fd = (int)syscall(SYS_openat,
- AT_FDCWD, "/proc/sys/vm/overcommit_memory", O_RDONLY);
- if (fd != -1) {
- fcntl(fd, F_SETFD, fcntl(fd, F_GETFD) | FD_CLOEXEC);
- }
- #endif
-#else
- #if defined(O_CLOEXEC)
- fd = open("/proc/sys/vm/overcommit_memory", O_RDONLY | O_CLOEXEC);
- #else
- fd = open("/proc/sys/vm/overcommit_memory", O_RDONLY);
- if (fd != -1) {
- fcntl(fd, F_SETFD, fcntl(fd, F_GETFD) | FD_CLOEXEC);
- }
- #endif
-#endif
-
- if (fd == -1) {
- return false; /* Error. */
- }
-
- ssize_t nread = malloc_read_fd(fd, &buf, sizeof(buf));
-#if defined(JEMALLOC_USE_SYSCALL) && defined(SYS_close)
- syscall(SYS_close, fd);
-#else
- close(fd);
-#endif
-
- if (nread < 1) {
- return false; /* Error. */
- }
- /*
- * /proc/sys/vm/overcommit_memory meanings:
- * 0: Heuristic overcommit.
- * 1: Always overcommit.
- * 2: Never overcommit.
- */
- return (buf[0] == '0' || buf[0] == '1');
-}
-#endif
-
-void
-pages_set_thp_state (void *ptr, size_t size) {
- if (opt_thp == thp_mode_default || opt_thp == init_system_thp_mode) {
- return;
- }
- assert(opt_thp != thp_mode_not_supported &&
- init_system_thp_mode != thp_mode_not_supported);
-
- if (opt_thp == thp_mode_always
- && init_system_thp_mode != thp_mode_never) {
- assert(init_system_thp_mode == thp_mode_default);
- pages_huge_unaligned(ptr, size);
- } else if (opt_thp == thp_mode_never) {
- assert(init_system_thp_mode == thp_mode_default ||
- init_system_thp_mode == thp_mode_always);
- pages_nohuge_unaligned(ptr, size);
- }
-}
-
-static void
-init_thp_state(void) {
- if (!have_madvise_huge && !have_memcntl) {
- if (metadata_thp_enabled() && opt_abort) {
- malloc_write("<jemalloc>: no MADV_HUGEPAGE support\n");
- abort();
- }
- goto label_error;
- }
-#if defined(JEMALLOC_HAVE_MADVISE_HUGE)
- static const char sys_state_madvise[] = "always [madvise] never\n";
- static const char sys_state_always[] = "[always] madvise never\n";
- static const char sys_state_never[] = "always madvise [never]\n";
- char buf[sizeof(sys_state_madvise)];
-
-#if defined(JEMALLOC_USE_SYSCALL) && defined(SYS_open)
- int fd = (int)syscall(SYS_open,
- "/sys/kernel/mm/transparent_hugepage/enabled", O_RDONLY);
-#elif defined(JEMALLOC_USE_SYSCALL) && defined(SYS_openat)
- int fd = (int)syscall(SYS_openat,
- AT_FDCWD, "/sys/kernel/mm/transparent_hugepage/enabled", O_RDONLY);
-#else
- int fd = open("/sys/kernel/mm/transparent_hugepage/enabled", O_RDONLY);
-#endif
- if (fd == -1) {
- goto label_error;
- }
-
- ssize_t nread = malloc_read_fd(fd, &buf, sizeof(buf));
-#if defined(JEMALLOC_USE_SYSCALL) && defined(SYS_close)
- syscall(SYS_close, fd);
-#else
- close(fd);
-#endif
-
- if (nread < 0) {
- goto label_error;
- }
-
- if (strncmp(buf, sys_state_madvise, (size_t)nread) == 0) {
- init_system_thp_mode = thp_mode_default;
- } else if (strncmp(buf, sys_state_always, (size_t)nread) == 0) {
- init_system_thp_mode = thp_mode_always;
- } else if (strncmp(buf, sys_state_never, (size_t)nread) == 0) {
- init_system_thp_mode = thp_mode_never;
- } else {
- goto label_error;
- }
- return;
-#elif defined(JEMALLOC_HAVE_MEMCNTL)
- init_system_thp_mode = thp_mode_default;
- return;
-#endif
-label_error:
- opt_thp = init_system_thp_mode = thp_mode_not_supported;
-}
-
-bool
-pages_boot(void) {
- os_page = os_page_detect();
- if (os_page > PAGE) {
- malloc_write("<jemalloc>: Unsupported system page size\n");
- if (opt_abort) {
- abort();
- }
- return true;
- }
-
-#ifdef JEMALLOC_PURGE_MADVISE_DONTNEED_ZEROS
- if (!opt_trust_madvise) {
- madvise_dont_need_zeros_is_faulty = !madvise_MADV_DONTNEED_zeroes_pages();
- if (madvise_dont_need_zeros_is_faulty) {
- malloc_write("<jemalloc>: MADV_DONTNEED does not work (memset will be used instead)\n");
- malloc_write("<jemalloc>: (This is the expected behaviour if you are running under QEMU)\n");
- }
- } else {
- /* In case opt_trust_madvise is disable,
- * do not do runtime check */
- madvise_dont_need_zeros_is_faulty = 0;
- }
-#endif
-
-#ifndef _WIN32
- mmap_flags = MAP_PRIVATE | MAP_ANON;
-#endif
-
-#ifdef JEMALLOC_SYSCTL_VM_OVERCOMMIT
- os_overcommits = os_overcommits_sysctl();
-#elif defined(JEMALLOC_PROC_SYS_VM_OVERCOMMIT_MEMORY)
- os_overcommits = os_overcommits_proc();
-# ifdef MAP_NORESERVE
- if (os_overcommits) {
- mmap_flags |= MAP_NORESERVE;
- }
-# endif
-#elif defined(__NetBSD__)
- os_overcommits = true;
-#else
- os_overcommits = false;
-#endif
-
- init_thp_state();
-
-#ifdef __FreeBSD__
- /*
- * FreeBSD doesn't need the check; madvise(2) is known to work.
- */
-#else
- /* Detect lazy purge runtime support. */
- if (pages_can_purge_lazy) {
- bool committed = false;
- void *madv_free_page = os_pages_map(NULL, PAGE, PAGE, &committed);
- if (madv_free_page == NULL) {
- return true;
- }
- assert(pages_can_purge_lazy_runtime);
- if (pages_purge_lazy(madv_free_page, PAGE)) {
- pages_can_purge_lazy_runtime = false;
- }
- os_pages_unmap(madv_free_page, PAGE);
- }
-#endif
-
- return false;
-}
diff --git a/fluent-bit/lib/jemalloc-5.3.0/src/pai.c b/fluent-bit/lib/jemalloc-5.3.0/src/pai.c
deleted file mode 100644
index 45c87729..00000000
--- a/fluent-bit/lib/jemalloc-5.3.0/src/pai.c
+++ /dev/null
@@ -1,31 +0,0 @@
-#include "jemalloc/internal/jemalloc_preamble.h"
-#include "jemalloc/internal/jemalloc_internal_includes.h"
-
-size_t
-pai_alloc_batch_default(tsdn_t *tsdn, pai_t *self, size_t size, size_t nallocs,
- edata_list_active_t *results, bool *deferred_work_generated) {
- for (size_t i = 0; i < nallocs; i++) {
- bool deferred_by_alloc = false;
- edata_t *edata = pai_alloc(tsdn, self, size, PAGE,
- /* zero */ false, /* guarded */ false,
- /* frequent_reuse */ false, &deferred_by_alloc);
- *deferred_work_generated |= deferred_by_alloc;
- if (edata == NULL) {
- return i;
- }
- edata_list_active_append(results, edata);
- }
- return nallocs;
-}
-
-void
-pai_dalloc_batch_default(tsdn_t *tsdn, pai_t *self,
- edata_list_active_t *list, bool *deferred_work_generated) {
- edata_t *edata;
- while ((edata = edata_list_active_first(list)) != NULL) {
- bool deferred_by_dalloc = false;
- edata_list_active_remove(list, edata);
- pai_dalloc(tsdn, self, edata, &deferred_by_dalloc);
- *deferred_work_generated |= deferred_by_dalloc;
- }
-}
diff --git a/fluent-bit/lib/jemalloc-5.3.0/src/peak_event.c b/fluent-bit/lib/jemalloc-5.3.0/src/peak_event.c
deleted file mode 100644
index 4093fbcc..00000000
--- a/fluent-bit/lib/jemalloc-5.3.0/src/peak_event.c
+++ /dev/null
@@ -1,82 +0,0 @@
-#include "jemalloc/internal/jemalloc_preamble.h"
-#include "jemalloc/internal/jemalloc_internal_includes.h"
-
-#include "jemalloc/internal/peak_event.h"
-
-#include "jemalloc/internal/activity_callback.h"
-#include "jemalloc/internal/peak.h"
-
-/*
- * Update every 64K by default. We're not exposing this as a configuration
- * option for now; we don't want to bind ourselves too tightly to any particular
- * performance requirements for small values, or guarantee that we'll even be
- * able to provide fine-grained accuracy.
- */
-#define PEAK_EVENT_WAIT (64 * 1024)
-
-/* Update the peak with current tsd state. */
-void
-peak_event_update(tsd_t *tsd) {
- uint64_t alloc = tsd_thread_allocated_get(tsd);
- uint64_t dalloc = tsd_thread_deallocated_get(tsd);
- peak_t *peak = tsd_peakp_get(tsd);
- peak_update(peak, alloc, dalloc);
-}
-
-static void
-peak_event_activity_callback(tsd_t *tsd) {
- activity_callback_thunk_t *thunk = tsd_activity_callback_thunkp_get(
- tsd);
- uint64_t alloc = tsd_thread_allocated_get(tsd);
- uint64_t dalloc = tsd_thread_deallocated_get(tsd);
- if (thunk->callback != NULL) {
- thunk->callback(thunk->uctx, alloc, dalloc);
- }
-}
-
-/* Set current state to zero. */
-void
-peak_event_zero(tsd_t *tsd) {
- uint64_t alloc = tsd_thread_allocated_get(tsd);
- uint64_t dalloc = tsd_thread_deallocated_get(tsd);
- peak_t *peak = tsd_peakp_get(tsd);
- peak_set_zero(peak, alloc, dalloc);
-}
-
-uint64_t
-peak_event_max(tsd_t *tsd) {
- peak_t *peak = tsd_peakp_get(tsd);
- return peak_max(peak);
-}
-
-uint64_t
-peak_alloc_new_event_wait(tsd_t *tsd) {
- return PEAK_EVENT_WAIT;
-}
-
-uint64_t
-peak_alloc_postponed_event_wait(tsd_t *tsd) {
- return TE_MIN_START_WAIT;
-}
-
-void
-peak_alloc_event_handler(tsd_t *tsd, uint64_t elapsed) {
- peak_event_update(tsd);
- peak_event_activity_callback(tsd);
-}
-
-uint64_t
-peak_dalloc_new_event_wait(tsd_t *tsd) {
- return PEAK_EVENT_WAIT;
-}
-
-uint64_t
-peak_dalloc_postponed_event_wait(tsd_t *tsd) {
- return TE_MIN_START_WAIT;
-}
-
-void
-peak_dalloc_event_handler(tsd_t *tsd, uint64_t elapsed) {
- peak_event_update(tsd);
- peak_event_activity_callback(tsd);
-}
diff --git a/fluent-bit/lib/jemalloc-5.3.0/src/prof.c b/fluent-bit/lib/jemalloc-5.3.0/src/prof.c
deleted file mode 100644
index 7a6d5d56..00000000
--- a/fluent-bit/lib/jemalloc-5.3.0/src/prof.c
+++ /dev/null
@@ -1,789 +0,0 @@
-#include "jemalloc/internal/jemalloc_preamble.h"
-#include "jemalloc/internal/jemalloc_internal_includes.h"
-
-#include "jemalloc/internal/ctl.h"
-#include "jemalloc/internal/assert.h"
-#include "jemalloc/internal/mutex.h"
-#include "jemalloc/internal/counter.h"
-#include "jemalloc/internal/prof_data.h"
-#include "jemalloc/internal/prof_log.h"
-#include "jemalloc/internal/prof_recent.h"
-#include "jemalloc/internal/prof_stats.h"
-#include "jemalloc/internal/prof_sys.h"
-#include "jemalloc/internal/prof_hook.h"
-#include "jemalloc/internal/thread_event.h"
-
-/*
- * This file implements the profiling "APIs" needed by other parts of jemalloc,
- * and also manages the relevant "operational" data, mainly options and mutexes;
- * the core profiling data structures are encapsulated in prof_data.c.
- */
-
-/******************************************************************************/
-
-/* Data. */
-
-bool opt_prof = false;
-bool opt_prof_active = true;
-bool opt_prof_thread_active_init = true;
-size_t opt_lg_prof_sample = LG_PROF_SAMPLE_DEFAULT;
-ssize_t opt_lg_prof_interval = LG_PROF_INTERVAL_DEFAULT;
-bool opt_prof_gdump = false;
-bool opt_prof_final = false;
-bool opt_prof_leak = false;
-bool opt_prof_leak_error = false;
-bool opt_prof_accum = false;
-char opt_prof_prefix[PROF_DUMP_FILENAME_LEN];
-bool opt_prof_sys_thread_name = false;
-bool opt_prof_unbias = true;
-
-/* Accessed via prof_sample_event_handler(). */
-static counter_accum_t prof_idump_accumulated;
-
-/*
- * Initialized as opt_prof_active, and accessed via
- * prof_active_[gs]et{_unlocked,}().
- */
-bool prof_active_state;
-static malloc_mutex_t prof_active_mtx;
-
-/*
- * Initialized as opt_prof_thread_active_init, and accessed via
- * prof_thread_active_init_[gs]et().
- */
-static bool prof_thread_active_init;
-static malloc_mutex_t prof_thread_active_init_mtx;
-
-/*
- * Initialized as opt_prof_gdump, and accessed via
- * prof_gdump_[gs]et{_unlocked,}().
- */
-bool prof_gdump_val;
-static malloc_mutex_t prof_gdump_mtx;
-
-uint64_t prof_interval = 0;
-
-size_t lg_prof_sample;
-
-static uint64_t next_thr_uid;
-static malloc_mutex_t next_thr_uid_mtx;
-
-/* Do not dump any profiles until bootstrapping is complete. */
-bool prof_booted = false;
-
-/* Logically a prof_backtrace_hook_t. */
-atomic_p_t prof_backtrace_hook;
-
-/* Logically a prof_dump_hook_t. */
-atomic_p_t prof_dump_hook;
-
-/******************************************************************************/
-
-void
-prof_alloc_rollback(tsd_t *tsd, prof_tctx_t *tctx) {
- cassert(config_prof);
-
- if (tsd_reentrancy_level_get(tsd) > 0) {
- assert((uintptr_t)tctx == (uintptr_t)1U);
- return;
- }
-
- if ((uintptr_t)tctx > (uintptr_t)1U) {
- malloc_mutex_lock(tsd_tsdn(tsd), tctx->tdata->lock);
- tctx->prepared = false;
- prof_tctx_try_destroy(tsd, tctx);
- }
-}
-
-void
-prof_malloc_sample_object(tsd_t *tsd, const void *ptr, size_t size,
- size_t usize, prof_tctx_t *tctx) {
- cassert(config_prof);
-
- if (opt_prof_sys_thread_name) {
- prof_sys_thread_name_fetch(tsd);
- }
-
- edata_t *edata = emap_edata_lookup(tsd_tsdn(tsd), &arena_emap_global,
- ptr);
- prof_info_set(tsd, edata, tctx, size);
-
- szind_t szind = sz_size2index(usize);
-
- malloc_mutex_lock(tsd_tsdn(tsd), tctx->tdata->lock);
- /*
- * We need to do these map lookups while holding the lock, to avoid the
- * possibility of races with prof_reset calls, which update the map and
- * then acquire the lock. This actually still leaves a data race on the
- * contents of the unbias map, but we have not yet gone through and
- * atomic-ified the prof module, and compilers are not yet causing us
- * issues. The key thing is to make sure that, if we read garbage data,
- * the prof_reset call is about to mark our tctx as expired before any
- * dumping of our corrupted output is attempted.
- */
- size_t shifted_unbiased_cnt = prof_shifted_unbiased_cnt[szind];
- size_t unbiased_bytes = prof_unbiased_sz[szind];
- tctx->cnts.curobjs++;
- tctx->cnts.curobjs_shifted_unbiased += shifted_unbiased_cnt;
- tctx->cnts.curbytes += usize;
- tctx->cnts.curbytes_unbiased += unbiased_bytes;
- if (opt_prof_accum) {
- tctx->cnts.accumobjs++;
- tctx->cnts.accumobjs_shifted_unbiased += shifted_unbiased_cnt;
- tctx->cnts.accumbytes += usize;
- tctx->cnts.accumbytes_unbiased += unbiased_bytes;
- }
- bool record_recent = prof_recent_alloc_prepare(tsd, tctx);
- tctx->prepared = false;
- malloc_mutex_unlock(tsd_tsdn(tsd), tctx->tdata->lock);
- if (record_recent) {
- assert(tctx == edata_prof_tctx_get(edata));
- prof_recent_alloc(tsd, edata, size, usize);
- }
-
- if (opt_prof_stats) {
- prof_stats_inc(tsd, szind, size);
- }
-}
-
-void
-prof_free_sampled_object(tsd_t *tsd, size_t usize, prof_info_t *prof_info) {
- cassert(config_prof);
-
- assert(prof_info != NULL);
- prof_tctx_t *tctx = prof_info->alloc_tctx;
- assert((uintptr_t)tctx > (uintptr_t)1U);
-
- szind_t szind = sz_size2index(usize);
- malloc_mutex_lock(tsd_tsdn(tsd), tctx->tdata->lock);
-
- assert(tctx->cnts.curobjs > 0);
- assert(tctx->cnts.curbytes >= usize);
- /*
- * It's not correct to do equivalent asserts for unbiased bytes, because
- * of the potential for races with prof.reset calls. The map contents
- * should really be atomic, but we have not atomic-ified the prof module
- * yet.
- */
- tctx->cnts.curobjs--;
- tctx->cnts.curobjs_shifted_unbiased -= prof_shifted_unbiased_cnt[szind];
- tctx->cnts.curbytes -= usize;
- tctx->cnts.curbytes_unbiased -= prof_unbiased_sz[szind];
-
- prof_try_log(tsd, usize, prof_info);
-
- prof_tctx_try_destroy(tsd, tctx);
-
- if (opt_prof_stats) {
- prof_stats_dec(tsd, szind, prof_info->alloc_size);
- }
-}
-
-prof_tctx_t *
-prof_tctx_create(tsd_t *tsd) {
- if (!tsd_nominal(tsd) || tsd_reentrancy_level_get(tsd) > 0) {
- return NULL;
- }
-
- prof_tdata_t *tdata = prof_tdata_get(tsd, true);
- if (tdata == NULL) {
- return NULL;
- }
-
- prof_bt_t bt;
- bt_init(&bt, tdata->vec);
- prof_backtrace(tsd, &bt);
- return prof_lookup(tsd, &bt);
-}
-
-/*
- * The bodies of this function and prof_leakcheck() are compiled out unless heap
- * profiling is enabled, so that it is possible to compile jemalloc with
- * floating point support completely disabled. Avoiding floating point code is
- * important on memory-constrained systems, but it also enables a workaround for
- * versions of glibc that don't properly save/restore floating point registers
- * during dynamic lazy symbol loading (which internally calls into whatever
- * malloc implementation happens to be integrated into the application). Note
- * that some compilers (e.g. gcc 4.8) may use floating point registers for fast
- * memory moves, so jemalloc must be compiled with such optimizations disabled
- * (e.g.
- * -mno-sse) in order for the workaround to be complete.
- */
-uint64_t
-prof_sample_new_event_wait(tsd_t *tsd) {
-#ifdef JEMALLOC_PROF
- if (lg_prof_sample == 0) {
- return TE_MIN_START_WAIT;
- }
-
- /*
- * Compute sample interval as a geometrically distributed random
- * variable with mean (2^lg_prof_sample).
- *
- * __ __
- * | log(u) | 1
- * bytes_until_sample = | -------- |, where p = ---------------
- * | log(1-p) | lg_prof_sample
- * 2
- *
- * For more information on the math, see:
- *
- * Non-Uniform Random Variate Generation
- * Luc Devroye
- * Springer-Verlag, New York, 1986
- * pp 500
- * (http://luc.devroye.org/rnbookindex.html)
- *
- * In the actual computation, there's a non-zero probability that our
- * pseudo random number generator generates an exact 0, and to avoid
- * log(0), we set u to 1.0 in case r is 0. Therefore u effectively is
- * uniformly distributed in (0, 1] instead of [0, 1). Further, rather
- * than taking the ceiling, we take the floor and then add 1, since
- * otherwise bytes_until_sample would be 0 if u is exactly 1.0.
- */
- uint64_t r = prng_lg_range_u64(tsd_prng_statep_get(tsd), 53);
- double u = (r == 0U) ? 1.0 : (double)r * (1.0/9007199254740992.0L);
- return (uint64_t)(log(u) /
- log(1.0 - (1.0 / (double)((uint64_t)1U << lg_prof_sample))))
- + (uint64_t)1U;
-#else
- not_reached();
- return TE_MAX_START_WAIT;
-#endif
-}
-
-uint64_t
-prof_sample_postponed_event_wait(tsd_t *tsd) {
- /*
- * The postponed wait time for prof sample event is computed as if we
- * want a new wait time (i.e. as if the event were triggered). If we
- * instead postpone to the immediate next allocation, like how we're
- * handling the other events, then we can have sampling bias, if e.g.
- * the allocation immediately following a reentrancy always comes from
- * the same stack trace.
- */
- return prof_sample_new_event_wait(tsd);
-}
-
-void
-prof_sample_event_handler(tsd_t *tsd, uint64_t elapsed) {
- cassert(config_prof);
- assert(elapsed > 0 && elapsed != TE_INVALID_ELAPSED);
- if (prof_interval == 0 || !prof_active_get_unlocked()) {
- return;
- }
- if (counter_accum(tsd_tsdn(tsd), &prof_idump_accumulated, elapsed)) {
- prof_idump(tsd_tsdn(tsd));
- }
-}
-
-static void
-prof_fdump(void) {
- tsd_t *tsd;
-
- cassert(config_prof);
- assert(opt_prof_final);
-
- if (!prof_booted) {
- return;
- }
- tsd = tsd_fetch();
- assert(tsd_reentrancy_level_get(tsd) == 0);
-
- prof_fdump_impl(tsd);
-}
-
-static bool
-prof_idump_accum_init(void) {
- cassert(config_prof);
-
- return counter_accum_init(&prof_idump_accumulated, prof_interval);
-}
-
-void
-prof_idump(tsdn_t *tsdn) {
- tsd_t *tsd;
- prof_tdata_t *tdata;
-
- cassert(config_prof);
-
- if (!prof_booted || tsdn_null(tsdn) || !prof_active_get_unlocked()) {
- return;
- }
- tsd = tsdn_tsd(tsdn);
- if (tsd_reentrancy_level_get(tsd) > 0) {
- return;
- }
-
- tdata = prof_tdata_get(tsd, true);
- if (tdata == NULL) {
- return;
- }
- if (tdata->enq) {
- tdata->enq_idump = true;
- return;
- }
-
- prof_idump_impl(tsd);
-}
-
-bool
-prof_mdump(tsd_t *tsd, const char *filename) {
- cassert(config_prof);
- assert(tsd_reentrancy_level_get(tsd) == 0);
-
- if (!opt_prof || !prof_booted) {
- return true;
- }
-
- return prof_mdump_impl(tsd, filename);
-}
-
-void
-prof_gdump(tsdn_t *tsdn) {
- tsd_t *tsd;
- prof_tdata_t *tdata;
-
- cassert(config_prof);
-
- if (!prof_booted || tsdn_null(tsdn) || !prof_active_get_unlocked()) {
- return;
- }
- tsd = tsdn_tsd(tsdn);
- if (tsd_reentrancy_level_get(tsd) > 0) {
- return;
- }
-
- tdata = prof_tdata_get(tsd, false);
- if (tdata == NULL) {
- return;
- }
- if (tdata->enq) {
- tdata->enq_gdump = true;
- return;
- }
-
- prof_gdump_impl(tsd);
-}
-
-static uint64_t
-prof_thr_uid_alloc(tsdn_t *tsdn) {
- uint64_t thr_uid;
-
- malloc_mutex_lock(tsdn, &next_thr_uid_mtx);
- thr_uid = next_thr_uid;
- next_thr_uid++;
- malloc_mutex_unlock(tsdn, &next_thr_uid_mtx);
-
- return thr_uid;
-}
-
-prof_tdata_t *
-prof_tdata_init(tsd_t *tsd) {
- return prof_tdata_init_impl(tsd, prof_thr_uid_alloc(tsd_tsdn(tsd)), 0,
- NULL, prof_thread_active_init_get(tsd_tsdn(tsd)));
-}
-
-prof_tdata_t *
-prof_tdata_reinit(tsd_t *tsd, prof_tdata_t *tdata) {
- uint64_t thr_uid = tdata->thr_uid;
- uint64_t thr_discrim = tdata->thr_discrim + 1;
- char *thread_name = (tdata->thread_name != NULL) ?
- prof_thread_name_alloc(tsd, tdata->thread_name) : NULL;
- bool active = tdata->active;
-
- prof_tdata_detach(tsd, tdata);
- return prof_tdata_init_impl(tsd, thr_uid, thr_discrim, thread_name,
- active);
-}
-
-void
-prof_tdata_cleanup(tsd_t *tsd) {
- prof_tdata_t *tdata;
-
- if (!config_prof) {
- return;
- }
-
- tdata = tsd_prof_tdata_get(tsd);
- if (tdata != NULL) {
- prof_tdata_detach(tsd, tdata);
- }
-}
-
-bool
-prof_active_get(tsdn_t *tsdn) {
- bool prof_active_current;
-
- prof_active_assert();
- malloc_mutex_lock(tsdn, &prof_active_mtx);
- prof_active_current = prof_active_state;
- malloc_mutex_unlock(tsdn, &prof_active_mtx);
- return prof_active_current;
-}
-
-bool
-prof_active_set(tsdn_t *tsdn, bool active) {
- bool prof_active_old;
-
- prof_active_assert();
- malloc_mutex_lock(tsdn, &prof_active_mtx);
- prof_active_old = prof_active_state;
- prof_active_state = active;
- malloc_mutex_unlock(tsdn, &prof_active_mtx);
- prof_active_assert();
- return prof_active_old;
-}
-
-const char *
-prof_thread_name_get(tsd_t *tsd) {
- assert(tsd_reentrancy_level_get(tsd) == 0);
-
- prof_tdata_t *tdata;
-
- tdata = prof_tdata_get(tsd, true);
- if (tdata == NULL) {
- return "";
- }
- return (tdata->thread_name != NULL ? tdata->thread_name : "");
-}
-
-int
-prof_thread_name_set(tsd_t *tsd, const char *thread_name) {
- if (opt_prof_sys_thread_name) {
- return ENOENT;
- } else {
- return prof_thread_name_set_impl(tsd, thread_name);
- }
-}
-
-bool
-prof_thread_active_get(tsd_t *tsd) {
- assert(tsd_reentrancy_level_get(tsd) == 0);
-
- prof_tdata_t *tdata;
-
- tdata = prof_tdata_get(tsd, true);
- if (tdata == NULL) {
- return false;
- }
- return tdata->active;
-}
-
-bool
-prof_thread_active_set(tsd_t *tsd, bool active) {
- assert(tsd_reentrancy_level_get(tsd) == 0);
-
- prof_tdata_t *tdata;
-
- tdata = prof_tdata_get(tsd, true);
- if (tdata == NULL) {
- return true;
- }
- tdata->active = active;
- return false;
-}
-
-bool
-prof_thread_active_init_get(tsdn_t *tsdn) {
- bool active_init;
-
- malloc_mutex_lock(tsdn, &prof_thread_active_init_mtx);
- active_init = prof_thread_active_init;
- malloc_mutex_unlock(tsdn, &prof_thread_active_init_mtx);
- return active_init;
-}
-
-bool
-prof_thread_active_init_set(tsdn_t *tsdn, bool active_init) {
- bool active_init_old;
-
- malloc_mutex_lock(tsdn, &prof_thread_active_init_mtx);
- active_init_old = prof_thread_active_init;
- prof_thread_active_init = active_init;
- malloc_mutex_unlock(tsdn, &prof_thread_active_init_mtx);
- return active_init_old;
-}
-
-bool
-prof_gdump_get(tsdn_t *tsdn) {
- bool prof_gdump_current;
-
- malloc_mutex_lock(tsdn, &prof_gdump_mtx);
- prof_gdump_current = prof_gdump_val;
- malloc_mutex_unlock(tsdn, &prof_gdump_mtx);
- return prof_gdump_current;
-}
-
-bool
-prof_gdump_set(tsdn_t *tsdn, bool gdump) {
- bool prof_gdump_old;
-
- malloc_mutex_lock(tsdn, &prof_gdump_mtx);
- prof_gdump_old = prof_gdump_val;
- prof_gdump_val = gdump;
- malloc_mutex_unlock(tsdn, &prof_gdump_mtx);
- return prof_gdump_old;
-}
-
-void
-prof_backtrace_hook_set(prof_backtrace_hook_t hook) {
- atomic_store_p(&prof_backtrace_hook, hook, ATOMIC_RELEASE);
-}
-
-prof_backtrace_hook_t
-prof_backtrace_hook_get() {
- return (prof_backtrace_hook_t)atomic_load_p(&prof_backtrace_hook,
- ATOMIC_ACQUIRE);
-}
-
-void
-prof_dump_hook_set(prof_dump_hook_t hook) {
- atomic_store_p(&prof_dump_hook, hook, ATOMIC_RELEASE);
-}
-
-prof_dump_hook_t
-prof_dump_hook_get() {
- return (prof_dump_hook_t)atomic_load_p(&prof_dump_hook,
- ATOMIC_ACQUIRE);
-}
-
-void
-prof_boot0(void) {
- cassert(config_prof);
-
- memcpy(opt_prof_prefix, PROF_PREFIX_DEFAULT,
- sizeof(PROF_PREFIX_DEFAULT));
-}
-
-void
-prof_boot1(void) {
- cassert(config_prof);
-
- /*
- * opt_prof must be in its final state before any arenas are
- * initialized, so this function must be executed early.
- */
- if (opt_prof_leak_error && !opt_prof_leak) {
- opt_prof_leak = true;
- }
-
- if (opt_prof_leak && !opt_prof) {
- /*
- * Enable opt_prof, but in such a way that profiles are never
- * automatically dumped.
- */
- opt_prof = true;
- opt_prof_gdump = false;
- } else if (opt_prof) {
- if (opt_lg_prof_interval >= 0) {
- prof_interval = (((uint64_t)1U) <<
- opt_lg_prof_interval);
- }
- }
-}
-
-bool
-prof_boot2(tsd_t *tsd, base_t *base) {
- cassert(config_prof);
-
- /*
- * Initialize the global mutexes unconditionally to maintain correct
- * stats when opt_prof is false.
- */
- if (malloc_mutex_init(&prof_active_mtx, "prof_active",
- WITNESS_RANK_PROF_ACTIVE, malloc_mutex_rank_exclusive)) {
- return true;
- }
- if (malloc_mutex_init(&prof_gdump_mtx, "prof_gdump",
- WITNESS_RANK_PROF_GDUMP, malloc_mutex_rank_exclusive)) {
- return true;
- }
- if (malloc_mutex_init(&prof_thread_active_init_mtx,
- "prof_thread_active_init", WITNESS_RANK_PROF_THREAD_ACTIVE_INIT,
- malloc_mutex_rank_exclusive)) {
- return true;
- }
- if (malloc_mutex_init(&bt2gctx_mtx, "prof_bt2gctx",
- WITNESS_RANK_PROF_BT2GCTX, malloc_mutex_rank_exclusive)) {
- return true;
- }
- if (malloc_mutex_init(&tdatas_mtx, "prof_tdatas",
- WITNESS_RANK_PROF_TDATAS, malloc_mutex_rank_exclusive)) {
- return true;
- }
- if (malloc_mutex_init(&next_thr_uid_mtx, "prof_next_thr_uid",
- WITNESS_RANK_PROF_NEXT_THR_UID, malloc_mutex_rank_exclusive)) {
- return true;
- }
- if (malloc_mutex_init(&prof_stats_mtx, "prof_stats",
- WITNESS_RANK_PROF_STATS, malloc_mutex_rank_exclusive)) {
- return true;
- }
- if (malloc_mutex_init(&prof_dump_filename_mtx,
- "prof_dump_filename", WITNESS_RANK_PROF_DUMP_FILENAME,
- malloc_mutex_rank_exclusive)) {
- return true;
- }
- if (malloc_mutex_init(&prof_dump_mtx, "prof_dump",
- WITNESS_RANK_PROF_DUMP, malloc_mutex_rank_exclusive)) {
- return true;
- }
-
- if (opt_prof) {
- lg_prof_sample = opt_lg_prof_sample;
- prof_unbias_map_init();
- prof_active_state = opt_prof_active;
- prof_gdump_val = opt_prof_gdump;
- prof_thread_active_init = opt_prof_thread_active_init;
-
- if (prof_data_init(tsd)) {
- return true;
- }
-
- next_thr_uid = 0;
- if (prof_idump_accum_init()) {
- return true;
- }
-
- if (opt_prof_final && opt_prof_prefix[0] != '\0' &&
- atexit(prof_fdump) != 0) {
- malloc_write("<jemalloc>: Error in atexit()\n");
- if (opt_abort) {
- abort();
- }
- }
-
- if (prof_log_init(tsd)) {
- return true;
- }
-
- if (prof_recent_init()) {
- return true;
- }
-
- prof_base = base;
-
- gctx_locks = (malloc_mutex_t *)base_alloc(tsd_tsdn(tsd), base,
- PROF_NCTX_LOCKS * sizeof(malloc_mutex_t), CACHELINE);
- if (gctx_locks == NULL) {
- return true;
- }
- for (unsigned i = 0; i < PROF_NCTX_LOCKS; i++) {
- if (malloc_mutex_init(&gctx_locks[i], "prof_gctx",
- WITNESS_RANK_PROF_GCTX,
- malloc_mutex_rank_exclusive)) {
- return true;
- }
- }
-
- tdata_locks = (malloc_mutex_t *)base_alloc(tsd_tsdn(tsd), base,
- PROF_NTDATA_LOCKS * sizeof(malloc_mutex_t), CACHELINE);
- if (tdata_locks == NULL) {
- return true;
- }
- for (unsigned i = 0; i < PROF_NTDATA_LOCKS; i++) {
- if (malloc_mutex_init(&tdata_locks[i], "prof_tdata",
- WITNESS_RANK_PROF_TDATA,
- malloc_mutex_rank_exclusive)) {
- return true;
- }
- }
-
- prof_unwind_init();
- prof_hooks_init();
- }
- prof_booted = true;
-
- return false;
-}
-
-void
-prof_prefork0(tsdn_t *tsdn) {
- if (config_prof && opt_prof) {
- unsigned i;
-
- malloc_mutex_prefork(tsdn, &prof_dump_mtx);
- malloc_mutex_prefork(tsdn, &bt2gctx_mtx);
- malloc_mutex_prefork(tsdn, &tdatas_mtx);
- for (i = 0; i < PROF_NTDATA_LOCKS; i++) {
- malloc_mutex_prefork(tsdn, &tdata_locks[i]);
- }
- malloc_mutex_prefork(tsdn, &log_mtx);
- for (i = 0; i < PROF_NCTX_LOCKS; i++) {
- malloc_mutex_prefork(tsdn, &gctx_locks[i]);
- }
- malloc_mutex_prefork(tsdn, &prof_recent_dump_mtx);
- }
-}
-
-void
-prof_prefork1(tsdn_t *tsdn) {
- if (config_prof && opt_prof) {
- counter_prefork(tsdn, &prof_idump_accumulated);
- malloc_mutex_prefork(tsdn, &prof_active_mtx);
- malloc_mutex_prefork(tsdn, &prof_dump_filename_mtx);
- malloc_mutex_prefork(tsdn, &prof_gdump_mtx);
- malloc_mutex_prefork(tsdn, &prof_recent_alloc_mtx);
- malloc_mutex_prefork(tsdn, &prof_stats_mtx);
- malloc_mutex_prefork(tsdn, &next_thr_uid_mtx);
- malloc_mutex_prefork(tsdn, &prof_thread_active_init_mtx);
- }
-}
-
-void
-prof_postfork_parent(tsdn_t *tsdn) {
- if (config_prof && opt_prof) {
- unsigned i;
-
- malloc_mutex_postfork_parent(tsdn,
- &prof_thread_active_init_mtx);
- malloc_mutex_postfork_parent(tsdn, &next_thr_uid_mtx);
- malloc_mutex_postfork_parent(tsdn, &prof_stats_mtx);
- malloc_mutex_postfork_parent(tsdn, &prof_recent_alloc_mtx);
- malloc_mutex_postfork_parent(tsdn, &prof_gdump_mtx);
- malloc_mutex_postfork_parent(tsdn, &prof_dump_filename_mtx);
- malloc_mutex_postfork_parent(tsdn, &prof_active_mtx);
- counter_postfork_parent(tsdn, &prof_idump_accumulated);
- malloc_mutex_postfork_parent(tsdn, &prof_recent_dump_mtx);
- for (i = 0; i < PROF_NCTX_LOCKS; i++) {
- malloc_mutex_postfork_parent(tsdn, &gctx_locks[i]);
- }
- malloc_mutex_postfork_parent(tsdn, &log_mtx);
- for (i = 0; i < PROF_NTDATA_LOCKS; i++) {
- malloc_mutex_postfork_parent(tsdn, &tdata_locks[i]);
- }
- malloc_mutex_postfork_parent(tsdn, &tdatas_mtx);
- malloc_mutex_postfork_parent(tsdn, &bt2gctx_mtx);
- malloc_mutex_postfork_parent(tsdn, &prof_dump_mtx);
- }
-}
-
-void
-prof_postfork_child(tsdn_t *tsdn) {
- if (config_prof && opt_prof) {
- unsigned i;
-
- malloc_mutex_postfork_child(tsdn, &prof_thread_active_init_mtx);
- malloc_mutex_postfork_child(tsdn, &next_thr_uid_mtx);
- malloc_mutex_postfork_child(tsdn, &prof_stats_mtx);
- malloc_mutex_postfork_child(tsdn, &prof_recent_alloc_mtx);
- malloc_mutex_postfork_child(tsdn, &prof_gdump_mtx);
- malloc_mutex_postfork_child(tsdn, &prof_dump_filename_mtx);
- malloc_mutex_postfork_child(tsdn, &prof_active_mtx);
- counter_postfork_child(tsdn, &prof_idump_accumulated);
- malloc_mutex_postfork_child(tsdn, &prof_recent_dump_mtx);
- for (i = 0; i < PROF_NCTX_LOCKS; i++) {
- malloc_mutex_postfork_child(tsdn, &gctx_locks[i]);
- }
- malloc_mutex_postfork_child(tsdn, &log_mtx);
- for (i = 0; i < PROF_NTDATA_LOCKS; i++) {
- malloc_mutex_postfork_child(tsdn, &tdata_locks[i]);
- }
- malloc_mutex_postfork_child(tsdn, &tdatas_mtx);
- malloc_mutex_postfork_child(tsdn, &bt2gctx_mtx);
- malloc_mutex_postfork_child(tsdn, &prof_dump_mtx);
- }
-}
-
-/******************************************************************************/
diff --git a/fluent-bit/lib/jemalloc-5.3.0/src/prof_data.c b/fluent-bit/lib/jemalloc-5.3.0/src/prof_data.c
deleted file mode 100644
index bfa55be1..00000000
--- a/fluent-bit/lib/jemalloc-5.3.0/src/prof_data.c
+++ /dev/null
@@ -1,1447 +0,0 @@
-#include "jemalloc/internal/jemalloc_preamble.h"
-#include "jemalloc/internal/jemalloc_internal_includes.h"
-
-#include "jemalloc/internal/assert.h"
-#include "jemalloc/internal/ckh.h"
-#include "jemalloc/internal/hash.h"
-#include "jemalloc/internal/malloc_io.h"
-#include "jemalloc/internal/prof_data.h"
-
-/*
- * This file defines and manages the core profiling data structures.
- *
- * Conceptually, profiling data can be imagined as a table with three columns:
- * thread, stack trace, and current allocation size. (When prof_accum is on,
- * there's one additional column which is the cumulative allocation size.)
- *
- * Implementation wise, each thread maintains a hash recording the stack trace
- * to allocation size correspondences, which are basically the individual rows
- * in the table. In addition, two global "indices" are built to make data
- * aggregation efficient (for dumping): bt2gctx and tdatas, which are basically
- * the "grouped by stack trace" and "grouped by thread" views of the same table,
- * respectively. Note that the allocation size is only aggregated to the two
- * indices at dumping time, so as to optimize for performance.
- */
-
-/******************************************************************************/
-
-malloc_mutex_t bt2gctx_mtx;
-malloc_mutex_t tdatas_mtx;
-malloc_mutex_t prof_dump_mtx;
-
-/*
- * Table of mutexes that are shared among gctx's. These are leaf locks, so
- * there is no problem with using them for more than one gctx at the same time.
- * The primary motivation for this sharing though is that gctx's are ephemeral,
- * and destroying mutexes causes complications for systems that allocate when
- * creating/destroying mutexes.
- */
-malloc_mutex_t *gctx_locks;
-static atomic_u_t cum_gctxs; /* Atomic counter. */
-
-/*
- * Table of mutexes that are shared among tdata's. No operations require
- * holding multiple tdata locks, so there is no problem with using them for more
- * than one tdata at the same time, even though a gctx lock may be acquired
- * while holding a tdata lock.
- */
-malloc_mutex_t *tdata_locks;
-
-/*
- * Global hash of (prof_bt_t *)-->(prof_gctx_t *). This is the master data
- * structure that knows about all backtraces currently captured.
- */
-static ckh_t bt2gctx;
-
-/*
- * Tree of all extant prof_tdata_t structures, regardless of state,
- * {attached,detached,expired}.
- */
-static prof_tdata_tree_t tdatas;
-
-size_t prof_unbiased_sz[PROF_SC_NSIZES];
-size_t prof_shifted_unbiased_cnt[PROF_SC_NSIZES];
-
-/******************************************************************************/
-/* Red-black trees. */
-
-static int
-prof_tctx_comp(const prof_tctx_t *a, const prof_tctx_t *b) {
- uint64_t a_thr_uid = a->thr_uid;
- uint64_t b_thr_uid = b->thr_uid;
- int ret = (a_thr_uid > b_thr_uid) - (a_thr_uid < b_thr_uid);
- if (ret == 0) {
- uint64_t a_thr_discrim = a->thr_discrim;
- uint64_t b_thr_discrim = b->thr_discrim;
- ret = (a_thr_discrim > b_thr_discrim) - (a_thr_discrim <
- b_thr_discrim);
- if (ret == 0) {
- uint64_t a_tctx_uid = a->tctx_uid;
- uint64_t b_tctx_uid = b->tctx_uid;
- ret = (a_tctx_uid > b_tctx_uid) - (a_tctx_uid <
- b_tctx_uid);
- }
- }
- return ret;
-}
-
-rb_gen(static UNUSED, tctx_tree_, prof_tctx_tree_t, prof_tctx_t,
- tctx_link, prof_tctx_comp)
-
-static int
-prof_gctx_comp(const prof_gctx_t *a, const prof_gctx_t *b) {
- unsigned a_len = a->bt.len;
- unsigned b_len = b->bt.len;
- unsigned comp_len = (a_len < b_len) ? a_len : b_len;
- int ret = memcmp(a->bt.vec, b->bt.vec, comp_len * sizeof(void *));
- if (ret == 0) {
- ret = (a_len > b_len) - (a_len < b_len);
- }
- return ret;
-}
-
-rb_gen(static UNUSED, gctx_tree_, prof_gctx_tree_t, prof_gctx_t, dump_link,
- prof_gctx_comp)
-
-static int
-prof_tdata_comp(const prof_tdata_t *a, const prof_tdata_t *b) {
- int ret;
- uint64_t a_uid = a->thr_uid;
- uint64_t b_uid = b->thr_uid;
-
- ret = ((a_uid > b_uid) - (a_uid < b_uid));
- if (ret == 0) {
- uint64_t a_discrim = a->thr_discrim;
- uint64_t b_discrim = b->thr_discrim;
-
- ret = ((a_discrim > b_discrim) - (a_discrim < b_discrim));
- }
- return ret;
-}
-
-rb_gen(static UNUSED, tdata_tree_, prof_tdata_tree_t, prof_tdata_t, tdata_link,
- prof_tdata_comp)
-
-/******************************************************************************/
-
-static malloc_mutex_t *
-prof_gctx_mutex_choose(void) {
- unsigned ngctxs = atomic_fetch_add_u(&cum_gctxs, 1, ATOMIC_RELAXED);
-
- return &gctx_locks[(ngctxs - 1) % PROF_NCTX_LOCKS];
-}
-
-static malloc_mutex_t *
-prof_tdata_mutex_choose(uint64_t thr_uid) {
- return &tdata_locks[thr_uid % PROF_NTDATA_LOCKS];
-}
-
-bool
-prof_data_init(tsd_t *tsd) {
- tdata_tree_new(&tdatas);
- return ckh_new(tsd, &bt2gctx, PROF_CKH_MINITEMS,
- prof_bt_hash, prof_bt_keycomp);
-}
-
-static void
-prof_enter(tsd_t *tsd, prof_tdata_t *tdata) {
- cassert(config_prof);
- assert(tdata == prof_tdata_get(tsd, false));
-
- if (tdata != NULL) {
- assert(!tdata->enq);
- tdata->enq = true;
- }
-
- malloc_mutex_lock(tsd_tsdn(tsd), &bt2gctx_mtx);
-}
-
-static void
-prof_leave(tsd_t *tsd, prof_tdata_t *tdata) {
- cassert(config_prof);
- assert(tdata == prof_tdata_get(tsd, false));
-
- malloc_mutex_unlock(tsd_tsdn(tsd), &bt2gctx_mtx);
-
- if (tdata != NULL) {
- bool idump, gdump;
-
- assert(tdata->enq);
- tdata->enq = false;
- idump = tdata->enq_idump;
- tdata->enq_idump = false;
- gdump = tdata->enq_gdump;
- tdata->enq_gdump = false;
-
- if (idump) {
- prof_idump(tsd_tsdn(tsd));
- }
- if (gdump) {
- prof_gdump(tsd_tsdn(tsd));
- }
- }
-}
-
-static prof_gctx_t *
-prof_gctx_create(tsdn_t *tsdn, prof_bt_t *bt) {
- /*
- * Create a single allocation that has space for vec of length bt->len.
- */
- size_t size = offsetof(prof_gctx_t, vec) + (bt->len * sizeof(void *));
- prof_gctx_t *gctx = (prof_gctx_t *)iallocztm(tsdn, size,
- sz_size2index(size), false, NULL, true, arena_get(TSDN_NULL, 0, true),
- true);
- if (gctx == NULL) {
- return NULL;
- }
- gctx->lock = prof_gctx_mutex_choose();
- /*
- * Set nlimbo to 1, in order to avoid a race condition with
- * prof_tctx_destroy()/prof_gctx_try_destroy().
- */
- gctx->nlimbo = 1;
- tctx_tree_new(&gctx->tctxs);
- /* Duplicate bt. */
- memcpy(gctx->vec, bt->vec, bt->len * sizeof(void *));
- gctx->bt.vec = gctx->vec;
- gctx->bt.len = bt->len;
- return gctx;
-}
-
-static void
-prof_gctx_try_destroy(tsd_t *tsd, prof_tdata_t *tdata_self,
- prof_gctx_t *gctx) {
- cassert(config_prof);
-
- /*
- * Check that gctx is still unused by any thread cache before destroying
- * it. prof_lookup() increments gctx->nlimbo in order to avoid a race
- * condition with this function, as does prof_tctx_destroy() in order to
- * avoid a race between the main body of prof_tctx_destroy() and entry
- * into this function.
- */
- prof_enter(tsd, tdata_self);
- malloc_mutex_lock(tsd_tsdn(tsd), gctx->lock);
- assert(gctx->nlimbo != 0);
- if (tctx_tree_empty(&gctx->tctxs) && gctx->nlimbo == 1) {
- /* Remove gctx from bt2gctx. */
- if (ckh_remove(tsd, &bt2gctx, &gctx->bt, NULL, NULL)) {
- not_reached();
- }
- prof_leave(tsd, tdata_self);
- /* Destroy gctx. */
- malloc_mutex_unlock(tsd_tsdn(tsd), gctx->lock);
- idalloctm(tsd_tsdn(tsd), gctx, NULL, NULL, true, true);
- } else {
- /*
- * Compensate for increment in prof_tctx_destroy() or
- * prof_lookup().
- */
- gctx->nlimbo--;
- malloc_mutex_unlock(tsd_tsdn(tsd), gctx->lock);
- prof_leave(tsd, tdata_self);
- }
-}
-
-static bool
-prof_gctx_should_destroy(prof_gctx_t *gctx) {
- if (opt_prof_accum) {
- return false;
- }
- if (!tctx_tree_empty(&gctx->tctxs)) {
- return false;
- }
- if (gctx->nlimbo != 0) {
- return false;
- }
- return true;
-}
-
-static bool
-prof_lookup_global(tsd_t *tsd, prof_bt_t *bt, prof_tdata_t *tdata,
- void **p_btkey, prof_gctx_t **p_gctx, bool *p_new_gctx) {
- union {
- prof_gctx_t *p;
- void *v;
- } gctx, tgctx;
- union {
- prof_bt_t *p;
- void *v;
- } btkey;
- bool new_gctx;
-
- prof_enter(tsd, tdata);
- if (ckh_search(&bt2gctx, bt, &btkey.v, &gctx.v)) {
- /* bt has never been seen before. Insert it. */
- prof_leave(tsd, tdata);
- tgctx.p = prof_gctx_create(tsd_tsdn(tsd), bt);
- if (tgctx.v == NULL) {
- return true;
- }
- prof_enter(tsd, tdata);
- if (ckh_search(&bt2gctx, bt, &btkey.v, &gctx.v)) {
- gctx.p = tgctx.p;
- btkey.p = &gctx.p->bt;
- if (ckh_insert(tsd, &bt2gctx, btkey.v, gctx.v)) {
- /* OOM. */
- prof_leave(tsd, tdata);
- idalloctm(tsd_tsdn(tsd), gctx.v, NULL, NULL,
- true, true);
- return true;
- }
- new_gctx = true;
- } else {
- new_gctx = false;
- }
- } else {
- tgctx.v = NULL;
- new_gctx = false;
- }
-
- if (!new_gctx) {
- /*
- * Increment nlimbo, in order to avoid a race condition with
- * prof_tctx_destroy()/prof_gctx_try_destroy().
- */
- malloc_mutex_lock(tsd_tsdn(tsd), gctx.p->lock);
- gctx.p->nlimbo++;
- malloc_mutex_unlock(tsd_tsdn(tsd), gctx.p->lock);
- new_gctx = false;
-
- if (tgctx.v != NULL) {
- /* Lost race to insert. */
- idalloctm(tsd_tsdn(tsd), tgctx.v, NULL, NULL, true,
- true);
- }
- }
- prof_leave(tsd, tdata);
-
- *p_btkey = btkey.v;
- *p_gctx = gctx.p;
- *p_new_gctx = new_gctx;
- return false;
-}
-
-prof_tctx_t *
-prof_lookup(tsd_t *tsd, prof_bt_t *bt) {
- union {
- prof_tctx_t *p;
- void *v;
- } ret;
- prof_tdata_t *tdata;
- bool not_found;
-
- cassert(config_prof);
-
- tdata = prof_tdata_get(tsd, false);
- assert(tdata != NULL);
-
- malloc_mutex_lock(tsd_tsdn(tsd), tdata->lock);
- not_found = ckh_search(&tdata->bt2tctx, bt, NULL, &ret.v);
- if (!not_found) { /* Note double negative! */
- ret.p->prepared = true;
- }
- malloc_mutex_unlock(tsd_tsdn(tsd), tdata->lock);
- if (not_found) {
- void *btkey;
- prof_gctx_t *gctx;
- bool new_gctx, error;
-
- /*
- * This thread's cache lacks bt. Look for it in the global
- * cache.
- */
- if (prof_lookup_global(tsd, bt, tdata, &btkey, &gctx,
- &new_gctx)) {
- return NULL;
- }
-
- /* Link a prof_tctx_t into gctx for this thread. */
- ret.v = iallocztm(tsd_tsdn(tsd), sizeof(prof_tctx_t),
- sz_size2index(sizeof(prof_tctx_t)), false, NULL, true,
- arena_ichoose(tsd, NULL), true);
- if (ret.p == NULL) {
- if (new_gctx) {
- prof_gctx_try_destroy(tsd, tdata, gctx);
- }
- return NULL;
- }
- ret.p->tdata = tdata;
- ret.p->thr_uid = tdata->thr_uid;
- ret.p->thr_discrim = tdata->thr_discrim;
- ret.p->recent_count = 0;
- memset(&ret.p->cnts, 0, sizeof(prof_cnt_t));
- ret.p->gctx = gctx;
- ret.p->tctx_uid = tdata->tctx_uid_next++;
- ret.p->prepared = true;
- ret.p->state = prof_tctx_state_initializing;
- malloc_mutex_lock(tsd_tsdn(tsd), tdata->lock);
- error = ckh_insert(tsd, &tdata->bt2tctx, btkey, ret.v);
- malloc_mutex_unlock(tsd_tsdn(tsd), tdata->lock);
- if (error) {
- if (new_gctx) {
- prof_gctx_try_destroy(tsd, tdata, gctx);
- }
- idalloctm(tsd_tsdn(tsd), ret.v, NULL, NULL, true, true);
- return NULL;
- }
- malloc_mutex_lock(tsd_tsdn(tsd), gctx->lock);
- ret.p->state = prof_tctx_state_nominal;
- tctx_tree_insert(&gctx->tctxs, ret.p);
- gctx->nlimbo--;
- malloc_mutex_unlock(tsd_tsdn(tsd), gctx->lock);
- }
-
- return ret.p;
-}
-
-/* Used in unit tests. */
-static prof_tdata_t *
-prof_tdata_count_iter(prof_tdata_tree_t *tdatas_ptr, prof_tdata_t *tdata,
- void *arg) {
- size_t *tdata_count = (size_t *)arg;
-
- (*tdata_count)++;
-
- return NULL;
-}
-
-/* Used in unit tests. */
-size_t
-prof_tdata_count(void) {
- size_t tdata_count = 0;
- tsdn_t *tsdn;
-
- tsdn = tsdn_fetch();
- malloc_mutex_lock(tsdn, &tdatas_mtx);
- tdata_tree_iter(&tdatas, NULL, prof_tdata_count_iter,
- (void *)&tdata_count);
- malloc_mutex_unlock(tsdn, &tdatas_mtx);
-
- return tdata_count;
-}
-
-/* Used in unit tests. */
-size_t
-prof_bt_count(void) {
- size_t bt_count;
- tsd_t *tsd;
- prof_tdata_t *tdata;
-
- tsd = tsd_fetch();
- tdata = prof_tdata_get(tsd, false);
- if (tdata == NULL) {
- return 0;
- }
-
- malloc_mutex_lock(tsd_tsdn(tsd), &bt2gctx_mtx);
- bt_count = ckh_count(&bt2gctx);
- malloc_mutex_unlock(tsd_tsdn(tsd), &bt2gctx_mtx);
-
- return bt_count;
-}
-
-char *
-prof_thread_name_alloc(tsd_t *tsd, const char *thread_name) {
- char *ret;
- size_t size;
-
- if (thread_name == NULL) {
- return NULL;
- }
-
- size = strlen(thread_name) + 1;
- if (size == 1) {
- return "";
- }
-
- ret = iallocztm(tsd_tsdn(tsd), size, sz_size2index(size), false, NULL,
- true, arena_get(TSDN_NULL, 0, true), true);
- if (ret == NULL) {
- return NULL;
- }
- memcpy(ret, thread_name, size);
- return ret;
-}
-
-int
-prof_thread_name_set_impl(tsd_t *tsd, const char *thread_name) {
- assert(tsd_reentrancy_level_get(tsd) == 0);
-
- prof_tdata_t *tdata;
- unsigned i;
- char *s;
-
- tdata = prof_tdata_get(tsd, true);
- if (tdata == NULL) {
- return EAGAIN;
- }
-
- /* Validate input. */
- if (thread_name == NULL) {
- return EFAULT;
- }
- for (i = 0; thread_name[i] != '\0'; i++) {
- char c = thread_name[i];
- if (!isgraph(c) && !isblank(c)) {
- return EFAULT;
- }
- }
-
- s = prof_thread_name_alloc(tsd, thread_name);
- if (s == NULL) {
- return EAGAIN;
- }
-
- if (tdata->thread_name != NULL) {
- idalloctm(tsd_tsdn(tsd), tdata->thread_name, NULL, NULL, true,
- true);
- tdata->thread_name = NULL;
- }
- if (strlen(s) > 0) {
- tdata->thread_name = s;
- }
- return 0;
-}
-
-JEMALLOC_FORMAT_PRINTF(3, 4)
-static void
-prof_dump_printf(write_cb_t *prof_dump_write, void *cbopaque,
- const char *format, ...) {
- va_list ap;
- char buf[PROF_PRINTF_BUFSIZE];
-
- va_start(ap, format);
- malloc_vsnprintf(buf, sizeof(buf), format, ap);
- va_end(ap);
- prof_dump_write(cbopaque, buf);
-}
-
-/*
- * Casting a double to a uint64_t may not necessarily be in range; this can be
- * UB. I don't think this is practically possible with the cur counters, but
- * plausibly could be with the accum counters.
- */
-#ifdef JEMALLOC_PROF
-static uint64_t
-prof_double_uint64_cast(double d) {
- /*
- * Note: UINT64_MAX + 1 is exactly representable as a double on all
- * reasonable platforms (certainly those we'll support). Writing this
- * as !(a < b) instead of (a >= b) means that we're NaN-safe.
- */
- double rounded = round(d);
- if (!(rounded < (double)UINT64_MAX)) {
- return UINT64_MAX;
- }
- return (uint64_t)rounded;
-}
-#endif
-
-void prof_unbias_map_init() {
- /* See the comment in prof_sample_new_event_wait */
-#ifdef JEMALLOC_PROF
- for (szind_t i = 0; i < SC_NSIZES; i++) {
- double sz = (double)sz_index2size(i);
- double rate = (double)(ZU(1) << lg_prof_sample);
- double div_val = 1.0 - exp(-sz / rate);
- double unbiased_sz = sz / div_val;
- /*
- * The "true" right value for the unbiased count is
- * 1.0/(1 - exp(-sz/rate)). The problem is, we keep the counts
- * as integers (for a variety of reasons -- rounding errors
- * could trigger asserts, and not all libcs can properly handle
- * floating point arithmetic during malloc calls inside libc).
- * Rounding to an integer, though, can lead to rounding errors
- * of over 30% for sizes close to the sampling rate. So
- * instead, we multiply by a constant, dividing the maximum
- * possible roundoff error by that constant. To avoid overflow
- * in summing up size_t values, the largest safe constant we can
- * pick is the size of the smallest allocation.
- */
- double cnt_shift = (double)(ZU(1) << SC_LG_TINY_MIN);
- double shifted_unbiased_cnt = cnt_shift / div_val;
- prof_unbiased_sz[i] = (size_t)round(unbiased_sz);
- prof_shifted_unbiased_cnt[i] = (size_t)round(
- shifted_unbiased_cnt);
- }
-#else
- unreachable();
-#endif
-}
-
-/*
- * The unbiasing story is long. The jeprof unbiasing logic was copied from
- * pprof. Both shared an issue: they unbiased using the average size of the
- * allocations at a particular stack trace. This can work out OK if allocations
- * are mostly of the same size given some stack, but not otherwise. We now
- * internally track what the unbiased results ought to be. We can't just report
- * them as they are though; they'll still go through the jeprof unbiasing
- * process. Instead, we figure out what values we can feed *into* jeprof's
- * unbiasing mechanism that will lead to getting the right values out.
- *
- * It'll unbias count and aggregate size as:
- *
- * c_out = c_in * 1/(1-exp(-s_in/c_in/R)
- * s_out = s_in * 1/(1-exp(-s_in/c_in/R)
- *
- * We want to solve for the values of c_in and s_in that will
- * give the c_out and s_out that we've computed internally.
- *
- * Let's do a change of variables (both to make the math easier and to make it
- * easier to write):
- * x = s_in / c_in
- * y = s_in
- * k = 1/R.
- *
- * Then
- * c_out = y/x * 1/(1-exp(-k*x))
- * s_out = y * 1/(1-exp(-k*x))
- *
- * The first equation gives:
- * y = x * c_out * (1-exp(-k*x))
- * The second gives:
- * y = s_out * (1-exp(-k*x))
- * So we have
- * x = s_out / c_out.
- * And all the other values fall out from that.
- *
- * This is all a fair bit of work. The thing we get out of it is that we don't
- * break backwards compatibility with jeprof (and the various tools that have
- * copied its unbiasing logic). Eventually, we anticipate a v3 heap profile
- * dump format based on JSON, at which point I think much of this logic can get
- * cleaned up (since we'll be taking a compatibility break there anyways).
- */
-static void
-prof_do_unbias(uint64_t c_out_shifted_i, uint64_t s_out_i, uint64_t *r_c_in,
- uint64_t *r_s_in) {
-#ifdef JEMALLOC_PROF
- if (c_out_shifted_i == 0 || s_out_i == 0) {
- *r_c_in = 0;
- *r_s_in = 0;
- return;
- }
- /*
- * See the note in prof_unbias_map_init() to see why we take c_out in a
- * shifted form.
- */
- double c_out = (double)c_out_shifted_i
- / (double)(ZU(1) << SC_LG_TINY_MIN);
- double s_out = (double)s_out_i;
- double R = (double)(ZU(1) << lg_prof_sample);
-
- double x = s_out / c_out;
- double y = s_out * (1.0 - exp(-x / R));
-
- double c_in = y / x;
- double s_in = y;
-
- *r_c_in = prof_double_uint64_cast(c_in);
- *r_s_in = prof_double_uint64_cast(s_in);
-#else
- unreachable();
-#endif
-}
-
-static void
-prof_dump_print_cnts(write_cb_t *prof_dump_write, void *cbopaque,
- const prof_cnt_t *cnts) {
- uint64_t curobjs;
- uint64_t curbytes;
- uint64_t accumobjs;
- uint64_t accumbytes;
- if (opt_prof_unbias) {
- prof_do_unbias(cnts->curobjs_shifted_unbiased,
- cnts->curbytes_unbiased, &curobjs, &curbytes);
- prof_do_unbias(cnts->accumobjs_shifted_unbiased,
- cnts->accumbytes_unbiased, &accumobjs, &accumbytes);
- } else {
- curobjs = cnts->curobjs;
- curbytes = cnts->curbytes;
- accumobjs = cnts->accumobjs;
- accumbytes = cnts->accumbytes;
- }
- prof_dump_printf(prof_dump_write, cbopaque,
- "%"FMTu64": %"FMTu64" [%"FMTu64": %"FMTu64"]",
- curobjs, curbytes, accumobjs, accumbytes);
-}
-
-static void
-prof_tctx_merge_tdata(tsdn_t *tsdn, prof_tctx_t *tctx, prof_tdata_t *tdata) {
- malloc_mutex_assert_owner(tsdn, tctx->tdata->lock);
-
- malloc_mutex_lock(tsdn, tctx->gctx->lock);
-
- switch (tctx->state) {
- case prof_tctx_state_initializing:
- malloc_mutex_unlock(tsdn, tctx->gctx->lock);
- return;
- case prof_tctx_state_nominal:
- tctx->state = prof_tctx_state_dumping;
- malloc_mutex_unlock(tsdn, tctx->gctx->lock);
-
- memcpy(&tctx->dump_cnts, &tctx->cnts, sizeof(prof_cnt_t));
-
- tdata->cnt_summed.curobjs += tctx->dump_cnts.curobjs;
- tdata->cnt_summed.curobjs_shifted_unbiased
- += tctx->dump_cnts.curobjs_shifted_unbiased;
- tdata->cnt_summed.curbytes += tctx->dump_cnts.curbytes;
- tdata->cnt_summed.curbytes_unbiased
- += tctx->dump_cnts.curbytes_unbiased;
- if (opt_prof_accum) {
- tdata->cnt_summed.accumobjs +=
- tctx->dump_cnts.accumobjs;
- tdata->cnt_summed.accumobjs_shifted_unbiased +=
- tctx->dump_cnts.accumobjs_shifted_unbiased;
- tdata->cnt_summed.accumbytes +=
- tctx->dump_cnts.accumbytes;
- tdata->cnt_summed.accumbytes_unbiased +=
- tctx->dump_cnts.accumbytes_unbiased;
- }
- break;
- case prof_tctx_state_dumping:
- case prof_tctx_state_purgatory:
- not_reached();
- }
-}
-
-static void
-prof_tctx_merge_gctx(tsdn_t *tsdn, prof_tctx_t *tctx, prof_gctx_t *gctx) {
- malloc_mutex_assert_owner(tsdn, gctx->lock);
-
- gctx->cnt_summed.curobjs += tctx->dump_cnts.curobjs;
- gctx->cnt_summed.curobjs_shifted_unbiased
- += tctx->dump_cnts.curobjs_shifted_unbiased;
- gctx->cnt_summed.curbytes += tctx->dump_cnts.curbytes;
- gctx->cnt_summed.curbytes_unbiased += tctx->dump_cnts.curbytes_unbiased;
- if (opt_prof_accum) {
- gctx->cnt_summed.accumobjs += tctx->dump_cnts.accumobjs;
- gctx->cnt_summed.accumobjs_shifted_unbiased
- += tctx->dump_cnts.accumobjs_shifted_unbiased;
- gctx->cnt_summed.accumbytes += tctx->dump_cnts.accumbytes;
- gctx->cnt_summed.accumbytes_unbiased
- += tctx->dump_cnts.accumbytes_unbiased;
- }
-}
-
-static prof_tctx_t *
-prof_tctx_merge_iter(prof_tctx_tree_t *tctxs, prof_tctx_t *tctx, void *arg) {
- tsdn_t *tsdn = (tsdn_t *)arg;
-
- malloc_mutex_assert_owner(tsdn, tctx->gctx->lock);
-
- switch (tctx->state) {
- case prof_tctx_state_nominal:
- /* New since dumping started; ignore. */
- break;
- case prof_tctx_state_dumping:
- case prof_tctx_state_purgatory:
- prof_tctx_merge_gctx(tsdn, tctx, tctx->gctx);
- break;
- default:
- not_reached();
- }
-
- return NULL;
-}
-
-typedef struct prof_dump_iter_arg_s prof_dump_iter_arg_t;
-struct prof_dump_iter_arg_s {
- tsdn_t *tsdn;
- write_cb_t *prof_dump_write;
- void *cbopaque;
-};
-
-static prof_tctx_t *
-prof_tctx_dump_iter(prof_tctx_tree_t *tctxs, prof_tctx_t *tctx, void *opaque) {
- prof_dump_iter_arg_t *arg = (prof_dump_iter_arg_t *)opaque;
- malloc_mutex_assert_owner(arg->tsdn, tctx->gctx->lock);
-
- switch (tctx->state) {
- case prof_tctx_state_initializing:
- case prof_tctx_state_nominal:
- /* Not captured by this dump. */
- break;
- case prof_tctx_state_dumping:
- case prof_tctx_state_purgatory:
- prof_dump_printf(arg->prof_dump_write, arg->cbopaque,
- " t%"FMTu64": ", tctx->thr_uid);
- prof_dump_print_cnts(arg->prof_dump_write, arg->cbopaque,
- &tctx->dump_cnts);
- arg->prof_dump_write(arg->cbopaque, "\n");
- break;
- default:
- not_reached();
- }
- return NULL;
-}
-
-static prof_tctx_t *
-prof_tctx_finish_iter(prof_tctx_tree_t *tctxs, prof_tctx_t *tctx, void *arg) {
- tsdn_t *tsdn = (tsdn_t *)arg;
- prof_tctx_t *ret;
-
- malloc_mutex_assert_owner(tsdn, tctx->gctx->lock);
-
- switch (tctx->state) {
- case prof_tctx_state_nominal:
- /* New since dumping started; ignore. */
- break;
- case prof_tctx_state_dumping:
- tctx->state = prof_tctx_state_nominal;
- break;
- case prof_tctx_state_purgatory:
- ret = tctx;
- goto label_return;
- default:
- not_reached();
- }
-
- ret = NULL;
-label_return:
- return ret;
-}
-
-static void
-prof_dump_gctx_prep(tsdn_t *tsdn, prof_gctx_t *gctx, prof_gctx_tree_t *gctxs) {
- cassert(config_prof);
-
- malloc_mutex_lock(tsdn, gctx->lock);
-
- /*
- * Increment nlimbo so that gctx won't go away before dump.
- * Additionally, link gctx into the dump list so that it is included in
- * prof_dump()'s second pass.
- */
- gctx->nlimbo++;
- gctx_tree_insert(gctxs, gctx);
-
- memset(&gctx->cnt_summed, 0, sizeof(prof_cnt_t));
-
- malloc_mutex_unlock(tsdn, gctx->lock);
-}
-
-typedef struct prof_gctx_merge_iter_arg_s prof_gctx_merge_iter_arg_t;
-struct prof_gctx_merge_iter_arg_s {
- tsdn_t *tsdn;
- size_t *leak_ngctx;
-};
-
-static prof_gctx_t *
-prof_gctx_merge_iter(prof_gctx_tree_t *gctxs, prof_gctx_t *gctx, void *opaque) {
- prof_gctx_merge_iter_arg_t *arg = (prof_gctx_merge_iter_arg_t *)opaque;
-
- malloc_mutex_lock(arg->tsdn, gctx->lock);
- tctx_tree_iter(&gctx->tctxs, NULL, prof_tctx_merge_iter,
- (void *)arg->tsdn);
- if (gctx->cnt_summed.curobjs != 0) {
- (*arg->leak_ngctx)++;
- }
- malloc_mutex_unlock(arg->tsdn, gctx->lock);
-
- return NULL;
-}
-
-static void
-prof_gctx_finish(tsd_t *tsd, prof_gctx_tree_t *gctxs) {
- prof_tdata_t *tdata = prof_tdata_get(tsd, false);
- prof_gctx_t *gctx;
-
- /*
- * Standard tree iteration won't work here, because as soon as we
- * decrement gctx->nlimbo and unlock gctx, another thread can
- * concurrently destroy it, which will corrupt the tree. Therefore,
- * tear down the tree one node at a time during iteration.
- */
- while ((gctx = gctx_tree_first(gctxs)) != NULL) {
- gctx_tree_remove(gctxs, gctx);
- malloc_mutex_lock(tsd_tsdn(tsd), gctx->lock);
- {
- prof_tctx_t *next;
-
- next = NULL;
- do {
- prof_tctx_t *to_destroy =
- tctx_tree_iter(&gctx->tctxs, next,
- prof_tctx_finish_iter,
- (void *)tsd_tsdn(tsd));
- if (to_destroy != NULL) {
- next = tctx_tree_next(&gctx->tctxs,
- to_destroy);
- tctx_tree_remove(&gctx->tctxs,
- to_destroy);
- idalloctm(tsd_tsdn(tsd), to_destroy,
- NULL, NULL, true, true);
- } else {
- next = NULL;
- }
- } while (next != NULL);
- }
- gctx->nlimbo--;
- if (prof_gctx_should_destroy(gctx)) {
- gctx->nlimbo++;
- malloc_mutex_unlock(tsd_tsdn(tsd), gctx->lock);
- prof_gctx_try_destroy(tsd, tdata, gctx);
- } else {
- malloc_mutex_unlock(tsd_tsdn(tsd), gctx->lock);
- }
- }
-}
-
-typedef struct prof_tdata_merge_iter_arg_s prof_tdata_merge_iter_arg_t;
-struct prof_tdata_merge_iter_arg_s {
- tsdn_t *tsdn;
- prof_cnt_t *cnt_all;
-};
-
-static prof_tdata_t *
-prof_tdata_merge_iter(prof_tdata_tree_t *tdatas_ptr, prof_tdata_t *tdata,
- void *opaque) {
- prof_tdata_merge_iter_arg_t *arg =
- (prof_tdata_merge_iter_arg_t *)opaque;
-
- malloc_mutex_lock(arg->tsdn, tdata->lock);
- if (!tdata->expired) {
- size_t tabind;
- union {
- prof_tctx_t *p;
- void *v;
- } tctx;
-
- tdata->dumping = true;
- memset(&tdata->cnt_summed, 0, sizeof(prof_cnt_t));
- for (tabind = 0; !ckh_iter(&tdata->bt2tctx, &tabind, NULL,
- &tctx.v);) {
- prof_tctx_merge_tdata(arg->tsdn, tctx.p, tdata);
- }
-
- arg->cnt_all->curobjs += tdata->cnt_summed.curobjs;
- arg->cnt_all->curobjs_shifted_unbiased
- += tdata->cnt_summed.curobjs_shifted_unbiased;
- arg->cnt_all->curbytes += tdata->cnt_summed.curbytes;
- arg->cnt_all->curbytes_unbiased
- += tdata->cnt_summed.curbytes_unbiased;
- if (opt_prof_accum) {
- arg->cnt_all->accumobjs += tdata->cnt_summed.accumobjs;
- arg->cnt_all->accumobjs_shifted_unbiased
- += tdata->cnt_summed.accumobjs_shifted_unbiased;
- arg->cnt_all->accumbytes +=
- tdata->cnt_summed.accumbytes;
- arg->cnt_all->accumbytes_unbiased +=
- tdata->cnt_summed.accumbytes_unbiased;
- }
- } else {
- tdata->dumping = false;
- }
- malloc_mutex_unlock(arg->tsdn, tdata->lock);
-
- return NULL;
-}
-
-static prof_tdata_t *
-prof_tdata_dump_iter(prof_tdata_tree_t *tdatas_ptr, prof_tdata_t *tdata,
- void *opaque) {
- if (!tdata->dumping) {
- return NULL;
- }
-
- prof_dump_iter_arg_t *arg = (prof_dump_iter_arg_t *)opaque;
- prof_dump_printf(arg->prof_dump_write, arg->cbopaque, " t%"FMTu64": ",
- tdata->thr_uid);
- prof_dump_print_cnts(arg->prof_dump_write, arg->cbopaque,
- &tdata->cnt_summed);
- if (tdata->thread_name != NULL) {
- arg->prof_dump_write(arg->cbopaque, " ");
- arg->prof_dump_write(arg->cbopaque, tdata->thread_name);
- }
- arg->prof_dump_write(arg->cbopaque, "\n");
- return NULL;
-}
-
-static void
-prof_dump_header(prof_dump_iter_arg_t *arg, const prof_cnt_t *cnt_all) {
- prof_dump_printf(arg->prof_dump_write, arg->cbopaque,
- "heap_v2/%"FMTu64"\n t*: ", ((uint64_t)1U << lg_prof_sample));
- prof_dump_print_cnts(arg->prof_dump_write, arg->cbopaque, cnt_all);
- arg->prof_dump_write(arg->cbopaque, "\n");
-
- malloc_mutex_lock(arg->tsdn, &tdatas_mtx);
- tdata_tree_iter(&tdatas, NULL, prof_tdata_dump_iter, arg);
- malloc_mutex_unlock(arg->tsdn, &tdatas_mtx);
-}
-
-static void
-prof_dump_gctx(prof_dump_iter_arg_t *arg, prof_gctx_t *gctx,
- const prof_bt_t *bt, prof_gctx_tree_t *gctxs) {
- cassert(config_prof);
- malloc_mutex_assert_owner(arg->tsdn, gctx->lock);
-
- /* Avoid dumping such gctx's that have no useful data. */
- if ((!opt_prof_accum && gctx->cnt_summed.curobjs == 0) ||
- (opt_prof_accum && gctx->cnt_summed.accumobjs == 0)) {
- assert(gctx->cnt_summed.curobjs == 0);
- assert(gctx->cnt_summed.curbytes == 0);
- /*
- * These asserts would not be correct -- see the comment on races
- * in prof.c
- * assert(gctx->cnt_summed.curobjs_unbiased == 0);
- * assert(gctx->cnt_summed.curbytes_unbiased == 0);
- */
- assert(gctx->cnt_summed.accumobjs == 0);
- assert(gctx->cnt_summed.accumobjs_shifted_unbiased == 0);
- assert(gctx->cnt_summed.accumbytes == 0);
- assert(gctx->cnt_summed.accumbytes_unbiased == 0);
- return;
- }
-
- arg->prof_dump_write(arg->cbopaque, "@");
- for (unsigned i = 0; i < bt->len; i++) {
- prof_dump_printf(arg->prof_dump_write, arg->cbopaque,
- " %#"FMTxPTR, (uintptr_t)bt->vec[i]);
- }
-
- arg->prof_dump_write(arg->cbopaque, "\n t*: ");
- prof_dump_print_cnts(arg->prof_dump_write, arg->cbopaque,
- &gctx->cnt_summed);
- arg->prof_dump_write(arg->cbopaque, "\n");
-
- tctx_tree_iter(&gctx->tctxs, NULL, prof_tctx_dump_iter, arg);
-}
-
-/*
- * See prof_sample_new_event_wait() comment for why the body of this function
- * is conditionally compiled.
- */
-static void
-prof_leakcheck(const prof_cnt_t *cnt_all, size_t leak_ngctx) {
-#ifdef JEMALLOC_PROF
- /*
- * Scaling is equivalent AdjustSamples() in jeprof, but the result may
- * differ slightly from what jeprof reports, because here we scale the
- * summary values, whereas jeprof scales each context individually and
- * reports the sums of the scaled values.
- */
- if (cnt_all->curbytes != 0) {
- double sample_period = (double)((uint64_t)1 << lg_prof_sample);
- double ratio = (((double)cnt_all->curbytes) /
- (double)cnt_all->curobjs) / sample_period;
- double scale_factor = 1.0 / (1.0 - exp(-ratio));
- uint64_t curbytes = (uint64_t)round(((double)cnt_all->curbytes)
- * scale_factor);
- uint64_t curobjs = (uint64_t)round(((double)cnt_all->curobjs) *
- scale_factor);
-
- malloc_printf("<jemalloc>: Leak approximation summary: ~%"FMTu64
- " byte%s, ~%"FMTu64" object%s, >= %zu context%s\n",
- curbytes, (curbytes != 1) ? "s" : "", curobjs, (curobjs !=
- 1) ? "s" : "", leak_ngctx, (leak_ngctx != 1) ? "s" : "");
- malloc_printf(
- "<jemalloc>: Run jeprof on dump output for leak detail\n");
- if (opt_prof_leak_error) {
- malloc_printf(
- "<jemalloc>: Exiting with error code because memory"
- " leaks were detected\n");
- /*
- * Use _exit() with underscore to avoid calling atexit()
- * and entering endless cycle.
- */
- _exit(1);
- }
- }
-#endif
-}
-
-static prof_gctx_t *
-prof_gctx_dump_iter(prof_gctx_tree_t *gctxs, prof_gctx_t *gctx, void *opaque) {
- prof_dump_iter_arg_t *arg = (prof_dump_iter_arg_t *)opaque;
- malloc_mutex_lock(arg->tsdn, gctx->lock);
- prof_dump_gctx(arg, gctx, &gctx->bt, gctxs);
- malloc_mutex_unlock(arg->tsdn, gctx->lock);
- return NULL;
-}
-
-static void
-prof_dump_prep(tsd_t *tsd, prof_tdata_t *tdata, prof_cnt_t *cnt_all,
- size_t *leak_ngctx, prof_gctx_tree_t *gctxs) {
- size_t tabind;
- union {
- prof_gctx_t *p;
- void *v;
- } gctx;
-
- prof_enter(tsd, tdata);
-
- /*
- * Put gctx's in limbo and clear their counters in preparation for
- * summing.
- */
- gctx_tree_new(gctxs);
- for (tabind = 0; !ckh_iter(&bt2gctx, &tabind, NULL, &gctx.v);) {
- prof_dump_gctx_prep(tsd_tsdn(tsd), gctx.p, gctxs);
- }
-
- /*
- * Iterate over tdatas, and for the non-expired ones snapshot their tctx
- * stats and merge them into the associated gctx's.
- */
- memset(cnt_all, 0, sizeof(prof_cnt_t));
- prof_tdata_merge_iter_arg_t prof_tdata_merge_iter_arg = {tsd_tsdn(tsd),
- cnt_all};
- malloc_mutex_lock(tsd_tsdn(tsd), &tdatas_mtx);
- tdata_tree_iter(&tdatas, NULL, prof_tdata_merge_iter,
- &prof_tdata_merge_iter_arg);
- malloc_mutex_unlock(tsd_tsdn(tsd), &tdatas_mtx);
-
- /* Merge tctx stats into gctx's. */
- *leak_ngctx = 0;
- prof_gctx_merge_iter_arg_t prof_gctx_merge_iter_arg = {tsd_tsdn(tsd),
- leak_ngctx};
- gctx_tree_iter(gctxs, NULL, prof_gctx_merge_iter,
- &prof_gctx_merge_iter_arg);
-
- prof_leave(tsd, tdata);
-}
-
-void
-prof_dump_impl(tsd_t *tsd, write_cb_t *prof_dump_write, void *cbopaque,
- prof_tdata_t *tdata, bool leakcheck) {
- malloc_mutex_assert_owner(tsd_tsdn(tsd), &prof_dump_mtx);
- prof_cnt_t cnt_all;
- size_t leak_ngctx;
- prof_gctx_tree_t gctxs;
- prof_dump_prep(tsd, tdata, &cnt_all, &leak_ngctx, &gctxs);
- prof_dump_iter_arg_t prof_dump_iter_arg = {tsd_tsdn(tsd),
- prof_dump_write, cbopaque};
- prof_dump_header(&prof_dump_iter_arg, &cnt_all);
- gctx_tree_iter(&gctxs, NULL, prof_gctx_dump_iter, &prof_dump_iter_arg);
- prof_gctx_finish(tsd, &gctxs);
- if (leakcheck) {
- prof_leakcheck(&cnt_all, leak_ngctx);
- }
-}
-
-/* Used in unit tests. */
-void
-prof_cnt_all(prof_cnt_t *cnt_all) {
- tsd_t *tsd = tsd_fetch();
- prof_tdata_t *tdata = prof_tdata_get(tsd, false);
- if (tdata == NULL) {
- memset(cnt_all, 0, sizeof(prof_cnt_t));
- } else {
- size_t leak_ngctx;
- prof_gctx_tree_t gctxs;
- prof_dump_prep(tsd, tdata, cnt_all, &leak_ngctx, &gctxs);
- prof_gctx_finish(tsd, &gctxs);
- }
-}
-
-void
-prof_bt_hash(const void *key, size_t r_hash[2]) {
- prof_bt_t *bt = (prof_bt_t *)key;
-
- cassert(config_prof);
-
- hash(bt->vec, bt->len * sizeof(void *), 0x94122f33U, r_hash);
-}
-
-bool
-prof_bt_keycomp(const void *k1, const void *k2) {
- const prof_bt_t *bt1 = (prof_bt_t *)k1;
- const prof_bt_t *bt2 = (prof_bt_t *)k2;
-
- cassert(config_prof);
-
- if (bt1->len != bt2->len) {
- return false;
- }
- return (memcmp(bt1->vec, bt2->vec, bt1->len * sizeof(void *)) == 0);
-}
-
-prof_tdata_t *
-prof_tdata_init_impl(tsd_t *tsd, uint64_t thr_uid, uint64_t thr_discrim,
- char *thread_name, bool active) {
- assert(tsd_reentrancy_level_get(tsd) == 0);
-
- prof_tdata_t *tdata;
-
- cassert(config_prof);
-
- /* Initialize an empty cache for this thread. */
- tdata = (prof_tdata_t *)iallocztm(tsd_tsdn(tsd), sizeof(prof_tdata_t),
- sz_size2index(sizeof(prof_tdata_t)), false, NULL, true,
- arena_get(TSDN_NULL, 0, true), true);
- if (tdata == NULL) {
- return NULL;
- }
-
- tdata->lock = prof_tdata_mutex_choose(thr_uid);
- tdata->thr_uid = thr_uid;
- tdata->thr_discrim = thr_discrim;
- tdata->thread_name = thread_name;
- tdata->attached = true;
- tdata->expired = false;
- tdata->tctx_uid_next = 0;
-
- if (ckh_new(tsd, &tdata->bt2tctx, PROF_CKH_MINITEMS, prof_bt_hash,
- prof_bt_keycomp)) {
- idalloctm(tsd_tsdn(tsd), tdata, NULL, NULL, true, true);
- return NULL;
- }
-
- tdata->enq = false;
- tdata->enq_idump = false;
- tdata->enq_gdump = false;
-
- tdata->dumping = false;
- tdata->active = active;
-
- malloc_mutex_lock(tsd_tsdn(tsd), &tdatas_mtx);
- tdata_tree_insert(&tdatas, tdata);
- malloc_mutex_unlock(tsd_tsdn(tsd), &tdatas_mtx);
-
- return tdata;
-}
-
-static bool
-prof_tdata_should_destroy_unlocked(prof_tdata_t *tdata, bool even_if_attached) {
- if (tdata->attached && !even_if_attached) {
- return false;
- }
- if (ckh_count(&tdata->bt2tctx) != 0) {
- return false;
- }
- return true;
-}
-
-static bool
-prof_tdata_should_destroy(tsdn_t *tsdn, prof_tdata_t *tdata,
- bool even_if_attached) {
- malloc_mutex_assert_owner(tsdn, tdata->lock);
-
- return prof_tdata_should_destroy_unlocked(tdata, even_if_attached);
-}
-
-static void
-prof_tdata_destroy_locked(tsd_t *tsd, prof_tdata_t *tdata,
- bool even_if_attached) {
- malloc_mutex_assert_owner(tsd_tsdn(tsd), &tdatas_mtx);
- malloc_mutex_assert_not_owner(tsd_tsdn(tsd), tdata->lock);
-
- tdata_tree_remove(&tdatas, tdata);
-
- assert(prof_tdata_should_destroy_unlocked(tdata, even_if_attached));
-
- if (tdata->thread_name != NULL) {
- idalloctm(tsd_tsdn(tsd), tdata->thread_name, NULL, NULL, true,
- true);
- }
- ckh_delete(tsd, &tdata->bt2tctx);
- idalloctm(tsd_tsdn(tsd), tdata, NULL, NULL, true, true);
-}
-
-static void
-prof_tdata_destroy(tsd_t *tsd, prof_tdata_t *tdata, bool even_if_attached) {
- malloc_mutex_lock(tsd_tsdn(tsd), &tdatas_mtx);
- prof_tdata_destroy_locked(tsd, tdata, even_if_attached);
- malloc_mutex_unlock(tsd_tsdn(tsd), &tdatas_mtx);
-}
-
-void
-prof_tdata_detach(tsd_t *tsd, prof_tdata_t *tdata) {
- bool destroy_tdata;
-
- malloc_mutex_lock(tsd_tsdn(tsd), tdata->lock);
- if (tdata->attached) {
- destroy_tdata = prof_tdata_should_destroy(tsd_tsdn(tsd), tdata,
- true);
- /*
- * Only detach if !destroy_tdata, because detaching would allow
- * another thread to win the race to destroy tdata.
- */
- if (!destroy_tdata) {
- tdata->attached = false;
- }
- tsd_prof_tdata_set(tsd, NULL);
- } else {
- destroy_tdata = false;
- }
- malloc_mutex_unlock(tsd_tsdn(tsd), tdata->lock);
- if (destroy_tdata) {
- prof_tdata_destroy(tsd, tdata, true);
- }
-}
-
-static bool
-prof_tdata_expire(tsdn_t *tsdn, prof_tdata_t *tdata) {
- bool destroy_tdata;
-
- malloc_mutex_lock(tsdn, tdata->lock);
- if (!tdata->expired) {
- tdata->expired = true;
- destroy_tdata = prof_tdata_should_destroy(tsdn, tdata, false);
- } else {
- destroy_tdata = false;
- }
- malloc_mutex_unlock(tsdn, tdata->lock);
-
- return destroy_tdata;
-}
-
-static prof_tdata_t *
-prof_tdata_reset_iter(prof_tdata_tree_t *tdatas_ptr, prof_tdata_t *tdata,
- void *arg) {
- tsdn_t *tsdn = (tsdn_t *)arg;
-
- return (prof_tdata_expire(tsdn, tdata) ? tdata : NULL);
-}
-
-void
-prof_reset(tsd_t *tsd, size_t lg_sample) {
- prof_tdata_t *next;
-
- assert(lg_sample < (sizeof(uint64_t) << 3));
-
- malloc_mutex_lock(tsd_tsdn(tsd), &prof_dump_mtx);
- malloc_mutex_lock(tsd_tsdn(tsd), &tdatas_mtx);
-
- lg_prof_sample = lg_sample;
- prof_unbias_map_init();
-
- next = NULL;
- do {
- prof_tdata_t *to_destroy = tdata_tree_iter(&tdatas, next,
- prof_tdata_reset_iter, (void *)tsd);
- if (to_destroy != NULL) {
- next = tdata_tree_next(&tdatas, to_destroy);
- prof_tdata_destroy_locked(tsd, to_destroy, false);
- } else {
- next = NULL;
- }
- } while (next != NULL);
-
- malloc_mutex_unlock(tsd_tsdn(tsd), &tdatas_mtx);
- malloc_mutex_unlock(tsd_tsdn(tsd), &prof_dump_mtx);
-}
-
-static bool
-prof_tctx_should_destroy(tsd_t *tsd, prof_tctx_t *tctx) {
- malloc_mutex_assert_owner(tsd_tsdn(tsd), tctx->tdata->lock);
-
- if (opt_prof_accum) {
- return false;
- }
- if (tctx->cnts.curobjs != 0) {
- return false;
- }
- if (tctx->prepared) {
- return false;
- }
- if (tctx->recent_count != 0) {
- return false;
- }
- return true;
-}
-
-static void
-prof_tctx_destroy(tsd_t *tsd, prof_tctx_t *tctx) {
- malloc_mutex_assert_owner(tsd_tsdn(tsd), tctx->tdata->lock);
-
- assert(tctx->cnts.curobjs == 0);
- assert(tctx->cnts.curbytes == 0);
- /*
- * These asserts are not correct -- see the comment about races in
- * prof.c
- *
- * assert(tctx->cnts.curobjs_shifted_unbiased == 0);
- * assert(tctx->cnts.curbytes_unbiased == 0);
- */
- assert(!opt_prof_accum);
- assert(tctx->cnts.accumobjs == 0);
- assert(tctx->cnts.accumbytes == 0);
- /*
- * These ones are, since accumbyte counts never go down. Either
- * prof_accum is off (in which case these should never have changed from
- * their initial value of zero), or it's on (in which case we shouldn't
- * be destroying this tctx).
- */
- assert(tctx->cnts.accumobjs_shifted_unbiased == 0);
- assert(tctx->cnts.accumbytes_unbiased == 0);
-
- prof_gctx_t *gctx = tctx->gctx;
-
- {
- prof_tdata_t *tdata = tctx->tdata;
- tctx->tdata = NULL;
- ckh_remove(tsd, &tdata->bt2tctx, &gctx->bt, NULL, NULL);
- bool destroy_tdata = prof_tdata_should_destroy(tsd_tsdn(tsd),
- tdata, false);
- malloc_mutex_unlock(tsd_tsdn(tsd), tdata->lock);
- if (destroy_tdata) {
- prof_tdata_destroy(tsd, tdata, false);
- }
- }
-
- bool destroy_tctx, destroy_gctx;
-
- malloc_mutex_lock(tsd_tsdn(tsd), gctx->lock);
- switch (tctx->state) {
- case prof_tctx_state_nominal:
- tctx_tree_remove(&gctx->tctxs, tctx);
- destroy_tctx = true;
- if (prof_gctx_should_destroy(gctx)) {
- /*
- * Increment gctx->nlimbo in order to keep another
- * thread from winning the race to destroy gctx while
- * this one has gctx->lock dropped. Without this, it
- * would be possible for another thread to:
- *
- * 1) Sample an allocation associated with gctx.
- * 2) Deallocate the sampled object.
- * 3) Successfully prof_gctx_try_destroy(gctx).
- *
- * The result would be that gctx no longer exists by the
- * time this thread accesses it in
- * prof_gctx_try_destroy().
- */
- gctx->nlimbo++;
- destroy_gctx = true;
- } else {
- destroy_gctx = false;
- }
- break;
- case prof_tctx_state_dumping:
- /*
- * A dumping thread needs tctx to remain valid until dumping
- * has finished. Change state such that the dumping thread will
- * complete destruction during a late dump iteration phase.
- */
- tctx->state = prof_tctx_state_purgatory;
- destroy_tctx = false;
- destroy_gctx = false;
- break;
- default:
- not_reached();
- destroy_tctx = false;
- destroy_gctx = false;
- }
- malloc_mutex_unlock(tsd_tsdn(tsd), gctx->lock);
- if (destroy_gctx) {
- prof_gctx_try_destroy(tsd, prof_tdata_get(tsd, false), gctx);
- }
- if (destroy_tctx) {
- idalloctm(tsd_tsdn(tsd), tctx, NULL, NULL, true, true);
- }
-}
-
-void
-prof_tctx_try_destroy(tsd_t *tsd, prof_tctx_t *tctx) {
- malloc_mutex_assert_owner(tsd_tsdn(tsd), tctx->tdata->lock);
- if (prof_tctx_should_destroy(tsd, tctx)) {
- /* tctx->tdata->lock will be released in prof_tctx_destroy(). */
- prof_tctx_destroy(tsd, tctx);
- } else {
- malloc_mutex_unlock(tsd_tsdn(tsd), tctx->tdata->lock);
- }
-}
-
-/******************************************************************************/
diff --git a/fluent-bit/lib/jemalloc-5.3.0/src/prof_log.c b/fluent-bit/lib/jemalloc-5.3.0/src/prof_log.c
deleted file mode 100644
index 0632c3b3..00000000
--- a/fluent-bit/lib/jemalloc-5.3.0/src/prof_log.c
+++ /dev/null
@@ -1,717 +0,0 @@
-#include "jemalloc/internal/jemalloc_preamble.h"
-#include "jemalloc/internal/jemalloc_internal_includes.h"
-
-#include "jemalloc/internal/assert.h"
-#include "jemalloc/internal/buf_writer.h"
-#include "jemalloc/internal/ckh.h"
-#include "jemalloc/internal/emitter.h"
-#include "jemalloc/internal/hash.h"
-#include "jemalloc/internal/malloc_io.h"
-#include "jemalloc/internal/mutex.h"
-#include "jemalloc/internal/prof_data.h"
-#include "jemalloc/internal/prof_log.h"
-#include "jemalloc/internal/prof_sys.h"
-
-bool opt_prof_log = false;
-typedef enum prof_logging_state_e prof_logging_state_t;
-enum prof_logging_state_e {
- prof_logging_state_stopped,
- prof_logging_state_started,
- prof_logging_state_dumping
-};
-
-/*
- * - stopped: log_start never called, or previous log_stop has completed.
- * - started: log_start called, log_stop not called yet. Allocations are logged.
- * - dumping: log_stop called but not finished; samples are not logged anymore.
- */
-prof_logging_state_t prof_logging_state = prof_logging_state_stopped;
-
-/* Used in unit tests. */
-static bool prof_log_dummy = false;
-
-/* Incremented for every log file that is output. */
-static uint64_t log_seq = 0;
-static char log_filename[
- /* Minimize memory bloat for non-prof builds. */
-#ifdef JEMALLOC_PROF
- PATH_MAX +
-#endif
- 1];
-
-/* Timestamp for most recent call to log_start(). */
-static nstime_t log_start_timestamp;
-
-/* Increment these when adding to the log_bt and log_thr linked lists. */
-static size_t log_bt_index = 0;
-static size_t log_thr_index = 0;
-
-/* Linked list node definitions. These are only used in this file. */
-typedef struct prof_bt_node_s prof_bt_node_t;
-
-struct prof_bt_node_s {
- prof_bt_node_t *next;
- size_t index;
- prof_bt_t bt;
- /* Variable size backtrace vector pointed to by bt. */
- void *vec[1];
-};
-
-typedef struct prof_thr_node_s prof_thr_node_t;
-
-struct prof_thr_node_s {
- prof_thr_node_t *next;
- size_t index;
- uint64_t thr_uid;
- /* Variable size based on thr_name_sz. */
- char name[1];
-};
-
-typedef struct prof_alloc_node_s prof_alloc_node_t;
-
-/* This is output when logging sampled allocations. */
-struct prof_alloc_node_s {
- prof_alloc_node_t *next;
- /* Indices into an array of thread data. */
- size_t alloc_thr_ind;
- size_t free_thr_ind;
-
- /* Indices into an array of backtraces. */
- size_t alloc_bt_ind;
- size_t free_bt_ind;
-
- uint64_t alloc_time_ns;
- uint64_t free_time_ns;
-
- size_t usize;
-};
-
-/*
- * Created on the first call to prof_try_log and deleted on prof_log_stop.
- * These are the backtraces and threads that have already been logged by an
- * allocation.
- */
-static bool log_tables_initialized = false;
-static ckh_t log_bt_node_set;
-static ckh_t log_thr_node_set;
-
-/* Store linked lists for logged data. */
-static prof_bt_node_t *log_bt_first = NULL;
-static prof_bt_node_t *log_bt_last = NULL;
-static prof_thr_node_t *log_thr_first = NULL;
-static prof_thr_node_t *log_thr_last = NULL;
-static prof_alloc_node_t *log_alloc_first = NULL;
-static prof_alloc_node_t *log_alloc_last = NULL;
-
-/* Protects the prof_logging_state and any log_{...} variable. */
-malloc_mutex_t log_mtx;
-
-/******************************************************************************/
-/*
- * Function prototypes for static functions that are referenced prior to
- * definition.
- */
-
-/* Hashtable functions for log_bt_node_set and log_thr_node_set. */
-static void prof_thr_node_hash(const void *key, size_t r_hash[2]);
-static bool prof_thr_node_keycomp(const void *k1, const void *k2);
-static void prof_bt_node_hash(const void *key, size_t r_hash[2]);
-static bool prof_bt_node_keycomp(const void *k1, const void *k2);
-
-/******************************************************************************/
-
-static size_t
-prof_log_bt_index(tsd_t *tsd, prof_bt_t *bt) {
- assert(prof_logging_state == prof_logging_state_started);
- malloc_mutex_assert_owner(tsd_tsdn(tsd), &log_mtx);
-
- prof_bt_node_t dummy_node;
- dummy_node.bt = *bt;
- prof_bt_node_t *node;
-
- /* See if this backtrace is already cached in the table. */
- if (ckh_search(&log_bt_node_set, (void *)(&dummy_node),
- (void **)(&node), NULL)) {
- size_t sz = offsetof(prof_bt_node_t, vec) +
- (bt->len * sizeof(void *));
- prof_bt_node_t *new_node = (prof_bt_node_t *)
- iallocztm(tsd_tsdn(tsd), sz, sz_size2index(sz), false, NULL,
- true, arena_get(TSDN_NULL, 0, true), true);
- if (log_bt_first == NULL) {
- log_bt_first = new_node;
- log_bt_last = new_node;
- } else {
- log_bt_last->next = new_node;
- log_bt_last = new_node;
- }
-
- new_node->next = NULL;
- new_node->index = log_bt_index;
- /*
- * Copy the backtrace: bt is inside a tdata or gctx, which
- * might die before prof_log_stop is called.
- */
- new_node->bt.len = bt->len;
- memcpy(new_node->vec, bt->vec, bt->len * sizeof(void *));
- new_node->bt.vec = new_node->vec;
-
- log_bt_index++;
- ckh_insert(tsd, &log_bt_node_set, (void *)new_node, NULL);
- return new_node->index;
- } else {
- return node->index;
- }
-}
-
-static size_t
-prof_log_thr_index(tsd_t *tsd, uint64_t thr_uid, const char *name) {
- assert(prof_logging_state == prof_logging_state_started);
- malloc_mutex_assert_owner(tsd_tsdn(tsd), &log_mtx);
-
- prof_thr_node_t dummy_node;
- dummy_node.thr_uid = thr_uid;
- prof_thr_node_t *node;
-
- /* See if this thread is already cached in the table. */
- if (ckh_search(&log_thr_node_set, (void *)(&dummy_node),
- (void **)(&node), NULL)) {
- size_t sz = offsetof(prof_thr_node_t, name) + strlen(name) + 1;
- prof_thr_node_t *new_node = (prof_thr_node_t *)
- iallocztm(tsd_tsdn(tsd), sz, sz_size2index(sz), false, NULL,
- true, arena_get(TSDN_NULL, 0, true), true);
- if (log_thr_first == NULL) {
- log_thr_first = new_node;
- log_thr_last = new_node;
- } else {
- log_thr_last->next = new_node;
- log_thr_last = new_node;
- }
-
- new_node->next = NULL;
- new_node->index = log_thr_index;
- new_node->thr_uid = thr_uid;
- strcpy(new_node->name, name);
-
- log_thr_index++;
- ckh_insert(tsd, &log_thr_node_set, (void *)new_node, NULL);
- return new_node->index;
- } else {
- return node->index;
- }
-}
-
-JEMALLOC_COLD
-void
-prof_try_log(tsd_t *tsd, size_t usize, prof_info_t *prof_info) {
- cassert(config_prof);
- prof_tctx_t *tctx = prof_info->alloc_tctx;
- malloc_mutex_assert_owner(tsd_tsdn(tsd), tctx->tdata->lock);
-
- prof_tdata_t *cons_tdata = prof_tdata_get(tsd, false);
- if (cons_tdata == NULL) {
- /*
- * We decide not to log these allocations. cons_tdata will be
- * NULL only when the current thread is in a weird state (e.g.
- * it's being destroyed).
- */
- return;
- }
-
- malloc_mutex_lock(tsd_tsdn(tsd), &log_mtx);
-
- if (prof_logging_state != prof_logging_state_started) {
- goto label_done;
- }
-
- if (!log_tables_initialized) {
- bool err1 = ckh_new(tsd, &log_bt_node_set, PROF_CKH_MINITEMS,
- prof_bt_node_hash, prof_bt_node_keycomp);
- bool err2 = ckh_new(tsd, &log_thr_node_set, PROF_CKH_MINITEMS,
- prof_thr_node_hash, prof_thr_node_keycomp);
- if (err1 || err2) {
- goto label_done;
- }
- log_tables_initialized = true;
- }
-
- nstime_t alloc_time = prof_info->alloc_time;
- nstime_t free_time;
- nstime_prof_init_update(&free_time);
-
- size_t sz = sizeof(prof_alloc_node_t);
- prof_alloc_node_t *new_node = (prof_alloc_node_t *)
- iallocztm(tsd_tsdn(tsd), sz, sz_size2index(sz), false, NULL, true,
- arena_get(TSDN_NULL, 0, true), true);
-
- const char *prod_thr_name = (tctx->tdata->thread_name == NULL)?
- "" : tctx->tdata->thread_name;
- const char *cons_thr_name = prof_thread_name_get(tsd);
-
- prof_bt_t bt;
- /* Initialize the backtrace, using the buffer in tdata to store it. */
- bt_init(&bt, cons_tdata->vec);
- prof_backtrace(tsd, &bt);
- prof_bt_t *cons_bt = &bt;
-
- /* We haven't destroyed tctx yet, so gctx should be good to read. */
- prof_bt_t *prod_bt = &tctx->gctx->bt;
-
- new_node->next = NULL;
- new_node->alloc_thr_ind = prof_log_thr_index(tsd, tctx->tdata->thr_uid,
- prod_thr_name);
- new_node->free_thr_ind = prof_log_thr_index(tsd, cons_tdata->thr_uid,
- cons_thr_name);
- new_node->alloc_bt_ind = prof_log_bt_index(tsd, prod_bt);
- new_node->free_bt_ind = prof_log_bt_index(tsd, cons_bt);
- new_node->alloc_time_ns = nstime_ns(&alloc_time);
- new_node->free_time_ns = nstime_ns(&free_time);
- new_node->usize = usize;
-
- if (log_alloc_first == NULL) {
- log_alloc_first = new_node;
- log_alloc_last = new_node;
- } else {
- log_alloc_last->next = new_node;
- log_alloc_last = new_node;
- }
-
-label_done:
- malloc_mutex_unlock(tsd_tsdn(tsd), &log_mtx);
-}
-
-static void
-prof_bt_node_hash(const void *key, size_t r_hash[2]) {
- const prof_bt_node_t *bt_node = (prof_bt_node_t *)key;
- prof_bt_hash((void *)(&bt_node->bt), r_hash);
-}
-
-static bool
-prof_bt_node_keycomp(const void *k1, const void *k2) {
- const prof_bt_node_t *bt_node1 = (prof_bt_node_t *)k1;
- const prof_bt_node_t *bt_node2 = (prof_bt_node_t *)k2;
- return prof_bt_keycomp((void *)(&bt_node1->bt),
- (void *)(&bt_node2->bt));
-}
-
-static void
-prof_thr_node_hash(const void *key, size_t r_hash[2]) {
- const prof_thr_node_t *thr_node = (prof_thr_node_t *)key;
- hash(&thr_node->thr_uid, sizeof(uint64_t), 0x94122f35U, r_hash);
-}
-
-static bool
-prof_thr_node_keycomp(const void *k1, const void *k2) {
- const prof_thr_node_t *thr_node1 = (prof_thr_node_t *)k1;
- const prof_thr_node_t *thr_node2 = (prof_thr_node_t *)k2;
- return thr_node1->thr_uid == thr_node2->thr_uid;
-}
-
-/* Used in unit tests. */
-size_t
-prof_log_bt_count(void) {
- cassert(config_prof);
- size_t cnt = 0;
- prof_bt_node_t *node = log_bt_first;
- while (node != NULL) {
- cnt++;
- node = node->next;
- }
- return cnt;
-}
-
-/* Used in unit tests. */
-size_t
-prof_log_alloc_count(void) {
- cassert(config_prof);
- size_t cnt = 0;
- prof_alloc_node_t *node = log_alloc_first;
- while (node != NULL) {
- cnt++;
- node = node->next;
- }
- return cnt;
-}
-
-/* Used in unit tests. */
-size_t
-prof_log_thr_count(void) {
- cassert(config_prof);
- size_t cnt = 0;
- prof_thr_node_t *node = log_thr_first;
- while (node != NULL) {
- cnt++;
- node = node->next;
- }
- return cnt;
-}
-
-/* Used in unit tests. */
-bool
-prof_log_is_logging(void) {
- cassert(config_prof);
- return prof_logging_state == prof_logging_state_started;
-}
-
-/* Used in unit tests. */
-bool
-prof_log_rep_check(void) {
- cassert(config_prof);
- if (prof_logging_state == prof_logging_state_stopped
- && log_tables_initialized) {
- return true;
- }
-
- if (log_bt_last != NULL && log_bt_last->next != NULL) {
- return true;
- }
- if (log_thr_last != NULL && log_thr_last->next != NULL) {
- return true;
- }
- if (log_alloc_last != NULL && log_alloc_last->next != NULL) {
- return true;
- }
-
- size_t bt_count = prof_log_bt_count();
- size_t thr_count = prof_log_thr_count();
- size_t alloc_count = prof_log_alloc_count();
-
-
- if (prof_logging_state == prof_logging_state_stopped) {
- if (bt_count != 0 || thr_count != 0 || alloc_count || 0) {
- return true;
- }
- }
-
- prof_alloc_node_t *node = log_alloc_first;
- while (node != NULL) {
- if (node->alloc_bt_ind >= bt_count) {
- return true;
- }
- if (node->free_bt_ind >= bt_count) {
- return true;
- }
- if (node->alloc_thr_ind >= thr_count) {
- return true;
- }
- if (node->free_thr_ind >= thr_count) {
- return true;
- }
- if (node->alloc_time_ns > node->free_time_ns) {
- return true;
- }
- node = node->next;
- }
-
- return false;
-}
-
-/* Used in unit tests. */
-void
-prof_log_dummy_set(bool new_value) {
- cassert(config_prof);
- prof_log_dummy = new_value;
-}
-
-/* Used as an atexit function to stop logging on exit. */
-static void
-prof_log_stop_final(void) {
- tsd_t *tsd = tsd_fetch();
- prof_log_stop(tsd_tsdn(tsd));
-}
-
-JEMALLOC_COLD
-bool
-prof_log_start(tsdn_t *tsdn, const char *filename) {
- cassert(config_prof);
-
- if (!opt_prof) {
- return true;
- }
-
- bool ret = false;
-
- malloc_mutex_lock(tsdn, &log_mtx);
-
- static bool prof_log_atexit_called = false;
- if (!prof_log_atexit_called) {
- prof_log_atexit_called = true;
- if (atexit(prof_log_stop_final) != 0) {
- malloc_write("<jemalloc>: Error in atexit() "
- "for logging\n");
- if (opt_abort) {
- abort();
- }
- ret = true;
- goto label_done;
- }
- }
-
- if (prof_logging_state != prof_logging_state_stopped) {
- ret = true;
- } else if (filename == NULL) {
- /* Make default name. */
- prof_get_default_filename(tsdn, log_filename, log_seq);
- log_seq++;
- prof_logging_state = prof_logging_state_started;
- } else if (strlen(filename) >= PROF_DUMP_FILENAME_LEN) {
- ret = true;
- } else {
- strcpy(log_filename, filename);
- prof_logging_state = prof_logging_state_started;
- }
-
- if (!ret) {
- nstime_prof_init_update(&log_start_timestamp);
- }
-label_done:
- malloc_mutex_unlock(tsdn, &log_mtx);
-
- return ret;
-}
-
-struct prof_emitter_cb_arg_s {
- int fd;
- ssize_t ret;
-};
-
-static void
-prof_emitter_write_cb(void *opaque, const char *to_write) {
- struct prof_emitter_cb_arg_s *arg =
- (struct prof_emitter_cb_arg_s *)opaque;
- size_t bytes = strlen(to_write);
- if (prof_log_dummy) {
- return;
- }
- arg->ret = malloc_write_fd(arg->fd, to_write, bytes);
-}
-
-/*
- * prof_log_emit_{...} goes through the appropriate linked list, emitting each
- * node to the json and deallocating it.
- */
-static void
-prof_log_emit_threads(tsd_t *tsd, emitter_t *emitter) {
- emitter_json_array_kv_begin(emitter, "threads");
- prof_thr_node_t *thr_node = log_thr_first;
- prof_thr_node_t *thr_old_node;
- while (thr_node != NULL) {
- emitter_json_object_begin(emitter);
-
- emitter_json_kv(emitter, "thr_uid", emitter_type_uint64,
- &thr_node->thr_uid);
-
- char *thr_name = thr_node->name;
-
- emitter_json_kv(emitter, "thr_name", emitter_type_string,
- &thr_name);
-
- emitter_json_object_end(emitter);
- thr_old_node = thr_node;
- thr_node = thr_node->next;
- idalloctm(tsd_tsdn(tsd), thr_old_node, NULL, NULL, true, true);
- }
- emitter_json_array_end(emitter);
-}
-
-static void
-prof_log_emit_traces(tsd_t *tsd, emitter_t *emitter) {
- emitter_json_array_kv_begin(emitter, "stack_traces");
- prof_bt_node_t *bt_node = log_bt_first;
- prof_bt_node_t *bt_old_node;
- /*
- * Calculate how many hex digits we need: twice number of bytes, two for
- * "0x", and then one more for terminating '\0'.
- */
- char buf[2 * sizeof(intptr_t) + 3];
- size_t buf_sz = sizeof(buf);
- while (bt_node != NULL) {
- emitter_json_array_begin(emitter);
- size_t i;
- for (i = 0; i < bt_node->bt.len; i++) {
- malloc_snprintf(buf, buf_sz, "%p", bt_node->bt.vec[i]);
- char *trace_str = buf;
- emitter_json_value(emitter, emitter_type_string,
- &trace_str);
- }
- emitter_json_array_end(emitter);
-
- bt_old_node = bt_node;
- bt_node = bt_node->next;
- idalloctm(tsd_tsdn(tsd), bt_old_node, NULL, NULL, true, true);
- }
- emitter_json_array_end(emitter);
-}
-
-static void
-prof_log_emit_allocs(tsd_t *tsd, emitter_t *emitter) {
- emitter_json_array_kv_begin(emitter, "allocations");
- prof_alloc_node_t *alloc_node = log_alloc_first;
- prof_alloc_node_t *alloc_old_node;
- while (alloc_node != NULL) {
- emitter_json_object_begin(emitter);
-
- emitter_json_kv(emitter, "alloc_thread", emitter_type_size,
- &alloc_node->alloc_thr_ind);
-
- emitter_json_kv(emitter, "free_thread", emitter_type_size,
- &alloc_node->free_thr_ind);
-
- emitter_json_kv(emitter, "alloc_trace", emitter_type_size,
- &alloc_node->alloc_bt_ind);
-
- emitter_json_kv(emitter, "free_trace", emitter_type_size,
- &alloc_node->free_bt_ind);
-
- emitter_json_kv(emitter, "alloc_timestamp",
- emitter_type_uint64, &alloc_node->alloc_time_ns);
-
- emitter_json_kv(emitter, "free_timestamp", emitter_type_uint64,
- &alloc_node->free_time_ns);
-
- emitter_json_kv(emitter, "usize", emitter_type_uint64,
- &alloc_node->usize);
-
- emitter_json_object_end(emitter);
-
- alloc_old_node = alloc_node;
- alloc_node = alloc_node->next;
- idalloctm(tsd_tsdn(tsd), alloc_old_node, NULL, NULL, true,
- true);
- }
- emitter_json_array_end(emitter);
-}
-
-static void
-prof_log_emit_metadata(emitter_t *emitter) {
- emitter_json_object_kv_begin(emitter, "info");
-
- nstime_t now;
-
- nstime_prof_init_update(&now);
- uint64_t ns = nstime_ns(&now) - nstime_ns(&log_start_timestamp);
- emitter_json_kv(emitter, "duration", emitter_type_uint64, &ns);
-
- char *vers = JEMALLOC_VERSION;
- emitter_json_kv(emitter, "version",
- emitter_type_string, &vers);
-
- emitter_json_kv(emitter, "lg_sample_rate",
- emitter_type_int, &lg_prof_sample);
-
- const char *res_type = prof_time_res_mode_names[opt_prof_time_res];
- emitter_json_kv(emitter, "prof_time_resolution", emitter_type_string,
- &res_type);
-
- int pid = prof_getpid();
- emitter_json_kv(emitter, "pid", emitter_type_int, &pid);
-
- emitter_json_object_end(emitter);
-}
-
-#define PROF_LOG_STOP_BUFSIZE PROF_DUMP_BUFSIZE
-JEMALLOC_COLD
-bool
-prof_log_stop(tsdn_t *tsdn) {
- cassert(config_prof);
- if (!opt_prof || !prof_booted) {
- return true;
- }
-
- tsd_t *tsd = tsdn_tsd(tsdn);
- malloc_mutex_lock(tsdn, &log_mtx);
-
- if (prof_logging_state != prof_logging_state_started) {
- malloc_mutex_unlock(tsdn, &log_mtx);
- return true;
- }
-
- /*
- * Set the state to dumping. We'll set it to stopped when we're done.
- * Since other threads won't be able to start/stop/log when the state is
- * dumping, we don't have to hold the lock during the whole method.
- */
- prof_logging_state = prof_logging_state_dumping;
- malloc_mutex_unlock(tsdn, &log_mtx);
-
-
- emitter_t emitter;
-
- /* Create a file. */
-
- int fd;
- if (prof_log_dummy) {
- fd = 0;
- } else {
- fd = creat(log_filename, 0644);
- }
-
- if (fd == -1) {
- malloc_printf("<jemalloc>: creat() for log file \"%s\" "
- " failed with %d\n", log_filename, errno);
- if (opt_abort) {
- abort();
- }
- return true;
- }
-
- struct prof_emitter_cb_arg_s arg;
- arg.fd = fd;
-
- buf_writer_t buf_writer;
- buf_writer_init(tsdn, &buf_writer, prof_emitter_write_cb, &arg, NULL,
- PROF_LOG_STOP_BUFSIZE);
- emitter_init(&emitter, emitter_output_json_compact, buf_writer_cb,
- &buf_writer);
-
- emitter_begin(&emitter);
- prof_log_emit_metadata(&emitter);
- prof_log_emit_threads(tsd, &emitter);
- prof_log_emit_traces(tsd, &emitter);
- prof_log_emit_allocs(tsd, &emitter);
- emitter_end(&emitter);
-
- buf_writer_terminate(tsdn, &buf_writer);
-
- /* Reset global state. */
- if (log_tables_initialized) {
- ckh_delete(tsd, &log_bt_node_set);
- ckh_delete(tsd, &log_thr_node_set);
- }
- log_tables_initialized = false;
- log_bt_index = 0;
- log_thr_index = 0;
- log_bt_first = NULL;
- log_bt_last = NULL;
- log_thr_first = NULL;
- log_thr_last = NULL;
- log_alloc_first = NULL;
- log_alloc_last = NULL;
-
- malloc_mutex_lock(tsdn, &log_mtx);
- prof_logging_state = prof_logging_state_stopped;
- malloc_mutex_unlock(tsdn, &log_mtx);
-
- if (prof_log_dummy) {
- return false;
- }
- return close(fd) || arg.ret == -1;
-}
-#undef PROF_LOG_STOP_BUFSIZE
-
-JEMALLOC_COLD
-bool
-prof_log_init(tsd_t *tsd) {
- cassert(config_prof);
- if (malloc_mutex_init(&log_mtx, "prof_log",
- WITNESS_RANK_PROF_LOG, malloc_mutex_rank_exclusive)) {
- return true;
- }
-
- if (opt_prof_log) {
- prof_log_start(tsd_tsdn(tsd), NULL);
- }
-
- return false;
-}
-
-/******************************************************************************/
diff --git a/fluent-bit/lib/jemalloc-5.3.0/src/prof_recent.c b/fluent-bit/lib/jemalloc-5.3.0/src/prof_recent.c
deleted file mode 100644
index 834a9446..00000000
--- a/fluent-bit/lib/jemalloc-5.3.0/src/prof_recent.c
+++ /dev/null
@@ -1,600 +0,0 @@
-#include "jemalloc/internal/jemalloc_preamble.h"
-#include "jemalloc/internal/jemalloc_internal_includes.h"
-
-#include "jemalloc/internal/assert.h"
-#include "jemalloc/internal/buf_writer.h"
-#include "jemalloc/internal/emitter.h"
-#include "jemalloc/internal/prof_data.h"
-#include "jemalloc/internal/prof_recent.h"
-
-ssize_t opt_prof_recent_alloc_max = PROF_RECENT_ALLOC_MAX_DEFAULT;
-malloc_mutex_t prof_recent_alloc_mtx; /* Protects the fields below */
-static atomic_zd_t prof_recent_alloc_max;
-static ssize_t prof_recent_alloc_count = 0;
-prof_recent_list_t prof_recent_alloc_list;
-
-malloc_mutex_t prof_recent_dump_mtx; /* Protects dumping. */
-
-static void
-prof_recent_alloc_max_init() {
- atomic_store_zd(&prof_recent_alloc_max, opt_prof_recent_alloc_max,
- ATOMIC_RELAXED);
-}
-
-static inline ssize_t
-prof_recent_alloc_max_get_no_lock() {
- return atomic_load_zd(&prof_recent_alloc_max, ATOMIC_RELAXED);
-}
-
-static inline ssize_t
-prof_recent_alloc_max_get(tsd_t *tsd) {
- malloc_mutex_assert_owner(tsd_tsdn(tsd), &prof_recent_alloc_mtx);
- return prof_recent_alloc_max_get_no_lock();
-}
-
-static inline ssize_t
-prof_recent_alloc_max_update(tsd_t *tsd, ssize_t max) {
- malloc_mutex_assert_owner(tsd_tsdn(tsd), &prof_recent_alloc_mtx);
- ssize_t old_max = prof_recent_alloc_max_get(tsd);
- atomic_store_zd(&prof_recent_alloc_max, max, ATOMIC_RELAXED);
- return old_max;
-}
-
-static prof_recent_t *
-prof_recent_allocate_node(tsdn_t *tsdn) {
- return (prof_recent_t *)iallocztm(tsdn, sizeof(prof_recent_t),
- sz_size2index(sizeof(prof_recent_t)), false, NULL, true,
- arena_get(tsdn, 0, false), true);
-}
-
-static void
-prof_recent_free_node(tsdn_t *tsdn, prof_recent_t *node) {
- assert(node != NULL);
- assert(isalloc(tsdn, node) == sz_s2u(sizeof(prof_recent_t)));
- idalloctm(tsdn, node, NULL, NULL, true, true);
-}
-
-static inline void
-increment_recent_count(tsd_t *tsd, prof_tctx_t *tctx) {
- malloc_mutex_assert_owner(tsd_tsdn(tsd), tctx->tdata->lock);
- ++tctx->recent_count;
- assert(tctx->recent_count > 0);
-}
-
-bool
-prof_recent_alloc_prepare(tsd_t *tsd, prof_tctx_t *tctx) {
- cassert(config_prof);
- assert(opt_prof && prof_booted);
- malloc_mutex_assert_owner(tsd_tsdn(tsd), tctx->tdata->lock);
- malloc_mutex_assert_not_owner(tsd_tsdn(tsd), &prof_recent_alloc_mtx);
-
- /*
- * Check whether last-N mode is turned on without trying to acquire the
- * lock, so as to optimize for the following two scenarios:
- * (1) Last-N mode is switched off;
- * (2) Dumping, during which last-N mode is temporarily turned off so
- * as not to block sampled allocations.
- */
- if (prof_recent_alloc_max_get_no_lock() == 0) {
- return false;
- }
-
- /*
- * Increment recent_count to hold the tctx so that it won't be gone
- * even after tctx->tdata->lock is released. This acts as a
- * "placeholder"; the real recording of the allocation requires a lock
- * on prof_recent_alloc_mtx and is done in prof_recent_alloc (when
- * tctx->tdata->lock has been released).
- */
- increment_recent_count(tsd, tctx);
- return true;
-}
-
-static void
-decrement_recent_count(tsd_t *tsd, prof_tctx_t *tctx) {
- malloc_mutex_assert_not_owner(tsd_tsdn(tsd), &prof_recent_alloc_mtx);
- assert(tctx != NULL);
- malloc_mutex_lock(tsd_tsdn(tsd), tctx->tdata->lock);
- assert(tctx->recent_count > 0);
- --tctx->recent_count;
- prof_tctx_try_destroy(tsd, tctx);
-}
-
-static inline edata_t *
-prof_recent_alloc_edata_get_no_lock(const prof_recent_t *n) {
- return (edata_t *)atomic_load_p(&n->alloc_edata, ATOMIC_ACQUIRE);
-}
-
-edata_t *
-prof_recent_alloc_edata_get_no_lock_test(const prof_recent_t *n) {
- cassert(config_prof);
- return prof_recent_alloc_edata_get_no_lock(n);
-}
-
-static inline edata_t *
-prof_recent_alloc_edata_get(tsd_t *tsd, const prof_recent_t *n) {
- malloc_mutex_assert_owner(tsd_tsdn(tsd), &prof_recent_alloc_mtx);
- return prof_recent_alloc_edata_get_no_lock(n);
-}
-
-static void
-prof_recent_alloc_edata_set(tsd_t *tsd, prof_recent_t *n, edata_t *edata) {
- malloc_mutex_assert_owner(tsd_tsdn(tsd), &prof_recent_alloc_mtx);
- atomic_store_p(&n->alloc_edata, edata, ATOMIC_RELEASE);
-}
-
-void
-edata_prof_recent_alloc_init(edata_t *edata) {
- cassert(config_prof);
- edata_prof_recent_alloc_set_dont_call_directly(edata, NULL);
-}
-
-static inline prof_recent_t *
-edata_prof_recent_alloc_get_no_lock(const edata_t *edata) {
- cassert(config_prof);
- return edata_prof_recent_alloc_get_dont_call_directly(edata);
-}
-
-prof_recent_t *
-edata_prof_recent_alloc_get_no_lock_test(const edata_t *edata) {
- cassert(config_prof);
- return edata_prof_recent_alloc_get_no_lock(edata);
-}
-
-static inline prof_recent_t *
-edata_prof_recent_alloc_get(tsd_t *tsd, const edata_t *edata) {
- malloc_mutex_assert_owner(tsd_tsdn(tsd), &prof_recent_alloc_mtx);
- prof_recent_t *recent_alloc =
- edata_prof_recent_alloc_get_no_lock(edata);
- assert(recent_alloc == NULL ||
- prof_recent_alloc_edata_get(tsd, recent_alloc) == edata);
- return recent_alloc;
-}
-
-static prof_recent_t *
-edata_prof_recent_alloc_update_internal(tsd_t *tsd, edata_t *edata,
- prof_recent_t *recent_alloc) {
- malloc_mutex_assert_owner(tsd_tsdn(tsd), &prof_recent_alloc_mtx);
- prof_recent_t *old_recent_alloc =
- edata_prof_recent_alloc_get(tsd, edata);
- edata_prof_recent_alloc_set_dont_call_directly(edata, recent_alloc);
- return old_recent_alloc;
-}
-
-static void
-edata_prof_recent_alloc_set(tsd_t *tsd, edata_t *edata,
- prof_recent_t *recent_alloc) {
- malloc_mutex_assert_owner(tsd_tsdn(tsd), &prof_recent_alloc_mtx);
- assert(recent_alloc != NULL);
- prof_recent_t *old_recent_alloc =
- edata_prof_recent_alloc_update_internal(tsd, edata, recent_alloc);
- assert(old_recent_alloc == NULL);
- prof_recent_alloc_edata_set(tsd, recent_alloc, edata);
-}
-
-static void
-edata_prof_recent_alloc_reset(tsd_t *tsd, edata_t *edata,
- prof_recent_t *recent_alloc) {
- malloc_mutex_assert_owner(tsd_tsdn(tsd), &prof_recent_alloc_mtx);
- assert(recent_alloc != NULL);
- prof_recent_t *old_recent_alloc =
- edata_prof_recent_alloc_update_internal(tsd, edata, NULL);
- assert(old_recent_alloc == recent_alloc);
- assert(edata == prof_recent_alloc_edata_get(tsd, recent_alloc));
- prof_recent_alloc_edata_set(tsd, recent_alloc, NULL);
-}
-
-/*
- * This function should be called right before an allocation is released, so
- * that the associated recent allocation record can contain the following
- * information:
- * (1) The allocation is released;
- * (2) The time of the deallocation; and
- * (3) The prof_tctx associated with the deallocation.
- */
-void
-prof_recent_alloc_reset(tsd_t *tsd, edata_t *edata) {
- cassert(config_prof);
- /*
- * Check whether the recent allocation record still exists without
- * trying to acquire the lock.
- */
- if (edata_prof_recent_alloc_get_no_lock(edata) == NULL) {
- return;
- }
-
- prof_tctx_t *dalloc_tctx = prof_tctx_create(tsd);
- /*
- * In case dalloc_tctx is NULL, e.g. due to OOM, we will not record the
- * deallocation time / tctx, which is handled later, after we check
- * again when holding the lock.
- */
-
- if (dalloc_tctx != NULL) {
- malloc_mutex_lock(tsd_tsdn(tsd), dalloc_tctx->tdata->lock);
- increment_recent_count(tsd, dalloc_tctx);
- dalloc_tctx->prepared = false;
- malloc_mutex_unlock(tsd_tsdn(tsd), dalloc_tctx->tdata->lock);
- }
-
- malloc_mutex_lock(tsd_tsdn(tsd), &prof_recent_alloc_mtx);
- /* Check again after acquiring the lock. */
- prof_recent_t *recent = edata_prof_recent_alloc_get(tsd, edata);
- if (recent != NULL) {
- assert(nstime_equals_zero(&recent->dalloc_time));
- assert(recent->dalloc_tctx == NULL);
- if (dalloc_tctx != NULL) {
- nstime_prof_update(&recent->dalloc_time);
- recent->dalloc_tctx = dalloc_tctx;
- dalloc_tctx = NULL;
- }
- edata_prof_recent_alloc_reset(tsd, edata, recent);
- }
- malloc_mutex_unlock(tsd_tsdn(tsd), &prof_recent_alloc_mtx);
-
- if (dalloc_tctx != NULL) {
- /* We lost the rase - the allocation record was just gone. */
- decrement_recent_count(tsd, dalloc_tctx);
- }
-}
-
-static void
-prof_recent_alloc_evict_edata(tsd_t *tsd, prof_recent_t *recent_alloc) {
- malloc_mutex_assert_owner(tsd_tsdn(tsd), &prof_recent_alloc_mtx);
- edata_t *edata = prof_recent_alloc_edata_get(tsd, recent_alloc);
- if (edata != NULL) {
- edata_prof_recent_alloc_reset(tsd, edata, recent_alloc);
- }
-}
-
-static bool
-prof_recent_alloc_is_empty(tsd_t *tsd) {
- malloc_mutex_assert_owner(tsd_tsdn(tsd), &prof_recent_alloc_mtx);
- if (ql_empty(&prof_recent_alloc_list)) {
- assert(prof_recent_alloc_count == 0);
- return true;
- } else {
- assert(prof_recent_alloc_count > 0);
- return false;
- }
-}
-
-static void
-prof_recent_alloc_assert_count(tsd_t *tsd) {
- malloc_mutex_assert_owner(tsd_tsdn(tsd), &prof_recent_alloc_mtx);
- if (!config_debug) {
- return;
- }
- ssize_t count = 0;
- prof_recent_t *n;
- ql_foreach(n, &prof_recent_alloc_list, link) {
- ++count;
- }
- assert(count == prof_recent_alloc_count);
- assert(prof_recent_alloc_max_get(tsd) == -1 ||
- count <= prof_recent_alloc_max_get(tsd));
-}
-
-void
-prof_recent_alloc(tsd_t *tsd, edata_t *edata, size_t size, size_t usize) {
- cassert(config_prof);
- assert(edata != NULL);
- prof_tctx_t *tctx = edata_prof_tctx_get(edata);
-
- malloc_mutex_assert_not_owner(tsd_tsdn(tsd), tctx->tdata->lock);
- malloc_mutex_lock(tsd_tsdn(tsd), &prof_recent_alloc_mtx);
- prof_recent_alloc_assert_count(tsd);
-
- /*
- * Reserve a new prof_recent_t node if needed. If needed, we release
- * the prof_recent_alloc_mtx lock and allocate. Then, rather than
- * immediately checking for OOM, we regain the lock and try to make use
- * of the reserve node if needed. There are six scenarios:
- *
- * \ now | no need | need but OOMed | need and allocated
- * later \ | | |
- * ------------------------------------------------------------
- * no need | (1) | (2) | (3)
- * ------------------------------------------------------------
- * need | (4) | (5) | (6)
- *
- * First, "(4)" never happens, because we don't release the lock in the
- * middle if there's no need for a new node; in such cases "(1)" always
- * takes place, which is trivial.
- *
- * Out of the remaining four scenarios, "(6)" is the common case and is
- * trivial. "(5)" is also trivial, in which case we'll rollback the
- * effect of prof_recent_alloc_prepare() as expected.
- *
- * "(2)" / "(3)" occurs when the need for a new node is gone after we
- * regain the lock. If the new node is successfully allocated, i.e. in
- * the case of "(3)", we'll release it in the end; otherwise, i.e. in
- * the case of "(2)", we do nothing - we're lucky that the OOM ends up
- * doing no harm at all.
- *
- * Therefore, the only performance cost of the "release lock" ->
- * "allocate" -> "regain lock" design is the "(3)" case, but it happens
- * very rarely, so the cost is relatively small compared to the gain of
- * not having to have the lock order of prof_recent_alloc_mtx above all
- * the allocation locks.
- */
- prof_recent_t *reserve = NULL;
- if (prof_recent_alloc_max_get(tsd) == -1 ||
- prof_recent_alloc_count < prof_recent_alloc_max_get(tsd)) {
- assert(prof_recent_alloc_max_get(tsd) != 0);
- malloc_mutex_unlock(tsd_tsdn(tsd), &prof_recent_alloc_mtx);
- reserve = prof_recent_allocate_node(tsd_tsdn(tsd));
- malloc_mutex_lock(tsd_tsdn(tsd), &prof_recent_alloc_mtx);
- prof_recent_alloc_assert_count(tsd);
- }
-
- if (prof_recent_alloc_max_get(tsd) == 0) {
- assert(prof_recent_alloc_is_empty(tsd));
- goto label_rollback;
- }
-
- prof_tctx_t *old_alloc_tctx, *old_dalloc_tctx;
- if (prof_recent_alloc_count == prof_recent_alloc_max_get(tsd)) {
- /* If upper limit is reached, rotate the head. */
- assert(prof_recent_alloc_max_get(tsd) != -1);
- assert(!prof_recent_alloc_is_empty(tsd));
- prof_recent_t *head = ql_first(&prof_recent_alloc_list);
- old_alloc_tctx = head->alloc_tctx;
- assert(old_alloc_tctx != NULL);
- old_dalloc_tctx = head->dalloc_tctx;
- prof_recent_alloc_evict_edata(tsd, head);
- ql_rotate(&prof_recent_alloc_list, link);
- } else {
- /* Otherwise make use of the new node. */
- assert(prof_recent_alloc_max_get(tsd) == -1 ||
- prof_recent_alloc_count < prof_recent_alloc_max_get(tsd));
- if (reserve == NULL) {
- goto label_rollback;
- }
- ql_elm_new(reserve, link);
- ql_tail_insert(&prof_recent_alloc_list, reserve, link);
- reserve = NULL;
- old_alloc_tctx = NULL;
- old_dalloc_tctx = NULL;
- ++prof_recent_alloc_count;
- }
-
- /* Fill content into the tail node. */
- prof_recent_t *tail = ql_last(&prof_recent_alloc_list, link);
- assert(tail != NULL);
- tail->size = size;
- tail->usize = usize;
- nstime_copy(&tail->alloc_time, edata_prof_alloc_time_get(edata));
- tail->alloc_tctx = tctx;
- nstime_init_zero(&tail->dalloc_time);
- tail->dalloc_tctx = NULL;
- edata_prof_recent_alloc_set(tsd, edata, tail);
-
- assert(!prof_recent_alloc_is_empty(tsd));
- prof_recent_alloc_assert_count(tsd);
- malloc_mutex_unlock(tsd_tsdn(tsd), &prof_recent_alloc_mtx);
-
- if (reserve != NULL) {
- prof_recent_free_node(tsd_tsdn(tsd), reserve);
- }
-
- /*
- * Asynchronously handle the tctx of the old node, so that there's no
- * simultaneous holdings of prof_recent_alloc_mtx and tdata->lock.
- * In the worst case this may delay the tctx release but it's better
- * than holding prof_recent_alloc_mtx for longer.
- */
- if (old_alloc_tctx != NULL) {
- decrement_recent_count(tsd, old_alloc_tctx);
- }
- if (old_dalloc_tctx != NULL) {
- decrement_recent_count(tsd, old_dalloc_tctx);
- }
- return;
-
-label_rollback:
- assert(edata_prof_recent_alloc_get(tsd, edata) == NULL);
- prof_recent_alloc_assert_count(tsd);
- malloc_mutex_unlock(tsd_tsdn(tsd), &prof_recent_alloc_mtx);
- if (reserve != NULL) {
- prof_recent_free_node(tsd_tsdn(tsd), reserve);
- }
- decrement_recent_count(tsd, tctx);
-}
-
-ssize_t
-prof_recent_alloc_max_ctl_read() {
- cassert(config_prof);
- /* Don't bother to acquire the lock. */
- return prof_recent_alloc_max_get_no_lock();
-}
-
-static void
-prof_recent_alloc_restore_locked(tsd_t *tsd, prof_recent_list_t *to_delete) {
- malloc_mutex_assert_owner(tsd_tsdn(tsd), &prof_recent_alloc_mtx);
- ssize_t max = prof_recent_alloc_max_get(tsd);
- if (max == -1 || prof_recent_alloc_count <= max) {
- /* Easy case - no need to alter the list. */
- ql_new(to_delete);
- prof_recent_alloc_assert_count(tsd);
- return;
- }
-
- prof_recent_t *node;
- ql_foreach(node, &prof_recent_alloc_list, link) {
- if (prof_recent_alloc_count == max) {
- break;
- }
- prof_recent_alloc_evict_edata(tsd, node);
- --prof_recent_alloc_count;
- }
- assert(prof_recent_alloc_count == max);
-
- ql_move(to_delete, &prof_recent_alloc_list);
- if (max == 0) {
- assert(node == NULL);
- } else {
- assert(node != NULL);
- ql_split(to_delete, node, &prof_recent_alloc_list, link);
- }
- assert(!ql_empty(to_delete));
- prof_recent_alloc_assert_count(tsd);
-}
-
-static void
-prof_recent_alloc_async_cleanup(tsd_t *tsd, prof_recent_list_t *to_delete) {
- malloc_mutex_assert_not_owner(tsd_tsdn(tsd), &prof_recent_dump_mtx);
- malloc_mutex_assert_not_owner(tsd_tsdn(tsd), &prof_recent_alloc_mtx);
- while (!ql_empty(to_delete)) {
- prof_recent_t *node = ql_first(to_delete);
- ql_remove(to_delete, node, link);
- decrement_recent_count(tsd, node->alloc_tctx);
- if (node->dalloc_tctx != NULL) {
- decrement_recent_count(tsd, node->dalloc_tctx);
- }
- prof_recent_free_node(tsd_tsdn(tsd), node);
- }
-}
-
-ssize_t
-prof_recent_alloc_max_ctl_write(tsd_t *tsd, ssize_t max) {
- cassert(config_prof);
- assert(max >= -1);
- malloc_mutex_lock(tsd_tsdn(tsd), &prof_recent_alloc_mtx);
- prof_recent_alloc_assert_count(tsd);
- const ssize_t old_max = prof_recent_alloc_max_update(tsd, max);
- prof_recent_list_t to_delete;
- prof_recent_alloc_restore_locked(tsd, &to_delete);
- malloc_mutex_unlock(tsd_tsdn(tsd), &prof_recent_alloc_mtx);
- prof_recent_alloc_async_cleanup(tsd, &to_delete);
- return old_max;
-}
-
-static void
-prof_recent_alloc_dump_bt(emitter_t *emitter, prof_tctx_t *tctx) {
- char bt_buf[2 * sizeof(intptr_t) + 3];
- char *s = bt_buf;
- assert(tctx != NULL);
- prof_bt_t *bt = &tctx->gctx->bt;
- for (size_t i = 0; i < bt->len; ++i) {
- malloc_snprintf(bt_buf, sizeof(bt_buf), "%p", bt->vec[i]);
- emitter_json_value(emitter, emitter_type_string, &s);
- }
-}
-
-static void
-prof_recent_alloc_dump_node(emitter_t *emitter, prof_recent_t *node) {
- emitter_json_object_begin(emitter);
-
- emitter_json_kv(emitter, "size", emitter_type_size, &node->size);
- emitter_json_kv(emitter, "usize", emitter_type_size, &node->usize);
- bool released = prof_recent_alloc_edata_get_no_lock(node) == NULL;
- emitter_json_kv(emitter, "released", emitter_type_bool, &released);
-
- emitter_json_kv(emitter, "alloc_thread_uid", emitter_type_uint64,
- &node->alloc_tctx->thr_uid);
- prof_tdata_t *alloc_tdata = node->alloc_tctx->tdata;
- assert(alloc_tdata != NULL);
- if (alloc_tdata->thread_name != NULL) {
- emitter_json_kv(emitter, "alloc_thread_name",
- emitter_type_string, &alloc_tdata->thread_name);
- }
- uint64_t alloc_time_ns = nstime_ns(&node->alloc_time);
- emitter_json_kv(emitter, "alloc_time", emitter_type_uint64,
- &alloc_time_ns);
- emitter_json_array_kv_begin(emitter, "alloc_trace");
- prof_recent_alloc_dump_bt(emitter, node->alloc_tctx);
- emitter_json_array_end(emitter);
-
- if (released && node->dalloc_tctx != NULL) {
- emitter_json_kv(emitter, "dalloc_thread_uid",
- emitter_type_uint64, &node->dalloc_tctx->thr_uid);
- prof_tdata_t *dalloc_tdata = node->dalloc_tctx->tdata;
- assert(dalloc_tdata != NULL);
- if (dalloc_tdata->thread_name != NULL) {
- emitter_json_kv(emitter, "dalloc_thread_name",
- emitter_type_string, &dalloc_tdata->thread_name);
- }
- assert(!nstime_equals_zero(&node->dalloc_time));
- uint64_t dalloc_time_ns = nstime_ns(&node->dalloc_time);
- emitter_json_kv(emitter, "dalloc_time", emitter_type_uint64,
- &dalloc_time_ns);
- emitter_json_array_kv_begin(emitter, "dalloc_trace");
- prof_recent_alloc_dump_bt(emitter, node->dalloc_tctx);
- emitter_json_array_end(emitter);
- }
-
- emitter_json_object_end(emitter);
-}
-
-#define PROF_RECENT_PRINT_BUFSIZE 65536
-JEMALLOC_COLD
-void
-prof_recent_alloc_dump(tsd_t *tsd, write_cb_t *write_cb, void *cbopaque) {
- cassert(config_prof);
- malloc_mutex_lock(tsd_tsdn(tsd), &prof_recent_dump_mtx);
- buf_writer_t buf_writer;
- buf_writer_init(tsd_tsdn(tsd), &buf_writer, write_cb, cbopaque, NULL,
- PROF_RECENT_PRINT_BUFSIZE);
- emitter_t emitter;
- emitter_init(&emitter, emitter_output_json_compact, buf_writer_cb,
- &buf_writer);
- prof_recent_list_t temp_list;
-
- malloc_mutex_lock(tsd_tsdn(tsd), &prof_recent_alloc_mtx);
- prof_recent_alloc_assert_count(tsd);
- ssize_t dump_max = prof_recent_alloc_max_get(tsd);
- ql_move(&temp_list, &prof_recent_alloc_list);
- ssize_t dump_count = prof_recent_alloc_count;
- prof_recent_alloc_count = 0;
- prof_recent_alloc_assert_count(tsd);
- malloc_mutex_unlock(tsd_tsdn(tsd), &prof_recent_alloc_mtx);
-
- emitter_begin(&emitter);
- uint64_t sample_interval = (uint64_t)1U << lg_prof_sample;
- emitter_json_kv(&emitter, "sample_interval", emitter_type_uint64,
- &sample_interval);
- emitter_json_kv(&emitter, "recent_alloc_max", emitter_type_ssize,
- &dump_max);
- emitter_json_array_kv_begin(&emitter, "recent_alloc");
- prof_recent_t *node;
- ql_foreach(node, &temp_list, link) {
- prof_recent_alloc_dump_node(&emitter, node);
- }
- emitter_json_array_end(&emitter);
- emitter_end(&emitter);
-
- malloc_mutex_lock(tsd_tsdn(tsd), &prof_recent_alloc_mtx);
- prof_recent_alloc_assert_count(tsd);
- ql_concat(&temp_list, &prof_recent_alloc_list, link);
- ql_move(&prof_recent_alloc_list, &temp_list);
- prof_recent_alloc_count += dump_count;
- prof_recent_alloc_restore_locked(tsd, &temp_list);
- malloc_mutex_unlock(tsd_tsdn(tsd), &prof_recent_alloc_mtx);
-
- buf_writer_terminate(tsd_tsdn(tsd), &buf_writer);
- malloc_mutex_unlock(tsd_tsdn(tsd), &prof_recent_dump_mtx);
-
- prof_recent_alloc_async_cleanup(tsd, &temp_list);
-}
-#undef PROF_RECENT_PRINT_BUFSIZE
-
-bool
-prof_recent_init() {
- cassert(config_prof);
- prof_recent_alloc_max_init();
-
- if (malloc_mutex_init(&prof_recent_alloc_mtx, "prof_recent_alloc",
- WITNESS_RANK_PROF_RECENT_ALLOC, malloc_mutex_rank_exclusive)) {
- return true;
- }
-
- if (malloc_mutex_init(&prof_recent_dump_mtx, "prof_recent_dump",
- WITNESS_RANK_PROF_RECENT_DUMP, malloc_mutex_rank_exclusive)) {
- return true;
- }
-
- ql_new(&prof_recent_alloc_list);
-
- return false;
-}
diff --git a/fluent-bit/lib/jemalloc-5.3.0/src/prof_stats.c b/fluent-bit/lib/jemalloc-5.3.0/src/prof_stats.c
deleted file mode 100644
index 5d1a506b..00000000
--- a/fluent-bit/lib/jemalloc-5.3.0/src/prof_stats.c
+++ /dev/null
@@ -1,57 +0,0 @@
-#include "jemalloc/internal/jemalloc_preamble.h"
-#include "jemalloc/internal/jemalloc_internal_includes.h"
-
-#include "jemalloc/internal/prof_stats.h"
-
-bool opt_prof_stats = false;
-malloc_mutex_t prof_stats_mtx;
-static prof_stats_t prof_stats_live[PROF_SC_NSIZES];
-static prof_stats_t prof_stats_accum[PROF_SC_NSIZES];
-
-static void
-prof_stats_enter(tsd_t *tsd, szind_t ind) {
- assert(opt_prof && opt_prof_stats);
- assert(ind < SC_NSIZES);
- malloc_mutex_lock(tsd_tsdn(tsd), &prof_stats_mtx);
-}
-
-static void
-prof_stats_leave(tsd_t *tsd) {
- malloc_mutex_unlock(tsd_tsdn(tsd), &prof_stats_mtx);
-}
-
-void
-prof_stats_inc(tsd_t *tsd, szind_t ind, size_t size) {
- cassert(config_prof);
- prof_stats_enter(tsd, ind);
- prof_stats_live[ind].req_sum += size;
- prof_stats_live[ind].count++;
- prof_stats_accum[ind].req_sum += size;
- prof_stats_accum[ind].count++;
- prof_stats_leave(tsd);
-}
-
-void
-prof_stats_dec(tsd_t *tsd, szind_t ind, size_t size) {
- cassert(config_prof);
- prof_stats_enter(tsd, ind);
- prof_stats_live[ind].req_sum -= size;
- prof_stats_live[ind].count--;
- prof_stats_leave(tsd);
-}
-
-void
-prof_stats_get_live(tsd_t *tsd, szind_t ind, prof_stats_t *stats) {
- cassert(config_prof);
- prof_stats_enter(tsd, ind);
- memcpy(stats, &prof_stats_live[ind], sizeof(prof_stats_t));
- prof_stats_leave(tsd);
-}
-
-void
-prof_stats_get_accum(tsd_t *tsd, szind_t ind, prof_stats_t *stats) {
- cassert(config_prof);
- prof_stats_enter(tsd, ind);
- memcpy(stats, &prof_stats_accum[ind], sizeof(prof_stats_t));
- prof_stats_leave(tsd);
-}
diff --git a/fluent-bit/lib/jemalloc-5.3.0/src/prof_sys.c b/fluent-bit/lib/jemalloc-5.3.0/src/prof_sys.c
deleted file mode 100644
index b5f1f5b2..00000000
--- a/fluent-bit/lib/jemalloc-5.3.0/src/prof_sys.c
+++ /dev/null
@@ -1,669 +0,0 @@
-#define JEMALLOC_PROF_SYS_C_
-#include "jemalloc/internal/jemalloc_preamble.h"
-#include "jemalloc/internal/jemalloc_internal_includes.h"
-
-#include "jemalloc/internal/buf_writer.h"
-#include "jemalloc/internal/ctl.h"
-#include "jemalloc/internal/prof_data.h"
-#include "jemalloc/internal/prof_sys.h"
-
-#ifdef JEMALLOC_PROF_LIBUNWIND
-#define UNW_LOCAL_ONLY
-#include <libunwind.h>
-#endif
-
-#ifdef JEMALLOC_PROF_LIBGCC
-/*
- * We have a circular dependency -- jemalloc_internal.h tells us if we should
- * use libgcc's unwinding functionality, but after we've included that, we've
- * already hooked _Unwind_Backtrace. We'll temporarily disable hooking.
- */
-#undef _Unwind_Backtrace
-#include <unwind.h>
-#define _Unwind_Backtrace JEMALLOC_TEST_HOOK(_Unwind_Backtrace, test_hooks_libc_hook)
-#endif
-
-/******************************************************************************/
-
-malloc_mutex_t prof_dump_filename_mtx;
-
-bool prof_do_mock = false;
-
-static uint64_t prof_dump_seq;
-static uint64_t prof_dump_iseq;
-static uint64_t prof_dump_mseq;
-static uint64_t prof_dump_useq;
-
-static char *prof_prefix = NULL;
-
-/* The fallback allocator profiling functionality will use. */
-base_t *prof_base;
-
-void
-bt_init(prof_bt_t *bt, void **vec) {
- cassert(config_prof);
-
- bt->vec = vec;
- bt->len = 0;
-}
-
-#ifdef JEMALLOC_PROF_LIBUNWIND
-static void
-prof_backtrace_impl(void **vec, unsigned *len, unsigned max_len) {
- int nframes;
-
- cassert(config_prof);
- assert(*len == 0);
- assert(vec != NULL);
- assert(max_len == PROF_BT_MAX);
-
- nframes = unw_backtrace(vec, PROF_BT_MAX);
- if (nframes <= 0) {
- return;
- }
- *len = nframes;
-}
-#elif (defined(JEMALLOC_PROF_LIBGCC))
-static _Unwind_Reason_Code
-prof_unwind_init_callback(struct _Unwind_Context *context, void *arg) {
- cassert(config_prof);
-
- return _URC_NO_REASON;
-}
-
-static _Unwind_Reason_Code
-prof_unwind_callback(struct _Unwind_Context *context, void *arg) {
- prof_unwind_data_t *data = (prof_unwind_data_t *)arg;
- void *ip;
-
- cassert(config_prof);
-
- ip = (void *)_Unwind_GetIP(context);
- if (ip == NULL) {
- return _URC_END_OF_STACK;
- }
- data->vec[*data->len] = ip;
- (*data->len)++;
- if (*data->len == data->max) {
- return _URC_END_OF_STACK;
- }
-
- return _URC_NO_REASON;
-}
-
-static void
-prof_backtrace_impl(void **vec, unsigned *len, unsigned max_len) {
- prof_unwind_data_t data = {vec, len, max_len};
-
- cassert(config_prof);
- assert(vec != NULL);
- assert(max_len == PROF_BT_MAX);
-
- _Unwind_Backtrace(prof_unwind_callback, &data);
-}
-#elif (defined(JEMALLOC_PROF_GCC))
-static void
-prof_backtrace_impl(void **vec, unsigned *len, unsigned max_len) {
-#define BT_FRAME(i) \
- if ((i) < max_len) { \
- void *p; \
- if (__builtin_frame_address(i) == 0) { \
- return; \
- } \
- p = __builtin_return_address(i); \
- if (p == NULL) { \
- return; \
- } \
- vec[(i)] = p; \
- *len = (i) + 1; \
- } else { \
- return; \
- }
-
- cassert(config_prof);
- assert(vec != NULL);
- assert(max_len == PROF_BT_MAX);
-
- BT_FRAME(0)
- BT_FRAME(1)
- BT_FRAME(2)
- BT_FRAME(3)
- BT_FRAME(4)
- BT_FRAME(5)
- BT_FRAME(6)
- BT_FRAME(7)
- BT_FRAME(8)
- BT_FRAME(9)
-
- BT_FRAME(10)
- BT_FRAME(11)
- BT_FRAME(12)
- BT_FRAME(13)
- BT_FRAME(14)
- BT_FRAME(15)
- BT_FRAME(16)
- BT_FRAME(17)
- BT_FRAME(18)
- BT_FRAME(19)
-
- BT_FRAME(20)
- BT_FRAME(21)
- BT_FRAME(22)
- BT_FRAME(23)
- BT_FRAME(24)
- BT_FRAME(25)
- BT_FRAME(26)
- BT_FRAME(27)
- BT_FRAME(28)
- BT_FRAME(29)
-
- BT_FRAME(30)
- BT_FRAME(31)
- BT_FRAME(32)
- BT_FRAME(33)
- BT_FRAME(34)
- BT_FRAME(35)
- BT_FRAME(36)
- BT_FRAME(37)
- BT_FRAME(38)
- BT_FRAME(39)
-
- BT_FRAME(40)
- BT_FRAME(41)
- BT_FRAME(42)
- BT_FRAME(43)
- BT_FRAME(44)
- BT_FRAME(45)
- BT_FRAME(46)
- BT_FRAME(47)
- BT_FRAME(48)
- BT_FRAME(49)
-
- BT_FRAME(50)
- BT_FRAME(51)
- BT_FRAME(52)
- BT_FRAME(53)
- BT_FRAME(54)
- BT_FRAME(55)
- BT_FRAME(56)
- BT_FRAME(57)
- BT_FRAME(58)
- BT_FRAME(59)
-
- BT_FRAME(60)
- BT_FRAME(61)
- BT_FRAME(62)
- BT_FRAME(63)
- BT_FRAME(64)
- BT_FRAME(65)
- BT_FRAME(66)
- BT_FRAME(67)
- BT_FRAME(68)
- BT_FRAME(69)
-
- BT_FRAME(70)
- BT_FRAME(71)
- BT_FRAME(72)
- BT_FRAME(73)
- BT_FRAME(74)
- BT_FRAME(75)
- BT_FRAME(76)
- BT_FRAME(77)
- BT_FRAME(78)
- BT_FRAME(79)
-
- BT_FRAME(80)
- BT_FRAME(81)
- BT_FRAME(82)
- BT_FRAME(83)
- BT_FRAME(84)
- BT_FRAME(85)
- BT_FRAME(86)
- BT_FRAME(87)
- BT_FRAME(88)
- BT_FRAME(89)
-
- BT_FRAME(90)
- BT_FRAME(91)
- BT_FRAME(92)
- BT_FRAME(93)
- BT_FRAME(94)
- BT_FRAME(95)
- BT_FRAME(96)
- BT_FRAME(97)
- BT_FRAME(98)
- BT_FRAME(99)
-
- BT_FRAME(100)
- BT_FRAME(101)
- BT_FRAME(102)
- BT_FRAME(103)
- BT_FRAME(104)
- BT_FRAME(105)
- BT_FRAME(106)
- BT_FRAME(107)
- BT_FRAME(108)
- BT_FRAME(109)
-
- BT_FRAME(110)
- BT_FRAME(111)
- BT_FRAME(112)
- BT_FRAME(113)
- BT_FRAME(114)
- BT_FRAME(115)
- BT_FRAME(116)
- BT_FRAME(117)
- BT_FRAME(118)
- BT_FRAME(119)
-
- BT_FRAME(120)
- BT_FRAME(121)
- BT_FRAME(122)
- BT_FRAME(123)
- BT_FRAME(124)
- BT_FRAME(125)
- BT_FRAME(126)
- BT_FRAME(127)
-#undef BT_FRAME
-}
-#else
-static void
-prof_backtrace_impl(void **vec, unsigned *len, unsigned max_len) {
- cassert(config_prof);
- not_reached();
-}
-#endif
-
-void
-prof_backtrace(tsd_t *tsd, prof_bt_t *bt) {
- cassert(config_prof);
- prof_backtrace_hook_t prof_backtrace_hook = prof_backtrace_hook_get();
- assert(prof_backtrace_hook != NULL);
-
- pre_reentrancy(tsd, NULL);
- prof_backtrace_hook(bt->vec, &bt->len, PROF_BT_MAX);
- post_reentrancy(tsd);
-}
-
-void
-prof_hooks_init() {
- prof_backtrace_hook_set(&prof_backtrace_impl);
- prof_dump_hook_set(NULL);
-}
-
-void
-prof_unwind_init() {
-#ifdef JEMALLOC_PROF_LIBGCC
- /*
- * Cause the backtracing machinery to allocate its internal
- * state before enabling profiling.
- */
- _Unwind_Backtrace(prof_unwind_init_callback, NULL);
-#endif
-}
-
-static int
-prof_sys_thread_name_read_impl(char *buf, size_t limit) {
-#if defined(JEMALLOC_HAVE_PTHREAD_GETNAME_NP)
- return pthread_getname_np(pthread_self(), buf, limit);
-#elif defined(JEMALLOC_HAVE_PTHREAD_GET_NAME_NP)
- pthread_get_name_np(pthread_self(), buf, limit);
- return 0;
-#else
- return ENOSYS;
-#endif
-}
-prof_sys_thread_name_read_t *JET_MUTABLE prof_sys_thread_name_read =
- prof_sys_thread_name_read_impl;
-
-void
-prof_sys_thread_name_fetch(tsd_t *tsd) {
-#define THREAD_NAME_MAX_LEN 16
- char buf[THREAD_NAME_MAX_LEN];
- if (!prof_sys_thread_name_read(buf, THREAD_NAME_MAX_LEN)) {
- prof_thread_name_set_impl(tsd, buf);
- }
-#undef THREAD_NAME_MAX_LEN
-}
-
-int
-prof_getpid(void) {
-#ifdef _WIN32
- return GetCurrentProcessId();
-#else
- return getpid();
-#endif
-}
-
-/*
- * This buffer is rather large for stack allocation, so use a single buffer for
- * all profile dumps; protected by prof_dump_mtx.
- */
-static char prof_dump_buf[PROF_DUMP_BUFSIZE];
-
-typedef struct prof_dump_arg_s prof_dump_arg_t;
-struct prof_dump_arg_s {
- /*
- * Whether error should be handled locally: if true, then we print out
- * error message as well as abort (if opt_abort is true) when an error
- * occurred, and we also report the error back to the caller in the end;
- * if false, then we only report the error back to the caller in the
- * end.
- */
- const bool handle_error_locally;
- /*
- * Whether there has been an error in the dumping process, which could
- * have happened either in file opening or in file writing. When an
- * error has already occurred, we will stop further writing to the file.
- */
- bool error;
- /* File descriptor of the dump file. */
- int prof_dump_fd;
-};
-
-static void
-prof_dump_check_possible_error(prof_dump_arg_t *arg, bool err_cond,
- const char *format, ...) {
- assert(!arg->error);
- if (!err_cond) {
- return;
- }
-
- arg->error = true;
- if (!arg->handle_error_locally) {
- return;
- }
-
- va_list ap;
- char buf[PROF_PRINTF_BUFSIZE];
- va_start(ap, format);
- malloc_vsnprintf(buf, sizeof(buf), format, ap);
- va_end(ap);
- malloc_write(buf);
-
- if (opt_abort) {
- abort();
- }
-}
-
-static int
-prof_dump_open_file_impl(const char *filename, int mode) {
- return creat(filename, mode);
-}
-prof_dump_open_file_t *JET_MUTABLE prof_dump_open_file =
- prof_dump_open_file_impl;
-
-static void
-prof_dump_open(prof_dump_arg_t *arg, const char *filename) {
- arg->prof_dump_fd = prof_dump_open_file(filename, 0644);
- prof_dump_check_possible_error(arg, arg->prof_dump_fd == -1,
- "<jemalloc>: failed to open \"%s\"\n", filename);
-}
-
-prof_dump_write_file_t *JET_MUTABLE prof_dump_write_file = malloc_write_fd;
-
-static void
-prof_dump_flush(void *opaque, const char *s) {
- cassert(config_prof);
- prof_dump_arg_t *arg = (prof_dump_arg_t *)opaque;
- if (!arg->error) {
- ssize_t err = prof_dump_write_file(arg->prof_dump_fd, s,
- strlen(s));
- prof_dump_check_possible_error(arg, err == -1,
- "<jemalloc>: failed to write during heap profile flush\n");
- }
-}
-
-static void
-prof_dump_close(prof_dump_arg_t *arg) {
- if (arg->prof_dump_fd != -1) {
- close(arg->prof_dump_fd);
- }
-}
-
-#ifndef _WIN32
-JEMALLOC_FORMAT_PRINTF(1, 2)
-static int
-prof_open_maps_internal(const char *format, ...) {
- int mfd;
- va_list ap;
- char filename[PATH_MAX + 1];
-
- va_start(ap, format);
- malloc_vsnprintf(filename, sizeof(filename), format, ap);
- va_end(ap);
-
-#if defined(O_CLOEXEC)
- mfd = open(filename, O_RDONLY | O_CLOEXEC);
-#else
- mfd = open(filename, O_RDONLY);
- if (mfd != -1) {
- fcntl(mfd, F_SETFD, fcntl(mfd, F_GETFD) | FD_CLOEXEC);
- }
-#endif
-
- return mfd;
-}
-#endif
-
-static int
-prof_dump_open_maps_impl() {
- int mfd;
-
- cassert(config_prof);
-#if defined(__FreeBSD__) || defined(__DragonFly__)
- mfd = prof_open_maps_internal("/proc/curproc/map");
-#elif defined(_WIN32)
- mfd = -1; // Not implemented
-#else
- int pid = prof_getpid();
-
- mfd = prof_open_maps_internal("/proc/%d/task/%d/maps", pid, pid);
- if (mfd == -1) {
- mfd = prof_open_maps_internal("/proc/%d/maps", pid);
- }
-#endif
- return mfd;
-}
-prof_dump_open_maps_t *JET_MUTABLE prof_dump_open_maps =
- prof_dump_open_maps_impl;
-
-static ssize_t
-prof_dump_read_maps_cb(void *read_cbopaque, void *buf, size_t limit) {
- int mfd = *(int *)read_cbopaque;
- assert(mfd != -1);
- return malloc_read_fd(mfd, buf, limit);
-}
-
-static void
-prof_dump_maps(buf_writer_t *buf_writer) {
- int mfd = prof_dump_open_maps();
- if (mfd == -1) {
- return;
- }
-
- buf_writer_cb(buf_writer, "\nMAPPED_LIBRARIES:\n");
- buf_writer_pipe(buf_writer, prof_dump_read_maps_cb, &mfd);
- close(mfd);
-}
-
-static bool
-prof_dump(tsd_t *tsd, bool propagate_err, const char *filename,
- bool leakcheck) {
- cassert(config_prof);
- assert(tsd_reentrancy_level_get(tsd) == 0);
-
- prof_tdata_t * tdata = prof_tdata_get(tsd, true);
- if (tdata == NULL) {
- return true;
- }
-
- prof_dump_arg_t arg = {/* handle_error_locally */ !propagate_err,
- /* error */ false, /* prof_dump_fd */ -1};
-
- pre_reentrancy(tsd, NULL);
- malloc_mutex_lock(tsd_tsdn(tsd), &prof_dump_mtx);
-
- prof_dump_open(&arg, filename);
- buf_writer_t buf_writer;
- bool err = buf_writer_init(tsd_tsdn(tsd), &buf_writer, prof_dump_flush,
- &arg, prof_dump_buf, PROF_DUMP_BUFSIZE);
- assert(!err);
- prof_dump_impl(tsd, buf_writer_cb, &buf_writer, tdata, leakcheck);
- prof_dump_maps(&buf_writer);
- buf_writer_terminate(tsd_tsdn(tsd), &buf_writer);
- prof_dump_close(&arg);
-
- prof_dump_hook_t dump_hook = prof_dump_hook_get();
- if (dump_hook != NULL) {
- dump_hook(filename);
- }
- malloc_mutex_unlock(tsd_tsdn(tsd), &prof_dump_mtx);
- post_reentrancy(tsd);
-
- return arg.error;
-}
-
-/*
- * If profiling is off, then PROF_DUMP_FILENAME_LEN is 1, so we'll end up
- * calling strncpy with a size of 0, which triggers a -Wstringop-truncation
- * warning (strncpy can never actually be called in this case, since we bail out
- * much earlier when config_prof is false). This function works around the
- * warning to let us leave the warning on.
- */
-static inline void
-prof_strncpy(char *UNUSED dest, const char *UNUSED src, size_t UNUSED size) {
- cassert(config_prof);
-#ifdef JEMALLOC_PROF
- strncpy(dest, src, size);
-#endif
-}
-
-static const char *
-prof_prefix_get(tsdn_t* tsdn) {
- malloc_mutex_assert_owner(tsdn, &prof_dump_filename_mtx);
-
- return prof_prefix == NULL ? opt_prof_prefix : prof_prefix;
-}
-
-static bool
-prof_prefix_is_empty(tsdn_t *tsdn) {
- malloc_mutex_lock(tsdn, &prof_dump_filename_mtx);
- bool ret = (prof_prefix_get(tsdn)[0] == '\0');
- malloc_mutex_unlock(tsdn, &prof_dump_filename_mtx);
- return ret;
-}
-
-#define DUMP_FILENAME_BUFSIZE (PATH_MAX + 1)
-#define VSEQ_INVALID UINT64_C(0xffffffffffffffff)
-static void
-prof_dump_filename(tsd_t *tsd, char *filename, char v, uint64_t vseq) {
- cassert(config_prof);
-
- assert(tsd_reentrancy_level_get(tsd) == 0);
- const char *prefix = prof_prefix_get(tsd_tsdn(tsd));
-
- if (vseq != VSEQ_INVALID) {
- /* "<prefix>.<pid>.<seq>.v<vseq>.heap" */
- malloc_snprintf(filename, DUMP_FILENAME_BUFSIZE,
- "%s.%d.%"FMTu64".%c%"FMTu64".heap", prefix, prof_getpid(),
- prof_dump_seq, v, vseq);
- } else {
- /* "<prefix>.<pid>.<seq>.<v>.heap" */
- malloc_snprintf(filename, DUMP_FILENAME_BUFSIZE,
- "%s.%d.%"FMTu64".%c.heap", prefix, prof_getpid(),
- prof_dump_seq, v);
- }
- prof_dump_seq++;
-}
-
-void
-prof_get_default_filename(tsdn_t *tsdn, char *filename, uint64_t ind) {
- malloc_mutex_lock(tsdn, &prof_dump_filename_mtx);
- malloc_snprintf(filename, PROF_DUMP_FILENAME_LEN,
- "%s.%d.%"FMTu64".json", prof_prefix_get(tsdn), prof_getpid(), ind);
- malloc_mutex_unlock(tsdn, &prof_dump_filename_mtx);
-}
-
-void
-prof_fdump_impl(tsd_t *tsd) {
- char filename[DUMP_FILENAME_BUFSIZE];
-
- assert(!prof_prefix_is_empty(tsd_tsdn(tsd)));
- malloc_mutex_lock(tsd_tsdn(tsd), &prof_dump_filename_mtx);
- prof_dump_filename(tsd, filename, 'f', VSEQ_INVALID);
- malloc_mutex_unlock(tsd_tsdn(tsd), &prof_dump_filename_mtx);
- prof_dump(tsd, false, filename, opt_prof_leak);
-}
-
-bool
-prof_prefix_set(tsdn_t *tsdn, const char *prefix) {
- cassert(config_prof);
- ctl_mtx_assert_held(tsdn);
- malloc_mutex_lock(tsdn, &prof_dump_filename_mtx);
- if (prof_prefix == NULL) {
- malloc_mutex_unlock(tsdn, &prof_dump_filename_mtx);
- /* Everything is still guarded by ctl_mtx. */
- char *buffer = base_alloc(tsdn, prof_base,
- PROF_DUMP_FILENAME_LEN, QUANTUM);
- if (buffer == NULL) {
- return true;
- }
- malloc_mutex_lock(tsdn, &prof_dump_filename_mtx);
- prof_prefix = buffer;
- }
- assert(prof_prefix != NULL);
-
- prof_strncpy(prof_prefix, prefix, PROF_DUMP_FILENAME_LEN - 1);
- prof_prefix[PROF_DUMP_FILENAME_LEN - 1] = '\0';
- malloc_mutex_unlock(tsdn, &prof_dump_filename_mtx);
-
- return false;
-}
-
-void
-prof_idump_impl(tsd_t *tsd) {
- malloc_mutex_lock(tsd_tsdn(tsd), &prof_dump_filename_mtx);
- if (prof_prefix_get(tsd_tsdn(tsd))[0] == '\0') {
- malloc_mutex_unlock(tsd_tsdn(tsd), &prof_dump_filename_mtx);
- return;
- }
- char filename[PATH_MAX + 1];
- prof_dump_filename(tsd, filename, 'i', prof_dump_iseq);
- prof_dump_iseq++;
- malloc_mutex_unlock(tsd_tsdn(tsd), &prof_dump_filename_mtx);
- prof_dump(tsd, false, filename, false);
-}
-
-bool
-prof_mdump_impl(tsd_t *tsd, const char *filename) {
- char filename_buf[DUMP_FILENAME_BUFSIZE];
- if (filename == NULL) {
- /* No filename specified, so automatically generate one. */
- malloc_mutex_lock(tsd_tsdn(tsd), &prof_dump_filename_mtx);
- if (prof_prefix_get(tsd_tsdn(tsd))[0] == '\0') {
- malloc_mutex_unlock(tsd_tsdn(tsd), &prof_dump_filename_mtx);
- return true;
- }
- prof_dump_filename(tsd, filename_buf, 'm', prof_dump_mseq);
- prof_dump_mseq++;
- malloc_mutex_unlock(tsd_tsdn(tsd), &prof_dump_filename_mtx);
- filename = filename_buf;
- }
- return prof_dump(tsd, true, filename, false);
-}
-
-void
-prof_gdump_impl(tsd_t *tsd) {
- tsdn_t *tsdn = tsd_tsdn(tsd);
- malloc_mutex_lock(tsdn, &prof_dump_filename_mtx);
- if (prof_prefix_get(tsdn)[0] == '\0') {
- malloc_mutex_unlock(tsdn, &prof_dump_filename_mtx);
- return;
- }
- char filename[DUMP_FILENAME_BUFSIZE];
- prof_dump_filename(tsd, filename, 'u', prof_dump_useq);
- prof_dump_useq++;
- malloc_mutex_unlock(tsdn, &prof_dump_filename_mtx);
- prof_dump(tsd, false, filename, false);
-}
diff --git a/fluent-bit/lib/jemalloc-5.3.0/src/psset.c b/fluent-bit/lib/jemalloc-5.3.0/src/psset.c
deleted file mode 100644
index 9a8f054f..00000000
--- a/fluent-bit/lib/jemalloc-5.3.0/src/psset.c
+++ /dev/null
@@ -1,385 +0,0 @@
-#include "jemalloc/internal/jemalloc_preamble.h"
-#include "jemalloc/internal/jemalloc_internal_includes.h"
-
-#include "jemalloc/internal/psset.h"
-
-#include "jemalloc/internal/fb.h"
-
-void
-psset_init(psset_t *psset) {
- for (unsigned i = 0; i < PSSET_NPSIZES; i++) {
- hpdata_age_heap_new(&psset->pageslabs[i]);
- }
- fb_init(psset->pageslab_bitmap, PSSET_NPSIZES);
- memset(&psset->merged_stats, 0, sizeof(psset->merged_stats));
- memset(&psset->stats, 0, sizeof(psset->stats));
- hpdata_empty_list_init(&psset->empty);
- for (int i = 0; i < PSSET_NPURGE_LISTS; i++) {
- hpdata_purge_list_init(&psset->to_purge[i]);
- }
- fb_init(psset->purge_bitmap, PSSET_NPURGE_LISTS);
- hpdata_hugify_list_init(&psset->to_hugify);
-}
-
-static void
-psset_bin_stats_accum(psset_bin_stats_t *dst, psset_bin_stats_t *src) {
- dst->npageslabs += src->npageslabs;
- dst->nactive += src->nactive;
- dst->ndirty += src->ndirty;
-}
-
-void
-psset_stats_accum(psset_stats_t *dst, psset_stats_t *src) {
- psset_bin_stats_accum(&dst->full_slabs[0], &src->full_slabs[0]);
- psset_bin_stats_accum(&dst->full_slabs[1], &src->full_slabs[1]);
- psset_bin_stats_accum(&dst->empty_slabs[0], &src->empty_slabs[0]);
- psset_bin_stats_accum(&dst->empty_slabs[1], &src->empty_slabs[1]);
- for (pszind_t i = 0; i < PSSET_NPSIZES; i++) {
- psset_bin_stats_accum(&dst->nonfull_slabs[i][0],
- &src->nonfull_slabs[i][0]);
- psset_bin_stats_accum(&dst->nonfull_slabs[i][1],
- &src->nonfull_slabs[i][1]);
- }
-}
-
-/*
- * The stats maintenance strategy is to remove a pageslab's contribution to the
- * stats when we call psset_update_begin, and re-add it (to a potentially new
- * bin) when we call psset_update_end.
- */
-JEMALLOC_ALWAYS_INLINE void
-psset_bin_stats_insert_remove(psset_t *psset, psset_bin_stats_t *binstats,
- hpdata_t *ps, bool insert) {
- size_t mul = insert ? (size_t)1 : (size_t)-1;
- size_t huge_idx = (size_t)hpdata_huge_get(ps);
-
- binstats[huge_idx].npageslabs += mul * 1;
- binstats[huge_idx].nactive += mul * hpdata_nactive_get(ps);
- binstats[huge_idx].ndirty += mul * hpdata_ndirty_get(ps);
-
- psset->merged_stats.npageslabs += mul * 1;
- psset->merged_stats.nactive += mul * hpdata_nactive_get(ps);
- psset->merged_stats.ndirty += mul * hpdata_ndirty_get(ps);
-
- if (config_debug) {
- psset_bin_stats_t check_stats = {0};
- for (size_t huge = 0; huge <= 1; huge++) {
- psset_bin_stats_accum(&check_stats,
- &psset->stats.full_slabs[huge]);
- psset_bin_stats_accum(&check_stats,
- &psset->stats.empty_slabs[huge]);
- for (pszind_t pind = 0; pind < PSSET_NPSIZES; pind++) {
- psset_bin_stats_accum(&check_stats,
- &psset->stats.nonfull_slabs[pind][huge]);
- }
- }
- assert(psset->merged_stats.npageslabs
- == check_stats.npageslabs);
- assert(psset->merged_stats.nactive == check_stats.nactive);
- assert(psset->merged_stats.ndirty == check_stats.ndirty);
- }
-}
-
-static void
-psset_bin_stats_insert(psset_t *psset, psset_bin_stats_t *binstats,
- hpdata_t *ps) {
- psset_bin_stats_insert_remove(psset, binstats, ps, true);
-}
-
-static void
-psset_bin_stats_remove(psset_t *psset, psset_bin_stats_t *binstats,
- hpdata_t *ps) {
- psset_bin_stats_insert_remove(psset, binstats, ps, false);
-}
-
-static void
-psset_hpdata_heap_remove(psset_t *psset, pszind_t pind, hpdata_t *ps) {
- hpdata_age_heap_remove(&psset->pageslabs[pind], ps);
- if (hpdata_age_heap_empty(&psset->pageslabs[pind])) {
- fb_unset(psset->pageslab_bitmap, PSSET_NPSIZES, (size_t)pind);
- }
-}
-
-static void
-psset_hpdata_heap_insert(psset_t *psset, pszind_t pind, hpdata_t *ps) {
- if (hpdata_age_heap_empty(&psset->pageslabs[pind])) {
- fb_set(psset->pageslab_bitmap, PSSET_NPSIZES, (size_t)pind);
- }
- hpdata_age_heap_insert(&psset->pageslabs[pind], ps);
-}
-
-static void
-psset_stats_insert(psset_t* psset, hpdata_t *ps) {
- if (hpdata_empty(ps)) {
- psset_bin_stats_insert(psset, psset->stats.empty_slabs, ps);
- } else if (hpdata_full(ps)) {
- psset_bin_stats_insert(psset, psset->stats.full_slabs, ps);
- } else {
- size_t longest_free_range = hpdata_longest_free_range_get(ps);
-
- pszind_t pind = sz_psz2ind(sz_psz_quantize_floor(
- longest_free_range << LG_PAGE));
- assert(pind < PSSET_NPSIZES);
-
- psset_bin_stats_insert(psset, psset->stats.nonfull_slabs[pind],
- ps);
- }
-}
-
-static void
-psset_stats_remove(psset_t *psset, hpdata_t *ps) {
- if (hpdata_empty(ps)) {
- psset_bin_stats_remove(psset, psset->stats.empty_slabs, ps);
- } else if (hpdata_full(ps)) {
- psset_bin_stats_remove(psset, psset->stats.full_slabs, ps);
- } else {
- size_t longest_free_range = hpdata_longest_free_range_get(ps);
-
- pszind_t pind = sz_psz2ind(sz_psz_quantize_floor(
- longest_free_range << LG_PAGE));
- assert(pind < PSSET_NPSIZES);
-
- psset_bin_stats_remove(psset, psset->stats.nonfull_slabs[pind],
- ps);
- }
-}
-
-/*
- * Put ps into some container so that it can be found during future allocation
- * requests.
- */
-static void
-psset_alloc_container_insert(psset_t *psset, hpdata_t *ps) {
- assert(!hpdata_in_psset_alloc_container_get(ps));
- hpdata_in_psset_alloc_container_set(ps, true);
- if (hpdata_empty(ps)) {
- /*
- * This prepend, paired with popping the head in psset_fit,
- * means we implement LIFO ordering for the empty slabs set,
- * which seems reasonable.
- */
- hpdata_empty_list_prepend(&psset->empty, ps);
- } else if (hpdata_full(ps)) {
- /*
- * We don't need to keep track of the full slabs; we're never
- * going to return them from a psset_pick_alloc call.
- */
- } else {
- size_t longest_free_range = hpdata_longest_free_range_get(ps);
-
- pszind_t pind = sz_psz2ind(sz_psz_quantize_floor(
- longest_free_range << LG_PAGE));
- assert(pind < PSSET_NPSIZES);
-
- psset_hpdata_heap_insert(psset, pind, ps);
- }
-}
-
-/* Remove ps from those collections. */
-static void
-psset_alloc_container_remove(psset_t *psset, hpdata_t *ps) {
- assert(hpdata_in_psset_alloc_container_get(ps));
- hpdata_in_psset_alloc_container_set(ps, false);
-
- if (hpdata_empty(ps)) {
- hpdata_empty_list_remove(&psset->empty, ps);
- } else if (hpdata_full(ps)) {
- /* Same as above -- do nothing in this case. */
- } else {
- size_t longest_free_range = hpdata_longest_free_range_get(ps);
-
- pszind_t pind = sz_psz2ind(sz_psz_quantize_floor(
- longest_free_range << LG_PAGE));
- assert(pind < PSSET_NPSIZES);
-
- psset_hpdata_heap_remove(psset, pind, ps);
- }
-}
-
-static size_t
-psset_purge_list_ind(hpdata_t *ps) {
- size_t ndirty = hpdata_ndirty_get(ps);
- /* Shouldn't have something with no dirty pages purgeable. */
- assert(ndirty > 0);
- /*
- * Higher indices correspond to lists we'd like to purge earlier; make
- * the two highest indices correspond to empty lists, which we attempt
- * to purge before purging any non-empty list. This has two advantages:
- * - Empty page slabs are the least likely to get reused (we'll only
- * pick them for an allocation if we have no other choice).
- * - Empty page slabs can purge every dirty page they contain in a
- * single call, which is not usually the case.
- *
- * We purge hugeified empty slabs before nonhugeified ones, on the basis
- * that they are fully dirty, while nonhugified slabs might not be, so
- * we free up more pages more easily.
- */
- if (hpdata_nactive_get(ps) == 0) {
- if (hpdata_huge_get(ps)) {
- return PSSET_NPURGE_LISTS - 1;
- } else {
- return PSSET_NPURGE_LISTS - 2;
- }
- }
-
- pszind_t pind = sz_psz2ind(sz_psz_quantize_floor(ndirty << LG_PAGE));
- /*
- * For non-empty slabs, we may reuse them again. Prefer purging
- * non-hugeified slabs before hugeified ones then, among pages of
- * similar dirtiness. We still get some benefit from the hugification.
- */
- return (size_t)pind * 2 + (hpdata_huge_get(ps) ? 0 : 1);
-}
-
-static void
-psset_maybe_remove_purge_list(psset_t *psset, hpdata_t *ps) {
- /*
- * Remove the hpdata from its purge list (if it's in one). Even if it's
- * going to stay in the same one, by appending it during
- * psset_update_end, we move it to the end of its queue, so that we
- * purge LRU within a given dirtiness bucket.
- */
- if (hpdata_purge_allowed_get(ps)) {
- size_t ind = psset_purge_list_ind(ps);
- hpdata_purge_list_t *purge_list = &psset->to_purge[ind];
- hpdata_purge_list_remove(purge_list, ps);
- if (hpdata_purge_list_empty(purge_list)) {
- fb_unset(psset->purge_bitmap, PSSET_NPURGE_LISTS, ind);
- }
- }
-}
-
-static void
-psset_maybe_insert_purge_list(psset_t *psset, hpdata_t *ps) {
- if (hpdata_purge_allowed_get(ps)) {
- size_t ind = psset_purge_list_ind(ps);
- hpdata_purge_list_t *purge_list = &psset->to_purge[ind];
- if (hpdata_purge_list_empty(purge_list)) {
- fb_set(psset->purge_bitmap, PSSET_NPURGE_LISTS, ind);
- }
- hpdata_purge_list_append(purge_list, ps);
- }
-
-}
-
-void
-psset_update_begin(psset_t *psset, hpdata_t *ps) {
- hpdata_assert_consistent(ps);
- assert(hpdata_in_psset_get(ps));
- hpdata_updating_set(ps, true);
- psset_stats_remove(psset, ps);
- if (hpdata_in_psset_alloc_container_get(ps)) {
- /*
- * Some metadata updates can break alloc container invariants
- * (e.g. the longest free range determines the hpdata_heap_t the
- * pageslab lives in).
- */
- assert(hpdata_alloc_allowed_get(ps));
- psset_alloc_container_remove(psset, ps);
- }
- psset_maybe_remove_purge_list(psset, ps);
- /*
- * We don't update presence in the hugify list; we try to keep it FIFO,
- * even in the presence of other metadata updates. We'll update
- * presence at the end of the metadata update if necessary.
- */
-}
-
-void
-psset_update_end(psset_t *psset, hpdata_t *ps) {
- assert(hpdata_in_psset_get(ps));
- hpdata_updating_set(ps, false);
- psset_stats_insert(psset, ps);
-
- /*
- * The update begin should have removed ps from whatever alloc container
- * it was in.
- */
- assert(!hpdata_in_psset_alloc_container_get(ps));
- if (hpdata_alloc_allowed_get(ps)) {
- psset_alloc_container_insert(psset, ps);
- }
- psset_maybe_insert_purge_list(psset, ps);
-
- if (hpdata_hugify_allowed_get(ps)
- && !hpdata_in_psset_hugify_container_get(ps)) {
- hpdata_in_psset_hugify_container_set(ps, true);
- hpdata_hugify_list_append(&psset->to_hugify, ps);
- } else if (!hpdata_hugify_allowed_get(ps)
- && hpdata_in_psset_hugify_container_get(ps)) {
- hpdata_in_psset_hugify_container_set(ps, false);
- hpdata_hugify_list_remove(&psset->to_hugify, ps);
- }
- hpdata_assert_consistent(ps);
-}
-
-hpdata_t *
-psset_pick_alloc(psset_t *psset, size_t size) {
- assert((size & PAGE_MASK) == 0);
- assert(size <= HUGEPAGE);
-
- pszind_t min_pind = sz_psz2ind(sz_psz_quantize_ceil(size));
- pszind_t pind = (pszind_t)fb_ffs(psset->pageslab_bitmap, PSSET_NPSIZES,
- (size_t)min_pind);
- if (pind == PSSET_NPSIZES) {
- return hpdata_empty_list_first(&psset->empty);
- }
- hpdata_t *ps = hpdata_age_heap_first(&psset->pageslabs[pind]);
- if (ps == NULL) {
- return NULL;
- }
-
- hpdata_assert_consistent(ps);
-
- return ps;
-}
-
-hpdata_t *
-psset_pick_purge(psset_t *psset) {
- ssize_t ind_ssz = fb_fls(psset->purge_bitmap, PSSET_NPURGE_LISTS,
- PSSET_NPURGE_LISTS - 1);
- if (ind_ssz < 0) {
- return NULL;
- }
- pszind_t ind = (pszind_t)ind_ssz;
- assert(ind < PSSET_NPURGE_LISTS);
- hpdata_t *ps = hpdata_purge_list_first(&psset->to_purge[ind]);
- assert(ps != NULL);
- return ps;
-}
-
-hpdata_t *
-psset_pick_hugify(psset_t *psset) {
- return hpdata_hugify_list_first(&psset->to_hugify);
-}
-
-void
-psset_insert(psset_t *psset, hpdata_t *ps) {
- hpdata_in_psset_set(ps, true);
-
- psset_stats_insert(psset, ps);
- if (hpdata_alloc_allowed_get(ps)) {
- psset_alloc_container_insert(psset, ps);
- }
- psset_maybe_insert_purge_list(psset, ps);
-
- if (hpdata_hugify_allowed_get(ps)) {
- hpdata_in_psset_hugify_container_set(ps, true);
- hpdata_hugify_list_append(&psset->to_hugify, ps);
- }
-}
-
-void
-psset_remove(psset_t *psset, hpdata_t *ps) {
- hpdata_in_psset_set(ps, false);
-
- psset_stats_remove(psset, ps);
- if (hpdata_in_psset_alloc_container_get(ps)) {
- psset_alloc_container_remove(psset, ps);
- }
- psset_maybe_remove_purge_list(psset, ps);
- if (hpdata_in_psset_hugify_container_get(ps)) {
- hpdata_in_psset_hugify_container_set(ps, false);
- hpdata_hugify_list_remove(&psset->to_hugify, ps);
- }
-}
diff --git a/fluent-bit/lib/jemalloc-5.3.0/src/rtree.c b/fluent-bit/lib/jemalloc-5.3.0/src/rtree.c
deleted file mode 100644
index 6496b5af..00000000
--- a/fluent-bit/lib/jemalloc-5.3.0/src/rtree.c
+++ /dev/null
@@ -1,261 +0,0 @@
-#include "jemalloc/internal/jemalloc_preamble.h"
-#include "jemalloc/internal/jemalloc_internal_includes.h"
-
-#include "jemalloc/internal/assert.h"
-#include "jemalloc/internal/mutex.h"
-
-/*
- * Only the most significant bits of keys passed to rtree_{read,write}() are
- * used.
- */
-bool
-rtree_new(rtree_t *rtree, base_t *base, bool zeroed) {
-#ifdef JEMALLOC_JET
- if (!zeroed) {
- memset(rtree, 0, sizeof(rtree_t)); /* Clear root. */
- }
-#else
- assert(zeroed);
-#endif
- rtree->base = base;
-
- if (malloc_mutex_init(&rtree->init_lock, "rtree", WITNESS_RANK_RTREE,
- malloc_mutex_rank_exclusive)) {
- return true;
- }
-
- return false;
-}
-
-static rtree_node_elm_t *
-rtree_node_alloc(tsdn_t *tsdn, rtree_t *rtree, size_t nelms) {
- return (rtree_node_elm_t *)base_alloc(tsdn, rtree->base,
- nelms * sizeof(rtree_node_elm_t), CACHELINE);
-}
-
-static rtree_leaf_elm_t *
-rtree_leaf_alloc(tsdn_t *tsdn, rtree_t *rtree, size_t nelms) {
- return (rtree_leaf_elm_t *)base_alloc(tsdn, rtree->base,
- nelms * sizeof(rtree_leaf_elm_t), CACHELINE);
-}
-
-static rtree_node_elm_t *
-rtree_node_init(tsdn_t *tsdn, rtree_t *rtree, unsigned level,
- atomic_p_t *elmp) {
- malloc_mutex_lock(tsdn, &rtree->init_lock);
- /*
- * If *elmp is non-null, then it was initialized with the init lock
- * held, so we can get by with 'relaxed' here.
- */
- rtree_node_elm_t *node = atomic_load_p(elmp, ATOMIC_RELAXED);
- if (node == NULL) {
- node = rtree_node_alloc(tsdn, rtree, ZU(1) <<
- rtree_levels[level].bits);
- if (node == NULL) {
- malloc_mutex_unlock(tsdn, &rtree->init_lock);
- return NULL;
- }
- /*
- * Even though we hold the lock, a later reader might not; we
- * need release semantics.
- */
- atomic_store_p(elmp, node, ATOMIC_RELEASE);
- }
- malloc_mutex_unlock(tsdn, &rtree->init_lock);
-
- return node;
-}
-
-static rtree_leaf_elm_t *
-rtree_leaf_init(tsdn_t *tsdn, rtree_t *rtree, atomic_p_t *elmp) {
- malloc_mutex_lock(tsdn, &rtree->init_lock);
- /*
- * If *elmp is non-null, then it was initialized with the init lock
- * held, so we can get by with 'relaxed' here.
- */
- rtree_leaf_elm_t *leaf = atomic_load_p(elmp, ATOMIC_RELAXED);
- if (leaf == NULL) {
- leaf = rtree_leaf_alloc(tsdn, rtree, ZU(1) <<
- rtree_levels[RTREE_HEIGHT-1].bits);
- if (leaf == NULL) {
- malloc_mutex_unlock(tsdn, &rtree->init_lock);
- return NULL;
- }
- /*
- * Even though we hold the lock, a later reader might not; we
- * need release semantics.
- */
- atomic_store_p(elmp, leaf, ATOMIC_RELEASE);
- }
- malloc_mutex_unlock(tsdn, &rtree->init_lock);
-
- return leaf;
-}
-
-static bool
-rtree_node_valid(rtree_node_elm_t *node) {
- return ((uintptr_t)node != (uintptr_t)0);
-}
-
-static bool
-rtree_leaf_valid(rtree_leaf_elm_t *leaf) {
- return ((uintptr_t)leaf != (uintptr_t)0);
-}
-
-static rtree_node_elm_t *
-rtree_child_node_tryread(rtree_node_elm_t *elm, bool dependent) {
- rtree_node_elm_t *node;
-
- if (dependent) {
- node = (rtree_node_elm_t *)atomic_load_p(&elm->child,
- ATOMIC_RELAXED);
- } else {
- node = (rtree_node_elm_t *)atomic_load_p(&elm->child,
- ATOMIC_ACQUIRE);
- }
-
- assert(!dependent || node != NULL);
- return node;
-}
-
-static rtree_node_elm_t *
-rtree_child_node_read(tsdn_t *tsdn, rtree_t *rtree, rtree_node_elm_t *elm,
- unsigned level, bool dependent) {
- rtree_node_elm_t *node;
-
- node = rtree_child_node_tryread(elm, dependent);
- if (!dependent && unlikely(!rtree_node_valid(node))) {
- node = rtree_node_init(tsdn, rtree, level + 1, &elm->child);
- }
- assert(!dependent || node != NULL);
- return node;
-}
-
-static rtree_leaf_elm_t *
-rtree_child_leaf_tryread(rtree_node_elm_t *elm, bool dependent) {
- rtree_leaf_elm_t *leaf;
-
- if (dependent) {
- leaf = (rtree_leaf_elm_t *)atomic_load_p(&elm->child,
- ATOMIC_RELAXED);
- } else {
- leaf = (rtree_leaf_elm_t *)atomic_load_p(&elm->child,
- ATOMIC_ACQUIRE);
- }
-
- assert(!dependent || leaf != NULL);
- return leaf;
-}
-
-static rtree_leaf_elm_t *
-rtree_child_leaf_read(tsdn_t *tsdn, rtree_t *rtree, rtree_node_elm_t *elm,
- unsigned level, bool dependent) {
- rtree_leaf_elm_t *leaf;
-
- leaf = rtree_child_leaf_tryread(elm, dependent);
- if (!dependent && unlikely(!rtree_leaf_valid(leaf))) {
- leaf = rtree_leaf_init(tsdn, rtree, &elm->child);
- }
- assert(!dependent || leaf != NULL);
- return leaf;
-}
-
-rtree_leaf_elm_t *
-rtree_leaf_elm_lookup_hard(tsdn_t *tsdn, rtree_t *rtree, rtree_ctx_t *rtree_ctx,
- uintptr_t key, bool dependent, bool init_missing) {
- rtree_node_elm_t *node;
- rtree_leaf_elm_t *leaf;
-#if RTREE_HEIGHT > 1
- node = rtree->root;
-#else
- leaf = rtree->root;
-#endif
-
- if (config_debug) {
- uintptr_t leafkey = rtree_leafkey(key);
- for (unsigned i = 0; i < RTREE_CTX_NCACHE; i++) {
- assert(rtree_ctx->cache[i].leafkey != leafkey);
- }
- for (unsigned i = 0; i < RTREE_CTX_NCACHE_L2; i++) {
- assert(rtree_ctx->l2_cache[i].leafkey != leafkey);
- }
- }
-
-#define RTREE_GET_CHILD(level) { \
- assert(level < RTREE_HEIGHT-1); \
- if (level != 0 && !dependent && \
- unlikely(!rtree_node_valid(node))) { \
- return NULL; \
- } \
- uintptr_t subkey = rtree_subkey(key, level); \
- if (level + 2 < RTREE_HEIGHT) { \
- node = init_missing ? \
- rtree_child_node_read(tsdn, rtree, \
- &node[subkey], level, dependent) : \
- rtree_child_node_tryread(&node[subkey], \
- dependent); \
- } else { \
- leaf = init_missing ? \
- rtree_child_leaf_read(tsdn, rtree, \
- &node[subkey], level, dependent) : \
- rtree_child_leaf_tryread(&node[subkey], \
- dependent); \
- } \
- }
- /*
- * Cache replacement upon hard lookup (i.e. L1 & L2 rtree cache miss):
- * (1) evict last entry in L2 cache; (2) move the collision slot from L1
- * cache down to L2; and 3) fill L1.
- */
-#define RTREE_GET_LEAF(level) { \
- assert(level == RTREE_HEIGHT-1); \
- if (!dependent && unlikely(!rtree_leaf_valid(leaf))) { \
- return NULL; \
- } \
- if (RTREE_CTX_NCACHE_L2 > 1) { \
- memmove(&rtree_ctx->l2_cache[1], \
- &rtree_ctx->l2_cache[0], \
- sizeof(rtree_ctx_cache_elm_t) * \
- (RTREE_CTX_NCACHE_L2 - 1)); \
- } \
- size_t slot = rtree_cache_direct_map(key); \
- rtree_ctx->l2_cache[0].leafkey = \
- rtree_ctx->cache[slot].leafkey; \
- rtree_ctx->l2_cache[0].leaf = \
- rtree_ctx->cache[slot].leaf; \
- uintptr_t leafkey = rtree_leafkey(key); \
- rtree_ctx->cache[slot].leafkey = leafkey; \
- rtree_ctx->cache[slot].leaf = leaf; \
- uintptr_t subkey = rtree_subkey(key, level); \
- return &leaf[subkey]; \
- }
- if (RTREE_HEIGHT > 1) {
- RTREE_GET_CHILD(0)
- }
- if (RTREE_HEIGHT > 2) {
- RTREE_GET_CHILD(1)
- }
- if (RTREE_HEIGHT > 3) {
- for (unsigned i = 2; i < RTREE_HEIGHT-1; i++) {
- RTREE_GET_CHILD(i)
- }
- }
- RTREE_GET_LEAF(RTREE_HEIGHT-1)
-#undef RTREE_GET_CHILD
-#undef RTREE_GET_LEAF
- not_reached();
-}
-
-void
-rtree_ctx_data_init(rtree_ctx_t *ctx) {
- for (unsigned i = 0; i < RTREE_CTX_NCACHE; i++) {
- rtree_ctx_cache_elm_t *cache = &ctx->cache[i];
- cache->leafkey = RTREE_LEAFKEY_INVALID;
- cache->leaf = NULL;
- }
- for (unsigned i = 0; i < RTREE_CTX_NCACHE_L2; i++) {
- rtree_ctx_cache_elm_t *cache = &ctx->l2_cache[i];
- cache->leafkey = RTREE_LEAFKEY_INVALID;
- cache->leaf = NULL;
- }
-}
diff --git a/fluent-bit/lib/jemalloc-5.3.0/src/safety_check.c b/fluent-bit/lib/jemalloc-5.3.0/src/safety_check.c
deleted file mode 100644
index 209fdda9..00000000
--- a/fluent-bit/lib/jemalloc-5.3.0/src/safety_check.c
+++ /dev/null
@@ -1,36 +0,0 @@
-#include "jemalloc/internal/jemalloc_preamble.h"
-#include "jemalloc/internal/jemalloc_internal_includes.h"
-
-static safety_check_abort_hook_t safety_check_abort;
-
-void safety_check_fail_sized_dealloc(bool current_dealloc, const void *ptr,
- size_t true_size, size_t input_size) {
- char *src = current_dealloc ? "the current pointer being freed" :
- "in thread cache, possibly from previous deallocations";
-
- safety_check_fail("<jemalloc>: size mismatch detected (true size %zu "
- "vs input size %zu), likely caused by application sized "
- "deallocation bugs (source address: %p, %s). Suggest building with "
- "--enable-debug or address sanitizer for debugging. Abort.\n",
- true_size, input_size, ptr, src);
-}
-
-void safety_check_set_abort(safety_check_abort_hook_t abort_fn) {
- safety_check_abort = abort_fn;
-}
-
-void safety_check_fail(const char *format, ...) {
- char buf[MALLOC_PRINTF_BUFSIZE];
-
- va_list ap;
- va_start(ap, format);
- malloc_vsnprintf(buf, MALLOC_PRINTF_BUFSIZE, format, ap);
- va_end(ap);
-
- if (safety_check_abort == NULL) {
- malloc_write(buf);
- abort();
- } else {
- safety_check_abort(buf);
- }
-}
diff --git a/fluent-bit/lib/jemalloc-5.3.0/src/san.c b/fluent-bit/lib/jemalloc-5.3.0/src/san.c
deleted file mode 100644
index 6e512911..00000000
--- a/fluent-bit/lib/jemalloc-5.3.0/src/san.c
+++ /dev/null
@@ -1,208 +0,0 @@
-#include "jemalloc/internal/jemalloc_preamble.h"
-#include "jemalloc/internal/jemalloc_internal_includes.h"
-
-#include "jemalloc/internal/assert.h"
-#include "jemalloc/internal/ehooks.h"
-#include "jemalloc/internal/san.h"
-#include "jemalloc/internal/tsd.h"
-
-/* The sanitizer options. */
-size_t opt_san_guard_large = SAN_GUARD_LARGE_EVERY_N_EXTENTS_DEFAULT;
-size_t opt_san_guard_small = SAN_GUARD_SMALL_EVERY_N_EXTENTS_DEFAULT;
-
-/* Aligned (-1 is off) ptrs will be junked & stashed on dealloc. */
-ssize_t opt_lg_san_uaf_align = SAN_LG_UAF_ALIGN_DEFAULT;
-
-/*
- * Initialized in san_init(). When disabled, the mask is set to (uintptr_t)-1
- * to always fail the nonfast_align check.
- */
-uintptr_t san_cache_bin_nonfast_mask = SAN_CACHE_BIN_NONFAST_MASK_DEFAULT;
-
-static inline void
-san_find_guarded_addr(edata_t *edata, uintptr_t *guard1, uintptr_t *guard2,
- uintptr_t *addr, size_t size, bool left, bool right) {
- assert(!edata_guarded_get(edata));
- assert(size % PAGE == 0);
- *addr = (uintptr_t)edata_base_get(edata);
- if (left) {
- *guard1 = *addr;
- *addr += SAN_PAGE_GUARD;
- } else {
- *guard1 = 0;
- }
-
- if (right) {
- *guard2 = *addr + size;
- } else {
- *guard2 = 0;
- }
-}
-
-static inline void
-san_find_unguarded_addr(edata_t *edata, uintptr_t *guard1, uintptr_t *guard2,
- uintptr_t *addr, size_t size, bool left, bool right) {
- assert(edata_guarded_get(edata));
- assert(size % PAGE == 0);
- *addr = (uintptr_t)edata_base_get(edata);
- if (right) {
- *guard2 = *addr + size;
- } else {
- *guard2 = 0;
- }
-
- if (left) {
- *guard1 = *addr - SAN_PAGE_GUARD;
- assert(*guard1 != 0);
- *addr = *guard1;
- } else {
- *guard1 = 0;
- }
-}
-
-void
-san_guard_pages(tsdn_t *tsdn, ehooks_t *ehooks, edata_t *edata, emap_t *emap,
- bool left, bool right, bool remap) {
- assert(left || right);
- if (remap) {
- emap_deregister_boundary(tsdn, emap, edata);
- }
-
- size_t size_with_guards = edata_size_get(edata);
- size_t usize = (left && right)
- ? san_two_side_unguarded_sz(size_with_guards)
- : san_one_side_unguarded_sz(size_with_guards);
-
- uintptr_t guard1, guard2, addr;
- san_find_guarded_addr(edata, &guard1, &guard2, &addr, usize, left,
- right);
-
- assert(edata_state_get(edata) == extent_state_active);
- ehooks_guard(tsdn, ehooks, (void *)guard1, (void *)guard2);
-
- /* Update the guarded addr and usable size of the edata. */
- edata_size_set(edata, usize);
- edata_addr_set(edata, (void *)addr);
- edata_guarded_set(edata, true);
-
- if (remap) {
- emap_register_boundary(tsdn, emap, edata, SC_NSIZES,
- /* slab */ false);
- }
-}
-
-static void
-san_unguard_pages_impl(tsdn_t *tsdn, ehooks_t *ehooks, edata_t *edata,
- emap_t *emap, bool left, bool right, bool remap) {
- assert(left || right);
- /* Remove the inner boundary which no longer exists. */
- if (remap) {
- assert(edata_state_get(edata) == extent_state_active);
- emap_deregister_boundary(tsdn, emap, edata);
- } else {
- assert(edata_state_get(edata) == extent_state_retained);
- }
-
- size_t size = edata_size_get(edata);
- size_t size_with_guards = (left && right)
- ? san_two_side_guarded_sz(size)
- : san_one_side_guarded_sz(size);
-
- uintptr_t guard1, guard2, addr;
- san_find_unguarded_addr(edata, &guard1, &guard2, &addr, size, left,
- right);
-
- ehooks_unguard(tsdn, ehooks, (void *)guard1, (void *)guard2);
-
- /* Update the true addr and usable size of the edata. */
- edata_size_set(edata, size_with_guards);
- edata_addr_set(edata, (void *)addr);
- edata_guarded_set(edata, false);
-
- /*
- * Then re-register the outer boundary including the guards, if
- * requested.
- */
- if (remap) {
- emap_register_boundary(tsdn, emap, edata, SC_NSIZES,
- /* slab */ false);
- }
-}
-
-void
-san_unguard_pages(tsdn_t *tsdn, ehooks_t *ehooks, edata_t *edata,
- emap_t *emap, bool left, bool right) {
- san_unguard_pages_impl(tsdn, ehooks, edata, emap, left, right,
- /* remap */ true);
-}
-
-void
-san_unguard_pages_pre_destroy(tsdn_t *tsdn, ehooks_t *ehooks, edata_t *edata,
- emap_t *emap) {
- emap_assert_not_mapped(tsdn, emap, edata);
- /*
- * We don't want to touch the emap of about to be destroyed extents, as
- * they have been unmapped upon eviction from the retained ecache. Also,
- * we unguard the extents to the right, because retained extents only
- * own their right guard page per san_bump_alloc's logic.
- */
- san_unguard_pages_impl(tsdn, ehooks, edata, emap, /* left */ false,
- /* right */ true, /* remap */ false);
-}
-
-static bool
-san_stashed_corrupted(void *ptr, size_t size) {
- if (san_junk_ptr_should_slow()) {
- for (size_t i = 0; i < size; i++) {
- if (((char *)ptr)[i] != (char)uaf_detect_junk) {
- return true;
- }
- }
- return false;
- }
-
- void *first, *mid, *last;
- san_junk_ptr_locations(ptr, size, &first, &mid, &last);
- if (*(uintptr_t *)first != uaf_detect_junk ||
- *(uintptr_t *)mid != uaf_detect_junk ||
- *(uintptr_t *)last != uaf_detect_junk) {
- return true;
- }
-
- return false;
-}
-
-void
-san_check_stashed_ptrs(void **ptrs, size_t nstashed, size_t usize) {
- /*
- * Verify that the junked-filled & stashed pointers remain unchanged, to
- * detect write-after-free.
- */
- for (size_t n = 0; n < nstashed; n++) {
- void *stashed = ptrs[n];
- assert(stashed != NULL);
- assert(cache_bin_nonfast_aligned(stashed));
- if (unlikely(san_stashed_corrupted(stashed, usize))) {
- safety_check_fail("<jemalloc>: Write-after-free "
- "detected on deallocated pointer %p (size %zu).\n",
- stashed, usize);
- }
- }
-}
-
-void
-tsd_san_init(tsd_t *tsd) {
- *tsd_san_extents_until_guard_smallp_get(tsd) = opt_san_guard_small;
- *tsd_san_extents_until_guard_largep_get(tsd) = opt_san_guard_large;
-}
-
-void
-san_init(ssize_t lg_san_uaf_align) {
- assert(lg_san_uaf_align == -1 || lg_san_uaf_align >= LG_PAGE);
- if (lg_san_uaf_align == -1) {
- san_cache_bin_nonfast_mask = (uintptr_t)-1;
- return;
- }
-
- san_cache_bin_nonfast_mask = ((uintptr_t)1 << lg_san_uaf_align) - 1;
-}
diff --git a/fluent-bit/lib/jemalloc-5.3.0/src/san_bump.c b/fluent-bit/lib/jemalloc-5.3.0/src/san_bump.c
deleted file mode 100644
index 88897455..00000000
--- a/fluent-bit/lib/jemalloc-5.3.0/src/san_bump.c
+++ /dev/null
@@ -1,104 +0,0 @@
-#include "jemalloc/internal/jemalloc_preamble.h"
-#include "jemalloc/internal/jemalloc_internal_includes.h"
-
-#include "jemalloc/internal/san_bump.h"
-#include "jemalloc/internal/pac.h"
-#include "jemalloc/internal/san.h"
-#include "jemalloc/internal/ehooks.h"
-#include "jemalloc/internal/edata_cache.h"
-
-static bool
-san_bump_grow_locked(tsdn_t *tsdn, san_bump_alloc_t *sba, pac_t *pac,
- ehooks_t *ehooks, size_t size);
-
-edata_t *
-san_bump_alloc(tsdn_t *tsdn, san_bump_alloc_t* sba, pac_t *pac,
- ehooks_t *ehooks, size_t size, bool zero) {
- assert(san_bump_enabled());
-
- edata_t* to_destroy;
- size_t guarded_size = san_one_side_guarded_sz(size);
-
- malloc_mutex_lock(tsdn, &sba->mtx);
-
- if (sba->curr_reg == NULL ||
- edata_size_get(sba->curr_reg) < guarded_size) {
- /*
- * If the current region can't accommodate the allocation,
- * try replacing it with a larger one and destroy current if the
- * replacement succeeds.
- */
- to_destroy = sba->curr_reg;
- bool err = san_bump_grow_locked(tsdn, sba, pac, ehooks,
- guarded_size);
- if (err) {
- goto label_err;
- }
- } else {
- to_destroy = NULL;
- }
- assert(guarded_size <= edata_size_get(sba->curr_reg));
- size_t trail_size = edata_size_get(sba->curr_reg) - guarded_size;
-
- edata_t* edata;
- if (trail_size != 0) {
- edata_t* curr_reg_trail = extent_split_wrapper(tsdn, pac,
- ehooks, sba->curr_reg, guarded_size, trail_size,
- /* holding_core_locks */ true);
- if (curr_reg_trail == NULL) {
- goto label_err;
- }
- edata = sba->curr_reg;
- sba->curr_reg = curr_reg_trail;
- } else {
- edata = sba->curr_reg;
- sba->curr_reg = NULL;
- }
-
- malloc_mutex_unlock(tsdn, &sba->mtx);
-
- assert(!edata_guarded_get(edata));
- assert(sba->curr_reg == NULL || !edata_guarded_get(sba->curr_reg));
- assert(to_destroy == NULL || !edata_guarded_get(to_destroy));
-
- if (to_destroy != NULL) {
- extent_destroy_wrapper(tsdn, pac, ehooks, to_destroy);
- }
-
- san_guard_pages(tsdn, ehooks, edata, pac->emap, /* left */ false,
- /* right */ true, /* remap */ true);
-
- if (extent_commit_zero(tsdn, ehooks, edata, /* commit */ true, zero,
- /* growing_retained */ false)) {
- extent_record(tsdn, pac, ehooks, &pac->ecache_retained,
- edata);
- return NULL;
- }
-
- if (config_prof) {
- extent_gdump_add(tsdn, edata);
- }
-
- return edata;
-label_err:
- malloc_mutex_unlock(tsdn, &sba->mtx);
- return NULL;
-}
-
-static bool
-san_bump_grow_locked(tsdn_t *tsdn, san_bump_alloc_t *sba, pac_t *pac,
- ehooks_t *ehooks, size_t size) {
- malloc_mutex_assert_owner(tsdn, &sba->mtx);
-
- bool committed = false, zeroed = false;
- size_t alloc_size = size > SBA_RETAINED_ALLOC_SIZE ? size :
- SBA_RETAINED_ALLOC_SIZE;
- assert((alloc_size & PAGE_MASK) == 0);
- sba->curr_reg = extent_alloc_wrapper(tsdn, pac, ehooks, NULL,
- alloc_size, PAGE, zeroed, &committed,
- /* growing_retained */ true);
- if (sba->curr_reg == NULL) {
- return true;
- }
- return false;
-}
diff --git a/fluent-bit/lib/jemalloc-5.3.0/src/sc.c b/fluent-bit/lib/jemalloc-5.3.0/src/sc.c
deleted file mode 100644
index e4a94d89..00000000
--- a/fluent-bit/lib/jemalloc-5.3.0/src/sc.c
+++ /dev/null
@@ -1,306 +0,0 @@
-#include "jemalloc/internal/jemalloc_preamble.h"
-
-#include "jemalloc/internal/assert.h"
-#include "jemalloc/internal/bit_util.h"
-#include "jemalloc/internal/bitmap.h"
-#include "jemalloc/internal/pages.h"
-#include "jemalloc/internal/sc.h"
-
-/*
- * This module computes the size classes used to satisfy allocations. The logic
- * here was ported more or less line-by-line from a shell script, and because of
- * that is not the most idiomatic C. Eventually we should fix this, but for now
- * at least the damage is compartmentalized to this file.
- */
-
-size_t
-reg_size_compute(int lg_base, int lg_delta, int ndelta) {
- return (ZU(1) << lg_base) + (ZU(ndelta) << lg_delta);
-}
-
-/* Returns the number of pages in the slab. */
-static int
-slab_size(int lg_page, int lg_base, int lg_delta, int ndelta) {
- size_t page = (ZU(1) << lg_page);
- size_t reg_size = reg_size_compute(lg_base, lg_delta, ndelta);
-
- size_t try_slab_size = page;
- size_t try_nregs = try_slab_size / reg_size;
- size_t perfect_slab_size = 0;
- bool perfect = false;
- /*
- * This loop continues until we find the least common multiple of the
- * page size and size class size. Size classes are all of the form
- * base + ndelta * delta == (ndelta + base/ndelta) * delta, which is
- * (ndelta + ngroup) * delta. The way we choose slabbing strategies
- * means that delta is at most the page size and ndelta < ngroup. So
- * the loop executes for at most 2 * ngroup - 1 iterations, which is
- * also the bound on the number of pages in a slab chosen by default.
- * With the current default settings, this is at most 7.
- */
- while (!perfect) {
- perfect_slab_size = try_slab_size;
- size_t perfect_nregs = try_nregs;
- try_slab_size += page;
- try_nregs = try_slab_size / reg_size;
- if (perfect_slab_size == perfect_nregs * reg_size) {
- perfect = true;
- }
- }
- return (int)(perfect_slab_size / page);
-}
-
-static void
-size_class(
- /* Output. */
- sc_t *sc,
- /* Configuration decisions. */
- int lg_max_lookup, int lg_page, int lg_ngroup,
- /* Inputs specific to the size class. */
- int index, int lg_base, int lg_delta, int ndelta) {
- sc->index = index;
- sc->lg_base = lg_base;
- sc->lg_delta = lg_delta;
- sc->ndelta = ndelta;
- size_t size = reg_size_compute(lg_base, lg_delta, ndelta);
- sc->psz = (size % (ZU(1) << lg_page) == 0);
- if (index == 0) {
- assert(!sc->psz);
- }
- if (size < (ZU(1) << (lg_page + lg_ngroup))) {
- sc->bin = true;
- sc->pgs = slab_size(lg_page, lg_base, lg_delta, ndelta);
- } else {
- sc->bin = false;
- sc->pgs = 0;
- }
- if (size <= (ZU(1) << lg_max_lookup)) {
- sc->lg_delta_lookup = lg_delta;
- } else {
- sc->lg_delta_lookup = 0;
- }
-}
-
-static void
-size_classes(
- /* Output. */
- sc_data_t *sc_data,
- /* Determined by the system. */
- size_t lg_ptr_size, int lg_quantum,
- /* Configuration decisions. */
- int lg_tiny_min, int lg_max_lookup, int lg_page, int lg_ngroup) {
- int ptr_bits = (1 << lg_ptr_size) * 8;
- int ngroup = (1 << lg_ngroup);
- int ntiny = 0;
- int nlbins = 0;
- int lg_tiny_maxclass = (unsigned)-1;
- int nbins = 0;
- int npsizes = 0;
-
- int index = 0;
-
- int ndelta = 0;
- int lg_base = lg_tiny_min;
- int lg_delta = lg_base;
-
- /* Outputs that we update as we go. */
- size_t lookup_maxclass = 0;
- size_t small_maxclass = 0;
- int lg_large_minclass = 0;
- size_t large_maxclass = 0;
-
- /* Tiny size classes. */
- while (lg_base < lg_quantum) {
- sc_t *sc = &sc_data->sc[index];
- size_class(sc, lg_max_lookup, lg_page, lg_ngroup, index,
- lg_base, lg_delta, ndelta);
- if (sc->lg_delta_lookup != 0) {
- nlbins = index + 1;
- }
- if (sc->psz) {
- npsizes++;
- }
- if (sc->bin) {
- nbins++;
- }
- ntiny++;
- /* Final written value is correct. */
- lg_tiny_maxclass = lg_base;
- index++;
- lg_delta = lg_base;
- lg_base++;
- }
-
- /* First non-tiny (pseudo) group. */
- if (ntiny != 0) {
- sc_t *sc = &sc_data->sc[index];
- /*
- * See the note in sc.h; the first non-tiny size class has an
- * unusual encoding.
- */
- lg_base--;
- ndelta = 1;
- size_class(sc, lg_max_lookup, lg_page, lg_ngroup, index,
- lg_base, lg_delta, ndelta);
- index++;
- lg_base++;
- lg_delta++;
- if (sc->psz) {
- npsizes++;
- }
- if (sc->bin) {
- nbins++;
- }
- }
- while (ndelta < ngroup) {
- sc_t *sc = &sc_data->sc[index];
- size_class(sc, lg_max_lookup, lg_page, lg_ngroup, index,
- lg_base, lg_delta, ndelta);
- index++;
- ndelta++;
- if (sc->psz) {
- npsizes++;
- }
- if (sc->bin) {
- nbins++;
- }
- }
-
- /* All remaining groups. */
- lg_base = lg_base + lg_ngroup;
- while (lg_base < ptr_bits - 1) {
- ndelta = 1;
- int ndelta_limit;
- if (lg_base == ptr_bits - 2) {
- ndelta_limit = ngroup - 1;
- } else {
- ndelta_limit = ngroup;
- }
- while (ndelta <= ndelta_limit) {
- sc_t *sc = &sc_data->sc[index];
- size_class(sc, lg_max_lookup, lg_page, lg_ngroup, index,
- lg_base, lg_delta, ndelta);
- if (sc->lg_delta_lookup != 0) {
- nlbins = index + 1;
- /* Final written value is correct. */
- lookup_maxclass = (ZU(1) << lg_base)
- + (ZU(ndelta) << lg_delta);
- }
- if (sc->psz) {
- npsizes++;
- }
- if (sc->bin) {
- nbins++;
- /* Final written value is correct. */
- small_maxclass = (ZU(1) << lg_base)
- + (ZU(ndelta) << lg_delta);
- if (lg_ngroup > 0) {
- lg_large_minclass = lg_base + 1;
- } else {
- lg_large_minclass = lg_base + 2;
- }
- }
- large_maxclass = (ZU(1) << lg_base)
- + (ZU(ndelta) << lg_delta);
- index++;
- ndelta++;
- }
- lg_base++;
- lg_delta++;
- }
- /* Additional outputs. */
- int nsizes = index;
- unsigned lg_ceil_nsizes = lg_ceil(nsizes);
-
- /* Fill in the output data. */
- sc_data->ntiny = ntiny;
- sc_data->nlbins = nlbins;
- sc_data->nbins = nbins;
- sc_data->nsizes = nsizes;
- sc_data->lg_ceil_nsizes = lg_ceil_nsizes;
- sc_data->npsizes = npsizes;
- sc_data->lg_tiny_maxclass = lg_tiny_maxclass;
- sc_data->lookup_maxclass = lookup_maxclass;
- sc_data->small_maxclass = small_maxclass;
- sc_data->lg_large_minclass = lg_large_minclass;
- sc_data->large_minclass = (ZU(1) << lg_large_minclass);
- sc_data->large_maxclass = large_maxclass;
-
- /*
- * We compute these values in two ways:
- * - Incrementally, as above.
- * - In macros, in sc.h.
- * The computation is easier when done incrementally, but putting it in
- * a constant makes it available to the fast paths without having to
- * touch the extra global cacheline. We assert, however, that the two
- * computations are equivalent.
- */
- assert(sc_data->npsizes == SC_NPSIZES);
- assert(sc_data->lg_tiny_maxclass == SC_LG_TINY_MAXCLASS);
- assert(sc_data->small_maxclass == SC_SMALL_MAXCLASS);
- assert(sc_data->large_minclass == SC_LARGE_MINCLASS);
- assert(sc_data->lg_large_minclass == SC_LG_LARGE_MINCLASS);
- assert(sc_data->large_maxclass == SC_LARGE_MAXCLASS);
-
- /*
- * In the allocation fastpath, we want to assume that we can
- * unconditionally subtract the requested allocation size from
- * a ssize_t, and detect passing through 0 correctly. This
- * results in optimal generated code. For this to work, the
- * maximum allocation size must be less than SSIZE_MAX.
- */
- assert(SC_LARGE_MAXCLASS < SSIZE_MAX);
-}
-
-void
-sc_data_init(sc_data_t *sc_data) {
- size_classes(sc_data, LG_SIZEOF_PTR, LG_QUANTUM, SC_LG_TINY_MIN,
- SC_LG_MAX_LOOKUP, LG_PAGE, SC_LG_NGROUP);
-
- sc_data->initialized = true;
-}
-
-static void
-sc_data_update_sc_slab_size(sc_t *sc, size_t reg_size, size_t pgs_guess) {
- size_t min_pgs = reg_size / PAGE;
- if (reg_size % PAGE != 0) {
- min_pgs++;
- }
- /*
- * BITMAP_MAXBITS is actually determined by putting the smallest
- * possible size-class on one page, so this can never be 0.
- */
- size_t max_pgs = BITMAP_MAXBITS * reg_size / PAGE;
-
- assert(min_pgs <= max_pgs);
- assert(min_pgs > 0);
- assert(max_pgs >= 1);
- if (pgs_guess < min_pgs) {
- sc->pgs = (int)min_pgs;
- } else if (pgs_guess > max_pgs) {
- sc->pgs = (int)max_pgs;
- } else {
- sc->pgs = (int)pgs_guess;
- }
-}
-
-void
-sc_data_update_slab_size(sc_data_t *data, size_t begin, size_t end, int pgs) {
- assert(data->initialized);
- for (int i = 0; i < data->nsizes; i++) {
- sc_t *sc = &data->sc[i];
- if (!sc->bin) {
- break;
- }
- size_t reg_size = reg_size_compute(sc->lg_base, sc->lg_delta,
- sc->ndelta);
- if (begin <= reg_size && reg_size <= end) {
- sc_data_update_sc_slab_size(sc, reg_size, pgs);
- }
- }
-}
-
-void
-sc_boot(sc_data_t *data) {
- sc_data_init(data);
-}
diff --git a/fluent-bit/lib/jemalloc-5.3.0/src/sec.c b/fluent-bit/lib/jemalloc-5.3.0/src/sec.c
deleted file mode 100644
index df675590..00000000
--- a/fluent-bit/lib/jemalloc-5.3.0/src/sec.c
+++ /dev/null
@@ -1,422 +0,0 @@
-#include "jemalloc/internal/jemalloc_preamble.h"
-#include "jemalloc/internal/jemalloc_internal_includes.h"
-
-#include "jemalloc/internal/sec.h"
-
-static edata_t *sec_alloc(tsdn_t *tsdn, pai_t *self, size_t size,
- size_t alignment, bool zero, bool guarded, bool frequent_reuse,
- bool *deferred_work_generated);
-static bool sec_expand(tsdn_t *tsdn, pai_t *self, edata_t *edata,
- size_t old_size, size_t new_size, bool zero, bool *deferred_work_generated);
-static bool sec_shrink(tsdn_t *tsdn, pai_t *self, edata_t *edata,
- size_t old_size, size_t new_size, bool *deferred_work_generated);
-static void sec_dalloc(tsdn_t *tsdn, pai_t *self, edata_t *edata,
- bool *deferred_work_generated);
-
-static void
-sec_bin_init(sec_bin_t *bin) {
- bin->being_batch_filled = false;
- bin->bytes_cur = 0;
- edata_list_active_init(&bin->freelist);
-}
-
-bool
-sec_init(tsdn_t *tsdn, sec_t *sec, base_t *base, pai_t *fallback,
- const sec_opts_t *opts) {
- assert(opts->max_alloc >= PAGE);
-
- size_t max_alloc = PAGE_FLOOR(opts->max_alloc);
- pszind_t npsizes = sz_psz2ind(max_alloc) + 1;
-
- size_t sz_shards = opts->nshards * sizeof(sec_shard_t);
- size_t sz_bins = opts->nshards * (size_t)npsizes * sizeof(sec_bin_t);
- size_t sz_alloc = sz_shards + sz_bins;
- void *dynalloc = base_alloc(tsdn, base, sz_alloc, CACHELINE);
- if (dynalloc == NULL) {
- return true;
- }
- sec_shard_t *shard_cur = (sec_shard_t *)dynalloc;
- sec->shards = shard_cur;
- sec_bin_t *bin_cur = (sec_bin_t *)&shard_cur[opts->nshards];
- /* Just for asserts, below. */
- sec_bin_t *bin_start = bin_cur;
-
- for (size_t i = 0; i < opts->nshards; i++) {
- sec_shard_t *shard = shard_cur;
- shard_cur++;
- bool err = malloc_mutex_init(&shard->mtx, "sec_shard",
- WITNESS_RANK_SEC_SHARD, malloc_mutex_rank_exclusive);
- if (err) {
- return true;
- }
- shard->enabled = true;
- shard->bins = bin_cur;
- for (pszind_t j = 0; j < npsizes; j++) {
- sec_bin_init(&shard->bins[j]);
- bin_cur++;
- }
- shard->bytes_cur = 0;
- shard->to_flush_next = 0;
- }
- /*
- * Should have exactly matched the bin_start to the first unused byte
- * after the shards.
- */
- assert((void *)shard_cur == (void *)bin_start);
- /* And the last bin to use up the last bytes of the allocation. */
- assert((char *)bin_cur == ((char *)dynalloc + sz_alloc));
- sec->fallback = fallback;
-
-
- sec->opts = *opts;
- sec->npsizes = npsizes;
-
- /*
- * Initialize these last so that an improper use of an SEC whose
- * initialization failed will segfault in an easy-to-spot way.
- */
- sec->pai.alloc = &sec_alloc;
- sec->pai.alloc_batch = &pai_alloc_batch_default;
- sec->pai.expand = &sec_expand;
- sec->pai.shrink = &sec_shrink;
- sec->pai.dalloc = &sec_dalloc;
- sec->pai.dalloc_batch = &pai_dalloc_batch_default;
-
- return false;
-}
-
-static sec_shard_t *
-sec_shard_pick(tsdn_t *tsdn, sec_t *sec) {
- /*
- * Eventually, we should implement affinity, tracking source shard using
- * the edata_t's newly freed up fields. For now, just randomly
- * distribute across all shards.
- */
- if (tsdn_null(tsdn)) {
- return &sec->shards[0];
- }
- tsd_t *tsd = tsdn_tsd(tsdn);
- uint8_t *idxp = tsd_sec_shardp_get(tsd);
- if (*idxp == (uint8_t)-1) {
- /*
- * First use; initialize using the trick from Daniel Lemire's
- * "A fast alternative to the modulo reduction. Use a 64 bit
- * number to store 32 bits, since we'll deliberately overflow
- * when we multiply by the number of shards.
- */
- uint64_t rand32 = prng_lg_range_u64(tsd_prng_statep_get(tsd), 32);
- uint32_t idx =
- (uint32_t)((rand32 * (uint64_t)sec->opts.nshards) >> 32);
- assert(idx < (uint32_t)sec->opts.nshards);
- *idxp = (uint8_t)idx;
- }
- return &sec->shards[*idxp];
-}
-
-/*
- * Perhaps surprisingly, this can be called on the alloc pathways; if we hit an
- * empty cache, we'll try to fill it, which can push the shard over it's limit.
- */
-static void
-sec_flush_some_and_unlock(tsdn_t *tsdn, sec_t *sec, sec_shard_t *shard) {
- malloc_mutex_assert_owner(tsdn, &shard->mtx);
- edata_list_active_t to_flush;
- edata_list_active_init(&to_flush);
- while (shard->bytes_cur > sec->opts.bytes_after_flush) {
- /* Pick a victim. */
- sec_bin_t *bin = &shard->bins[shard->to_flush_next];
-
- /* Update our victim-picking state. */
- shard->to_flush_next++;
- if (shard->to_flush_next == sec->npsizes) {
- shard->to_flush_next = 0;
- }
-
- assert(shard->bytes_cur >= bin->bytes_cur);
- if (bin->bytes_cur != 0) {
- shard->bytes_cur -= bin->bytes_cur;
- bin->bytes_cur = 0;
- edata_list_active_concat(&to_flush, &bin->freelist);
- }
- /*
- * Either bin->bytes_cur was 0, in which case we didn't touch
- * the bin list but it should be empty anyways (or else we
- * missed a bytes_cur update on a list modification), or it
- * *was* 0 and we emptied it ourselves. Either way, it should
- * be empty now.
- */
- assert(edata_list_active_empty(&bin->freelist));
- }
-
- malloc_mutex_unlock(tsdn, &shard->mtx);
- bool deferred_work_generated = false;
- pai_dalloc_batch(tsdn, sec->fallback, &to_flush,
- &deferred_work_generated);
-}
-
-static edata_t *
-sec_shard_alloc_locked(tsdn_t *tsdn, sec_t *sec, sec_shard_t *shard,
- sec_bin_t *bin) {
- malloc_mutex_assert_owner(tsdn, &shard->mtx);
- if (!shard->enabled) {
- return NULL;
- }
- edata_t *edata = edata_list_active_first(&bin->freelist);
- if (edata != NULL) {
- edata_list_active_remove(&bin->freelist, edata);
- assert(edata_size_get(edata) <= bin->bytes_cur);
- bin->bytes_cur -= edata_size_get(edata);
- assert(edata_size_get(edata) <= shard->bytes_cur);
- shard->bytes_cur -= edata_size_get(edata);
- }
- return edata;
-}
-
-static edata_t *
-sec_batch_fill_and_alloc(tsdn_t *tsdn, sec_t *sec, sec_shard_t *shard,
- sec_bin_t *bin, size_t size) {
- malloc_mutex_assert_not_owner(tsdn, &shard->mtx);
-
- edata_list_active_t result;
- edata_list_active_init(&result);
- bool deferred_work_generated = false;
- size_t nalloc = pai_alloc_batch(tsdn, sec->fallback, size,
- 1 + sec->opts.batch_fill_extra, &result, &deferred_work_generated);
-
- edata_t *ret = edata_list_active_first(&result);
- if (ret != NULL) {
- edata_list_active_remove(&result, ret);
- }
-
- malloc_mutex_lock(tsdn, &shard->mtx);
- bin->being_batch_filled = false;
- /*
- * Handle the easy case first: nothing to cache. Note that this can
- * only happen in case of OOM, since sec_alloc checks the expected
- * number of allocs, and doesn't bother going down the batch_fill
- * pathway if there won't be anything left to cache. So to be in this
- * code path, we must have asked for > 1 alloc, but only gotten 1 back.
- */
- if (nalloc <= 1) {
- malloc_mutex_unlock(tsdn, &shard->mtx);
- return ret;
- }
-
- size_t new_cached_bytes = (nalloc - 1) * size;
-
- edata_list_active_concat(&bin->freelist, &result);
- bin->bytes_cur += new_cached_bytes;
- shard->bytes_cur += new_cached_bytes;
-
- if (shard->bytes_cur > sec->opts.max_bytes) {
- sec_flush_some_and_unlock(tsdn, sec, shard);
- } else {
- malloc_mutex_unlock(tsdn, &shard->mtx);
- }
-
- return ret;
-}
-
-static edata_t *
-sec_alloc(tsdn_t *tsdn, pai_t *self, size_t size, size_t alignment, bool zero,
- bool guarded, bool frequent_reuse, bool *deferred_work_generated) {
- assert((size & PAGE_MASK) == 0);
- assert(!guarded);
-
- sec_t *sec = (sec_t *)self;
-
- if (zero || alignment > PAGE || sec->opts.nshards == 0
- || size > sec->opts.max_alloc) {
- return pai_alloc(tsdn, sec->fallback, size, alignment, zero,
- /* guarded */ false, frequent_reuse,
- deferred_work_generated);
- }
- pszind_t pszind = sz_psz2ind(size);
- assert(pszind < sec->npsizes);
-
- sec_shard_t *shard = sec_shard_pick(tsdn, sec);
- sec_bin_t *bin = &shard->bins[pszind];
- bool do_batch_fill = false;
-
- malloc_mutex_lock(tsdn, &shard->mtx);
- edata_t *edata = sec_shard_alloc_locked(tsdn, sec, shard, bin);
- if (edata == NULL) {
- if (!bin->being_batch_filled
- && sec->opts.batch_fill_extra > 0) {
- bin->being_batch_filled = true;
- do_batch_fill = true;
- }
- }
- malloc_mutex_unlock(tsdn, &shard->mtx);
- if (edata == NULL) {
- if (do_batch_fill) {
- edata = sec_batch_fill_and_alloc(tsdn, sec, shard, bin,
- size);
- } else {
- edata = pai_alloc(tsdn, sec->fallback, size, alignment,
- zero, /* guarded */ false, frequent_reuse,
- deferred_work_generated);
- }
- }
- return edata;
-}
-
-static bool
-sec_expand(tsdn_t *tsdn, pai_t *self, edata_t *edata, size_t old_size,
- size_t new_size, bool zero, bool *deferred_work_generated) {
- sec_t *sec = (sec_t *)self;
- return pai_expand(tsdn, sec->fallback, edata, old_size, new_size, zero,
- deferred_work_generated);
-}
-
-static bool
-sec_shrink(tsdn_t *tsdn, pai_t *self, edata_t *edata, size_t old_size,
- size_t new_size, bool *deferred_work_generated) {
- sec_t *sec = (sec_t *)self;
- return pai_shrink(tsdn, sec->fallback, edata, old_size, new_size,
- deferred_work_generated);
-}
-
-static void
-sec_flush_all_locked(tsdn_t *tsdn, sec_t *sec, sec_shard_t *shard) {
- malloc_mutex_assert_owner(tsdn, &shard->mtx);
- shard->bytes_cur = 0;
- edata_list_active_t to_flush;
- edata_list_active_init(&to_flush);
- for (pszind_t i = 0; i < sec->npsizes; i++) {
- sec_bin_t *bin = &shard->bins[i];
- bin->bytes_cur = 0;
- edata_list_active_concat(&to_flush, &bin->freelist);
- }
-
- /*
- * Ordinarily we would try to avoid doing the batch deallocation while
- * holding the shard mutex, but the flush_all pathways only happen when
- * we're disabling the HPA or resetting the arena, both of which are
- * rare pathways.
- */
- bool deferred_work_generated = false;
- pai_dalloc_batch(tsdn, sec->fallback, &to_flush,
- &deferred_work_generated);
-}
-
-static void
-sec_shard_dalloc_and_unlock(tsdn_t *tsdn, sec_t *sec, sec_shard_t *shard,
- edata_t *edata) {
- malloc_mutex_assert_owner(tsdn, &shard->mtx);
- assert(shard->bytes_cur <= sec->opts.max_bytes);
- size_t size = edata_size_get(edata);
- pszind_t pszind = sz_psz2ind(size);
- assert(pszind < sec->npsizes);
- /*
- * Prepending here results in LIFO allocation per bin, which seems
- * reasonable.
- */
- sec_bin_t *bin = &shard->bins[pszind];
- edata_list_active_prepend(&bin->freelist, edata);
- bin->bytes_cur += size;
- shard->bytes_cur += size;
- if (shard->bytes_cur > sec->opts.max_bytes) {
- /*
- * We've exceeded the shard limit. We make two nods in the
- * direction of fragmentation avoidance: we flush everything in
- * the shard, rather than one particular bin, and we hold the
- * lock while flushing (in case one of the extents we flush is
- * highly preferred from a fragmentation-avoidance perspective
- * in the backing allocator). This has the extra advantage of
- * not requiring advanced cache balancing strategies.
- */
- sec_flush_some_and_unlock(tsdn, sec, shard);
- malloc_mutex_assert_not_owner(tsdn, &shard->mtx);
- } else {
- malloc_mutex_unlock(tsdn, &shard->mtx);
- }
-}
-
-static void
-sec_dalloc(tsdn_t *tsdn, pai_t *self, edata_t *edata,
- bool *deferred_work_generated) {
- sec_t *sec = (sec_t *)self;
- if (sec->opts.nshards == 0
- || edata_size_get(edata) > sec->opts.max_alloc) {
- pai_dalloc(tsdn, sec->fallback, edata,
- deferred_work_generated);
- return;
- }
- sec_shard_t *shard = sec_shard_pick(tsdn, sec);
- malloc_mutex_lock(tsdn, &shard->mtx);
- if (shard->enabled) {
- sec_shard_dalloc_and_unlock(tsdn, sec, shard, edata);
- } else {
- malloc_mutex_unlock(tsdn, &shard->mtx);
- pai_dalloc(tsdn, sec->fallback, edata,
- deferred_work_generated);
- }
-}
-
-void
-sec_flush(tsdn_t *tsdn, sec_t *sec) {
- for (size_t i = 0; i < sec->opts.nshards; i++) {
- malloc_mutex_lock(tsdn, &sec->shards[i].mtx);
- sec_flush_all_locked(tsdn, sec, &sec->shards[i]);
- malloc_mutex_unlock(tsdn, &sec->shards[i].mtx);
- }
-}
-
-void
-sec_disable(tsdn_t *tsdn, sec_t *sec) {
- for (size_t i = 0; i < sec->opts.nshards; i++) {
- malloc_mutex_lock(tsdn, &sec->shards[i].mtx);
- sec->shards[i].enabled = false;
- sec_flush_all_locked(tsdn, sec, &sec->shards[i]);
- malloc_mutex_unlock(tsdn, &sec->shards[i].mtx);
- }
-}
-
-void
-sec_stats_merge(tsdn_t *tsdn, sec_t *sec, sec_stats_t *stats) {
- size_t sum = 0;
- for (size_t i = 0; i < sec->opts.nshards; i++) {
- /*
- * We could save these lock acquisitions by making bytes_cur
- * atomic, but stats collection is rare anyways and we expect
- * the number and type of stats to get more interesting.
- */
- malloc_mutex_lock(tsdn, &sec->shards[i].mtx);
- sum += sec->shards[i].bytes_cur;
- malloc_mutex_unlock(tsdn, &sec->shards[i].mtx);
- }
- stats->bytes += sum;
-}
-
-void
-sec_mutex_stats_read(tsdn_t *tsdn, sec_t *sec,
- mutex_prof_data_t *mutex_prof_data) {
- for (size_t i = 0; i < sec->opts.nshards; i++) {
- malloc_mutex_lock(tsdn, &sec->shards[i].mtx);
- malloc_mutex_prof_accum(tsdn, mutex_prof_data,
- &sec->shards[i].mtx);
- malloc_mutex_unlock(tsdn, &sec->shards[i].mtx);
- }
-}
-
-void
-sec_prefork2(tsdn_t *tsdn, sec_t *sec) {
- for (size_t i = 0; i < sec->opts.nshards; i++) {
- malloc_mutex_prefork(tsdn, &sec->shards[i].mtx);
- }
-}
-
-void
-sec_postfork_parent(tsdn_t *tsdn, sec_t *sec) {
- for (size_t i = 0; i < sec->opts.nshards; i++) {
- malloc_mutex_postfork_parent(tsdn, &sec->shards[i].mtx);
- }
-}
-
-void
-sec_postfork_child(tsdn_t *tsdn, sec_t *sec) {
- for (size_t i = 0; i < sec->opts.nshards; i++) {
- malloc_mutex_postfork_child(tsdn, &sec->shards[i].mtx);
- }
-}
diff --git a/fluent-bit/lib/jemalloc-5.3.0/src/stats.c b/fluent-bit/lib/jemalloc-5.3.0/src/stats.c
deleted file mode 100644
index efc70fd3..00000000
--- a/fluent-bit/lib/jemalloc-5.3.0/src/stats.c
+++ /dev/null
@@ -1,1973 +0,0 @@
-#include "jemalloc/internal/jemalloc_preamble.h"
-#include "jemalloc/internal/jemalloc_internal_includes.h"
-
-#include "jemalloc/internal/assert.h"
-#include "jemalloc/internal/ctl.h"
-#include "jemalloc/internal/emitter.h"
-#include "jemalloc/internal/fxp.h"
-#include "jemalloc/internal/mutex.h"
-#include "jemalloc/internal/mutex_prof.h"
-#include "jemalloc/internal/prof_stats.h"
-
-const char *global_mutex_names[mutex_prof_num_global_mutexes] = {
-#define OP(mtx) #mtx,
- MUTEX_PROF_GLOBAL_MUTEXES
-#undef OP
-};
-
-const char *arena_mutex_names[mutex_prof_num_arena_mutexes] = {
-#define OP(mtx) #mtx,
- MUTEX_PROF_ARENA_MUTEXES
-#undef OP
-};
-
-#define CTL_GET(n, v, t) do { \
- size_t sz = sizeof(t); \
- xmallctl(n, (void *)v, &sz, NULL, 0); \
-} while (0)
-
-#define CTL_LEAF_PREPARE(mib, miblen, name) do { \
- assert(miblen < CTL_MAX_DEPTH); \
- size_t miblen_new = CTL_MAX_DEPTH; \
- xmallctlmibnametomib(mib, miblen, name, &miblen_new); \
- assert(miblen_new > miblen); \
-} while (0)
-
-#define CTL_LEAF(mib, miblen, leaf, v, t) do { \
- assert(miblen < CTL_MAX_DEPTH); \
- size_t miblen_new = CTL_MAX_DEPTH; \
- size_t sz = sizeof(t); \
- xmallctlbymibname(mib, miblen, leaf, &miblen_new, (void *)v, \
- &sz, NULL, 0); \
- assert(miblen_new == miblen + 1); \
-} while (0)
-
-#define CTL_M2_GET(n, i, v, t) do { \
- size_t mib[CTL_MAX_DEPTH]; \
- size_t miblen = sizeof(mib) / sizeof(size_t); \
- size_t sz = sizeof(t); \
- xmallctlnametomib(n, mib, &miblen); \
- mib[2] = (i); \
- xmallctlbymib(mib, miblen, (void *)v, &sz, NULL, 0); \
-} while (0)
-
-/******************************************************************************/
-/* Data. */
-
-bool opt_stats_print = false;
-char opt_stats_print_opts[stats_print_tot_num_options+1] = "";
-
-int64_t opt_stats_interval = STATS_INTERVAL_DEFAULT;
-char opt_stats_interval_opts[stats_print_tot_num_options+1] = "";
-
-static counter_accum_t stats_interval_accumulated;
-/* Per thread batch accum size for stats_interval. */
-static uint64_t stats_interval_accum_batch;
-
-/******************************************************************************/
-
-static uint64_t
-rate_per_second(uint64_t value, uint64_t uptime_ns) {
- uint64_t billion = 1000000000;
- if (uptime_ns == 0 || value == 0) {
- return 0;
- }
- if (uptime_ns < billion) {
- return value;
- } else {
- uint64_t uptime_s = uptime_ns / billion;
- return value / uptime_s;
- }
-}
-
-/* Calculate x.yyy and output a string (takes a fixed sized char array). */
-static bool
-get_rate_str(uint64_t dividend, uint64_t divisor, char str[6]) {
- if (divisor == 0 || dividend > divisor) {
- /* The rate is not supposed to be greater than 1. */
- return true;
- }
- if (dividend > 0) {
- assert(UINT64_MAX / dividend >= 1000);
- }
-
- unsigned n = (unsigned)((dividend * 1000) / divisor);
- if (n < 10) {
- malloc_snprintf(str, 6, "0.00%u", n);
- } else if (n < 100) {
- malloc_snprintf(str, 6, "0.0%u", n);
- } else if (n < 1000) {
- malloc_snprintf(str, 6, "0.%u", n);
- } else {
- malloc_snprintf(str, 6, "1");
- }
-
- return false;
-}
-
-static void
-mutex_stats_init_cols(emitter_row_t *row, const char *table_name,
- emitter_col_t *name,
- emitter_col_t col_uint64_t[mutex_prof_num_uint64_t_counters],
- emitter_col_t col_uint32_t[mutex_prof_num_uint32_t_counters]) {
- mutex_prof_uint64_t_counter_ind_t k_uint64_t = 0;
- mutex_prof_uint32_t_counter_ind_t k_uint32_t = 0;
-
- emitter_col_t *col;
-
- if (name != NULL) {
- emitter_col_init(name, row);
- name->justify = emitter_justify_left;
- name->width = 21;
- name->type = emitter_type_title;
- name->str_val = table_name;
- }
-
-#define WIDTH_uint32_t 12
-#define WIDTH_uint64_t 16
-#define OP(counter, counter_type, human, derived, base_counter) \
- col = &col_##counter_type[k_##counter_type]; \
- ++k_##counter_type; \
- emitter_col_init(col, row); \
- col->justify = emitter_justify_right; \
- col->width = derived ? 8 : WIDTH_##counter_type; \
- col->type = emitter_type_title; \
- col->str_val = human;
- MUTEX_PROF_COUNTERS
-#undef OP
-#undef WIDTH_uint32_t
-#undef WIDTH_uint64_t
- col_uint64_t[mutex_counter_total_wait_time_ps].width = 10;
-}
-
-static void
-mutex_stats_read_global(size_t mib[], size_t miblen, const char *name,
- emitter_col_t *col_name,
- emitter_col_t col_uint64_t[mutex_prof_num_uint64_t_counters],
- emitter_col_t col_uint32_t[mutex_prof_num_uint32_t_counters],
- uint64_t uptime) {
- CTL_LEAF_PREPARE(mib, miblen, name);
- size_t miblen_name = miblen + 1;
-
- col_name->str_val = name;
-
- emitter_col_t *dst;
-#define EMITTER_TYPE_uint32_t emitter_type_uint32
-#define EMITTER_TYPE_uint64_t emitter_type_uint64
-#define OP(counter, counter_type, human, derived, base_counter) \
- dst = &col_##counter_type[mutex_counter_##counter]; \
- dst->type = EMITTER_TYPE_##counter_type; \
- if (!derived) { \
- CTL_LEAF(mib, miblen_name, #counter, \
- (counter_type *)&dst->bool_val, counter_type); \
- } else { \
- emitter_col_t *base = \
- &col_##counter_type[mutex_counter_##base_counter]; \
- dst->counter_type##_val = \
- (counter_type)rate_per_second( \
- base->counter_type##_val, uptime); \
- }
- MUTEX_PROF_COUNTERS
-#undef OP
-#undef EMITTER_TYPE_uint32_t
-#undef EMITTER_TYPE_uint64_t
-}
-
-static void
-mutex_stats_read_arena(size_t mib[], size_t miblen, const char *name,
- emitter_col_t *col_name,
- emitter_col_t col_uint64_t[mutex_prof_num_uint64_t_counters],
- emitter_col_t col_uint32_t[mutex_prof_num_uint32_t_counters],
- uint64_t uptime) {
- CTL_LEAF_PREPARE(mib, miblen, name);
- size_t miblen_name = miblen + 1;
-
- col_name->str_val = name;
-
- emitter_col_t *dst;
-#define EMITTER_TYPE_uint32_t emitter_type_uint32
-#define EMITTER_TYPE_uint64_t emitter_type_uint64
-#define OP(counter, counter_type, human, derived, base_counter) \
- dst = &col_##counter_type[mutex_counter_##counter]; \
- dst->type = EMITTER_TYPE_##counter_type; \
- if (!derived) { \
- CTL_LEAF(mib, miblen_name, #counter, \
- (counter_type *)&dst->bool_val, counter_type); \
- } else { \
- emitter_col_t *base = \
- &col_##counter_type[mutex_counter_##base_counter]; \
- dst->counter_type##_val = \
- (counter_type)rate_per_second( \
- base->counter_type##_val, uptime); \
- }
- MUTEX_PROF_COUNTERS
-#undef OP
-#undef EMITTER_TYPE_uint32_t
-#undef EMITTER_TYPE_uint64_t
-}
-
-static void
-mutex_stats_read_arena_bin(size_t mib[], size_t miblen,
- emitter_col_t col_uint64_t[mutex_prof_num_uint64_t_counters],
- emitter_col_t col_uint32_t[mutex_prof_num_uint32_t_counters],
- uint64_t uptime) {
- CTL_LEAF_PREPARE(mib, miblen, "mutex");
- size_t miblen_mutex = miblen + 1;
-
- emitter_col_t *dst;
-
-#define EMITTER_TYPE_uint32_t emitter_type_uint32
-#define EMITTER_TYPE_uint64_t emitter_type_uint64
-#define OP(counter, counter_type, human, derived, base_counter) \
- dst = &col_##counter_type[mutex_counter_##counter]; \
- dst->type = EMITTER_TYPE_##counter_type; \
- if (!derived) { \
- CTL_LEAF(mib, miblen_mutex, #counter, \
- (counter_type *)&dst->bool_val, counter_type); \
- } else { \
- emitter_col_t *base = \
- &col_##counter_type[mutex_counter_##base_counter]; \
- dst->counter_type##_val = \
- (counter_type)rate_per_second( \
- base->counter_type##_val, uptime); \
- }
- MUTEX_PROF_COUNTERS
-#undef OP
-#undef EMITTER_TYPE_uint32_t
-#undef EMITTER_TYPE_uint64_t
-}
-
-/* "row" can be NULL to avoid emitting in table mode. */
-static void
-mutex_stats_emit(emitter_t *emitter, emitter_row_t *row,
- emitter_col_t col_uint64_t[mutex_prof_num_uint64_t_counters],
- emitter_col_t col_uint32_t[mutex_prof_num_uint32_t_counters]) {
- if (row != NULL) {
- emitter_table_row(emitter, row);
- }
-
- mutex_prof_uint64_t_counter_ind_t k_uint64_t = 0;
- mutex_prof_uint32_t_counter_ind_t k_uint32_t = 0;
-
- emitter_col_t *col;
-
-#define EMITTER_TYPE_uint32_t emitter_type_uint32
-#define EMITTER_TYPE_uint64_t emitter_type_uint64
-#define OP(counter, type, human, derived, base_counter) \
- if (!derived) { \
- col = &col_##type[k_##type]; \
- ++k_##type; \
- emitter_json_kv(emitter, #counter, EMITTER_TYPE_##type, \
- (const void *)&col->bool_val); \
- }
- MUTEX_PROF_COUNTERS;
-#undef OP
-#undef EMITTER_TYPE_uint32_t
-#undef EMITTER_TYPE_uint64_t
-}
-
-#define COL_DECLARE(column_name) \
- emitter_col_t col_##column_name;
-
-#define COL_INIT(row_name, column_name, left_or_right, col_width, etype)\
- emitter_col_init(&col_##column_name, &row_name); \
- col_##column_name.justify = emitter_justify_##left_or_right; \
- col_##column_name.width = col_width; \
- col_##column_name.type = emitter_type_##etype;
-
-#define COL(row_name, column_name, left_or_right, col_width, etype) \
- COL_DECLARE(column_name); \
- COL_INIT(row_name, column_name, left_or_right, col_width, etype)
-
-#define COL_HDR_DECLARE(column_name) \
- COL_DECLARE(column_name); \
- emitter_col_t header_##column_name;
-
-#define COL_HDR_INIT(row_name, column_name, human, left_or_right, \
- col_width, etype) \
- COL_INIT(row_name, column_name, left_or_right, col_width, etype)\
- emitter_col_init(&header_##column_name, &header_##row_name); \
- header_##column_name.justify = emitter_justify_##left_or_right; \
- header_##column_name.width = col_width; \
- header_##column_name.type = emitter_type_title; \
- header_##column_name.str_val = human ? human : #column_name;
-
-#define COL_HDR(row_name, column_name, human, left_or_right, col_width, \
- etype) \
- COL_HDR_DECLARE(column_name) \
- COL_HDR_INIT(row_name, column_name, human, left_or_right, \
- col_width, etype)
-
-JEMALLOC_COLD
-static void
-stats_arena_bins_print(emitter_t *emitter, bool mutex, unsigned i,
- uint64_t uptime) {
- size_t page;
- bool in_gap, in_gap_prev;
- unsigned nbins, j;
-
- CTL_GET("arenas.page", &page, size_t);
-
- CTL_GET("arenas.nbins", &nbins, unsigned);
-
- emitter_row_t header_row;
- emitter_row_init(&header_row);
-
- emitter_row_t row;
- emitter_row_init(&row);
-
- bool prof_stats_on = config_prof && opt_prof && opt_prof_stats
- && i == MALLCTL_ARENAS_ALL;
-
- COL_HDR(row, size, NULL, right, 20, size)
- COL_HDR(row, ind, NULL, right, 4, unsigned)
- COL_HDR(row, allocated, NULL, right, 13, uint64)
- COL_HDR(row, nmalloc, NULL, right, 13, uint64)
- COL_HDR(row, nmalloc_ps, "(#/sec)", right, 8, uint64)
- COL_HDR(row, ndalloc, NULL, right, 13, uint64)
- COL_HDR(row, ndalloc_ps, "(#/sec)", right, 8, uint64)
- COL_HDR(row, nrequests, NULL, right, 13, uint64)
- COL_HDR(row, nrequests_ps, "(#/sec)", right, 10, uint64)
- COL_HDR_DECLARE(prof_live_requested);
- COL_HDR_DECLARE(prof_live_count);
- COL_HDR_DECLARE(prof_accum_requested);
- COL_HDR_DECLARE(prof_accum_count);
- if (prof_stats_on) {
- COL_HDR_INIT(row, prof_live_requested, NULL, right, 21, uint64)
- COL_HDR_INIT(row, prof_live_count, NULL, right, 17, uint64)
- COL_HDR_INIT(row, prof_accum_requested, NULL, right, 21, uint64)
- COL_HDR_INIT(row, prof_accum_count, NULL, right, 17, uint64)
- }
- COL_HDR(row, nshards, NULL, right, 9, unsigned)
- COL_HDR(row, curregs, NULL, right, 13, size)
- COL_HDR(row, curslabs, NULL, right, 13, size)
- COL_HDR(row, nonfull_slabs, NULL, right, 15, size)
- COL_HDR(row, regs, NULL, right, 5, unsigned)
- COL_HDR(row, pgs, NULL, right, 4, size)
- /* To buffer a right- and left-justified column. */
- COL_HDR(row, justify_spacer, NULL, right, 1, title)
- COL_HDR(row, util, NULL, right, 6, title)
- COL_HDR(row, nfills, NULL, right, 13, uint64)
- COL_HDR(row, nfills_ps, "(#/sec)", right, 8, uint64)
- COL_HDR(row, nflushes, NULL, right, 13, uint64)
- COL_HDR(row, nflushes_ps, "(#/sec)", right, 8, uint64)
- COL_HDR(row, nslabs, NULL, right, 13, uint64)
- COL_HDR(row, nreslabs, NULL, right, 13, uint64)
- COL_HDR(row, nreslabs_ps, "(#/sec)", right, 8, uint64)
-
- /* Don't want to actually print the name. */
- header_justify_spacer.str_val = " ";
- col_justify_spacer.str_val = " ";
-
- emitter_col_t col_mutex64[mutex_prof_num_uint64_t_counters];
- emitter_col_t col_mutex32[mutex_prof_num_uint32_t_counters];
-
- emitter_col_t header_mutex64[mutex_prof_num_uint64_t_counters];
- emitter_col_t header_mutex32[mutex_prof_num_uint32_t_counters];
-
- if (mutex) {
- mutex_stats_init_cols(&row, NULL, NULL, col_mutex64,
- col_mutex32);
- mutex_stats_init_cols(&header_row, NULL, NULL, header_mutex64,
- header_mutex32);
- }
-
- /*
- * We print a "bins:" header as part of the table row; we need to adjust
- * the header size column to compensate.
- */
- header_size.width -=5;
- emitter_table_printf(emitter, "bins:");
- emitter_table_row(emitter, &header_row);
- emitter_json_array_kv_begin(emitter, "bins");
-
- size_t stats_arenas_mib[CTL_MAX_DEPTH];
- CTL_LEAF_PREPARE(stats_arenas_mib, 0, "stats.arenas");
- stats_arenas_mib[2] = i;
- CTL_LEAF_PREPARE(stats_arenas_mib, 3, "bins");
-
- size_t arenas_bin_mib[CTL_MAX_DEPTH];
- CTL_LEAF_PREPARE(arenas_bin_mib, 0, "arenas.bin");
-
- size_t prof_stats_mib[CTL_MAX_DEPTH];
- if (prof_stats_on) {
- CTL_LEAF_PREPARE(prof_stats_mib, 0, "prof.stats.bins");
- }
-
- for (j = 0, in_gap = false; j < nbins; j++) {
- uint64_t nslabs;
- size_t reg_size, slab_size, curregs;
- size_t curslabs;
- size_t nonfull_slabs;
- uint32_t nregs, nshards;
- uint64_t nmalloc, ndalloc, nrequests, nfills, nflushes;
- uint64_t nreslabs;
- prof_stats_t prof_live;
- prof_stats_t prof_accum;
-
- stats_arenas_mib[4] = j;
- arenas_bin_mib[2] = j;
-
- CTL_LEAF(stats_arenas_mib, 5, "nslabs", &nslabs, uint64_t);
-
- if (prof_stats_on) {
- prof_stats_mib[3] = j;
- CTL_LEAF(prof_stats_mib, 4, "live", &prof_live,
- prof_stats_t);
- CTL_LEAF(prof_stats_mib, 4, "accum", &prof_accum,
- prof_stats_t);
- }
-
- in_gap_prev = in_gap;
- if (prof_stats_on) {
- in_gap = (nslabs == 0 && prof_accum.count == 0);
- } else {
- in_gap = (nslabs == 0);
- }
-
- if (in_gap_prev && !in_gap) {
- emitter_table_printf(emitter,
- " ---\n");
- }
-
- if (in_gap && !emitter_outputs_json(emitter)) {
- continue;
- }
-
- CTL_LEAF(arenas_bin_mib, 3, "size", &reg_size, size_t);
- CTL_LEAF(arenas_bin_mib, 3, "nregs", &nregs, uint32_t);
- CTL_LEAF(arenas_bin_mib, 3, "slab_size", &slab_size, size_t);
- CTL_LEAF(arenas_bin_mib, 3, "nshards", &nshards, uint32_t);
- CTL_LEAF(stats_arenas_mib, 5, "nmalloc", &nmalloc, uint64_t);
- CTL_LEAF(stats_arenas_mib, 5, "ndalloc", &ndalloc, uint64_t);
- CTL_LEAF(stats_arenas_mib, 5, "curregs", &curregs, size_t);
- CTL_LEAF(stats_arenas_mib, 5, "nrequests", &nrequests,
- uint64_t);
- CTL_LEAF(stats_arenas_mib, 5, "nfills", &nfills, uint64_t);
- CTL_LEAF(stats_arenas_mib, 5, "nflushes", &nflushes, uint64_t);
- CTL_LEAF(stats_arenas_mib, 5, "nreslabs", &nreslabs, uint64_t);
- CTL_LEAF(stats_arenas_mib, 5, "curslabs", &curslabs, size_t);
- CTL_LEAF(stats_arenas_mib, 5, "nonfull_slabs", &nonfull_slabs,
- size_t);
-
- if (mutex) {
- mutex_stats_read_arena_bin(stats_arenas_mib, 5,
- col_mutex64, col_mutex32, uptime);
- }
-
- emitter_json_object_begin(emitter);
- emitter_json_kv(emitter, "nmalloc", emitter_type_uint64,
- &nmalloc);
- emitter_json_kv(emitter, "ndalloc", emitter_type_uint64,
- &ndalloc);
- emitter_json_kv(emitter, "curregs", emitter_type_size,
- &curregs);
- emitter_json_kv(emitter, "nrequests", emitter_type_uint64,
- &nrequests);
- if (prof_stats_on) {
- emitter_json_kv(emitter, "prof_live_requested",
- emitter_type_uint64, &prof_live.req_sum);
- emitter_json_kv(emitter, "prof_live_count",
- emitter_type_uint64, &prof_live.count);
- emitter_json_kv(emitter, "prof_accum_requested",
- emitter_type_uint64, &prof_accum.req_sum);
- emitter_json_kv(emitter, "prof_accum_count",
- emitter_type_uint64, &prof_accum.count);
- }
- emitter_json_kv(emitter, "nfills", emitter_type_uint64,
- &nfills);
- emitter_json_kv(emitter, "nflushes", emitter_type_uint64,
- &nflushes);
- emitter_json_kv(emitter, "nreslabs", emitter_type_uint64,
- &nreslabs);
- emitter_json_kv(emitter, "curslabs", emitter_type_size,
- &curslabs);
- emitter_json_kv(emitter, "nonfull_slabs", emitter_type_size,
- &nonfull_slabs);
- if (mutex) {
- emitter_json_object_kv_begin(emitter, "mutex");
- mutex_stats_emit(emitter, NULL, col_mutex64,
- col_mutex32);
- emitter_json_object_end(emitter);
- }
- emitter_json_object_end(emitter);
-
- size_t availregs = nregs * curslabs;
- char util[6];
- if (get_rate_str((uint64_t)curregs, (uint64_t)availregs, util))
- {
- if (availregs == 0) {
- malloc_snprintf(util, sizeof(util), "1");
- } else if (curregs > availregs) {
- /*
- * Race detected: the counters were read in
- * separate mallctl calls and concurrent
- * operations happened in between. In this case
- * no meaningful utilization can be computed.
- */
- malloc_snprintf(util, sizeof(util), " race");
- } else {
- not_reached();
- }
- }
-
- col_size.size_val = reg_size;
- col_ind.unsigned_val = j;
- col_allocated.size_val = curregs * reg_size;
- col_nmalloc.uint64_val = nmalloc;
- col_nmalloc_ps.uint64_val = rate_per_second(nmalloc, uptime);
- col_ndalloc.uint64_val = ndalloc;
- col_ndalloc_ps.uint64_val = rate_per_second(ndalloc, uptime);
- col_nrequests.uint64_val = nrequests;
- col_nrequests_ps.uint64_val = rate_per_second(nrequests, uptime);
- if (prof_stats_on) {
- col_prof_live_requested.uint64_val = prof_live.req_sum;
- col_prof_live_count.uint64_val = prof_live.count;
- col_prof_accum_requested.uint64_val =
- prof_accum.req_sum;
- col_prof_accum_count.uint64_val = prof_accum.count;
- }
- col_nshards.unsigned_val = nshards;
- col_curregs.size_val = curregs;
- col_curslabs.size_val = curslabs;
- col_nonfull_slabs.size_val = nonfull_slabs;
- col_regs.unsigned_val = nregs;
- col_pgs.size_val = slab_size / page;
- col_util.str_val = util;
- col_nfills.uint64_val = nfills;
- col_nfills_ps.uint64_val = rate_per_second(nfills, uptime);
- col_nflushes.uint64_val = nflushes;
- col_nflushes_ps.uint64_val = rate_per_second(nflushes, uptime);
- col_nslabs.uint64_val = nslabs;
- col_nreslabs.uint64_val = nreslabs;
- col_nreslabs_ps.uint64_val = rate_per_second(nreslabs, uptime);
-
- /*
- * Note that mutex columns were initialized above, if mutex ==
- * true.
- */
-
- emitter_table_row(emitter, &row);
- }
- emitter_json_array_end(emitter); /* Close "bins". */
-
- if (in_gap) {
- emitter_table_printf(emitter, " ---\n");
- }
-}
-
-JEMALLOC_COLD
-static void
-stats_arena_lextents_print(emitter_t *emitter, unsigned i, uint64_t uptime) {
- unsigned nbins, nlextents, j;
- bool in_gap, in_gap_prev;
-
- CTL_GET("arenas.nbins", &nbins, unsigned);
- CTL_GET("arenas.nlextents", &nlextents, unsigned);
-
- emitter_row_t header_row;
- emitter_row_init(&header_row);
- emitter_row_t row;
- emitter_row_init(&row);
-
- bool prof_stats_on = config_prof && opt_prof && opt_prof_stats
- && i == MALLCTL_ARENAS_ALL;
-
- COL_HDR(row, size, NULL, right, 20, size)
- COL_HDR(row, ind, NULL, right, 4, unsigned)
- COL_HDR(row, allocated, NULL, right, 13, size)
- COL_HDR(row, nmalloc, NULL, right, 13, uint64)
- COL_HDR(row, nmalloc_ps, "(#/sec)", right, 8, uint64)
- COL_HDR(row, ndalloc, NULL, right, 13, uint64)
- COL_HDR(row, ndalloc_ps, "(#/sec)", right, 8, uint64)
- COL_HDR(row, nrequests, NULL, right, 13, uint64)
- COL_HDR(row, nrequests_ps, "(#/sec)", right, 8, uint64)
- COL_HDR_DECLARE(prof_live_requested)
- COL_HDR_DECLARE(prof_live_count)
- COL_HDR_DECLARE(prof_accum_requested)
- COL_HDR_DECLARE(prof_accum_count)
- if (prof_stats_on) {
- COL_HDR_INIT(row, prof_live_requested, NULL, right, 21, uint64)
- COL_HDR_INIT(row, prof_live_count, NULL, right, 17, uint64)
- COL_HDR_INIT(row, prof_accum_requested, NULL, right, 21, uint64)
- COL_HDR_INIT(row, prof_accum_count, NULL, right, 17, uint64)
- }
- COL_HDR(row, curlextents, NULL, right, 13, size)
-
- /* As with bins, we label the large extents table. */
- header_size.width -= 6;
- emitter_table_printf(emitter, "large:");
- emitter_table_row(emitter, &header_row);
- emitter_json_array_kv_begin(emitter, "lextents");
-
- size_t stats_arenas_mib[CTL_MAX_DEPTH];
- CTL_LEAF_PREPARE(stats_arenas_mib, 0, "stats.arenas");
- stats_arenas_mib[2] = i;
- CTL_LEAF_PREPARE(stats_arenas_mib, 3, "lextents");
-
- size_t arenas_lextent_mib[CTL_MAX_DEPTH];
- CTL_LEAF_PREPARE(arenas_lextent_mib, 0, "arenas.lextent");
-
- size_t prof_stats_mib[CTL_MAX_DEPTH];
- if (prof_stats_on) {
- CTL_LEAF_PREPARE(prof_stats_mib, 0, "prof.stats.lextents");
- }
-
- for (j = 0, in_gap = false; j < nlextents; j++) {
- uint64_t nmalloc, ndalloc, nrequests;
- size_t lextent_size, curlextents;
- prof_stats_t prof_live;
- prof_stats_t prof_accum;
-
- stats_arenas_mib[4] = j;
- arenas_lextent_mib[2] = j;
-
- CTL_LEAF(stats_arenas_mib, 5, "nmalloc", &nmalloc, uint64_t);
- CTL_LEAF(stats_arenas_mib, 5, "ndalloc", &ndalloc, uint64_t);
- CTL_LEAF(stats_arenas_mib, 5, "nrequests", &nrequests,
- uint64_t);
-
- in_gap_prev = in_gap;
- in_gap = (nrequests == 0);
-
- if (in_gap_prev && !in_gap) {
- emitter_table_printf(emitter,
- " ---\n");
- }
-
- CTL_LEAF(arenas_lextent_mib, 3, "size", &lextent_size, size_t);
- CTL_LEAF(stats_arenas_mib, 5, "curlextents", &curlextents,
- size_t);
-
- if (prof_stats_on) {
- prof_stats_mib[3] = j;
- CTL_LEAF(prof_stats_mib, 4, "live", &prof_live,
- prof_stats_t);
- CTL_LEAF(prof_stats_mib, 4, "accum", &prof_accum,
- prof_stats_t);
- }
-
- emitter_json_object_begin(emitter);
- if (prof_stats_on) {
- emitter_json_kv(emitter, "prof_live_requested",
- emitter_type_uint64, &prof_live.req_sum);
- emitter_json_kv(emitter, "prof_live_count",
- emitter_type_uint64, &prof_live.count);
- emitter_json_kv(emitter, "prof_accum_requested",
- emitter_type_uint64, &prof_accum.req_sum);
- emitter_json_kv(emitter, "prof_accum_count",
- emitter_type_uint64, &prof_accum.count);
- }
- emitter_json_kv(emitter, "curlextents", emitter_type_size,
- &curlextents);
- emitter_json_object_end(emitter);
-
- col_size.size_val = lextent_size;
- col_ind.unsigned_val = nbins + j;
- col_allocated.size_val = curlextents * lextent_size;
- col_nmalloc.uint64_val = nmalloc;
- col_nmalloc_ps.uint64_val = rate_per_second(nmalloc, uptime);
- col_ndalloc.uint64_val = ndalloc;
- col_ndalloc_ps.uint64_val = rate_per_second(ndalloc, uptime);
- col_nrequests.uint64_val = nrequests;
- col_nrequests_ps.uint64_val = rate_per_second(nrequests, uptime);
- if (prof_stats_on) {
- col_prof_live_requested.uint64_val = prof_live.req_sum;
- col_prof_live_count.uint64_val = prof_live.count;
- col_prof_accum_requested.uint64_val =
- prof_accum.req_sum;
- col_prof_accum_count.uint64_val = prof_accum.count;
- }
- col_curlextents.size_val = curlextents;
-
- if (!in_gap) {
- emitter_table_row(emitter, &row);
- }
- }
- emitter_json_array_end(emitter); /* Close "lextents". */
- if (in_gap) {
- emitter_table_printf(emitter, " ---\n");
- }
-}
-
-JEMALLOC_COLD
-static void
-stats_arena_extents_print(emitter_t *emitter, unsigned i) {
- unsigned j;
- bool in_gap, in_gap_prev;
- emitter_row_t header_row;
- emitter_row_init(&header_row);
- emitter_row_t row;
- emitter_row_init(&row);
-
- COL_HDR(row, size, NULL, right, 20, size)
- COL_HDR(row, ind, NULL, right, 4, unsigned)
- COL_HDR(row, ndirty, NULL, right, 13, size)
- COL_HDR(row, dirty, NULL, right, 13, size)
- COL_HDR(row, nmuzzy, NULL, right, 13, size)
- COL_HDR(row, muzzy, NULL, right, 13, size)
- COL_HDR(row, nretained, NULL, right, 13, size)
- COL_HDR(row, retained, NULL, right, 13, size)
- COL_HDR(row, ntotal, NULL, right, 13, size)
- COL_HDR(row, total, NULL, right, 13, size)
-
- /* Label this section. */
- header_size.width -= 8;
- emitter_table_printf(emitter, "extents:");
- emitter_table_row(emitter, &header_row);
- emitter_json_array_kv_begin(emitter, "extents");
-
- size_t stats_arenas_mib[CTL_MAX_DEPTH];
- CTL_LEAF_PREPARE(stats_arenas_mib, 0, "stats.arenas");
- stats_arenas_mib[2] = i;
- CTL_LEAF_PREPARE(stats_arenas_mib, 3, "extents");
-
- in_gap = false;
- for (j = 0; j < SC_NPSIZES; j++) {
- size_t ndirty, nmuzzy, nretained, total, dirty_bytes,
- muzzy_bytes, retained_bytes, total_bytes;
- stats_arenas_mib[4] = j;
-
- CTL_LEAF(stats_arenas_mib, 5, "ndirty", &ndirty, size_t);
- CTL_LEAF(stats_arenas_mib, 5, "nmuzzy", &nmuzzy, size_t);
- CTL_LEAF(stats_arenas_mib, 5, "nretained", &nretained, size_t);
- CTL_LEAF(stats_arenas_mib, 5, "dirty_bytes", &dirty_bytes,
- size_t);
- CTL_LEAF(stats_arenas_mib, 5, "muzzy_bytes", &muzzy_bytes,
- size_t);
- CTL_LEAF(stats_arenas_mib, 5, "retained_bytes",
- &retained_bytes, size_t);
-
- total = ndirty + nmuzzy + nretained;
- total_bytes = dirty_bytes + muzzy_bytes + retained_bytes;
-
- in_gap_prev = in_gap;
- in_gap = (total == 0);
-
- if (in_gap_prev && !in_gap) {
- emitter_table_printf(emitter,
- " ---\n");
- }
-
- emitter_json_object_begin(emitter);
- emitter_json_kv(emitter, "ndirty", emitter_type_size, &ndirty);
- emitter_json_kv(emitter, "nmuzzy", emitter_type_size, &nmuzzy);
- emitter_json_kv(emitter, "nretained", emitter_type_size,
- &nretained);
-
- emitter_json_kv(emitter, "dirty_bytes", emitter_type_size,
- &dirty_bytes);
- emitter_json_kv(emitter, "muzzy_bytes", emitter_type_size,
- &muzzy_bytes);
- emitter_json_kv(emitter, "retained_bytes", emitter_type_size,
- &retained_bytes);
- emitter_json_object_end(emitter);
-
- col_size.size_val = sz_pind2sz(j);
- col_ind.size_val = j;
- col_ndirty.size_val = ndirty;
- col_dirty.size_val = dirty_bytes;
- col_nmuzzy.size_val = nmuzzy;
- col_muzzy.size_val = muzzy_bytes;
- col_nretained.size_val = nretained;
- col_retained.size_val = retained_bytes;
- col_ntotal.size_val = total;
- col_total.size_val = total_bytes;
-
- if (!in_gap) {
- emitter_table_row(emitter, &row);
- }
- }
- emitter_json_array_end(emitter); /* Close "extents". */
- if (in_gap) {
- emitter_table_printf(emitter, " ---\n");
- }
-}
-
-static void
-stats_arena_hpa_shard_print(emitter_t *emitter, unsigned i, uint64_t uptime) {
- emitter_row_t header_row;
- emitter_row_init(&header_row);
- emitter_row_t row;
- emitter_row_init(&row);
-
- uint64_t npurge_passes;
- uint64_t npurges;
- uint64_t nhugifies;
- uint64_t ndehugifies;
-
- CTL_M2_GET("stats.arenas.0.hpa_shard.npurge_passes",
- i, &npurge_passes, uint64_t);
- CTL_M2_GET("stats.arenas.0.hpa_shard.npurges",
- i, &npurges, uint64_t);
- CTL_M2_GET("stats.arenas.0.hpa_shard.nhugifies",
- i, &nhugifies, uint64_t);
- CTL_M2_GET("stats.arenas.0.hpa_shard.ndehugifies",
- i, &ndehugifies, uint64_t);
-
- size_t npageslabs_huge;
- size_t nactive_huge;
- size_t ndirty_huge;
-
- size_t npageslabs_nonhuge;
- size_t nactive_nonhuge;
- size_t ndirty_nonhuge;
- size_t nretained_nonhuge;
-
- size_t sec_bytes;
- CTL_M2_GET("stats.arenas.0.hpa_sec_bytes", i, &sec_bytes, size_t);
- emitter_kv(emitter, "sec_bytes", "Bytes in small extent cache",
- emitter_type_size, &sec_bytes);
-
- /* First, global stats. */
- emitter_table_printf(emitter,
- "HPA shard stats:\n"
- " Purge passes: %" FMTu64 " (%" FMTu64 " / sec)\n"
- " Purges: %" FMTu64 " (%" FMTu64 " / sec)\n"
- " Hugeifies: %" FMTu64 " (%" FMTu64 " / sec)\n"
- " Dehugifies: %" FMTu64 " (%" FMTu64 " / sec)\n"
- "\n",
- npurge_passes, rate_per_second(npurge_passes, uptime),
- npurges, rate_per_second(npurges, uptime),
- nhugifies, rate_per_second(nhugifies, uptime),
- ndehugifies, rate_per_second(ndehugifies, uptime));
-
- emitter_json_object_kv_begin(emitter, "hpa_shard");
- emitter_json_kv(emitter, "npurge_passes", emitter_type_uint64,
- &npurge_passes);
- emitter_json_kv(emitter, "npurges", emitter_type_uint64,
- &npurges);
- emitter_json_kv(emitter, "nhugifies", emitter_type_uint64,
- &nhugifies);
- emitter_json_kv(emitter, "ndehugifies", emitter_type_uint64,
- &ndehugifies);
-
- /* Next, full slab stats. */
- CTL_M2_GET("stats.arenas.0.hpa_shard.full_slabs.npageslabs_huge",
- i, &npageslabs_huge, size_t);
- CTL_M2_GET("stats.arenas.0.hpa_shard.full_slabs.nactive_huge",
- i, &nactive_huge, size_t);
- CTL_M2_GET("stats.arenas.0.hpa_shard.full_slabs.ndirty_huge",
- i, &ndirty_huge, size_t);
-
- CTL_M2_GET("stats.arenas.0.hpa_shard.full_slabs.npageslabs_nonhuge",
- i, &npageslabs_nonhuge, size_t);
- CTL_M2_GET("stats.arenas.0.hpa_shard.full_slabs.nactive_nonhuge",
- i, &nactive_nonhuge, size_t);
- CTL_M2_GET("stats.arenas.0.hpa_shard.full_slabs.ndirty_nonhuge",
- i, &ndirty_nonhuge, size_t);
- nretained_nonhuge = npageslabs_nonhuge * HUGEPAGE_PAGES
- - nactive_nonhuge - ndirty_nonhuge;
-
- emitter_table_printf(emitter,
- " In full slabs:\n"
- " npageslabs: %zu huge, %zu nonhuge\n"
- " nactive: %zu huge, %zu nonhuge \n"
- " ndirty: %zu huge, %zu nonhuge \n"
- " nretained: 0 huge, %zu nonhuge \n",
- npageslabs_huge, npageslabs_nonhuge,
- nactive_huge, nactive_nonhuge,
- ndirty_huge, ndirty_nonhuge,
- nretained_nonhuge);
-
- emitter_json_object_kv_begin(emitter, "full_slabs");
- emitter_json_kv(emitter, "npageslabs_huge", emitter_type_size,
- &npageslabs_huge);
- emitter_json_kv(emitter, "nactive_huge", emitter_type_size,
- &nactive_huge);
- emitter_json_kv(emitter, "nactive_huge", emitter_type_size,
- &nactive_huge);
- emitter_json_kv(emitter, "npageslabs_nonhuge", emitter_type_size,
- &npageslabs_nonhuge);
- emitter_json_kv(emitter, "nactive_nonhuge", emitter_type_size,
- &nactive_nonhuge);
- emitter_json_kv(emitter, "ndirty_nonhuge", emitter_type_size,
- &ndirty_nonhuge);
- emitter_json_object_end(emitter); /* End "full_slabs" */
-
- /* Next, empty slab stats. */
- CTL_M2_GET("stats.arenas.0.hpa_shard.empty_slabs.npageslabs_huge",
- i, &npageslabs_huge, size_t);
- CTL_M2_GET("stats.arenas.0.hpa_shard.empty_slabs.nactive_huge",
- i, &nactive_huge, size_t);
- CTL_M2_GET("stats.arenas.0.hpa_shard.empty_slabs.ndirty_huge",
- i, &ndirty_huge, size_t);
-
- CTL_M2_GET("stats.arenas.0.hpa_shard.empty_slabs.npageslabs_nonhuge",
- i, &npageslabs_nonhuge, size_t);
- CTL_M2_GET("stats.arenas.0.hpa_shard.empty_slabs.nactive_nonhuge",
- i, &nactive_nonhuge, size_t);
- CTL_M2_GET("stats.arenas.0.hpa_shard.empty_slabs.ndirty_nonhuge",
- i, &ndirty_nonhuge, size_t);
- nretained_nonhuge = npageslabs_nonhuge * HUGEPAGE_PAGES
- - nactive_nonhuge - ndirty_nonhuge;
-
- emitter_table_printf(emitter,
- " In empty slabs:\n"
- " npageslabs: %zu huge, %zu nonhuge\n"
- " nactive: %zu huge, %zu nonhuge \n"
- " ndirty: %zu huge, %zu nonhuge \n"
- " nretained: 0 huge, %zu nonhuge \n"
- "\n",
- npageslabs_huge, npageslabs_nonhuge,
- nactive_huge, nactive_nonhuge,
- ndirty_huge, ndirty_nonhuge,
- nretained_nonhuge);
-
- emitter_json_object_kv_begin(emitter, "empty_slabs");
- emitter_json_kv(emitter, "npageslabs_huge", emitter_type_size,
- &npageslabs_huge);
- emitter_json_kv(emitter, "nactive_huge", emitter_type_size,
- &nactive_huge);
- emitter_json_kv(emitter, "nactive_huge", emitter_type_size,
- &nactive_huge);
- emitter_json_kv(emitter, "npageslabs_nonhuge", emitter_type_size,
- &npageslabs_nonhuge);
- emitter_json_kv(emitter, "nactive_nonhuge", emitter_type_size,
- &nactive_nonhuge);
- emitter_json_kv(emitter, "ndirty_nonhuge", emitter_type_size,
- &ndirty_nonhuge);
- emitter_json_object_end(emitter); /* End "empty_slabs" */
-
- COL_HDR(row, size, NULL, right, 20, size)
- COL_HDR(row, ind, NULL, right, 4, unsigned)
- COL_HDR(row, npageslabs_huge, NULL, right, 16, size)
- COL_HDR(row, nactive_huge, NULL, right, 16, size)
- COL_HDR(row, ndirty_huge, NULL, right, 16, size)
- COL_HDR(row, npageslabs_nonhuge, NULL, right, 20, size)
- COL_HDR(row, nactive_nonhuge, NULL, right, 20, size)
- COL_HDR(row, ndirty_nonhuge, NULL, right, 20, size)
- COL_HDR(row, nretained_nonhuge, NULL, right, 20, size)
-
- size_t stats_arenas_mib[CTL_MAX_DEPTH];
- CTL_LEAF_PREPARE(stats_arenas_mib, 0, "stats.arenas");
- stats_arenas_mib[2] = i;
- CTL_LEAF_PREPARE(stats_arenas_mib, 3, "hpa_shard.nonfull_slabs");
-
- emitter_table_row(emitter, &header_row);
- emitter_json_array_kv_begin(emitter, "nonfull_slabs");
- bool in_gap = false;
- for (pszind_t j = 0; j < PSSET_NPSIZES && j < SC_NPSIZES; j++) {
- stats_arenas_mib[5] = j;
-
- CTL_LEAF(stats_arenas_mib, 6, "npageslabs_huge",
- &npageslabs_huge, size_t);
- CTL_LEAF(stats_arenas_mib, 6, "nactive_huge",
- &nactive_huge, size_t);
- CTL_LEAF(stats_arenas_mib, 6, "ndirty_huge",
- &ndirty_huge, size_t);
-
- CTL_LEAF(stats_arenas_mib, 6, "npageslabs_nonhuge",
- &npageslabs_nonhuge, size_t);
- CTL_LEAF(stats_arenas_mib, 6, "nactive_nonhuge",
- &nactive_nonhuge, size_t);
- CTL_LEAF(stats_arenas_mib, 6, "ndirty_nonhuge",
- &ndirty_nonhuge, size_t);
- nretained_nonhuge = npageslabs_nonhuge * HUGEPAGE_PAGES
- - nactive_nonhuge - ndirty_nonhuge;
-
- bool in_gap_prev = in_gap;
- in_gap = (npageslabs_huge == 0 && npageslabs_nonhuge == 0);
- if (in_gap_prev && !in_gap) {
- emitter_table_printf(emitter,
- " ---\n");
- }
-
- col_size.size_val = sz_pind2sz(j);
- col_ind.size_val = j;
- col_npageslabs_huge.size_val = npageslabs_huge;
- col_nactive_huge.size_val = nactive_huge;
- col_ndirty_huge.size_val = ndirty_huge;
- col_npageslabs_nonhuge.size_val = npageslabs_nonhuge;
- col_nactive_nonhuge.size_val = nactive_nonhuge;
- col_ndirty_nonhuge.size_val = ndirty_nonhuge;
- col_nretained_nonhuge.size_val = nretained_nonhuge;
- if (!in_gap) {
- emitter_table_row(emitter, &row);
- }
-
- emitter_json_object_begin(emitter);
- emitter_json_kv(emitter, "npageslabs_huge", emitter_type_size,
- &npageslabs_huge);
- emitter_json_kv(emitter, "nactive_huge", emitter_type_size,
- &nactive_huge);
- emitter_json_kv(emitter, "ndirty_huge", emitter_type_size,
- &ndirty_huge);
- emitter_json_kv(emitter, "npageslabs_nonhuge", emitter_type_size,
- &npageslabs_nonhuge);
- emitter_json_kv(emitter, "nactive_nonhuge", emitter_type_size,
- &nactive_nonhuge);
- emitter_json_kv(emitter, "ndirty_nonhuge", emitter_type_size,
- &ndirty_nonhuge);
- emitter_json_object_end(emitter);
- }
- emitter_json_array_end(emitter); /* End "nonfull_slabs" */
- emitter_json_object_end(emitter); /* End "hpa_shard" */
- if (in_gap) {
- emitter_table_printf(emitter, " ---\n");
- }
-}
-
-static void
-stats_arena_mutexes_print(emitter_t *emitter, unsigned arena_ind, uint64_t uptime) {
- emitter_row_t row;
- emitter_col_t col_name;
- emitter_col_t col64[mutex_prof_num_uint64_t_counters];
- emitter_col_t col32[mutex_prof_num_uint32_t_counters];
-
- emitter_row_init(&row);
- mutex_stats_init_cols(&row, "", &col_name, col64, col32);
-
- emitter_json_object_kv_begin(emitter, "mutexes");
- emitter_table_row(emitter, &row);
-
- size_t stats_arenas_mib[CTL_MAX_DEPTH];
- CTL_LEAF_PREPARE(stats_arenas_mib, 0, "stats.arenas");
- stats_arenas_mib[2] = arena_ind;
- CTL_LEAF_PREPARE(stats_arenas_mib, 3, "mutexes");
-
- for (mutex_prof_arena_ind_t i = 0; i < mutex_prof_num_arena_mutexes;
- i++) {
- const char *name = arena_mutex_names[i];
- emitter_json_object_kv_begin(emitter, name);
- mutex_stats_read_arena(stats_arenas_mib, 4, name, &col_name,
- col64, col32, uptime);
- mutex_stats_emit(emitter, &row, col64, col32);
- emitter_json_object_end(emitter); /* Close the mutex dict. */
- }
- emitter_json_object_end(emitter); /* End "mutexes". */
-}
-
-JEMALLOC_COLD
-static void
-stats_arena_print(emitter_t *emitter, unsigned i, bool bins, bool large,
- bool mutex, bool extents, bool hpa) {
- unsigned nthreads;
- const char *dss;
- ssize_t dirty_decay_ms, muzzy_decay_ms;
- size_t page, pactive, pdirty, pmuzzy, mapped, retained;
- size_t base, internal, resident, metadata_thp, extent_avail;
- uint64_t dirty_npurge, dirty_nmadvise, dirty_purged;
- uint64_t muzzy_npurge, muzzy_nmadvise, muzzy_purged;
- size_t small_allocated;
- uint64_t small_nmalloc, small_ndalloc, small_nrequests, small_nfills,
- small_nflushes;
- size_t large_allocated;
- uint64_t large_nmalloc, large_ndalloc, large_nrequests, large_nfills,
- large_nflushes;
- size_t tcache_bytes, tcache_stashed_bytes, abandoned_vm;
- uint64_t uptime;
-
- CTL_GET("arenas.page", &page, size_t);
-
- CTL_M2_GET("stats.arenas.0.nthreads", i, &nthreads, unsigned);
- emitter_kv(emitter, "nthreads", "assigned threads",
- emitter_type_unsigned, &nthreads);
-
- CTL_M2_GET("stats.arenas.0.uptime", i, &uptime, uint64_t);
- emitter_kv(emitter, "uptime_ns", "uptime", emitter_type_uint64,
- &uptime);
-
- CTL_M2_GET("stats.arenas.0.dss", i, &dss, const char *);
- emitter_kv(emitter, "dss", "dss allocation precedence",
- emitter_type_string, &dss);
-
- CTL_M2_GET("stats.arenas.0.dirty_decay_ms", i, &dirty_decay_ms,
- ssize_t);
- CTL_M2_GET("stats.arenas.0.muzzy_decay_ms", i, &muzzy_decay_ms,
- ssize_t);
- CTL_M2_GET("stats.arenas.0.pactive", i, &pactive, size_t);
- CTL_M2_GET("stats.arenas.0.pdirty", i, &pdirty, size_t);
- CTL_M2_GET("stats.arenas.0.pmuzzy", i, &pmuzzy, size_t);
- CTL_M2_GET("stats.arenas.0.dirty_npurge", i, &dirty_npurge, uint64_t);
- CTL_M2_GET("stats.arenas.0.dirty_nmadvise", i, &dirty_nmadvise,
- uint64_t);
- CTL_M2_GET("stats.arenas.0.dirty_purged", i, &dirty_purged, uint64_t);
- CTL_M2_GET("stats.arenas.0.muzzy_npurge", i, &muzzy_npurge, uint64_t);
- CTL_M2_GET("stats.arenas.0.muzzy_nmadvise", i, &muzzy_nmadvise,
- uint64_t);
- CTL_M2_GET("stats.arenas.0.muzzy_purged", i, &muzzy_purged, uint64_t);
-
- emitter_row_t decay_row;
- emitter_row_init(&decay_row);
-
- /* JSON-style emission. */
- emitter_json_kv(emitter, "dirty_decay_ms", emitter_type_ssize,
- &dirty_decay_ms);
- emitter_json_kv(emitter, "muzzy_decay_ms", emitter_type_ssize,
- &muzzy_decay_ms);
-
- emitter_json_kv(emitter, "pactive", emitter_type_size, &pactive);
- emitter_json_kv(emitter, "pdirty", emitter_type_size, &pdirty);
- emitter_json_kv(emitter, "pmuzzy", emitter_type_size, &pmuzzy);
-
- emitter_json_kv(emitter, "dirty_npurge", emitter_type_uint64,
- &dirty_npurge);
- emitter_json_kv(emitter, "dirty_nmadvise", emitter_type_uint64,
- &dirty_nmadvise);
- emitter_json_kv(emitter, "dirty_purged", emitter_type_uint64,
- &dirty_purged);
-
- emitter_json_kv(emitter, "muzzy_npurge", emitter_type_uint64,
- &muzzy_npurge);
- emitter_json_kv(emitter, "muzzy_nmadvise", emitter_type_uint64,
- &muzzy_nmadvise);
- emitter_json_kv(emitter, "muzzy_purged", emitter_type_uint64,
- &muzzy_purged);
-
- /* Table-style emission. */
- COL(decay_row, decay_type, right, 9, title);
- col_decay_type.str_val = "decaying:";
-
- COL(decay_row, decay_time, right, 6, title);
- col_decay_time.str_val = "time";
-
- COL(decay_row, decay_npages, right, 13, title);
- col_decay_npages.str_val = "npages";
-
- COL(decay_row, decay_sweeps, right, 13, title);
- col_decay_sweeps.str_val = "sweeps";
-
- COL(decay_row, decay_madvises, right, 13, title);
- col_decay_madvises.str_val = "madvises";
-
- COL(decay_row, decay_purged, right, 13, title);
- col_decay_purged.str_val = "purged";
-
- /* Title row. */
- emitter_table_row(emitter, &decay_row);
-
- /* Dirty row. */
- col_decay_type.str_val = "dirty:";
-
- if (dirty_decay_ms >= 0) {
- col_decay_time.type = emitter_type_ssize;
- col_decay_time.ssize_val = dirty_decay_ms;
- } else {
- col_decay_time.type = emitter_type_title;
- col_decay_time.str_val = "N/A";
- }
-
- col_decay_npages.type = emitter_type_size;
- col_decay_npages.size_val = pdirty;
-
- col_decay_sweeps.type = emitter_type_uint64;
- col_decay_sweeps.uint64_val = dirty_npurge;
-
- col_decay_madvises.type = emitter_type_uint64;
- col_decay_madvises.uint64_val = dirty_nmadvise;
-
- col_decay_purged.type = emitter_type_uint64;
- col_decay_purged.uint64_val = dirty_purged;
-
- emitter_table_row(emitter, &decay_row);
-
- /* Muzzy row. */
- col_decay_type.str_val = "muzzy:";
-
- if (muzzy_decay_ms >= 0) {
- col_decay_time.type = emitter_type_ssize;
- col_decay_time.ssize_val = muzzy_decay_ms;
- } else {
- col_decay_time.type = emitter_type_title;
- col_decay_time.str_val = "N/A";
- }
-
- col_decay_npages.type = emitter_type_size;
- col_decay_npages.size_val = pmuzzy;
-
- col_decay_sweeps.type = emitter_type_uint64;
- col_decay_sweeps.uint64_val = muzzy_npurge;
-
- col_decay_madvises.type = emitter_type_uint64;
- col_decay_madvises.uint64_val = muzzy_nmadvise;
-
- col_decay_purged.type = emitter_type_uint64;
- col_decay_purged.uint64_val = muzzy_purged;
-
- emitter_table_row(emitter, &decay_row);
-
- /* Small / large / total allocation counts. */
- emitter_row_t alloc_count_row;
- emitter_row_init(&alloc_count_row);
-
- COL(alloc_count_row, count_title, left, 21, title);
- col_count_title.str_val = "";
-
- COL(alloc_count_row, count_allocated, right, 16, title);
- col_count_allocated.str_val = "allocated";
-
- COL(alloc_count_row, count_nmalloc, right, 16, title);
- col_count_nmalloc.str_val = "nmalloc";
- COL(alloc_count_row, count_nmalloc_ps, right, 10, title);
- col_count_nmalloc_ps.str_val = "(#/sec)";
-
- COL(alloc_count_row, count_ndalloc, right, 16, title);
- col_count_ndalloc.str_val = "ndalloc";
- COL(alloc_count_row, count_ndalloc_ps, right, 10, title);
- col_count_ndalloc_ps.str_val = "(#/sec)";
-
- COL(alloc_count_row, count_nrequests, right, 16, title);
- col_count_nrequests.str_val = "nrequests";
- COL(alloc_count_row, count_nrequests_ps, right, 10, title);
- col_count_nrequests_ps.str_val = "(#/sec)";
-
- COL(alloc_count_row, count_nfills, right, 16, title);
- col_count_nfills.str_val = "nfill";
- COL(alloc_count_row, count_nfills_ps, right, 10, title);
- col_count_nfills_ps.str_val = "(#/sec)";
-
- COL(alloc_count_row, count_nflushes, right, 16, title);
- col_count_nflushes.str_val = "nflush";
- COL(alloc_count_row, count_nflushes_ps, right, 10, title);
- col_count_nflushes_ps.str_val = "(#/sec)";
-
- emitter_table_row(emitter, &alloc_count_row);
-
- col_count_nmalloc_ps.type = emitter_type_uint64;
- col_count_ndalloc_ps.type = emitter_type_uint64;
- col_count_nrequests_ps.type = emitter_type_uint64;
- col_count_nfills_ps.type = emitter_type_uint64;
- col_count_nflushes_ps.type = emitter_type_uint64;
-
-#define GET_AND_EMIT_ALLOC_STAT(small_or_large, name, valtype) \
- CTL_M2_GET("stats.arenas.0." #small_or_large "." #name, i, \
- &small_or_large##_##name, valtype##_t); \
- emitter_json_kv(emitter, #name, emitter_type_##valtype, \
- &small_or_large##_##name); \
- col_count_##name.type = emitter_type_##valtype; \
- col_count_##name.valtype##_val = small_or_large##_##name;
-
- emitter_json_object_kv_begin(emitter, "small");
- col_count_title.str_val = "small:";
-
- GET_AND_EMIT_ALLOC_STAT(small, allocated, size)
- GET_AND_EMIT_ALLOC_STAT(small, nmalloc, uint64)
- col_count_nmalloc_ps.uint64_val =
- rate_per_second(col_count_nmalloc.uint64_val, uptime);
- GET_AND_EMIT_ALLOC_STAT(small, ndalloc, uint64)
- col_count_ndalloc_ps.uint64_val =
- rate_per_second(col_count_ndalloc.uint64_val, uptime);
- GET_AND_EMIT_ALLOC_STAT(small, nrequests, uint64)
- col_count_nrequests_ps.uint64_val =
- rate_per_second(col_count_nrequests.uint64_val, uptime);
- GET_AND_EMIT_ALLOC_STAT(small, nfills, uint64)
- col_count_nfills_ps.uint64_val =
- rate_per_second(col_count_nfills.uint64_val, uptime);
- GET_AND_EMIT_ALLOC_STAT(small, nflushes, uint64)
- col_count_nflushes_ps.uint64_val =
- rate_per_second(col_count_nflushes.uint64_val, uptime);
-
- emitter_table_row(emitter, &alloc_count_row);
- emitter_json_object_end(emitter); /* Close "small". */
-
- emitter_json_object_kv_begin(emitter, "large");
- col_count_title.str_val = "large:";
-
- GET_AND_EMIT_ALLOC_STAT(large, allocated, size)
- GET_AND_EMIT_ALLOC_STAT(large, nmalloc, uint64)
- col_count_nmalloc_ps.uint64_val =
- rate_per_second(col_count_nmalloc.uint64_val, uptime);
- GET_AND_EMIT_ALLOC_STAT(large, ndalloc, uint64)
- col_count_ndalloc_ps.uint64_val =
- rate_per_second(col_count_ndalloc.uint64_val, uptime);
- GET_AND_EMIT_ALLOC_STAT(large, nrequests, uint64)
- col_count_nrequests_ps.uint64_val =
- rate_per_second(col_count_nrequests.uint64_val, uptime);
- GET_AND_EMIT_ALLOC_STAT(large, nfills, uint64)
- col_count_nfills_ps.uint64_val =
- rate_per_second(col_count_nfills.uint64_val, uptime);
- GET_AND_EMIT_ALLOC_STAT(large, nflushes, uint64)
- col_count_nflushes_ps.uint64_val =
- rate_per_second(col_count_nflushes.uint64_val, uptime);
-
- emitter_table_row(emitter, &alloc_count_row);
- emitter_json_object_end(emitter); /* Close "large". */
-
-#undef GET_AND_EMIT_ALLOC_STAT
-
- /* Aggregated small + large stats are emitter only in table mode. */
- col_count_title.str_val = "total:";
- col_count_allocated.size_val = small_allocated + large_allocated;
- col_count_nmalloc.uint64_val = small_nmalloc + large_nmalloc;
- col_count_ndalloc.uint64_val = small_ndalloc + large_ndalloc;
- col_count_nrequests.uint64_val = small_nrequests + large_nrequests;
- col_count_nfills.uint64_val = small_nfills + large_nfills;
- col_count_nflushes.uint64_val = small_nflushes + large_nflushes;
- col_count_nmalloc_ps.uint64_val =
- rate_per_second(col_count_nmalloc.uint64_val, uptime);
- col_count_ndalloc_ps.uint64_val =
- rate_per_second(col_count_ndalloc.uint64_val, uptime);
- col_count_nrequests_ps.uint64_val =
- rate_per_second(col_count_nrequests.uint64_val, uptime);
- col_count_nfills_ps.uint64_val =
- rate_per_second(col_count_nfills.uint64_val, uptime);
- col_count_nflushes_ps.uint64_val =
- rate_per_second(col_count_nflushes.uint64_val, uptime);
- emitter_table_row(emitter, &alloc_count_row);
-
- emitter_row_t mem_count_row;
- emitter_row_init(&mem_count_row);
-
- emitter_col_t mem_count_title;
- emitter_col_init(&mem_count_title, &mem_count_row);
- mem_count_title.justify = emitter_justify_left;
- mem_count_title.width = 21;
- mem_count_title.type = emitter_type_title;
- mem_count_title.str_val = "";
-
- emitter_col_t mem_count_val;
- emitter_col_init(&mem_count_val, &mem_count_row);
- mem_count_val.justify = emitter_justify_right;
- mem_count_val.width = 16;
- mem_count_val.type = emitter_type_title;
- mem_count_val.str_val = "";
-
- emitter_table_row(emitter, &mem_count_row);
- mem_count_val.type = emitter_type_size;
-
- /* Active count in bytes is emitted only in table mode. */
- mem_count_title.str_val = "active:";
- mem_count_val.size_val = pactive * page;
- emitter_table_row(emitter, &mem_count_row);
-
-#define GET_AND_EMIT_MEM_STAT(stat) \
- CTL_M2_GET("stats.arenas.0."#stat, i, &stat, size_t); \
- emitter_json_kv(emitter, #stat, emitter_type_size, &stat); \
- mem_count_title.str_val = #stat":"; \
- mem_count_val.size_val = stat; \
- emitter_table_row(emitter, &mem_count_row);
-
- GET_AND_EMIT_MEM_STAT(mapped)
- GET_AND_EMIT_MEM_STAT(retained)
- GET_AND_EMIT_MEM_STAT(base)
- GET_AND_EMIT_MEM_STAT(internal)
- GET_AND_EMIT_MEM_STAT(metadata_thp)
- GET_AND_EMIT_MEM_STAT(tcache_bytes)
- GET_AND_EMIT_MEM_STAT(tcache_stashed_bytes)
- GET_AND_EMIT_MEM_STAT(resident)
- GET_AND_EMIT_MEM_STAT(abandoned_vm)
- GET_AND_EMIT_MEM_STAT(extent_avail)
-#undef GET_AND_EMIT_MEM_STAT
-
- if (mutex) {
- stats_arena_mutexes_print(emitter, i, uptime);
- }
- if (bins) {
- stats_arena_bins_print(emitter, mutex, i, uptime);
- }
- if (large) {
- stats_arena_lextents_print(emitter, i, uptime);
- }
- if (extents) {
- stats_arena_extents_print(emitter, i);
- }
- if (hpa) {
- stats_arena_hpa_shard_print(emitter, i, uptime);
- }
-}
-
-JEMALLOC_COLD
-static void
-stats_general_print(emitter_t *emitter) {
- const char *cpv;
- bool bv, bv2;
- unsigned uv;
- uint32_t u32v;
- uint64_t u64v;
- int64_t i64v;
- ssize_t ssv, ssv2;
- size_t sv, bsz, usz, u32sz, u64sz, i64sz, ssz, sssz, cpsz;
-
- bsz = sizeof(bool);
- usz = sizeof(unsigned);
- ssz = sizeof(size_t);
- sssz = sizeof(ssize_t);
- cpsz = sizeof(const char *);
- u32sz = sizeof(uint32_t);
- i64sz = sizeof(int64_t);
- u64sz = sizeof(uint64_t);
-
- CTL_GET("version", &cpv, const char *);
- emitter_kv(emitter, "version", "Version", emitter_type_string, &cpv);
-
- /* config. */
- emitter_dict_begin(emitter, "config", "Build-time option settings");
-#define CONFIG_WRITE_BOOL(name) \
- do { \
- CTL_GET("config."#name, &bv, bool); \
- emitter_kv(emitter, #name, "config."#name, \
- emitter_type_bool, &bv); \
- } while (0)
-
- CONFIG_WRITE_BOOL(cache_oblivious);
- CONFIG_WRITE_BOOL(debug);
- CONFIG_WRITE_BOOL(fill);
- CONFIG_WRITE_BOOL(lazy_lock);
- emitter_kv(emitter, "malloc_conf", "config.malloc_conf",
- emitter_type_string, &config_malloc_conf);
-
- CONFIG_WRITE_BOOL(opt_safety_checks);
- CONFIG_WRITE_BOOL(prof);
- CONFIG_WRITE_BOOL(prof_libgcc);
- CONFIG_WRITE_BOOL(prof_libunwind);
- CONFIG_WRITE_BOOL(stats);
- CONFIG_WRITE_BOOL(utrace);
- CONFIG_WRITE_BOOL(xmalloc);
-#undef CONFIG_WRITE_BOOL
- emitter_dict_end(emitter); /* Close "config" dict. */
-
- /* opt. */
-#define OPT_WRITE(name, var, size, emitter_type) \
- if (je_mallctl("opt."name, (void *)&var, &size, NULL, 0) == \
- 0) { \
- emitter_kv(emitter, name, "opt."name, emitter_type, \
- &var); \
- }
-
-#define OPT_WRITE_MUTABLE(name, var1, var2, size, emitter_type, \
- altname) \
- if (je_mallctl("opt."name, (void *)&var1, &size, NULL, 0) == \
- 0 && je_mallctl(altname, (void *)&var2, &size, NULL, 0) \
- == 0) { \
- emitter_kv_note(emitter, name, "opt."name, \
- emitter_type, &var1, altname, emitter_type, \
- &var2); \
- }
-
-#define OPT_WRITE_BOOL(name) OPT_WRITE(name, bv, bsz, emitter_type_bool)
-#define OPT_WRITE_BOOL_MUTABLE(name, altname) \
- OPT_WRITE_MUTABLE(name, bv, bv2, bsz, emitter_type_bool, altname)
-
-#define OPT_WRITE_UNSIGNED(name) \
- OPT_WRITE(name, uv, usz, emitter_type_unsigned)
-
-#define OPT_WRITE_INT64(name) \
- OPT_WRITE(name, i64v, i64sz, emitter_type_int64)
-#define OPT_WRITE_UINT64(name) \
- OPT_WRITE(name, u64v, u64sz, emitter_type_uint64)
-
-#define OPT_WRITE_SIZE_T(name) \
- OPT_WRITE(name, sv, ssz, emitter_type_size)
-#define OPT_WRITE_SSIZE_T(name) \
- OPT_WRITE(name, ssv, sssz, emitter_type_ssize)
-#define OPT_WRITE_SSIZE_T_MUTABLE(name, altname) \
- OPT_WRITE_MUTABLE(name, ssv, ssv2, sssz, emitter_type_ssize, \
- altname)
-
-#define OPT_WRITE_CHAR_P(name) \
- OPT_WRITE(name, cpv, cpsz, emitter_type_string)
-
- emitter_dict_begin(emitter, "opt", "Run-time option settings");
-
- OPT_WRITE_BOOL("abort")
- OPT_WRITE_BOOL("abort_conf")
- OPT_WRITE_BOOL("cache_oblivious")
- OPT_WRITE_BOOL("confirm_conf")
- OPT_WRITE_BOOL("retain")
- OPT_WRITE_CHAR_P("dss")
- OPT_WRITE_UNSIGNED("narenas")
- OPT_WRITE_CHAR_P("percpu_arena")
- OPT_WRITE_SIZE_T("oversize_threshold")
- OPT_WRITE_BOOL("hpa")
- OPT_WRITE_SIZE_T("hpa_slab_max_alloc")
- OPT_WRITE_SIZE_T("hpa_hugification_threshold")
- OPT_WRITE_UINT64("hpa_hugify_delay_ms")
- OPT_WRITE_UINT64("hpa_min_purge_interval_ms")
- if (je_mallctl("opt.hpa_dirty_mult", (void *)&u32v, &u32sz, NULL, 0)
- == 0) {
- /*
- * We cheat a little and "know" the secret meaning of this
- * representation.
- */
- if (u32v == (uint32_t)-1) {
- const char *neg1 = "-1";
- emitter_kv(emitter, "hpa_dirty_mult",
- "opt.hpa_dirty_mult", emitter_type_string, &neg1);
- } else {
- char buf[FXP_BUF_SIZE];
- fxp_print(u32v, buf);
- const char *bufp = buf;
- emitter_kv(emitter, "hpa_dirty_mult",
- "opt.hpa_dirty_mult", emitter_type_string, &bufp);
- }
- }
- OPT_WRITE_SIZE_T("hpa_sec_nshards")
- OPT_WRITE_SIZE_T("hpa_sec_max_alloc")
- OPT_WRITE_SIZE_T("hpa_sec_max_bytes")
- OPT_WRITE_SIZE_T("hpa_sec_bytes_after_flush")
- OPT_WRITE_SIZE_T("hpa_sec_batch_fill_extra")
- OPT_WRITE_CHAR_P("metadata_thp")
- OPT_WRITE_INT64("mutex_max_spin")
- OPT_WRITE_BOOL_MUTABLE("background_thread", "background_thread")
- OPT_WRITE_SSIZE_T_MUTABLE("dirty_decay_ms", "arenas.dirty_decay_ms")
- OPT_WRITE_SSIZE_T_MUTABLE("muzzy_decay_ms", "arenas.muzzy_decay_ms")
- OPT_WRITE_SIZE_T("lg_extent_max_active_fit")
- OPT_WRITE_CHAR_P("junk")
- OPT_WRITE_BOOL("zero")
- OPT_WRITE_BOOL("utrace")
- OPT_WRITE_BOOL("xmalloc")
- OPT_WRITE_BOOL("experimental_infallible_new")
- OPT_WRITE_BOOL("tcache")
- OPT_WRITE_SIZE_T("tcache_max")
- OPT_WRITE_UNSIGNED("tcache_nslots_small_min")
- OPT_WRITE_UNSIGNED("tcache_nslots_small_max")
- OPT_WRITE_UNSIGNED("tcache_nslots_large")
- OPT_WRITE_SSIZE_T("lg_tcache_nslots_mul")
- OPT_WRITE_SIZE_T("tcache_gc_incr_bytes")
- OPT_WRITE_SIZE_T("tcache_gc_delay_bytes")
- OPT_WRITE_UNSIGNED("lg_tcache_flush_small_div")
- OPT_WRITE_UNSIGNED("lg_tcache_flush_large_div")
- OPT_WRITE_CHAR_P("thp")
- OPT_WRITE_BOOL("prof")
- OPT_WRITE_CHAR_P("prof_prefix")
- OPT_WRITE_BOOL_MUTABLE("prof_active", "prof.active")
- OPT_WRITE_BOOL_MUTABLE("prof_thread_active_init",
- "prof.thread_active_init")
- OPT_WRITE_SSIZE_T_MUTABLE("lg_prof_sample", "prof.lg_sample")
- OPT_WRITE_BOOL("prof_accum")
- OPT_WRITE_SSIZE_T("lg_prof_interval")
- OPT_WRITE_BOOL("prof_gdump")
- OPT_WRITE_BOOL("prof_final")
- OPT_WRITE_BOOL("prof_leak")
- OPT_WRITE_BOOL("prof_leak_error")
- OPT_WRITE_BOOL("stats_print")
- OPT_WRITE_CHAR_P("stats_print_opts")
- OPT_WRITE_BOOL("stats_print")
- OPT_WRITE_CHAR_P("stats_print_opts")
- OPT_WRITE_INT64("stats_interval")
- OPT_WRITE_CHAR_P("stats_interval_opts")
- OPT_WRITE_CHAR_P("zero_realloc")
-
- emitter_dict_end(emitter);
-
-#undef OPT_WRITE
-#undef OPT_WRITE_MUTABLE
-#undef OPT_WRITE_BOOL
-#undef OPT_WRITE_BOOL_MUTABLE
-#undef OPT_WRITE_UNSIGNED
-#undef OPT_WRITE_SSIZE_T
-#undef OPT_WRITE_SSIZE_T_MUTABLE
-#undef OPT_WRITE_CHAR_P
-
- /* prof. */
- if (config_prof) {
- emitter_dict_begin(emitter, "prof", "Profiling settings");
-
- CTL_GET("prof.thread_active_init", &bv, bool);
- emitter_kv(emitter, "thread_active_init",
- "prof.thread_active_init", emitter_type_bool, &bv);
-
- CTL_GET("prof.active", &bv, bool);
- emitter_kv(emitter, "active", "prof.active", emitter_type_bool,
- &bv);
-
- CTL_GET("prof.gdump", &bv, bool);
- emitter_kv(emitter, "gdump", "prof.gdump", emitter_type_bool,
- &bv);
-
- CTL_GET("prof.interval", &u64v, uint64_t);
- emitter_kv(emitter, "interval", "prof.interval",
- emitter_type_uint64, &u64v);
-
- CTL_GET("prof.lg_sample", &ssv, ssize_t);
- emitter_kv(emitter, "lg_sample", "prof.lg_sample",
- emitter_type_ssize, &ssv);
-
- emitter_dict_end(emitter); /* Close "prof". */
- }
-
- /* arenas. */
- /*
- * The json output sticks arena info into an "arenas" dict; the table
- * output puts them at the top-level.
- */
- emitter_json_object_kv_begin(emitter, "arenas");
-
- CTL_GET("arenas.narenas", &uv, unsigned);
- emitter_kv(emitter, "narenas", "Arenas", emitter_type_unsigned, &uv);
-
- /*
- * Decay settings are emitted only in json mode; in table mode, they're
- * emitted as notes with the opt output, above.
- */
- CTL_GET("arenas.dirty_decay_ms", &ssv, ssize_t);
- emitter_json_kv(emitter, "dirty_decay_ms", emitter_type_ssize, &ssv);
-
- CTL_GET("arenas.muzzy_decay_ms", &ssv, ssize_t);
- emitter_json_kv(emitter, "muzzy_decay_ms", emitter_type_ssize, &ssv);
-
- CTL_GET("arenas.quantum", &sv, size_t);
- emitter_kv(emitter, "quantum", "Quantum size", emitter_type_size, &sv);
-
- CTL_GET("arenas.page", &sv, size_t);
- emitter_kv(emitter, "page", "Page size", emitter_type_size, &sv);
-
- if (je_mallctl("arenas.tcache_max", (void *)&sv, &ssz, NULL, 0) == 0) {
- emitter_kv(emitter, "tcache_max",
- "Maximum thread-cached size class", emitter_type_size, &sv);
- }
-
- unsigned arenas_nbins;
- CTL_GET("arenas.nbins", &arenas_nbins, unsigned);
- emitter_kv(emitter, "nbins", "Number of bin size classes",
- emitter_type_unsigned, &arenas_nbins);
-
- unsigned arenas_nhbins;
- CTL_GET("arenas.nhbins", &arenas_nhbins, unsigned);
- emitter_kv(emitter, "nhbins", "Number of thread-cache bin size classes",
- emitter_type_unsigned, &arenas_nhbins);
-
- /*
- * We do enough mallctls in a loop that we actually want to omit them
- * (not just omit the printing).
- */
- if (emitter_outputs_json(emitter)) {
- emitter_json_array_kv_begin(emitter, "bin");
- size_t arenas_bin_mib[CTL_MAX_DEPTH];
- CTL_LEAF_PREPARE(arenas_bin_mib, 0, "arenas.bin");
- for (unsigned i = 0; i < arenas_nbins; i++) {
- arenas_bin_mib[2] = i;
- emitter_json_object_begin(emitter);
-
- CTL_LEAF(arenas_bin_mib, 3, "size", &sv, size_t);
- emitter_json_kv(emitter, "size", emitter_type_size,
- &sv);
-
- CTL_LEAF(arenas_bin_mib, 3, "nregs", &u32v, uint32_t);
- emitter_json_kv(emitter, "nregs", emitter_type_uint32,
- &u32v);
-
- CTL_LEAF(arenas_bin_mib, 3, "slab_size", &sv, size_t);
- emitter_json_kv(emitter, "slab_size", emitter_type_size,
- &sv);
-
- CTL_LEAF(arenas_bin_mib, 3, "nshards", &u32v, uint32_t);
- emitter_json_kv(emitter, "nshards", emitter_type_uint32,
- &u32v);
-
- emitter_json_object_end(emitter);
- }
- emitter_json_array_end(emitter); /* Close "bin". */
- }
-
- unsigned nlextents;
- CTL_GET("arenas.nlextents", &nlextents, unsigned);
- emitter_kv(emitter, "nlextents", "Number of large size classes",
- emitter_type_unsigned, &nlextents);
-
- if (emitter_outputs_json(emitter)) {
- emitter_json_array_kv_begin(emitter, "lextent");
- size_t arenas_lextent_mib[CTL_MAX_DEPTH];
- CTL_LEAF_PREPARE(arenas_lextent_mib, 0, "arenas.lextent");
- for (unsigned i = 0; i < nlextents; i++) {
- arenas_lextent_mib[2] = i;
- emitter_json_object_begin(emitter);
-
- CTL_LEAF(arenas_lextent_mib, 3, "size", &sv, size_t);
- emitter_json_kv(emitter, "size", emitter_type_size,
- &sv);
-
- emitter_json_object_end(emitter);
- }
- emitter_json_array_end(emitter); /* Close "lextent". */
- }
-
- emitter_json_object_end(emitter); /* Close "arenas" */
-}
-
-JEMALLOC_COLD
-static void
-stats_print_helper(emitter_t *emitter, bool merged, bool destroyed,
- bool unmerged, bool bins, bool large, bool mutex, bool extents, bool hpa) {
- /*
- * These should be deleted. We keep them around for a while, to aid in
- * the transition to the emitter code.
- */
- size_t allocated, active, metadata, metadata_thp, resident, mapped,
- retained;
- size_t num_background_threads;
- size_t zero_reallocs;
- uint64_t background_thread_num_runs, background_thread_run_interval;
-
- CTL_GET("stats.allocated", &allocated, size_t);
- CTL_GET("stats.active", &active, size_t);
- CTL_GET("stats.metadata", &metadata, size_t);
- CTL_GET("stats.metadata_thp", &metadata_thp, size_t);
- CTL_GET("stats.resident", &resident, size_t);
- CTL_GET("stats.mapped", &mapped, size_t);
- CTL_GET("stats.retained", &retained, size_t);
-
- CTL_GET("stats.zero_reallocs", &zero_reallocs, size_t);
-
- if (have_background_thread) {
- CTL_GET("stats.background_thread.num_threads",
- &num_background_threads, size_t);
- CTL_GET("stats.background_thread.num_runs",
- &background_thread_num_runs, uint64_t);
- CTL_GET("stats.background_thread.run_interval",
- &background_thread_run_interval, uint64_t);
- } else {
- num_background_threads = 0;
- background_thread_num_runs = 0;
- background_thread_run_interval = 0;
- }
-
- /* Generic global stats. */
- emitter_json_object_kv_begin(emitter, "stats");
- emitter_json_kv(emitter, "allocated", emitter_type_size, &allocated);
- emitter_json_kv(emitter, "active", emitter_type_size, &active);
- emitter_json_kv(emitter, "metadata", emitter_type_size, &metadata);
- emitter_json_kv(emitter, "metadata_thp", emitter_type_size,
- &metadata_thp);
- emitter_json_kv(emitter, "resident", emitter_type_size, &resident);
- emitter_json_kv(emitter, "mapped", emitter_type_size, &mapped);
- emitter_json_kv(emitter, "retained", emitter_type_size, &retained);
- emitter_json_kv(emitter, "zero_reallocs", emitter_type_size,
- &zero_reallocs);
-
- emitter_table_printf(emitter, "Allocated: %zu, active: %zu, "
- "metadata: %zu (n_thp %zu), resident: %zu, mapped: %zu, "
- "retained: %zu\n", allocated, active, metadata, metadata_thp,
- resident, mapped, retained);
-
- /* Strange behaviors */
- emitter_table_printf(emitter,
- "Count of realloc(non-null-ptr, 0) calls: %zu\n", zero_reallocs);
-
- /* Background thread stats. */
- emitter_json_object_kv_begin(emitter, "background_thread");
- emitter_json_kv(emitter, "num_threads", emitter_type_size,
- &num_background_threads);
- emitter_json_kv(emitter, "num_runs", emitter_type_uint64,
- &background_thread_num_runs);
- emitter_json_kv(emitter, "run_interval", emitter_type_uint64,
- &background_thread_run_interval);
- emitter_json_object_end(emitter); /* Close "background_thread". */
-
- emitter_table_printf(emitter, "Background threads: %zu, "
- "num_runs: %"FMTu64", run_interval: %"FMTu64" ns\n",
- num_background_threads, background_thread_num_runs,
- background_thread_run_interval);
-
- if (mutex) {
- emitter_row_t row;
- emitter_col_t name;
- emitter_col_t col64[mutex_prof_num_uint64_t_counters];
- emitter_col_t col32[mutex_prof_num_uint32_t_counters];
- uint64_t uptime;
-
- emitter_row_init(&row);
- mutex_stats_init_cols(&row, "", &name, col64, col32);
-
- emitter_table_row(emitter, &row);
- emitter_json_object_kv_begin(emitter, "mutexes");
-
- CTL_M2_GET("stats.arenas.0.uptime", 0, &uptime, uint64_t);
-
- size_t stats_mutexes_mib[CTL_MAX_DEPTH];
- CTL_LEAF_PREPARE(stats_mutexes_mib, 0, "stats.mutexes");
- for (int i = 0; i < mutex_prof_num_global_mutexes; i++) {
- mutex_stats_read_global(stats_mutexes_mib, 2,
- global_mutex_names[i], &name, col64, col32, uptime);
- emitter_json_object_kv_begin(emitter, global_mutex_names[i]);
- mutex_stats_emit(emitter, &row, col64, col32);
- emitter_json_object_end(emitter);
- }
-
- emitter_json_object_end(emitter); /* Close "mutexes". */
- }
-
- emitter_json_object_end(emitter); /* Close "stats". */
-
- if (merged || destroyed || unmerged) {
- unsigned narenas;
-
- emitter_json_object_kv_begin(emitter, "stats.arenas");
-
- CTL_GET("arenas.narenas", &narenas, unsigned);
- size_t mib[3];
- size_t miblen = sizeof(mib) / sizeof(size_t);
- size_t sz;
- VARIABLE_ARRAY(bool, initialized, narenas);
- bool destroyed_initialized;
- unsigned i, j, ninitialized;
-
- xmallctlnametomib("arena.0.initialized", mib, &miblen);
- for (i = ninitialized = 0; i < narenas; i++) {
- mib[1] = i;
- sz = sizeof(bool);
- xmallctlbymib(mib, miblen, &initialized[i], &sz,
- NULL, 0);
- if (initialized[i]) {
- ninitialized++;
- }
- }
- mib[1] = MALLCTL_ARENAS_DESTROYED;
- sz = sizeof(bool);
- xmallctlbymib(mib, miblen, &destroyed_initialized, &sz,
- NULL, 0);
-
- /* Merged stats. */
- if (merged && (ninitialized > 1 || !unmerged)) {
- /* Print merged arena stats. */
- emitter_table_printf(emitter, "Merged arenas stats:\n");
- emitter_json_object_kv_begin(emitter, "merged");
- stats_arena_print(emitter, MALLCTL_ARENAS_ALL, bins,
- large, mutex, extents, hpa);
- emitter_json_object_end(emitter); /* Close "merged". */
- }
-
- /* Destroyed stats. */
- if (destroyed_initialized && destroyed) {
- /* Print destroyed arena stats. */
- emitter_table_printf(emitter,
- "Destroyed arenas stats:\n");
- emitter_json_object_kv_begin(emitter, "destroyed");
- stats_arena_print(emitter, MALLCTL_ARENAS_DESTROYED,
- bins, large, mutex, extents, hpa);
- emitter_json_object_end(emitter); /* Close "destroyed". */
- }
-
- /* Unmerged stats. */
- if (unmerged) {
- for (i = j = 0; i < narenas; i++) {
- if (initialized[i]) {
- char arena_ind_str[20];
- malloc_snprintf(arena_ind_str,
- sizeof(arena_ind_str), "%u", i);
- emitter_json_object_kv_begin(emitter,
- arena_ind_str);
- emitter_table_printf(emitter,
- "arenas[%s]:\n", arena_ind_str);
- stats_arena_print(emitter, i, bins,
- large, mutex, extents, hpa);
- /* Close "<arena-ind>". */
- emitter_json_object_end(emitter);
- }
- }
- }
- emitter_json_object_end(emitter); /* Close "stats.arenas". */
- }
-}
-
-void
-stats_print(write_cb_t *write_cb, void *cbopaque, const char *opts) {
- int err;
- uint64_t epoch;
- size_t u64sz;
-#define OPTION(o, v, d, s) bool v = d;
- STATS_PRINT_OPTIONS
-#undef OPTION
-
- /*
- * Refresh stats, in case mallctl() was called by the application.
- *
- * Check for OOM here, since refreshing the ctl cache can trigger
- * allocation. In practice, none of the subsequent mallctl()-related
- * calls in this function will cause OOM if this one succeeds.
- * */
- epoch = 1;
- u64sz = sizeof(uint64_t);
- err = je_mallctl("epoch", (void *)&epoch, &u64sz, (void *)&epoch,
- sizeof(uint64_t));
- if (err != 0) {
- if (err == EAGAIN) {
- malloc_write("<jemalloc>: Memory allocation failure in "
- "mallctl(\"epoch\", ...)\n");
- return;
- }
- malloc_write("<jemalloc>: Failure in mallctl(\"epoch\", "
- "...)\n");
- abort();
- }
-
- if (opts != NULL) {
- for (unsigned i = 0; opts[i] != '\0'; i++) {
- switch (opts[i]) {
-#define OPTION(o, v, d, s) case o: v = s; break;
- STATS_PRINT_OPTIONS
-#undef OPTION
- default:;
- }
- }
- }
-
- emitter_t emitter;
- emitter_init(&emitter,
- json ? emitter_output_json_compact : emitter_output_table,
- write_cb, cbopaque);
- emitter_begin(&emitter);
- emitter_table_printf(&emitter, "___ Begin jemalloc statistics ___\n");
- emitter_json_object_kv_begin(&emitter, "jemalloc");
-
- if (general) {
- stats_general_print(&emitter);
- }
- if (config_stats) {
- stats_print_helper(&emitter, merged, destroyed, unmerged,
- bins, large, mutex, extents, hpa);
- }
-
- emitter_json_object_end(&emitter); /* Closes the "jemalloc" dict. */
- emitter_table_printf(&emitter, "--- End jemalloc statistics ---\n");
- emitter_end(&emitter);
-}
-
-uint64_t
-stats_interval_new_event_wait(tsd_t *tsd) {
- return stats_interval_accum_batch;
-}
-
-uint64_t
-stats_interval_postponed_event_wait(tsd_t *tsd) {
- return TE_MIN_START_WAIT;
-}
-
-void
-stats_interval_event_handler(tsd_t *tsd, uint64_t elapsed) {
- assert(elapsed > 0 && elapsed != TE_INVALID_ELAPSED);
- if (counter_accum(tsd_tsdn(tsd), &stats_interval_accumulated,
- elapsed)) {
- je_malloc_stats_print(NULL, NULL, opt_stats_interval_opts);
- }
-}
-
-bool
-stats_boot(void) {
- uint64_t stats_interval;
- if (opt_stats_interval < 0) {
- assert(opt_stats_interval == -1);
- stats_interval = 0;
- stats_interval_accum_batch = 0;
- } else{
- /* See comments in stats.h */
- stats_interval = (opt_stats_interval > 0) ?
- opt_stats_interval : 1;
- uint64_t batch = stats_interval >>
- STATS_INTERVAL_ACCUM_LG_BATCH_SIZE;
- if (batch > STATS_INTERVAL_ACCUM_BATCH_MAX) {
- batch = STATS_INTERVAL_ACCUM_BATCH_MAX;
- } else if (batch == 0) {
- batch = 1;
- }
- stats_interval_accum_batch = batch;
- }
-
- return counter_accum_init(&stats_interval_accumulated, stats_interval);
-}
-
-void
-stats_prefork(tsdn_t *tsdn) {
- counter_prefork(tsdn, &stats_interval_accumulated);
-}
-
-void
-stats_postfork_parent(tsdn_t *tsdn) {
- counter_postfork_parent(tsdn, &stats_interval_accumulated);
-}
-
-void
-stats_postfork_child(tsdn_t *tsdn) {
- counter_postfork_child(tsdn, &stats_interval_accumulated);
-}
diff --git a/fluent-bit/lib/jemalloc-5.3.0/src/sz.c b/fluent-bit/lib/jemalloc-5.3.0/src/sz.c
deleted file mode 100644
index d3115dda..00000000
--- a/fluent-bit/lib/jemalloc-5.3.0/src/sz.c
+++ /dev/null
@@ -1,114 +0,0 @@
-#include "jemalloc/internal/jemalloc_preamble.h"
-#include "jemalloc/internal/jemalloc_internal_includes.h"
-#include "jemalloc/internal/sz.h"
-
-JEMALLOC_ALIGNED(CACHELINE)
-size_t sz_pind2sz_tab[SC_NPSIZES+1];
-size_t sz_large_pad;
-
-size_t
-sz_psz_quantize_floor(size_t size) {
- size_t ret;
- pszind_t pind;
-
- assert(size > 0);
- assert((size & PAGE_MASK) == 0);
-
- pind = sz_psz2ind(size - sz_large_pad + 1);
- if (pind == 0) {
- /*
- * Avoid underflow. This short-circuit would also do the right
- * thing for all sizes in the range for which there are
- * PAGE-spaced size classes, but it's simplest to just handle
- * the one case that would cause erroneous results.
- */
- return size;
- }
- ret = sz_pind2sz(pind - 1) + sz_large_pad;
- assert(ret <= size);
- return ret;
-}
-
-size_t
-sz_psz_quantize_ceil(size_t size) {
- size_t ret;
-
- assert(size > 0);
- assert(size - sz_large_pad <= SC_LARGE_MAXCLASS);
- assert((size & PAGE_MASK) == 0);
-
- ret = sz_psz_quantize_floor(size);
- if (ret < size) {
- /*
- * Skip a quantization that may have an adequately large extent,
- * because under-sized extents may be mixed in. This only
- * happens when an unusual size is requested, i.e. for aligned
- * allocation, and is just one of several places where linear
- * search would potentially find sufficiently aligned available
- * memory somewhere lower.
- */
- ret = sz_pind2sz(sz_psz2ind(ret - sz_large_pad + 1)) +
- sz_large_pad;
- }
- return ret;
-}
-
-static void
-sz_boot_pind2sz_tab(const sc_data_t *sc_data) {
- int pind = 0;
- for (unsigned i = 0; i < SC_NSIZES; i++) {
- const sc_t *sc = &sc_data->sc[i];
- if (sc->psz) {
- sz_pind2sz_tab[pind] = (ZU(1) << sc->lg_base)
- + (ZU(sc->ndelta) << sc->lg_delta);
- pind++;
- }
- }
- for (int i = pind; i <= (int)SC_NPSIZES; i++) {
- sz_pind2sz_tab[pind] = sc_data->large_maxclass + PAGE;
- }
-}
-
-JEMALLOC_ALIGNED(CACHELINE)
-size_t sz_index2size_tab[SC_NSIZES];
-
-static void
-sz_boot_index2size_tab(const sc_data_t *sc_data) {
- for (unsigned i = 0; i < SC_NSIZES; i++) {
- const sc_t *sc = &sc_data->sc[i];
- sz_index2size_tab[i] = (ZU(1) << sc->lg_base)
- + (ZU(sc->ndelta) << (sc->lg_delta));
- }
-}
-
-/*
- * To keep this table small, we divide sizes by the tiny min size, which gives
- * the smallest interval for which the result can change.
- */
-JEMALLOC_ALIGNED(CACHELINE)
-uint8_t sz_size2index_tab[(SC_LOOKUP_MAXCLASS >> SC_LG_TINY_MIN) + 1];
-
-static void
-sz_boot_size2index_tab(const sc_data_t *sc_data) {
- size_t dst_max = (SC_LOOKUP_MAXCLASS >> SC_LG_TINY_MIN) + 1;
- size_t dst_ind = 0;
- for (unsigned sc_ind = 0; sc_ind < SC_NSIZES && dst_ind < dst_max;
- sc_ind++) {
- const sc_t *sc = &sc_data->sc[sc_ind];
- size_t sz = (ZU(1) << sc->lg_base)
- + (ZU(sc->ndelta) << sc->lg_delta);
- size_t max_ind = ((sz + (ZU(1) << SC_LG_TINY_MIN) - 1)
- >> SC_LG_TINY_MIN);
- for (; dst_ind <= max_ind && dst_ind < dst_max; dst_ind++) {
- sz_size2index_tab[dst_ind] = sc_ind;
- }
- }
-}
-
-void
-sz_boot(const sc_data_t *sc_data, bool cache_oblivious) {
- sz_large_pad = cache_oblivious ? PAGE : 0;
- sz_boot_pind2sz_tab(sc_data);
- sz_boot_index2size_tab(sc_data);
- sz_boot_size2index_tab(sc_data);
-}
diff --git a/fluent-bit/lib/jemalloc-5.3.0/src/tcache.c b/fluent-bit/lib/jemalloc-5.3.0/src/tcache.c
deleted file mode 100644
index fa16732e..00000000
--- a/fluent-bit/lib/jemalloc-5.3.0/src/tcache.c
+++ /dev/null
@@ -1,1101 +0,0 @@
-#include "jemalloc/internal/jemalloc_preamble.h"
-#include "jemalloc/internal/jemalloc_internal_includes.h"
-
-#include "jemalloc/internal/assert.h"
-#include "jemalloc/internal/mutex.h"
-#include "jemalloc/internal/safety_check.h"
-#include "jemalloc/internal/san.h"
-#include "jemalloc/internal/sc.h"
-
-/******************************************************************************/
-/* Data. */
-
-bool opt_tcache = true;
-
-/* tcache_maxclass is set to 32KB by default. */
-size_t opt_tcache_max = ((size_t)1) << 15;
-
-/* Reasonable defaults for min and max values. */
-unsigned opt_tcache_nslots_small_min = 20;
-unsigned opt_tcache_nslots_small_max = 200;
-unsigned opt_tcache_nslots_large = 20;
-
-/*
- * We attempt to make the number of slots in a tcache bin for a given size class
- * equal to the number of objects in a slab times some multiplier. By default,
- * the multiplier is 2 (i.e. we set the maximum number of objects in the tcache
- * to twice the number of objects in a slab).
- * This is bounded by some other constraints as well, like the fact that it
- * must be even, must be less than opt_tcache_nslots_small_max, etc..
- */
-ssize_t opt_lg_tcache_nslots_mul = 1;
-
-/*
- * Number of allocation bytes between tcache incremental GCs. Again, this
- * default just seems to work well; more tuning is possible.
- */
-size_t opt_tcache_gc_incr_bytes = 65536;
-
-/*
- * With default settings, we may end up flushing small bins frequently with
- * small flush amounts. To limit this tendency, we can set a number of bytes to
- * "delay" by. If we try to flush N M-byte items, we decrease that size-class's
- * delay by N * M. So, if delay is 1024 and we're looking at the 64-byte size
- * class, we won't do any flushing until we've been asked to flush 1024/64 == 16
- * items. This can happen in any configuration (i.e. being asked to flush 16
- * items once, or 4 items 4 times).
- *
- * Practically, this is stored as a count of items in a uint8_t, so the
- * effective maximum value for a size class is 255 * sz.
- */
-size_t opt_tcache_gc_delay_bytes = 0;
-
-/*
- * When a cache bin is flushed because it's full, how much of it do we flush?
- * By default, we flush half the maximum number of items.
- */
-unsigned opt_lg_tcache_flush_small_div = 1;
-unsigned opt_lg_tcache_flush_large_div = 1;
-
-cache_bin_info_t *tcache_bin_info;
-
-/* Total stack size required (per tcache). Include the padding above. */
-static size_t tcache_bin_alloc_size;
-static size_t tcache_bin_alloc_alignment;
-
-/* Number of cache bins enabled, including both large and small. */
-unsigned nhbins;
-/* Max size class to be cached (can be small or large). */
-size_t tcache_maxclass;
-
-tcaches_t *tcaches;
-
-/* Index of first element within tcaches that has never been used. */
-static unsigned tcaches_past;
-
-/* Head of singly linked list tracking available tcaches elements. */
-static tcaches_t *tcaches_avail;
-
-/* Protects tcaches{,_past,_avail}. */
-static malloc_mutex_t tcaches_mtx;
-
-/******************************************************************************/
-
-size_t
-tcache_salloc(tsdn_t *tsdn, const void *ptr) {
- return arena_salloc(tsdn, ptr);
-}
-
-uint64_t
-tcache_gc_new_event_wait(tsd_t *tsd) {
- return opt_tcache_gc_incr_bytes;
-}
-
-uint64_t
-tcache_gc_postponed_event_wait(tsd_t *tsd) {
- return TE_MIN_START_WAIT;
-}
-
-uint64_t
-tcache_gc_dalloc_new_event_wait(tsd_t *tsd) {
- return opt_tcache_gc_incr_bytes;
-}
-
-uint64_t
-tcache_gc_dalloc_postponed_event_wait(tsd_t *tsd) {
- return TE_MIN_START_WAIT;
-}
-
-static uint8_t
-tcache_gc_item_delay_compute(szind_t szind) {
- assert(szind < SC_NBINS);
- size_t sz = sz_index2size(szind);
- size_t item_delay = opt_tcache_gc_delay_bytes / sz;
- size_t delay_max = ZU(1)
- << (sizeof(((tcache_slow_t *)NULL)->bin_flush_delay_items[0]) * 8);
- if (item_delay >= delay_max) {
- item_delay = delay_max - 1;
- }
- return (uint8_t)item_delay;
-}
-
-static void
-tcache_gc_small(tsd_t *tsd, tcache_slow_t *tcache_slow, tcache_t *tcache,
- szind_t szind) {
- /* Aim to flush 3/4 of items below low-water. */
- assert(szind < SC_NBINS);
-
- cache_bin_t *cache_bin = &tcache->bins[szind];
- cache_bin_sz_t ncached = cache_bin_ncached_get_local(cache_bin,
- &tcache_bin_info[szind]);
- cache_bin_sz_t low_water = cache_bin_low_water_get(cache_bin,
- &tcache_bin_info[szind]);
- assert(!tcache_slow->bin_refilled[szind]);
-
- size_t nflush = low_water - (low_water >> 2);
- if (nflush < tcache_slow->bin_flush_delay_items[szind]) {
- /* Workaround for a conversion warning. */
- uint8_t nflush_uint8 = (uint8_t)nflush;
- assert(sizeof(tcache_slow->bin_flush_delay_items[0]) ==
- sizeof(nflush_uint8));
- tcache_slow->bin_flush_delay_items[szind] -= nflush_uint8;
- return;
- } else {
- tcache_slow->bin_flush_delay_items[szind]
- = tcache_gc_item_delay_compute(szind);
- }
-
- tcache_bin_flush_small(tsd, tcache, cache_bin, szind,
- (unsigned)(ncached - nflush));
-
- /*
- * Reduce fill count by 2X. Limit lg_fill_div such that
- * the fill count is always at least 1.
- */
- if ((cache_bin_info_ncached_max(&tcache_bin_info[szind])
- >> (tcache_slow->lg_fill_div[szind] + 1)) >= 1) {
- tcache_slow->lg_fill_div[szind]++;
- }
-}
-
-static void
-tcache_gc_large(tsd_t *tsd, tcache_slow_t *tcache_slow, tcache_t *tcache,
- szind_t szind) {
- /* Like the small GC; flush 3/4 of untouched items. */
- assert(szind >= SC_NBINS);
- cache_bin_t *cache_bin = &tcache->bins[szind];
- cache_bin_sz_t ncached = cache_bin_ncached_get_local(cache_bin,
- &tcache_bin_info[szind]);
- cache_bin_sz_t low_water = cache_bin_low_water_get(cache_bin,
- &tcache_bin_info[szind]);
- tcache_bin_flush_large(tsd, tcache, cache_bin, szind,
- (unsigned)(ncached - low_water + (low_water >> 2)));
-}
-
-static void
-tcache_event(tsd_t *tsd) {
- tcache_t *tcache = tcache_get(tsd);
- if (tcache == NULL) {
- return;
- }
-
- tcache_slow_t *tcache_slow = tsd_tcache_slowp_get(tsd);
- szind_t szind = tcache_slow->next_gc_bin;
- bool is_small = (szind < SC_NBINS);
- cache_bin_t *cache_bin = &tcache->bins[szind];
-
- tcache_bin_flush_stashed(tsd, tcache, cache_bin, szind, is_small);
-
- cache_bin_sz_t low_water = cache_bin_low_water_get(cache_bin,
- &tcache_bin_info[szind]);
- if (low_water > 0) {
- if (is_small) {
- tcache_gc_small(tsd, tcache_slow, tcache, szind);
- } else {
- tcache_gc_large(tsd, tcache_slow, tcache, szind);
- }
- } else if (is_small && tcache_slow->bin_refilled[szind]) {
- assert(low_water == 0);
- /*
- * Increase fill count by 2X for small bins. Make sure
- * lg_fill_div stays greater than 0.
- */
- if (tcache_slow->lg_fill_div[szind] > 1) {
- tcache_slow->lg_fill_div[szind]--;
- }
- tcache_slow->bin_refilled[szind] = false;
- }
- cache_bin_low_water_set(cache_bin);
-
- tcache_slow->next_gc_bin++;
- if (tcache_slow->next_gc_bin == nhbins) {
- tcache_slow->next_gc_bin = 0;
- }
-}
-
-void
-tcache_gc_event_handler(tsd_t *tsd, uint64_t elapsed) {
- assert(elapsed == TE_INVALID_ELAPSED);
- tcache_event(tsd);
-}
-
-void
-tcache_gc_dalloc_event_handler(tsd_t *tsd, uint64_t elapsed) {
- assert(elapsed == TE_INVALID_ELAPSED);
- tcache_event(tsd);
-}
-
-void *
-tcache_alloc_small_hard(tsdn_t *tsdn, arena_t *arena,
- tcache_t *tcache, cache_bin_t *cache_bin, szind_t binind,
- bool *tcache_success) {
- tcache_slow_t *tcache_slow = tcache->tcache_slow;
- void *ret;
-
- assert(tcache_slow->arena != NULL);
- unsigned nfill = cache_bin_info_ncached_max(&tcache_bin_info[binind])
- >> tcache_slow->lg_fill_div[binind];
- arena_cache_bin_fill_small(tsdn, arena, cache_bin,
- &tcache_bin_info[binind], binind, nfill);
- tcache_slow->bin_refilled[binind] = true;
- ret = cache_bin_alloc(cache_bin, tcache_success);
-
- return ret;
-}
-
-static const void *
-tcache_bin_flush_ptr_getter(void *arr_ctx, size_t ind) {
- cache_bin_ptr_array_t *arr = (cache_bin_ptr_array_t *)arr_ctx;
- return arr->ptr[ind];
-}
-
-static void
-tcache_bin_flush_metadata_visitor(void *szind_sum_ctx,
- emap_full_alloc_ctx_t *alloc_ctx) {
- size_t *szind_sum = (size_t *)szind_sum_ctx;
- *szind_sum -= alloc_ctx->szind;
- util_prefetch_write_range(alloc_ctx->edata, sizeof(edata_t));
-}
-
-JEMALLOC_NOINLINE static void
-tcache_bin_flush_size_check_fail(cache_bin_ptr_array_t *arr, szind_t szind,
- size_t nptrs, emap_batch_lookup_result_t *edatas) {
- bool found_mismatch = false;
- for (size_t i = 0; i < nptrs; i++) {
- szind_t true_szind = edata_szind_get(edatas[i].edata);
- if (true_szind != szind) {
- found_mismatch = true;
- safety_check_fail_sized_dealloc(
- /* current_dealloc */ false,
- /* ptr */ tcache_bin_flush_ptr_getter(arr, i),
- /* true_size */ sz_index2size(true_szind),
- /* input_size */ sz_index2size(szind));
- }
- }
- assert(found_mismatch);
-}
-
-static void
-tcache_bin_flush_edatas_lookup(tsd_t *tsd, cache_bin_ptr_array_t *arr,
- szind_t binind, size_t nflush, emap_batch_lookup_result_t *edatas) {
-
- /*
- * This gets compiled away when config_opt_safety_checks is false.
- * Checks for sized deallocation bugs, failing early rather than
- * corrupting metadata.
- */
- size_t szind_sum = binind * nflush;
- emap_edata_lookup_batch(tsd, &arena_emap_global, nflush,
- &tcache_bin_flush_ptr_getter, (void *)arr,
- &tcache_bin_flush_metadata_visitor, (void *)&szind_sum,
- edatas);
- if (config_opt_safety_checks && unlikely(szind_sum != 0)) {
- tcache_bin_flush_size_check_fail(arr, binind, nflush, edatas);
- }
-}
-
-JEMALLOC_ALWAYS_INLINE bool
-tcache_bin_flush_match(edata_t *edata, unsigned cur_arena_ind,
- unsigned cur_binshard, bool small) {
- if (small) {
- return edata_arena_ind_get(edata) == cur_arena_ind
- && edata_binshard_get(edata) == cur_binshard;
- } else {
- return edata_arena_ind_get(edata) == cur_arena_ind;
- }
-}
-
-JEMALLOC_ALWAYS_INLINE void
-tcache_bin_flush_impl(tsd_t *tsd, tcache_t *tcache, cache_bin_t *cache_bin,
- szind_t binind, cache_bin_ptr_array_t *ptrs, unsigned nflush, bool small) {
- tcache_slow_t *tcache_slow = tcache->tcache_slow;
- /*
- * A couple lookup calls take tsdn; declare it once for convenience
- * instead of calling tsd_tsdn(tsd) all the time.
- */
- tsdn_t *tsdn = tsd_tsdn(tsd);
-
- if (small) {
- assert(binind < SC_NBINS);
- } else {
- assert(binind < nhbins);
- }
- arena_t *tcache_arena = tcache_slow->arena;
- assert(tcache_arena != NULL);
-
- /*
- * Variable length array must have > 0 length; the last element is never
- * touched (it's just included to satisfy the no-zero-length rule).
- */
- VARIABLE_ARRAY(emap_batch_lookup_result_t, item_edata, nflush + 1);
- tcache_bin_flush_edatas_lookup(tsd, ptrs, binind, nflush, item_edata);
-
- /*
- * The slabs where we freed the last remaining object in the slab (and
- * so need to free the slab itself).
- * Used only if small == true.
- */
- unsigned dalloc_count = 0;
- VARIABLE_ARRAY(edata_t *, dalloc_slabs, nflush + 1);
-
- /*
- * We're about to grab a bunch of locks. If one of them happens to be
- * the one guarding the arena-level stats counters we flush our
- * thread-local ones to, we do so under one critical section.
- */
- bool merged_stats = false;
- while (nflush > 0) {
- /* Lock the arena, or bin, associated with the first object. */
- edata_t *edata = item_edata[0].edata;
- unsigned cur_arena_ind = edata_arena_ind_get(edata);
- arena_t *cur_arena = arena_get(tsdn, cur_arena_ind, false);
-
- /*
- * These assignments are always overwritten when small is true,
- * and their values are always ignored when small is false, but
- * to avoid the technical UB when we pass them as parameters, we
- * need to intialize them.
- */
- unsigned cur_binshard = 0;
- bin_t *cur_bin = NULL;
- if (small) {
- cur_binshard = edata_binshard_get(edata);
- cur_bin = arena_get_bin(cur_arena, binind,
- cur_binshard);
- assert(cur_binshard < bin_infos[binind].n_shards);
- /*
- * If you're looking at profiles, you might think this
- * is a good place to prefetch the bin stats, which are
- * often a cache miss. This turns out not to be
- * helpful on the workloads we've looked at, with moving
- * the bin stats next to the lock seeming to do better.
- */
- }
-
- if (small) {
- malloc_mutex_lock(tsdn, &cur_bin->lock);
- }
- if (!small && !arena_is_auto(cur_arena)) {
- malloc_mutex_lock(tsdn, &cur_arena->large_mtx);
- }
-
- /*
- * If we acquired the right lock and have some stats to flush,
- * flush them.
- */
- if (config_stats && tcache_arena == cur_arena
- && !merged_stats) {
- merged_stats = true;
- if (small) {
- cur_bin->stats.nflushes++;
- cur_bin->stats.nrequests +=
- cache_bin->tstats.nrequests;
- cache_bin->tstats.nrequests = 0;
- } else {
- arena_stats_large_flush_nrequests_add(tsdn,
- &tcache_arena->stats, binind,
- cache_bin->tstats.nrequests);
- cache_bin->tstats.nrequests = 0;
- }
- }
-
- /*
- * Large allocations need special prep done. Afterwards, we can
- * drop the large lock.
- */
- if (!small) {
- for (unsigned i = 0; i < nflush; i++) {
- void *ptr = ptrs->ptr[i];
- edata = item_edata[i].edata;
- assert(ptr != NULL && edata != NULL);
-
- if (tcache_bin_flush_match(edata, cur_arena_ind,
- cur_binshard, small)) {
- large_dalloc_prep_locked(tsdn,
- edata);
- }
- }
- }
- if (!small && !arena_is_auto(cur_arena)) {
- malloc_mutex_unlock(tsdn, &cur_arena->large_mtx);
- }
-
- /* Deallocate whatever we can. */
- unsigned ndeferred = 0;
- /* Init only to avoid used-uninitialized warning. */
- arena_dalloc_bin_locked_info_t dalloc_bin_info = {0};
- if (small) {
- arena_dalloc_bin_locked_begin(&dalloc_bin_info, binind);
- }
- for (unsigned i = 0; i < nflush; i++) {
- void *ptr = ptrs->ptr[i];
- edata = item_edata[i].edata;
- assert(ptr != NULL && edata != NULL);
- if (!tcache_bin_flush_match(edata, cur_arena_ind,
- cur_binshard, small)) {
- /*
- * The object was allocated either via a
- * different arena, or a different bin in this
- * arena. Either way, stash the object so that
- * it can be handled in a future pass.
- */
- ptrs->ptr[ndeferred] = ptr;
- item_edata[ndeferred].edata = edata;
- ndeferred++;
- continue;
- }
- if (small) {
- if (arena_dalloc_bin_locked_step(tsdn,
- cur_arena, cur_bin, &dalloc_bin_info,
- binind, edata, ptr)) {
- dalloc_slabs[dalloc_count] = edata;
- dalloc_count++;
- }
- } else {
- if (large_dalloc_safety_checks(edata, ptr,
- binind)) {
- /* See the comment in isfree. */
- continue;
- }
- large_dalloc_finish(tsdn, edata);
- }
- }
-
- if (small) {
- arena_dalloc_bin_locked_finish(tsdn, cur_arena, cur_bin,
- &dalloc_bin_info);
- malloc_mutex_unlock(tsdn, &cur_bin->lock);
- }
- arena_decay_ticks(tsdn, cur_arena, nflush - ndeferred);
- nflush = ndeferred;
- }
-
- /* Handle all deferred slab dalloc. */
- assert(small || dalloc_count == 0);
- for (unsigned i = 0; i < dalloc_count; i++) {
- edata_t *slab = dalloc_slabs[i];
- arena_slab_dalloc(tsdn, arena_get_from_edata(slab), slab);
-
- }
-
- if (config_stats && !merged_stats) {
- if (small) {
- /*
- * The flush loop didn't happen to flush to this
- * thread's arena, so the stats didn't get merged.
- * Manually do so now.
- */
- bin_t *bin = arena_bin_choose(tsdn, tcache_arena,
- binind, NULL);
- malloc_mutex_lock(tsdn, &bin->lock);
- bin->stats.nflushes++;
- bin->stats.nrequests += cache_bin->tstats.nrequests;
- cache_bin->tstats.nrequests = 0;
- malloc_mutex_unlock(tsdn, &bin->lock);
- } else {
- arena_stats_large_flush_nrequests_add(tsdn,
- &tcache_arena->stats, binind,
- cache_bin->tstats.nrequests);
- cache_bin->tstats.nrequests = 0;
- }
- }
-
-}
-
-JEMALLOC_ALWAYS_INLINE void
-tcache_bin_flush_bottom(tsd_t *tsd, tcache_t *tcache, cache_bin_t *cache_bin,
- szind_t binind, unsigned rem, bool small) {
- tcache_bin_flush_stashed(tsd, tcache, cache_bin, binind, small);
-
- cache_bin_sz_t ncached = cache_bin_ncached_get_local(cache_bin,
- &tcache_bin_info[binind]);
- assert((cache_bin_sz_t)rem <= ncached);
- unsigned nflush = ncached - rem;
-
- CACHE_BIN_PTR_ARRAY_DECLARE(ptrs, nflush);
- cache_bin_init_ptr_array_for_flush(cache_bin, &tcache_bin_info[binind],
- &ptrs, nflush);
-
- tcache_bin_flush_impl(tsd, tcache, cache_bin, binind, &ptrs, nflush,
- small);
-
- cache_bin_finish_flush(cache_bin, &tcache_bin_info[binind], &ptrs,
- ncached - rem);
-}
-
-void
-tcache_bin_flush_small(tsd_t *tsd, tcache_t *tcache, cache_bin_t *cache_bin,
- szind_t binind, unsigned rem) {
- tcache_bin_flush_bottom(tsd, tcache, cache_bin, binind, rem, true);
-}
-
-void
-tcache_bin_flush_large(tsd_t *tsd, tcache_t *tcache, cache_bin_t *cache_bin,
- szind_t binind, unsigned rem) {
- tcache_bin_flush_bottom(tsd, tcache, cache_bin, binind, rem, false);
-}
-
-/*
- * Flushing stashed happens when 1) tcache fill, 2) tcache flush, or 3) tcache
- * GC event. This makes sure that the stashed items do not hold memory for too
- * long, and new buffers can only be allocated when nothing is stashed.
- *
- * The downside is, the time between stash and flush may be relatively short,
- * especially when the request rate is high. It lowers the chance of detecting
- * write-after-free -- however that is a delayed detection anyway, and is less
- * of a focus than the memory overhead.
- */
-void
-tcache_bin_flush_stashed(tsd_t *tsd, tcache_t *tcache, cache_bin_t *cache_bin,
- szind_t binind, bool is_small) {
- cache_bin_info_t *info = &tcache_bin_info[binind];
- /*
- * The two below are for assertion only. The content of original cached
- * items remain unchanged -- the stashed items reside on the other end
- * of the stack. Checking the stack head and ncached to verify.
- */
- void *head_content = *cache_bin->stack_head;
- cache_bin_sz_t orig_cached = cache_bin_ncached_get_local(cache_bin,
- info);
-
- cache_bin_sz_t nstashed = cache_bin_nstashed_get_local(cache_bin, info);
- assert(orig_cached + nstashed <= cache_bin_info_ncached_max(info));
- if (nstashed == 0) {
- return;
- }
-
- CACHE_BIN_PTR_ARRAY_DECLARE(ptrs, nstashed);
- cache_bin_init_ptr_array_for_stashed(cache_bin, binind, info, &ptrs,
- nstashed);
- san_check_stashed_ptrs(ptrs.ptr, nstashed, sz_index2size(binind));
- tcache_bin_flush_impl(tsd, tcache, cache_bin, binind, &ptrs, nstashed,
- is_small);
- cache_bin_finish_flush_stashed(cache_bin, info);
-
- assert(cache_bin_nstashed_get_local(cache_bin, info) == 0);
- assert(cache_bin_ncached_get_local(cache_bin, info) == orig_cached);
- assert(head_content == *cache_bin->stack_head);
-}
-
-void
-tcache_arena_associate(tsdn_t *tsdn, tcache_slow_t *tcache_slow,
- tcache_t *tcache, arena_t *arena) {
- assert(tcache_slow->arena == NULL);
- tcache_slow->arena = arena;
-
- if (config_stats) {
- /* Link into list of extant tcaches. */
- malloc_mutex_lock(tsdn, &arena->tcache_ql_mtx);
-
- ql_elm_new(tcache_slow, link);
- ql_tail_insert(&arena->tcache_ql, tcache_slow, link);
- cache_bin_array_descriptor_init(
- &tcache_slow->cache_bin_array_descriptor, tcache->bins);
- ql_tail_insert(&arena->cache_bin_array_descriptor_ql,
- &tcache_slow->cache_bin_array_descriptor, link);
-
- malloc_mutex_unlock(tsdn, &arena->tcache_ql_mtx);
- }
-}
-
-static void
-tcache_arena_dissociate(tsdn_t *tsdn, tcache_slow_t *tcache_slow,
- tcache_t *tcache) {
- arena_t *arena = tcache_slow->arena;
- assert(arena != NULL);
- if (config_stats) {
- /* Unlink from list of extant tcaches. */
- malloc_mutex_lock(tsdn, &arena->tcache_ql_mtx);
- if (config_debug) {
- bool in_ql = false;
- tcache_slow_t *iter;
- ql_foreach(iter, &arena->tcache_ql, link) {
- if (iter == tcache_slow) {
- in_ql = true;
- break;
- }
- }
- assert(in_ql);
- }
- ql_remove(&arena->tcache_ql, tcache_slow, link);
- ql_remove(&arena->cache_bin_array_descriptor_ql,
- &tcache_slow->cache_bin_array_descriptor, link);
- tcache_stats_merge(tsdn, tcache_slow->tcache, arena);
- malloc_mutex_unlock(tsdn, &arena->tcache_ql_mtx);
- }
- tcache_slow->arena = NULL;
-}
-
-void
-tcache_arena_reassociate(tsdn_t *tsdn, tcache_slow_t *tcache_slow,
- tcache_t *tcache, arena_t *arena) {
- tcache_arena_dissociate(tsdn, tcache_slow, tcache);
- tcache_arena_associate(tsdn, tcache_slow, tcache, arena);
-}
-
-bool
-tsd_tcache_enabled_data_init(tsd_t *tsd) {
- /* Called upon tsd initialization. */
- tsd_tcache_enabled_set(tsd, opt_tcache);
- tsd_slow_update(tsd);
-
- if (opt_tcache) {
- /* Trigger tcache init. */
- tsd_tcache_data_init(tsd);
- }
-
- return false;
-}
-
-static void
-tcache_init(tsd_t *tsd, tcache_slow_t *tcache_slow, tcache_t *tcache,
- void *mem) {
- tcache->tcache_slow = tcache_slow;
- tcache_slow->tcache = tcache;
-
- memset(&tcache_slow->link, 0, sizeof(ql_elm(tcache_t)));
- tcache_slow->next_gc_bin = 0;
- tcache_slow->arena = NULL;
- tcache_slow->dyn_alloc = mem;
-
- /*
- * We reserve cache bins for all small size classes, even if some may
- * not get used (i.e. bins higher than nhbins). This allows the fast
- * and common paths to access cache bin metadata safely w/o worrying
- * about which ones are disabled.
- */
- unsigned n_reserved_bins = nhbins < SC_NBINS ? SC_NBINS : nhbins;
- memset(tcache->bins, 0, sizeof(cache_bin_t) * n_reserved_bins);
-
- size_t cur_offset = 0;
- cache_bin_preincrement(tcache_bin_info, nhbins, mem,
- &cur_offset);
- for (unsigned i = 0; i < nhbins; i++) {
- if (i < SC_NBINS) {
- tcache_slow->lg_fill_div[i] = 1;
- tcache_slow->bin_refilled[i] = false;
- tcache_slow->bin_flush_delay_items[i]
- = tcache_gc_item_delay_compute(i);
- }
- cache_bin_t *cache_bin = &tcache->bins[i];
- cache_bin_init(cache_bin, &tcache_bin_info[i], mem,
- &cur_offset);
- }
- /*
- * For small size classes beyond tcache_maxclass (i.e. nhbins < NBINS),
- * their cache bins are initialized to a state to safely and efficiently
- * fail all fastpath alloc / free, so that no additional check around
- * nhbins is needed on fastpath.
- */
- for (unsigned i = nhbins; i < SC_NBINS; i++) {
- /* Disabled small bins. */
- cache_bin_t *cache_bin = &tcache->bins[i];
- void *fake_stack = mem;
- size_t fake_offset = 0;
-
- cache_bin_init(cache_bin, &tcache_bin_info[i], fake_stack,
- &fake_offset);
- assert(tcache_small_bin_disabled(i, cache_bin));
- }
-
- cache_bin_postincrement(tcache_bin_info, nhbins, mem,
- &cur_offset);
- /* Sanity check that the whole stack is used. */
- assert(cur_offset == tcache_bin_alloc_size);
-}
-
-/* Initialize auto tcache (embedded in TSD). */
-bool
-tsd_tcache_data_init(tsd_t *tsd) {
- tcache_slow_t *tcache_slow = tsd_tcache_slowp_get_unsafe(tsd);
- tcache_t *tcache = tsd_tcachep_get_unsafe(tsd);
-
- assert(cache_bin_still_zero_initialized(&tcache->bins[0]));
- size_t alignment = tcache_bin_alloc_alignment;
- size_t size = sz_sa2u(tcache_bin_alloc_size, alignment);
-
- void *mem = ipallocztm(tsd_tsdn(tsd), size, alignment, true, NULL,
- true, arena_get(TSDN_NULL, 0, true));
- if (mem == NULL) {
- return true;
- }
-
- tcache_init(tsd, tcache_slow, tcache, mem);
- /*
- * Initialization is a bit tricky here. After malloc init is done, all
- * threads can rely on arena_choose and associate tcache accordingly.
- * However, the thread that does actual malloc bootstrapping relies on
- * functional tsd, and it can only rely on a0. In that case, we
- * associate its tcache to a0 temporarily, and later on
- * arena_choose_hard() will re-associate properly.
- */
- tcache_slow->arena = NULL;
- arena_t *arena;
- if (!malloc_initialized()) {
- /* If in initialization, assign to a0. */
- arena = arena_get(tsd_tsdn(tsd), 0, false);
- tcache_arena_associate(tsd_tsdn(tsd), tcache_slow, tcache,
- arena);
- } else {
- arena = arena_choose(tsd, NULL);
- /* This may happen if thread.tcache.enabled is used. */
- if (tcache_slow->arena == NULL) {
- tcache_arena_associate(tsd_tsdn(tsd), tcache_slow,
- tcache, arena);
- }
- }
- assert(arena == tcache_slow->arena);
-
- return false;
-}
-
-/* Created manual tcache for tcache.create mallctl. */
-tcache_t *
-tcache_create_explicit(tsd_t *tsd) {
- /*
- * We place the cache bin stacks, then the tcache_t, then a pointer to
- * the beginning of the whole allocation (for freeing). The makes sure
- * the cache bins have the requested alignment.
- */
- size_t size = tcache_bin_alloc_size + sizeof(tcache_t)
- + sizeof(tcache_slow_t);
- /* Naturally align the pointer stacks. */
- size = PTR_CEILING(size);
- size = sz_sa2u(size, tcache_bin_alloc_alignment);
-
- void *mem = ipallocztm(tsd_tsdn(tsd), size, tcache_bin_alloc_alignment,
- true, NULL, true, arena_get(TSDN_NULL, 0, true));
- if (mem == NULL) {
- return NULL;
- }
- tcache_t *tcache = (void *)((uintptr_t)mem + tcache_bin_alloc_size);
- tcache_slow_t *tcache_slow =
- (void *)((uintptr_t)mem + tcache_bin_alloc_size + sizeof(tcache_t));
- tcache_init(tsd, tcache_slow, tcache, mem);
-
- tcache_arena_associate(tsd_tsdn(tsd), tcache_slow, tcache,
- arena_ichoose(tsd, NULL));
-
- return tcache;
-}
-
-static void
-tcache_flush_cache(tsd_t *tsd, tcache_t *tcache) {
- tcache_slow_t *tcache_slow = tcache->tcache_slow;
- assert(tcache_slow->arena != NULL);
-
- for (unsigned i = 0; i < nhbins; i++) {
- cache_bin_t *cache_bin = &tcache->bins[i];
- if (i < SC_NBINS) {
- tcache_bin_flush_small(tsd, tcache, cache_bin, i, 0);
- } else {
- tcache_bin_flush_large(tsd, tcache, cache_bin, i, 0);
- }
- if (config_stats) {
- assert(cache_bin->tstats.nrequests == 0);
- }
- }
-}
-
-void
-tcache_flush(tsd_t *tsd) {
- assert(tcache_available(tsd));
- tcache_flush_cache(tsd, tsd_tcachep_get(tsd));
-}
-
-static void
-tcache_destroy(tsd_t *tsd, tcache_t *tcache, bool tsd_tcache) {
- tcache_slow_t *tcache_slow = tcache->tcache_slow;
- tcache_flush_cache(tsd, tcache);
- arena_t *arena = tcache_slow->arena;
- tcache_arena_dissociate(tsd_tsdn(tsd), tcache_slow, tcache);
-
- if (tsd_tcache) {
- cache_bin_t *cache_bin = &tcache->bins[0];
- cache_bin_assert_empty(cache_bin, &tcache_bin_info[0]);
- }
- idalloctm(tsd_tsdn(tsd), tcache_slow->dyn_alloc, NULL, NULL, true,
- true);
-
- /*
- * The deallocation and tcache flush above may not trigger decay since
- * we are on the tcache shutdown path (potentially with non-nominal
- * tsd). Manually trigger decay to avoid pathological cases. Also
- * include arena 0 because the tcache array is allocated from it.
- */
- arena_decay(tsd_tsdn(tsd), arena_get(tsd_tsdn(tsd), 0, false),
- false, false);
-
- if (arena_nthreads_get(arena, false) == 0 &&
- !background_thread_enabled()) {
- /* Force purging when no threads assigned to the arena anymore. */
- arena_decay(tsd_tsdn(tsd), arena,
- /* is_background_thread */ false, /* all */ true);
- } else {
- arena_decay(tsd_tsdn(tsd), arena,
- /* is_background_thread */ false, /* all */ false);
- }
-}
-
-/* For auto tcache (embedded in TSD) only. */
-void
-tcache_cleanup(tsd_t *tsd) {
- tcache_t *tcache = tsd_tcachep_get(tsd);
- if (!tcache_available(tsd)) {
- assert(tsd_tcache_enabled_get(tsd) == false);
- assert(cache_bin_still_zero_initialized(&tcache->bins[0]));
- return;
- }
- assert(tsd_tcache_enabled_get(tsd));
- assert(!cache_bin_still_zero_initialized(&tcache->bins[0]));
-
- tcache_destroy(tsd, tcache, true);
- if (config_debug) {
- /*
- * For debug testing only, we want to pretend we're still in the
- * zero-initialized state.
- */
- memset(tcache->bins, 0, sizeof(cache_bin_t) * nhbins);
- }
-}
-
-void
-tcache_stats_merge(tsdn_t *tsdn, tcache_t *tcache, arena_t *arena) {
- cassert(config_stats);
-
- /* Merge and reset tcache stats. */
- for (unsigned i = 0; i < nhbins; i++) {
- cache_bin_t *cache_bin = &tcache->bins[i];
- if (i < SC_NBINS) {
- bin_t *bin = arena_bin_choose(tsdn, arena, i, NULL);
- malloc_mutex_lock(tsdn, &bin->lock);
- bin->stats.nrequests += cache_bin->tstats.nrequests;
- malloc_mutex_unlock(tsdn, &bin->lock);
- } else {
- arena_stats_large_flush_nrequests_add(tsdn,
- &arena->stats, i, cache_bin->tstats.nrequests);
- }
- cache_bin->tstats.nrequests = 0;
- }
-}
-
-static bool
-tcaches_create_prep(tsd_t *tsd, base_t *base) {
- bool err;
-
- malloc_mutex_assert_owner(tsd_tsdn(tsd), &tcaches_mtx);
-
- if (tcaches == NULL) {
- tcaches = base_alloc(tsd_tsdn(tsd), base,
- sizeof(tcache_t *) * (MALLOCX_TCACHE_MAX+1), CACHELINE);
- if (tcaches == NULL) {
- err = true;
- goto label_return;
- }
- }
-
- if (tcaches_avail == NULL && tcaches_past > MALLOCX_TCACHE_MAX) {
- err = true;
- goto label_return;
- }
-
- err = false;
-label_return:
- return err;
-}
-
-bool
-tcaches_create(tsd_t *tsd, base_t *base, unsigned *r_ind) {
- witness_assert_depth(tsdn_witness_tsdp_get(tsd_tsdn(tsd)), 0);
-
- bool err;
-
- malloc_mutex_lock(tsd_tsdn(tsd), &tcaches_mtx);
-
- if (tcaches_create_prep(tsd, base)) {
- err = true;
- goto label_return;
- }
-
- tcache_t *tcache = tcache_create_explicit(tsd);
- if (tcache == NULL) {
- err = true;
- goto label_return;
- }
-
- tcaches_t *elm;
- if (tcaches_avail != NULL) {
- elm = tcaches_avail;
- tcaches_avail = tcaches_avail->next;
- elm->tcache = tcache;
- *r_ind = (unsigned)(elm - tcaches);
- } else {
- elm = &tcaches[tcaches_past];
- elm->tcache = tcache;
- *r_ind = tcaches_past;
- tcaches_past++;
- }
-
- err = false;
-label_return:
- malloc_mutex_unlock(tsd_tsdn(tsd), &tcaches_mtx);
- witness_assert_depth(tsdn_witness_tsdp_get(tsd_tsdn(tsd)), 0);
- return err;
-}
-
-static tcache_t *
-tcaches_elm_remove(tsd_t *tsd, tcaches_t *elm, bool allow_reinit) {
- malloc_mutex_assert_owner(tsd_tsdn(tsd), &tcaches_mtx);
-
- if (elm->tcache == NULL) {
- return NULL;
- }
- tcache_t *tcache = elm->tcache;
- if (allow_reinit) {
- elm->tcache = TCACHES_ELM_NEED_REINIT;
- } else {
- elm->tcache = NULL;
- }
-
- if (tcache == TCACHES_ELM_NEED_REINIT) {
- return NULL;
- }
- return tcache;
-}
-
-void
-tcaches_flush(tsd_t *tsd, unsigned ind) {
- malloc_mutex_lock(tsd_tsdn(tsd), &tcaches_mtx);
- tcache_t *tcache = tcaches_elm_remove(tsd, &tcaches[ind], true);
- malloc_mutex_unlock(tsd_tsdn(tsd), &tcaches_mtx);
- if (tcache != NULL) {
- /* Destroy the tcache; recreate in tcaches_get() if needed. */
- tcache_destroy(tsd, tcache, false);
- }
-}
-
-void
-tcaches_destroy(tsd_t *tsd, unsigned ind) {
- malloc_mutex_lock(tsd_tsdn(tsd), &tcaches_mtx);
- tcaches_t *elm = &tcaches[ind];
- tcache_t *tcache = tcaches_elm_remove(tsd, elm, false);
- elm->next = tcaches_avail;
- tcaches_avail = elm;
- malloc_mutex_unlock(tsd_tsdn(tsd), &tcaches_mtx);
- if (tcache != NULL) {
- tcache_destroy(tsd, tcache, false);
- }
-}
-
-static unsigned
-tcache_ncached_max_compute(szind_t szind) {
- if (szind >= SC_NBINS) {
- assert(szind < nhbins);
- return opt_tcache_nslots_large;
- }
- unsigned slab_nregs = bin_infos[szind].nregs;
-
- /* We may modify these values; start with the opt versions. */
- unsigned nslots_small_min = opt_tcache_nslots_small_min;
- unsigned nslots_small_max = opt_tcache_nslots_small_max;
-
- /*
- * Clamp values to meet our constraints -- even, nonzero, min < max, and
- * suitable for a cache bin size.
- */
- if (opt_tcache_nslots_small_max > CACHE_BIN_NCACHED_MAX) {
- nslots_small_max = CACHE_BIN_NCACHED_MAX;
- }
- if (nslots_small_min % 2 != 0) {
- nslots_small_min++;
- }
- if (nslots_small_max % 2 != 0) {
- nslots_small_max--;
- }
- if (nslots_small_min < 2) {
- nslots_small_min = 2;
- }
- if (nslots_small_max < 2) {
- nslots_small_max = 2;
- }
- if (nslots_small_min > nslots_small_max) {
- nslots_small_min = nslots_small_max;
- }
-
- unsigned candidate;
- if (opt_lg_tcache_nslots_mul < 0) {
- candidate = slab_nregs >> (-opt_lg_tcache_nslots_mul);
- } else {
- candidate = slab_nregs << opt_lg_tcache_nslots_mul;
- }
- if (candidate % 2 != 0) {
- /*
- * We need the candidate size to be even -- we assume that we
- * can divide by two and get a positive number (e.g. when
- * flushing).
- */
- ++candidate;
- }
- if (candidate <= nslots_small_min) {
- return nslots_small_min;
- } else if (candidate <= nslots_small_max) {
- return candidate;
- } else {
- return nslots_small_max;
- }
-}
-
-bool
-tcache_boot(tsdn_t *tsdn, base_t *base) {
- tcache_maxclass = sz_s2u(opt_tcache_max);
- assert(tcache_maxclass <= TCACHE_MAXCLASS_LIMIT);
- nhbins = sz_size2index(tcache_maxclass) + 1;
-
- if (malloc_mutex_init(&tcaches_mtx, "tcaches", WITNESS_RANK_TCACHES,
- malloc_mutex_rank_exclusive)) {
- return true;
- }
-
- /* Initialize tcache_bin_info. See comments in tcache_init(). */
- unsigned n_reserved_bins = nhbins < SC_NBINS ? SC_NBINS : nhbins;
- size_t size = n_reserved_bins * sizeof(cache_bin_info_t);
- tcache_bin_info = (cache_bin_info_t *)base_alloc(tsdn, base, size,
- CACHELINE);
- if (tcache_bin_info == NULL) {
- return true;
- }
-
- for (szind_t i = 0; i < nhbins; i++) {
- unsigned ncached_max = tcache_ncached_max_compute(i);
- cache_bin_info_init(&tcache_bin_info[i], ncached_max);
- }
- for (szind_t i = nhbins; i < SC_NBINS; i++) {
- /* Disabled small bins. */
- cache_bin_info_init(&tcache_bin_info[i], 0);
- assert(tcache_small_bin_disabled(i, NULL));
- }
-
- cache_bin_info_compute_alloc(tcache_bin_info, nhbins,
- &tcache_bin_alloc_size, &tcache_bin_alloc_alignment);
-
- return false;
-}
-
-void
-tcache_prefork(tsdn_t *tsdn) {
- malloc_mutex_prefork(tsdn, &tcaches_mtx);
-}
-
-void
-tcache_postfork_parent(tsdn_t *tsdn) {
- malloc_mutex_postfork_parent(tsdn, &tcaches_mtx);
-}
-
-void
-tcache_postfork_child(tsdn_t *tsdn) {
- malloc_mutex_postfork_child(tsdn, &tcaches_mtx);
-}
-
-void tcache_assert_initialized(tcache_t *tcache) {
- assert(!cache_bin_still_zero_initialized(&tcache->bins[0]));
-}
diff --git a/fluent-bit/lib/jemalloc-5.3.0/src/test_hooks.c b/fluent-bit/lib/jemalloc-5.3.0/src/test_hooks.c
deleted file mode 100644
index ace00d9c..00000000
--- a/fluent-bit/lib/jemalloc-5.3.0/src/test_hooks.c
+++ /dev/null
@@ -1,12 +0,0 @@
-#include "jemalloc/internal/jemalloc_preamble.h"
-
-/*
- * The hooks are a little bit screwy -- they're not genuinely exported in the
- * sense that we want them available to end-users, but we do want them visible
- * from outside the generated library, so that we can use them in test code.
- */
-JEMALLOC_EXPORT
-void (*test_hooks_arena_new_hook)() = NULL;
-
-JEMALLOC_EXPORT
-void (*test_hooks_libc_hook)() = NULL;
diff --git a/fluent-bit/lib/jemalloc-5.3.0/src/thread_event.c b/fluent-bit/lib/jemalloc-5.3.0/src/thread_event.c
deleted file mode 100644
index 37eb5827..00000000
--- a/fluent-bit/lib/jemalloc-5.3.0/src/thread_event.c
+++ /dev/null
@@ -1,343 +0,0 @@
-#include "jemalloc/internal/jemalloc_preamble.h"
-#include "jemalloc/internal/jemalloc_internal_includes.h"
-
-#include "jemalloc/internal/thread_event.h"
-
-/*
- * Signatures for event specific functions. These functions should be defined
- * by the modules owning each event. The signatures here verify that the
- * definitions follow the right format.
- *
- * The first two are functions computing new / postponed event wait time. New
- * event wait time is the time till the next event if an event is currently
- * being triggered; postponed event wait time is the time till the next event
- * if an event should be triggered but needs to be postponed, e.g. when the TSD
- * is not nominal or during reentrancy.
- *
- * The third is the event handler function, which is called whenever an event
- * is triggered. The parameter is the elapsed time since the last time an
- * event of the same type was triggered.
- */
-#define E(event, condition_unused, is_alloc_event_unused) \
-uint64_t event##_new_event_wait(tsd_t *tsd); \
-uint64_t event##_postponed_event_wait(tsd_t *tsd); \
-void event##_event_handler(tsd_t *tsd, uint64_t elapsed);
-
-ITERATE_OVER_ALL_EVENTS
-#undef E
-
-/* Signatures for internal functions fetching elapsed time. */
-#define E(event, condition_unused, is_alloc_event_unused) \
-static uint64_t event##_fetch_elapsed(tsd_t *tsd);
-
-ITERATE_OVER_ALL_EVENTS
-#undef E
-
-static uint64_t
-tcache_gc_fetch_elapsed(tsd_t *tsd) {
- return TE_INVALID_ELAPSED;
-}
-
-static uint64_t
-tcache_gc_dalloc_fetch_elapsed(tsd_t *tsd) {
- return TE_INVALID_ELAPSED;
-}
-
-static uint64_t
-prof_sample_fetch_elapsed(tsd_t *tsd) {
- uint64_t last_event = thread_allocated_last_event_get(tsd);
- uint64_t last_sample_event = prof_sample_last_event_get(tsd);
- prof_sample_last_event_set(tsd, last_event);
- return last_event - last_sample_event;
-}
-
-static uint64_t
-stats_interval_fetch_elapsed(tsd_t *tsd) {
- uint64_t last_event = thread_allocated_last_event_get(tsd);
- uint64_t last_stats_event = stats_interval_last_event_get(tsd);
- stats_interval_last_event_set(tsd, last_event);
- return last_event - last_stats_event;
-}
-
-static uint64_t
-peak_alloc_fetch_elapsed(tsd_t *tsd) {
- return TE_INVALID_ELAPSED;
-}
-
-static uint64_t
-peak_dalloc_fetch_elapsed(tsd_t *tsd) {
- return TE_INVALID_ELAPSED;
-}
-
-/* Per event facilities done. */
-
-static bool
-te_ctx_has_active_events(te_ctx_t *ctx) {
- assert(config_debug);
-#define E(event, condition, alloc_event) \
- if (condition && alloc_event == ctx->is_alloc) { \
- return true; \
- }
- ITERATE_OVER_ALL_EVENTS
-#undef E
- return false;
-}
-
-static uint64_t
-te_next_event_compute(tsd_t *tsd, bool is_alloc) {
- uint64_t wait = TE_MAX_START_WAIT;
-#define E(event, condition, alloc_event) \
- if (is_alloc == alloc_event && condition) { \
- uint64_t event_wait = \
- event##_event_wait_get(tsd); \
- assert(event_wait <= TE_MAX_START_WAIT); \
- if (event_wait > 0U && event_wait < wait) { \
- wait = event_wait; \
- } \
- }
-
- ITERATE_OVER_ALL_EVENTS
-#undef E
- assert(wait <= TE_MAX_START_WAIT);
- return wait;
-}
-
-static void
-te_assert_invariants_impl(tsd_t *tsd, te_ctx_t *ctx) {
- uint64_t current_bytes = te_ctx_current_bytes_get(ctx);
- uint64_t last_event = te_ctx_last_event_get(ctx);
- uint64_t next_event = te_ctx_next_event_get(ctx);
- uint64_t next_event_fast = te_ctx_next_event_fast_get(ctx);
-
- assert(last_event != next_event);
- if (next_event > TE_NEXT_EVENT_FAST_MAX || !tsd_fast(tsd)) {
- assert(next_event_fast == 0U);
- } else {
- assert(next_event_fast == next_event);
- }
-
- /* The subtraction is intentionally susceptible to underflow. */
- uint64_t interval = next_event - last_event;
-
- /* The subtraction is intentionally susceptible to underflow. */
- assert(current_bytes - last_event < interval);
- uint64_t min_wait = te_next_event_compute(tsd, te_ctx_is_alloc(ctx));
- /*
- * next_event should have been pushed up only except when no event is
- * on and the TSD is just initialized. The last_event == 0U guard
- * below is stronger than needed, but having an exactly accurate guard
- * is more complicated to implement.
- */
- assert((!te_ctx_has_active_events(ctx) && last_event == 0U) ||
- interval == min_wait ||
- (interval < min_wait && interval == TE_MAX_INTERVAL));
-}
-
-void
-te_assert_invariants_debug(tsd_t *tsd) {
- te_ctx_t ctx;
- te_ctx_get(tsd, &ctx, true);
- te_assert_invariants_impl(tsd, &ctx);
-
- te_ctx_get(tsd, &ctx, false);
- te_assert_invariants_impl(tsd, &ctx);
-}
-
-/*
- * Synchronization around the fast threshold in tsd --
- * There are two threads to consider in the synchronization here:
- * - The owner of the tsd being updated by a slow path change
- * - The remote thread, doing that slow path change.
- *
- * As a design constraint, we want to ensure that a slow-path transition cannot
- * be ignored for arbitrarily long, and that if the remote thread causes a
- * slow-path transition and then communicates with the owner thread that it has
- * occurred, then the owner will go down the slow path on the next allocator
- * operation (so that we don't want to just wait until the owner hits its slow
- * path reset condition on its own).
- *
- * Here's our strategy to do that:
- *
- * The remote thread will update the slow-path stores to TSD variables, issue a
- * SEQ_CST fence, and then update the TSD next_event_fast counter. The owner
- * thread will update next_event_fast, issue an SEQ_CST fence, and then check
- * its TSD to see if it's on the slow path.
-
- * This is fairly straightforward when 64-bit atomics are supported. Assume that
- * the remote fence is sandwiched between two owner fences in the reset pathway.
- * The case where there is no preceding or trailing owner fence (i.e. because
- * the owner thread is near the beginning or end of its life) can be analyzed
- * similarly. The owner store to next_event_fast preceding the earlier owner
- * fence will be earlier in coherence order than the remote store to it, so that
- * the owner thread will go down the slow path once the store becomes visible to
- * it, which is no later than the time of the second fence.
-
- * The case where we don't support 64-bit atomics is trickier, since word
- * tearing is possible. We'll repeat the same analysis, and look at the two
- * owner fences sandwiching the remote fence. The next_event_fast stores done
- * alongside the earlier owner fence cannot overwrite any of the remote stores
- * (since they precede the earlier owner fence in sb, which precedes the remote
- * fence in sc, which precedes the remote stores in sb). After the second owner
- * fence there will be a re-check of the slow-path variables anyways, so the
- * "owner will notice that it's on the slow path eventually" guarantee is
- * satisfied. To make sure that the out-of-band-messaging constraint is as well,
- * note that either the message passing is sequenced before the second owner
- * fence (in which case the remote stores happen before the second set of owner
- * stores, so malloc sees a value of zero for next_event_fast and goes down the
- * slow path), or it is not (in which case the owner sees the tsd slow-path
- * writes on its previous update). This leaves open the possibility that the
- * remote thread will (at some arbitrary point in the future) zero out one half
- * of the owner thread's next_event_fast, but that's always safe (it just sends
- * it down the slow path earlier).
- */
-static void
-te_ctx_next_event_fast_update(te_ctx_t *ctx) {
- uint64_t next_event = te_ctx_next_event_get(ctx);
- uint64_t next_event_fast = (next_event <= TE_NEXT_EVENT_FAST_MAX) ?
- next_event : 0U;
- te_ctx_next_event_fast_set(ctx, next_event_fast);
-}
-
-void
-te_recompute_fast_threshold(tsd_t *tsd) {
- if (tsd_state_get(tsd) != tsd_state_nominal) {
- /* Check first because this is also called on purgatory. */
- te_next_event_fast_set_non_nominal(tsd);
- return;
- }
-
- te_ctx_t ctx;
- te_ctx_get(tsd, &ctx, true);
- te_ctx_next_event_fast_update(&ctx);
- te_ctx_get(tsd, &ctx, false);
- te_ctx_next_event_fast_update(&ctx);
-
- atomic_fence(ATOMIC_SEQ_CST);
- if (tsd_state_get(tsd) != tsd_state_nominal) {
- te_next_event_fast_set_non_nominal(tsd);
- }
-}
-
-static void
-te_adjust_thresholds_helper(tsd_t *tsd, te_ctx_t *ctx,
- uint64_t wait) {
- /*
- * The next threshold based on future events can only be adjusted after
- * progressing the last_event counter (which is set to current).
- */
- assert(te_ctx_current_bytes_get(ctx) == te_ctx_last_event_get(ctx));
- assert(wait <= TE_MAX_START_WAIT);
-
- uint64_t next_event = te_ctx_last_event_get(ctx) + (wait <=
- TE_MAX_INTERVAL ? wait : TE_MAX_INTERVAL);
- te_ctx_next_event_set(tsd, ctx, next_event);
-}
-
-static uint64_t
-te_clip_event_wait(uint64_t event_wait) {
- assert(event_wait > 0U);
- if (TE_MIN_START_WAIT > 1U &&
- unlikely(event_wait < TE_MIN_START_WAIT)) {
- event_wait = TE_MIN_START_WAIT;
- }
- if (TE_MAX_START_WAIT < UINT64_MAX &&
- unlikely(event_wait > TE_MAX_START_WAIT)) {
- event_wait = TE_MAX_START_WAIT;
- }
- return event_wait;
-}
-
-void
-te_event_trigger(tsd_t *tsd, te_ctx_t *ctx) {
- /* usize has already been added to thread_allocated. */
- uint64_t bytes_after = te_ctx_current_bytes_get(ctx);
- /* The subtraction is intentionally susceptible to underflow. */
- uint64_t accumbytes = bytes_after - te_ctx_last_event_get(ctx);
-
- te_ctx_last_event_set(ctx, bytes_after);
-
- bool allow_event_trigger = tsd_nominal(tsd) &&
- tsd_reentrancy_level_get(tsd) == 0;
- bool is_alloc = ctx->is_alloc;
- uint64_t wait = TE_MAX_START_WAIT;
-
-#define E(event, condition, alloc_event) \
- bool is_##event##_triggered = false; \
- if (is_alloc == alloc_event && condition) { \
- uint64_t event_wait = event##_event_wait_get(tsd); \
- assert(event_wait <= TE_MAX_START_WAIT); \
- if (event_wait > accumbytes) { \
- event_wait -= accumbytes; \
- } else if (!allow_event_trigger) { \
- event_wait = event##_postponed_event_wait(tsd); \
- } else { \
- is_##event##_triggered = true; \
- event_wait = event##_new_event_wait(tsd); \
- } \
- event_wait = te_clip_event_wait(event_wait); \
- event##_event_wait_set(tsd, event_wait); \
- if (event_wait < wait) { \
- wait = event_wait; \
- } \
- }
-
- ITERATE_OVER_ALL_EVENTS
-#undef E
-
- assert(wait <= TE_MAX_START_WAIT);
- te_adjust_thresholds_helper(tsd, ctx, wait);
- te_assert_invariants(tsd);
-
-#define E(event, condition, alloc_event) \
- if (is_alloc == alloc_event && condition && \
- is_##event##_triggered) { \
- assert(allow_event_trigger); \
- uint64_t elapsed = event##_fetch_elapsed(tsd); \
- event##_event_handler(tsd, elapsed); \
- }
-
- ITERATE_OVER_ALL_EVENTS
-#undef E
-
- te_assert_invariants(tsd);
-}
-
-static void
-te_init(tsd_t *tsd, bool is_alloc) {
- te_ctx_t ctx;
- te_ctx_get(tsd, &ctx, is_alloc);
- /*
- * Reset the last event to current, which starts the events from a clean
- * state. This is necessary when re-init the tsd event counters.
- *
- * The event counters maintain a relationship with the current bytes:
- * last_event <= current < next_event. When a reinit happens (e.g.
- * reincarnated tsd), the last event needs progressing because all
- * events start fresh from the current bytes.
- */
- te_ctx_last_event_set(&ctx, te_ctx_current_bytes_get(&ctx));
-
- uint64_t wait = TE_MAX_START_WAIT;
-#define E(event, condition, alloc_event) \
- if (is_alloc == alloc_event && condition) { \
- uint64_t event_wait = event##_new_event_wait(tsd); \
- event_wait = te_clip_event_wait(event_wait); \
- event##_event_wait_set(tsd, event_wait); \
- if (event_wait < wait) { \
- wait = event_wait; \
- } \
- }
-
- ITERATE_OVER_ALL_EVENTS
-#undef E
- te_adjust_thresholds_helper(tsd, &ctx, wait);
-}
-
-void
-tsd_te_init(tsd_t *tsd) {
- /* Make sure no overflow for the bytes accumulated on event_trigger. */
- assert(TE_MAX_INTERVAL <= UINT64_MAX - SC_LARGE_MAXCLASS + 1);
- te_init(tsd, true);
- te_init(tsd, false);
- te_assert_invariants(tsd);
-}
diff --git a/fluent-bit/lib/jemalloc-5.3.0/src/ticker.c b/fluent-bit/lib/jemalloc-5.3.0/src/ticker.c
deleted file mode 100644
index 790b5c20..00000000
--- a/fluent-bit/lib/jemalloc-5.3.0/src/ticker.c
+++ /dev/null
@@ -1,32 +0,0 @@
-#include "jemalloc/internal/jemalloc_preamble.h"
-#include "jemalloc/internal/jemalloc_internal_includes.h"
-
-/*
- * To avoid using floating point math down core paths (still necessary because
- * versions of the glibc dynamic loader that did not preserve xmm registers are
- * still somewhat common, requiring us to be compilable with -mno-sse), and also
- * to avoid generally expensive library calls, we use a precomputed table of
- * values. We want to sample U uniformly on [0, 1], and then compute
- * ceil(log(u)/log(1-1/nticks)). We're mostly interested in the case where
- * nticks is reasonably big, so 1/log(1-1/nticks) is well-approximated by
- * -nticks.
- *
- * To compute log(u), we sample an integer in [1, 64] and divide, then just look
- * up results in a table. As a space-compression mechanism, we store these as
- * uint8_t by dividing the range (255) by the highest-magnitude value the log
- * can take on, and using that as a multiplier. We then have to divide by that
- * multiplier at the end of the computation.
- *
- * The values here are computed in src/ticker.py
- */
-
-const uint8_t ticker_geom_table[1 << TICKER_GEOM_NBITS] = {
- 254, 211, 187, 169, 156, 144, 135, 127,
- 120, 113, 107, 102, 97, 93, 89, 85,
- 81, 77, 74, 71, 68, 65, 62, 60,
- 57, 55, 53, 50, 48, 46, 44, 42,
- 40, 39, 37, 35, 33, 32, 30, 29,
- 27, 26, 24, 23, 21, 20, 19, 18,
- 16, 15, 14, 13, 12, 10, 9, 8,
- 7, 6, 5, 4, 3, 2, 1, 0
-};
diff --git a/fluent-bit/lib/jemalloc-5.3.0/src/ticker.py b/fluent-bit/lib/jemalloc-5.3.0/src/ticker.py
deleted file mode 100755
index 3807740c..00000000
--- a/fluent-bit/lib/jemalloc-5.3.0/src/ticker.py
+++ /dev/null
@@ -1,15 +0,0 @@
-#!/usr/bin/env python3
-
-import math
-
-# Must match TICKER_GEOM_NBITS
-lg_table_size = 6
-table_size = 2**lg_table_size
-byte_max = 255
-mul = math.floor(-byte_max/math.log(1 / table_size))
-values = [round(-mul * math.log(i / table_size))
- for i in range(1, table_size+1)]
-print("mul =", mul)
-print("values:")
-for i in range(table_size // 8):
- print(", ".join((str(x) for x in values[i*8 : i*8 + 8])))
diff --git a/fluent-bit/lib/jemalloc-5.3.0/src/tsd.c b/fluent-bit/lib/jemalloc-5.3.0/src/tsd.c
deleted file mode 100644
index e8e4f3a3..00000000
--- a/fluent-bit/lib/jemalloc-5.3.0/src/tsd.c
+++ /dev/null
@@ -1,549 +0,0 @@
-#include "jemalloc/internal/jemalloc_preamble.h"
-#include "jemalloc/internal/jemalloc_internal_includes.h"
-
-#include "jemalloc/internal/assert.h"
-#include "jemalloc/internal/san.h"
-#include "jemalloc/internal/mutex.h"
-#include "jemalloc/internal/rtree.h"
-
-/******************************************************************************/
-/* Data. */
-
-/* TSD_INITIALIZER triggers "-Wmissing-field-initializer" */
-JEMALLOC_DIAGNOSTIC_PUSH
-JEMALLOC_DIAGNOSTIC_IGNORE_MISSING_STRUCT_FIELD_INITIALIZERS
-
-#ifdef JEMALLOC_MALLOC_THREAD_CLEANUP
-JEMALLOC_TSD_TYPE_ATTR(tsd_t) tsd_tls = TSD_INITIALIZER;
-JEMALLOC_TSD_TYPE_ATTR(bool) JEMALLOC_TLS_MODEL tsd_initialized = false;
-bool tsd_booted = false;
-#elif (defined(JEMALLOC_TLS))
-JEMALLOC_TSD_TYPE_ATTR(tsd_t) tsd_tls = TSD_INITIALIZER;
-pthread_key_t tsd_tsd;
-bool tsd_booted = false;
-#elif (defined(_WIN32))
-DWORD tsd_tsd;
-tsd_wrapper_t tsd_boot_wrapper = {false, TSD_INITIALIZER};
-bool tsd_booted = false;
-#else
-
-/*
- * This contains a mutex, but it's pretty convenient to allow the mutex code to
- * have a dependency on tsd. So we define the struct here, and only refer to it
- * by pointer in the header.
- */
-struct tsd_init_head_s {
- ql_head(tsd_init_block_t) blocks;
- malloc_mutex_t lock;
-};
-
-pthread_key_t tsd_tsd;
-tsd_init_head_t tsd_init_head = {
- ql_head_initializer(blocks),
- MALLOC_MUTEX_INITIALIZER
-};
-
-tsd_wrapper_t tsd_boot_wrapper = {
- false,
- TSD_INITIALIZER
-};
-bool tsd_booted = false;
-#endif
-
-JEMALLOC_DIAGNOSTIC_POP
-
-/******************************************************************************/
-
-/* A list of all the tsds in the nominal state. */
-typedef ql_head(tsd_t) tsd_list_t;
-static tsd_list_t tsd_nominal_tsds = ql_head_initializer(tsd_nominal_tsds);
-static malloc_mutex_t tsd_nominal_tsds_lock;
-
-/* How many slow-path-enabling features are turned on. */
-static atomic_u32_t tsd_global_slow_count = ATOMIC_INIT(0);
-
-static bool
-tsd_in_nominal_list(tsd_t *tsd) {
- tsd_t *tsd_list;
- bool found = false;
- /*
- * We don't know that tsd is nominal; it might not be safe to get data
- * out of it here.
- */
- malloc_mutex_lock(TSDN_NULL, &tsd_nominal_tsds_lock);
- ql_foreach(tsd_list, &tsd_nominal_tsds, TSD_MANGLE(tsd_link)) {
- if (tsd == tsd_list) {
- found = true;
- break;
- }
- }
- malloc_mutex_unlock(TSDN_NULL, &tsd_nominal_tsds_lock);
- return found;
-}
-
-static void
-tsd_add_nominal(tsd_t *tsd) {
- assert(!tsd_in_nominal_list(tsd));
- assert(tsd_state_get(tsd) <= tsd_state_nominal_max);
- ql_elm_new(tsd, TSD_MANGLE(tsd_link));
- malloc_mutex_lock(tsd_tsdn(tsd), &tsd_nominal_tsds_lock);
- ql_tail_insert(&tsd_nominal_tsds, tsd, TSD_MANGLE(tsd_link));
- malloc_mutex_unlock(tsd_tsdn(tsd), &tsd_nominal_tsds_lock);
-}
-
-static void
-tsd_remove_nominal(tsd_t *tsd) {
- assert(tsd_in_nominal_list(tsd));
- assert(tsd_state_get(tsd) <= tsd_state_nominal_max);
- malloc_mutex_lock(tsd_tsdn(tsd), &tsd_nominal_tsds_lock);
- ql_remove(&tsd_nominal_tsds, tsd, TSD_MANGLE(tsd_link));
- malloc_mutex_unlock(tsd_tsdn(tsd), &tsd_nominal_tsds_lock);
-}
-
-static void
-tsd_force_recompute(tsdn_t *tsdn) {
- /*
- * The stores to tsd->state here need to synchronize with the exchange
- * in tsd_slow_update.
- */
- atomic_fence(ATOMIC_RELEASE);
- malloc_mutex_lock(tsdn, &tsd_nominal_tsds_lock);
- tsd_t *remote_tsd;
- ql_foreach(remote_tsd, &tsd_nominal_tsds, TSD_MANGLE(tsd_link)) {
- assert(tsd_atomic_load(&remote_tsd->state, ATOMIC_RELAXED)
- <= tsd_state_nominal_max);
- tsd_atomic_store(&remote_tsd->state,
- tsd_state_nominal_recompute, ATOMIC_RELAXED);
- /* See comments in te_recompute_fast_threshold(). */
- atomic_fence(ATOMIC_SEQ_CST);
- te_next_event_fast_set_non_nominal(remote_tsd);
- }
- malloc_mutex_unlock(tsdn, &tsd_nominal_tsds_lock);
-}
-
-void
-tsd_global_slow_inc(tsdn_t *tsdn) {
- atomic_fetch_add_u32(&tsd_global_slow_count, 1, ATOMIC_RELAXED);
- /*
- * We unconditionally force a recompute, even if the global slow count
- * was already positive. If we didn't, then it would be possible for us
- * to return to the user, have the user synchronize externally with some
- * other thread, and then have that other thread not have picked up the
- * update yet (since the original incrementing thread might still be
- * making its way through the tsd list).
- */
- tsd_force_recompute(tsdn);
-}
-
-void tsd_global_slow_dec(tsdn_t *tsdn) {
- atomic_fetch_sub_u32(&tsd_global_slow_count, 1, ATOMIC_RELAXED);
- /* See the note in ..._inc(). */
- tsd_force_recompute(tsdn);
-}
-
-static bool
-tsd_local_slow(tsd_t *tsd) {
- return !tsd_tcache_enabled_get(tsd)
- || tsd_reentrancy_level_get(tsd) > 0;
-}
-
-bool
-tsd_global_slow() {
- return atomic_load_u32(&tsd_global_slow_count, ATOMIC_RELAXED) > 0;
-}
-
-/******************************************************************************/
-
-static uint8_t
-tsd_state_compute(tsd_t *tsd) {
- if (!tsd_nominal(tsd)) {
- return tsd_state_get(tsd);
- }
- /* We're in *a* nominal state; but which one? */
- if (malloc_slow || tsd_local_slow(tsd) || tsd_global_slow()) {
- return tsd_state_nominal_slow;
- } else {
- return tsd_state_nominal;
- }
-}
-
-void
-tsd_slow_update(tsd_t *tsd) {
- uint8_t old_state;
- do {
- uint8_t new_state = tsd_state_compute(tsd);
- old_state = tsd_atomic_exchange(&tsd->state, new_state,
- ATOMIC_ACQUIRE);
- } while (old_state == tsd_state_nominal_recompute);
-
- te_recompute_fast_threshold(tsd);
-}
-
-void
-tsd_state_set(tsd_t *tsd, uint8_t new_state) {
- /* Only the tsd module can change the state *to* recompute. */
- assert(new_state != tsd_state_nominal_recompute);
- uint8_t old_state = tsd_atomic_load(&tsd->state, ATOMIC_RELAXED);
- if (old_state > tsd_state_nominal_max) {
- /*
- * Not currently in the nominal list, but it might need to be
- * inserted there.
- */
- assert(!tsd_in_nominal_list(tsd));
- tsd_atomic_store(&tsd->state, new_state, ATOMIC_RELAXED);
- if (new_state <= tsd_state_nominal_max) {
- tsd_add_nominal(tsd);
- }
- } else {
- /*
- * We're currently nominal. If the new state is non-nominal,
- * great; we take ourselves off the list and just enter the new
- * state.
- */
- assert(tsd_in_nominal_list(tsd));
- if (new_state > tsd_state_nominal_max) {
- tsd_remove_nominal(tsd);
- tsd_atomic_store(&tsd->state, new_state,
- ATOMIC_RELAXED);
- } else {
- /*
- * This is the tricky case. We're transitioning from
- * one nominal state to another. The caller can't know
- * about any races that are occurring at the same time,
- * so we always have to recompute no matter what.
- */
- tsd_slow_update(tsd);
- }
- }
- te_recompute_fast_threshold(tsd);
-}
-
-static void
-tsd_prng_state_init(tsd_t *tsd) {
- /*
- * A nondeterministic seed based on the address of tsd reduces
- * the likelihood of lockstep non-uniform cache index
- * utilization among identical concurrent processes, but at the
- * cost of test repeatability. For debug builds, instead use a
- * deterministic seed.
- */
- *tsd_prng_statep_get(tsd) = config_debug ? 0 :
- (uint64_t)(uintptr_t)tsd;
-}
-
-static bool
-tsd_data_init(tsd_t *tsd) {
- /*
- * We initialize the rtree context first (before the tcache), since the
- * tcache initialization depends on it.
- */
- rtree_ctx_data_init(tsd_rtree_ctxp_get_unsafe(tsd));
- tsd_prng_state_init(tsd);
- tsd_te_init(tsd); /* event_init may use the prng state above. */
- tsd_san_init(tsd);
- return tsd_tcache_enabled_data_init(tsd);
-}
-
-static void
-assert_tsd_data_cleanup_done(tsd_t *tsd) {
- assert(!tsd_nominal(tsd));
- assert(!tsd_in_nominal_list(tsd));
- assert(*tsd_arenap_get_unsafe(tsd) == NULL);
- assert(*tsd_iarenap_get_unsafe(tsd) == NULL);
- assert(*tsd_tcache_enabledp_get_unsafe(tsd) == false);
- assert(*tsd_prof_tdatap_get_unsafe(tsd) == NULL);
-}
-
-static bool
-tsd_data_init_nocleanup(tsd_t *tsd) {
- assert(tsd_state_get(tsd) == tsd_state_reincarnated ||
- tsd_state_get(tsd) == tsd_state_minimal_initialized);
- /*
- * During reincarnation, there is no guarantee that the cleanup function
- * will be called (deallocation may happen after all tsd destructors).
- * We set up tsd in a way that no cleanup is needed.
- */
- rtree_ctx_data_init(tsd_rtree_ctxp_get_unsafe(tsd));
- *tsd_tcache_enabledp_get_unsafe(tsd) = false;
- *tsd_reentrancy_levelp_get(tsd) = 1;
- tsd_prng_state_init(tsd);
- tsd_te_init(tsd); /* event_init may use the prng state above. */
- tsd_san_init(tsd);
- assert_tsd_data_cleanup_done(tsd);
-
- return false;
-}
-
-tsd_t *
-tsd_fetch_slow(tsd_t *tsd, bool minimal) {
- assert(!tsd_fast(tsd));
-
- if (tsd_state_get(tsd) == tsd_state_nominal_slow) {
- /*
- * On slow path but no work needed. Note that we can't
- * necessarily *assert* that we're slow, because we might be
- * slow because of an asynchronous modification to global state,
- * which might be asynchronously modified *back*.
- */
- } else if (tsd_state_get(tsd) == tsd_state_nominal_recompute) {
- tsd_slow_update(tsd);
- } else if (tsd_state_get(tsd) == tsd_state_uninitialized) {
- if (!minimal) {
- if (tsd_booted) {
- tsd_state_set(tsd, tsd_state_nominal);
- tsd_slow_update(tsd);
- /* Trigger cleanup handler registration. */
- tsd_set(tsd);
- tsd_data_init(tsd);
- }
- } else {
- tsd_state_set(tsd, tsd_state_minimal_initialized);
- tsd_set(tsd);
- tsd_data_init_nocleanup(tsd);
- }
- } else if (tsd_state_get(tsd) == tsd_state_minimal_initialized) {
- if (!minimal) {
- /* Switch to fully initialized. */
- tsd_state_set(tsd, tsd_state_nominal);
- assert(*tsd_reentrancy_levelp_get(tsd) >= 1);
- (*tsd_reentrancy_levelp_get(tsd))--;
- tsd_slow_update(tsd);
- tsd_data_init(tsd);
- } else {
- assert_tsd_data_cleanup_done(tsd);
- }
- } else if (tsd_state_get(tsd) == tsd_state_purgatory) {
- tsd_state_set(tsd, tsd_state_reincarnated);
- tsd_set(tsd);
- tsd_data_init_nocleanup(tsd);
- } else {
- assert(tsd_state_get(tsd) == tsd_state_reincarnated);
- }
-
- return tsd;
-}
-
-void *
-malloc_tsd_malloc(size_t size) {
- return a0malloc(CACHELINE_CEILING(size));
-}
-
-void
-malloc_tsd_dalloc(void *wrapper) {
- a0dalloc(wrapper);
-}
-
-#if defined(JEMALLOC_MALLOC_THREAD_CLEANUP) || defined(_WIN32)
-static unsigned ncleanups;
-static malloc_tsd_cleanup_t cleanups[MALLOC_TSD_CLEANUPS_MAX];
-
-#ifndef _WIN32
-JEMALLOC_EXPORT
-#endif
-void
-_malloc_thread_cleanup(void) {
- bool pending[MALLOC_TSD_CLEANUPS_MAX], again;
- unsigned i;
-
- for (i = 0; i < ncleanups; i++) {
- pending[i] = true;
- }
-
- do {
- again = false;
- for (i = 0; i < ncleanups; i++) {
- if (pending[i]) {
- pending[i] = cleanups[i]();
- if (pending[i]) {
- again = true;
- }
- }
- }
- } while (again);
-}
-
-#ifndef _WIN32
-JEMALLOC_EXPORT
-#endif
-void
-_malloc_tsd_cleanup_register(bool (*f)(void)) {
- assert(ncleanups < MALLOC_TSD_CLEANUPS_MAX);
- cleanups[ncleanups] = f;
- ncleanups++;
-}
-
-#endif
-
-static void
-tsd_do_data_cleanup(tsd_t *tsd) {
- prof_tdata_cleanup(tsd);
- iarena_cleanup(tsd);
- arena_cleanup(tsd);
- tcache_cleanup(tsd);
- witnesses_cleanup(tsd_witness_tsdp_get_unsafe(tsd));
- *tsd_reentrancy_levelp_get(tsd) = 1;
-}
-
-void
-tsd_cleanup(void *arg) {
- tsd_t *tsd = (tsd_t *)arg;
-
- switch (tsd_state_get(tsd)) {
- case tsd_state_uninitialized:
- /* Do nothing. */
- break;
- case tsd_state_minimal_initialized:
- /* This implies the thread only did free() in its life time. */
- /* Fall through. */
- case tsd_state_reincarnated:
- /*
- * Reincarnated means another destructor deallocated memory
- * after the destructor was called. Cleanup isn't required but
- * is still called for testing and completeness.
- */
- assert_tsd_data_cleanup_done(tsd);
- JEMALLOC_FALLTHROUGH;
- case tsd_state_nominal:
- case tsd_state_nominal_slow:
- tsd_do_data_cleanup(tsd);
- tsd_state_set(tsd, tsd_state_purgatory);
- tsd_set(tsd);
- break;
- case tsd_state_purgatory:
- /*
- * The previous time this destructor was called, we set the
- * state to tsd_state_purgatory so that other destructors
- * wouldn't cause re-creation of the tsd. This time, do
- * nothing, and do not request another callback.
- */
- break;
- default:
- not_reached();
- }
-#ifdef JEMALLOC_JET
- test_callback_t test_callback = *tsd_test_callbackp_get_unsafe(tsd);
- int *data = tsd_test_datap_get_unsafe(tsd);
- if (test_callback != NULL) {
- test_callback(data);
- }
-#endif
-}
-
-tsd_t *
-malloc_tsd_boot0(void) {
- tsd_t *tsd;
-
-#if defined(JEMALLOC_MALLOC_THREAD_CLEANUP) || defined(_WIN32)
- ncleanups = 0;
-#endif
- if (malloc_mutex_init(&tsd_nominal_tsds_lock, "tsd_nominal_tsds_lock",
- WITNESS_RANK_OMIT, malloc_mutex_rank_exclusive)) {
- return NULL;
- }
- if (tsd_boot0()) {
- return NULL;
- }
- tsd = tsd_fetch();
- return tsd;
-}
-
-void
-malloc_tsd_boot1(void) {
- tsd_boot1();
- tsd_t *tsd = tsd_fetch();
- /* malloc_slow has been set properly. Update tsd_slow. */
- tsd_slow_update(tsd);
-}
-
-#ifdef _WIN32
-static BOOL WINAPI
-_tls_callback(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) {
- switch (fdwReason) {
-#ifdef JEMALLOC_LAZY_LOCK
- case DLL_THREAD_ATTACH:
- isthreaded = true;
- break;
-#endif
- case DLL_THREAD_DETACH:
- _malloc_thread_cleanup();
- break;
- default:
- break;
- }
- return true;
-}
-
-/*
- * We need to be able to say "read" here (in the "pragma section"), but have
- * hooked "read". We won't read for the rest of the file, so we can get away
- * with unhooking.
- */
-#ifdef read
-# undef read
-#endif
-
-#ifdef _MSC_VER
-# ifdef _M_IX86
-# pragma comment(linker, "/INCLUDE:__tls_used")
-# pragma comment(linker, "/INCLUDE:_tls_callback")
-# else
-# pragma comment(linker, "/INCLUDE:_tls_used")
-# pragma comment(linker, "/INCLUDE:" STRINGIFY(tls_callback) )
-# endif
-# pragma section(".CRT$XLY",long,read)
-#endif
-JEMALLOC_SECTION(".CRT$XLY") JEMALLOC_ATTR(used)
-BOOL (WINAPI *const tls_callback)(HINSTANCE hinstDLL,
- DWORD fdwReason, LPVOID lpvReserved) = _tls_callback;
-#endif
-
-#if (!defined(JEMALLOC_MALLOC_THREAD_CLEANUP) && !defined(JEMALLOC_TLS) && \
- !defined(_WIN32))
-void *
-tsd_init_check_recursion(tsd_init_head_t *head, tsd_init_block_t *block) {
- pthread_t self = pthread_self();
- tsd_init_block_t *iter;
-
- /* Check whether this thread has already inserted into the list. */
- malloc_mutex_lock(TSDN_NULL, &head->lock);
- ql_foreach(iter, &head->blocks, link) {
- if (iter->thread == self) {
- malloc_mutex_unlock(TSDN_NULL, &head->lock);
- return iter->data;
- }
- }
- /* Insert block into list. */
- ql_elm_new(block, link);
- block->thread = self;
- ql_tail_insert(&head->blocks, block, link);
- malloc_mutex_unlock(TSDN_NULL, &head->lock);
- return NULL;
-}
-
-void
-tsd_init_finish(tsd_init_head_t *head, tsd_init_block_t *block) {
- malloc_mutex_lock(TSDN_NULL, &head->lock);
- ql_remove(&head->blocks, block, link);
- malloc_mutex_unlock(TSDN_NULL, &head->lock);
-}
-#endif
-
-void
-tsd_prefork(tsd_t *tsd) {
- malloc_mutex_prefork(tsd_tsdn(tsd), &tsd_nominal_tsds_lock);
-}
-
-void
-tsd_postfork_parent(tsd_t *tsd) {
- malloc_mutex_postfork_parent(tsd_tsdn(tsd), &tsd_nominal_tsds_lock);
-}
-
-void
-tsd_postfork_child(tsd_t *tsd) {
- malloc_mutex_postfork_child(tsd_tsdn(tsd), &tsd_nominal_tsds_lock);
- ql_new(&tsd_nominal_tsds);
-
- if (tsd_state_get(tsd) <= tsd_state_nominal_max) {
- tsd_add_nominal(tsd);
- }
-}
diff --git a/fluent-bit/lib/jemalloc-5.3.0/src/witness.c b/fluent-bit/lib/jemalloc-5.3.0/src/witness.c
deleted file mode 100644
index 4474af04..00000000
--- a/fluent-bit/lib/jemalloc-5.3.0/src/witness.c
+++ /dev/null
@@ -1,122 +0,0 @@
-#include "jemalloc/internal/jemalloc_preamble.h"
-#include "jemalloc/internal/jemalloc_internal_includes.h"
-
-#include "jemalloc/internal/assert.h"
-#include "jemalloc/internal/malloc_io.h"
-
-void
-witness_init(witness_t *witness, const char *name, witness_rank_t rank,
- witness_comp_t *comp, void *opaque) {
- witness->name = name;
- witness->rank = rank;
- witness->comp = comp;
- witness->opaque = opaque;
-}
-
-static void
-witness_print_witness(witness_t *w, unsigned n) {
- assert(n > 0);
- if (n == 1) {
- malloc_printf(" %s(%u)", w->name, w->rank);
- } else {
- malloc_printf(" %s(%u)X%u", w->name, w->rank, n);
- }
-}
-
-static void
-witness_print_witnesses(const witness_list_t *witnesses) {
- witness_t *w, *last = NULL;
- unsigned n = 0;
- ql_foreach(w, witnesses, link) {
- if (last != NULL && w->rank > last->rank) {
- assert(w->name != last->name);
- witness_print_witness(last, n);
- n = 0;
- } else if (last != NULL) {
- assert(w->rank == last->rank);
- assert(w->name == last->name);
- }
- last = w;
- ++n;
- }
- if (last != NULL) {
- witness_print_witness(last, n);
- }
-}
-
-static void
-witness_lock_error_impl(const witness_list_t *witnesses,
- const witness_t *witness) {
- malloc_printf("<jemalloc>: Lock rank order reversal:");
- witness_print_witnesses(witnesses);
- malloc_printf(" %s(%u)\n", witness->name, witness->rank);
- abort();
-}
-witness_lock_error_t *JET_MUTABLE witness_lock_error = witness_lock_error_impl;
-
-static void
-witness_owner_error_impl(const witness_t *witness) {
- malloc_printf("<jemalloc>: Should own %s(%u)\n", witness->name,
- witness->rank);
- abort();
-}
-witness_owner_error_t *JET_MUTABLE witness_owner_error =
- witness_owner_error_impl;
-
-static void
-witness_not_owner_error_impl(const witness_t *witness) {
- malloc_printf("<jemalloc>: Should not own %s(%u)\n", witness->name,
- witness->rank);
- abort();
-}
-witness_not_owner_error_t *JET_MUTABLE witness_not_owner_error =
- witness_not_owner_error_impl;
-
-static void
-witness_depth_error_impl(const witness_list_t *witnesses,
- witness_rank_t rank_inclusive, unsigned depth) {
- malloc_printf("<jemalloc>: Should own %u lock%s of rank >= %u:", depth,
- (depth != 1) ? "s" : "", rank_inclusive);
- witness_print_witnesses(witnesses);
- malloc_printf("\n");
- abort();
-}
-witness_depth_error_t *JET_MUTABLE witness_depth_error =
- witness_depth_error_impl;
-
-void
-witnesses_cleanup(witness_tsd_t *witness_tsd) {
- witness_assert_lockless(witness_tsd_tsdn(witness_tsd));
-
- /* Do nothing. */
-}
-
-void
-witness_prefork(witness_tsd_t *witness_tsd) {
- if (!config_debug) {
- return;
- }
- witness_tsd->forking = true;
-}
-
-void
-witness_postfork_parent(witness_tsd_t *witness_tsd) {
- if (!config_debug) {
- return;
- }
- witness_tsd->forking = false;
-}
-
-void
-witness_postfork_child(witness_tsd_t *witness_tsd) {
- if (!config_debug) {
- return;
- }
-#ifndef JEMALLOC_MUTEX_INIT_CB
- witness_list_t *witnesses;
-
- witnesses = &witness_tsd->witnesses;
- ql_new(witnesses);
-#endif
- witness_tsd->forking = false;
-}
diff --git a/fluent-bit/lib/jemalloc-5.3.0/src/zone.c b/fluent-bit/lib/jemalloc-5.3.0/src/zone.c
deleted file mode 100644
index 23dfdd04..00000000
--- a/fluent-bit/lib/jemalloc-5.3.0/src/zone.c
+++ /dev/null
@@ -1,469 +0,0 @@
-#include "jemalloc/internal/jemalloc_preamble.h"
-#include "jemalloc/internal/jemalloc_internal_includes.h"
-
-#include "jemalloc/internal/assert.h"
-
-#ifndef JEMALLOC_ZONE
-# error "This source file is for zones on Darwin (OS X)."
-#endif
-
-/* Definitions of the following structs in malloc/malloc.h might be too old
- * for the built binary to run on newer versions of OSX. So use the newest
- * possible version of those structs.
- */
-typedef struct _malloc_zone_t {
- void *reserved1;
- void *reserved2;
- size_t (*size)(struct _malloc_zone_t *, const void *);
- void *(*malloc)(struct _malloc_zone_t *, size_t);
- void *(*calloc)(struct _malloc_zone_t *, size_t, size_t);
- void *(*valloc)(struct _malloc_zone_t *, size_t);
- void (*free)(struct _malloc_zone_t *, void *);
- void *(*realloc)(struct _malloc_zone_t *, void *, size_t);
- void (*destroy)(struct _malloc_zone_t *);
- const char *zone_name;
- unsigned (*batch_malloc)(struct _malloc_zone_t *, size_t, void **, unsigned);
- void (*batch_free)(struct _malloc_zone_t *, void **, unsigned);
- struct malloc_introspection_t *introspect;
- unsigned version;
- void *(*memalign)(struct _malloc_zone_t *, size_t, size_t);
- void (*free_definite_size)(struct _malloc_zone_t *, void *, size_t);
- size_t (*pressure_relief)(struct _malloc_zone_t *, size_t);
-} malloc_zone_t;
-
-typedef struct {
- vm_address_t address;
- vm_size_t size;
-} vm_range_t;
-
-typedef struct malloc_statistics_t {
- unsigned blocks_in_use;
- size_t size_in_use;
- size_t max_size_in_use;
- size_t size_allocated;
-} malloc_statistics_t;
-
-typedef kern_return_t memory_reader_t(task_t, vm_address_t, vm_size_t, void **);
-
-typedef void vm_range_recorder_t(task_t, void *, unsigned type, vm_range_t *, unsigned);
-
-typedef struct malloc_introspection_t {
- kern_return_t (*enumerator)(task_t, void *, unsigned, vm_address_t, memory_reader_t, vm_range_recorder_t);
- size_t (*good_size)(malloc_zone_t *, size_t);
- boolean_t (*check)(malloc_zone_t *);
- void (*print)(malloc_zone_t *, boolean_t);
- void (*log)(malloc_zone_t *, void *);
- void (*force_lock)(malloc_zone_t *);
- void (*force_unlock)(malloc_zone_t *);
- void (*statistics)(malloc_zone_t *, malloc_statistics_t *);
- boolean_t (*zone_locked)(malloc_zone_t *);
- boolean_t (*enable_discharge_checking)(malloc_zone_t *);
- boolean_t (*disable_discharge_checking)(malloc_zone_t *);
- void (*discharge)(malloc_zone_t *, void *);
-#ifdef __BLOCKS__
- void (*enumerate_discharged_pointers)(malloc_zone_t *, void (^)(void *, void *));
-#else
- void *enumerate_unavailable_without_blocks;
-#endif
- void (*reinit_lock)(malloc_zone_t *);
-} malloc_introspection_t;
-
-extern kern_return_t malloc_get_all_zones(task_t, memory_reader_t, vm_address_t **, unsigned *);
-
-extern malloc_zone_t *malloc_default_zone(void);
-
-extern void malloc_zone_register(malloc_zone_t *zone);
-
-extern void malloc_zone_unregister(malloc_zone_t *zone);
-
-/*
- * The malloc_default_purgeable_zone() function is only available on >= 10.6.
- * We need to check whether it is present at runtime, thus the weak_import.
- */
-extern malloc_zone_t *malloc_default_purgeable_zone(void)
-JEMALLOC_ATTR(weak_import);
-
-/******************************************************************************/
-/* Data. */
-
-static malloc_zone_t *default_zone, *purgeable_zone;
-static malloc_zone_t jemalloc_zone;
-static struct malloc_introspection_t jemalloc_zone_introspect;
-static pid_t zone_force_lock_pid = -1;
-
-/******************************************************************************/
-/* Function prototypes for non-inline static functions. */
-
-static size_t zone_size(malloc_zone_t *zone, const void *ptr);
-static void *zone_malloc(malloc_zone_t *zone, size_t size);
-static void *zone_calloc(malloc_zone_t *zone, size_t num, size_t size);
-static void *zone_valloc(malloc_zone_t *zone, size_t size);
-static void zone_free(malloc_zone_t *zone, void *ptr);
-static void *zone_realloc(malloc_zone_t *zone, void *ptr, size_t size);
-static void *zone_memalign(malloc_zone_t *zone, size_t alignment,
- size_t size);
-static void zone_free_definite_size(malloc_zone_t *zone, void *ptr,
- size_t size);
-static void zone_destroy(malloc_zone_t *zone);
-static unsigned zone_batch_malloc(struct _malloc_zone_t *zone, size_t size,
- void **results, unsigned num_requested);
-static void zone_batch_free(struct _malloc_zone_t *zone,
- void **to_be_freed, unsigned num_to_be_freed);
-static size_t zone_pressure_relief(struct _malloc_zone_t *zone, size_t goal);
-static size_t zone_good_size(malloc_zone_t *zone, size_t size);
-static kern_return_t zone_enumerator(task_t task, void *data, unsigned type_mask,
- vm_address_t zone_address, memory_reader_t reader,
- vm_range_recorder_t recorder);
-static boolean_t zone_check(malloc_zone_t *zone);
-static void zone_print(malloc_zone_t *zone, boolean_t verbose);
-static void zone_log(malloc_zone_t *zone, void *address);
-static void zone_force_lock(malloc_zone_t *zone);
-static void zone_force_unlock(malloc_zone_t *zone);
-static void zone_statistics(malloc_zone_t *zone,
- malloc_statistics_t *stats);
-static boolean_t zone_locked(malloc_zone_t *zone);
-static void zone_reinit_lock(malloc_zone_t *zone);
-
-/******************************************************************************/
-/*
- * Functions.
- */
-
-static size_t
-zone_size(malloc_zone_t *zone, const void *ptr) {
- /*
- * There appear to be places within Darwin (such as setenv(3)) that
- * cause calls to this function with pointers that *no* zone owns. If
- * we knew that all pointers were owned by *some* zone, we could split
- * our zone into two parts, and use one as the default allocator and
- * the other as the default deallocator/reallocator. Since that will
- * not work in practice, we must check all pointers to assure that they
- * reside within a mapped extent before determining size.
- */
- return ivsalloc(tsdn_fetch(), ptr);
-}
-
-static void *
-zone_malloc(malloc_zone_t *zone, size_t size) {
- return je_malloc(size);
-}
-
-static void *
-zone_calloc(malloc_zone_t *zone, size_t num, size_t size) {
- return je_calloc(num, size);
-}
-
-static void *
-zone_valloc(malloc_zone_t *zone, size_t size) {
- void *ret = NULL; /* Assignment avoids useless compiler warning. */
-
- je_posix_memalign(&ret, PAGE, size);
-
- return ret;
-}
-
-static void
-zone_free(malloc_zone_t *zone, void *ptr) {
- if (ivsalloc(tsdn_fetch(), ptr) != 0) {
- je_free(ptr);
- return;
- }
-
- free(ptr);
-}
-
-static void *
-zone_realloc(malloc_zone_t *zone, void *ptr, size_t size) {
- if (ivsalloc(tsdn_fetch(), ptr) != 0) {
- return je_realloc(ptr, size);
- }
-
- return realloc(ptr, size);
-}
-
-static void *
-zone_memalign(malloc_zone_t *zone, size_t alignment, size_t size) {
- void *ret = NULL; /* Assignment avoids useless compiler warning. */
-
- je_posix_memalign(&ret, alignment, size);
-
- return ret;
-}
-
-static void
-zone_free_definite_size(malloc_zone_t *zone, void *ptr, size_t size) {
- size_t alloc_size;
-
- alloc_size = ivsalloc(tsdn_fetch(), ptr);
- if (alloc_size != 0) {
- assert(alloc_size == size);
- je_free(ptr);
- return;
- }
-
- free(ptr);
-}
-
-static void
-zone_destroy(malloc_zone_t *zone) {
- /* This function should never be called. */
- not_reached();
-}
-
-static unsigned
-zone_batch_malloc(struct _malloc_zone_t *zone, size_t size, void **results,
- unsigned num_requested) {
- unsigned i;
-
- for (i = 0; i < num_requested; i++) {
- results[i] = je_malloc(size);
- if (!results[i])
- break;
- }
-
- return i;
-}
-
-static void
-zone_batch_free(struct _malloc_zone_t *zone, void **to_be_freed,
- unsigned num_to_be_freed) {
- unsigned i;
-
- for (i = 0; i < num_to_be_freed; i++) {
- zone_free(zone, to_be_freed[i]);
- to_be_freed[i] = NULL;
- }
-}
-
-static size_t
-zone_pressure_relief(struct _malloc_zone_t *zone, size_t goal) {
- return 0;
-}
-
-static size_t
-zone_good_size(malloc_zone_t *zone, size_t size) {
- if (size == 0) {
- size = 1;
- }
- return sz_s2u(size);
-}
-
-static kern_return_t
-zone_enumerator(task_t task, void *data, unsigned type_mask,
- vm_address_t zone_address, memory_reader_t reader,
- vm_range_recorder_t recorder) {
- return KERN_SUCCESS;
-}
-
-static boolean_t
-zone_check(malloc_zone_t *zone) {
- return true;
-}
-
-static void
-zone_print(malloc_zone_t *zone, boolean_t verbose) {
-}
-
-static void
-zone_log(malloc_zone_t *zone, void *address) {
-}
-
-static void
-zone_force_lock(malloc_zone_t *zone) {
- if (isthreaded) {
- /*
- * See the note in zone_force_unlock, below, to see why we need
- * this.
- */
- assert(zone_force_lock_pid == -1);
- zone_force_lock_pid = getpid();
- jemalloc_prefork();
- }
-}
-
-static void
-zone_force_unlock(malloc_zone_t *zone) {
- /*
- * zone_force_lock and zone_force_unlock are the entry points to the
- * forking machinery on OS X. The tricky thing is, the child is not
- * allowed to unlock mutexes locked in the parent, even if owned by the
- * forking thread (and the mutex type we use in OS X will fail an assert
- * if we try). In the child, we can get away with reinitializing all
- * the mutexes, which has the effect of unlocking them. In the parent,
- * doing this would mean we wouldn't wake any waiters blocked on the
- * mutexes we unlock. So, we record the pid of the current thread in
- * zone_force_lock, and use that to detect if we're in the parent or
- * child here, to decide which unlock logic we need.
- */
- if (isthreaded) {
- assert(zone_force_lock_pid != -1);
- if (getpid() == zone_force_lock_pid) {
- jemalloc_postfork_parent();
- } else {
- jemalloc_postfork_child();
- }
- zone_force_lock_pid = -1;
- }
-}
-
-static void
-zone_statistics(malloc_zone_t *zone, malloc_statistics_t *stats) {
- /* We make no effort to actually fill the values */
- stats->blocks_in_use = 0;
- stats->size_in_use = 0;
- stats->max_size_in_use = 0;
- stats->size_allocated = 0;
-}
-
-static boolean_t
-zone_locked(malloc_zone_t *zone) {
- /* Pretend no lock is being held */
- return false;
-}
-
-static void
-zone_reinit_lock(malloc_zone_t *zone) {
- /* As of OSX 10.12, this function is only used when force_unlock would
- * be used if the zone version were < 9. So just use force_unlock. */
- zone_force_unlock(zone);
-}
-
-static void
-zone_init(void) {
- jemalloc_zone.size = zone_size;
- jemalloc_zone.malloc = zone_malloc;
- jemalloc_zone.calloc = zone_calloc;
- jemalloc_zone.valloc = zone_valloc;
- jemalloc_zone.free = zone_free;
- jemalloc_zone.realloc = zone_realloc;
- jemalloc_zone.destroy = zone_destroy;
- jemalloc_zone.zone_name = "jemalloc_zone";
- jemalloc_zone.batch_malloc = zone_batch_malloc;
- jemalloc_zone.batch_free = zone_batch_free;
- jemalloc_zone.introspect = &jemalloc_zone_introspect;
- jemalloc_zone.version = 9;
- jemalloc_zone.memalign = zone_memalign;
- jemalloc_zone.free_definite_size = zone_free_definite_size;
- jemalloc_zone.pressure_relief = zone_pressure_relief;
-
- jemalloc_zone_introspect.enumerator = zone_enumerator;
- jemalloc_zone_introspect.good_size = zone_good_size;
- jemalloc_zone_introspect.check = zone_check;
- jemalloc_zone_introspect.print = zone_print;
- jemalloc_zone_introspect.log = zone_log;
- jemalloc_zone_introspect.force_lock = zone_force_lock;
- jemalloc_zone_introspect.force_unlock = zone_force_unlock;
- jemalloc_zone_introspect.statistics = zone_statistics;
- jemalloc_zone_introspect.zone_locked = zone_locked;
- jemalloc_zone_introspect.enable_discharge_checking = NULL;
- jemalloc_zone_introspect.disable_discharge_checking = NULL;
- jemalloc_zone_introspect.discharge = NULL;
-#ifdef __BLOCKS__
- jemalloc_zone_introspect.enumerate_discharged_pointers = NULL;
-#else
- jemalloc_zone_introspect.enumerate_unavailable_without_blocks = NULL;
-#endif
- jemalloc_zone_introspect.reinit_lock = zone_reinit_lock;
-}
-
-static malloc_zone_t *
-zone_default_get(void) {
- malloc_zone_t **zones = NULL;
- unsigned int num_zones = 0;
-
- /*
- * On OSX 10.12, malloc_default_zone returns a special zone that is not
- * present in the list of registered zones. That zone uses a "lite zone"
- * if one is present (apparently enabled when malloc stack logging is
- * enabled), or the first registered zone otherwise. In practice this
- * means unless malloc stack logging is enabled, the first registered
- * zone is the default. So get the list of zones to get the first one,
- * instead of relying on malloc_default_zone.
- */
- if (KERN_SUCCESS != malloc_get_all_zones(0, NULL,
- (vm_address_t**)&zones, &num_zones)) {
- /*
- * Reset the value in case the failure happened after it was
- * set.
- */
- num_zones = 0;
- }
-
- if (num_zones) {
- return zones[0];
- }
-
- return malloc_default_zone();
-}
-
-/* As written, this function can only promote jemalloc_zone. */
-static void
-zone_promote(void) {
- malloc_zone_t *zone;
-
- do {
- /*
- * Unregister and reregister the default zone. On OSX >= 10.6,
- * unregistering takes the last registered zone and places it
- * at the location of the specified zone. Unregistering the
- * default zone thus makes the last registered one the default.
- * On OSX < 10.6, unregistering shifts all registered zones.
- * The first registered zone then becomes the default.
- */
- malloc_zone_unregister(default_zone);
- malloc_zone_register(default_zone);
-
- /*
- * On OSX 10.6, having the default purgeable zone appear before
- * the default zone makes some things crash because it thinks it
- * owns the default zone allocated pointers. We thus
- * unregister/re-register it in order to ensure it's always
- * after the default zone. On OSX < 10.6, there is no purgeable
- * zone, so this does nothing. On OSX >= 10.6, unregistering
- * replaces the purgeable zone with the last registered zone
- * above, i.e. the default zone. Registering it again then puts
- * it at the end, obviously after the default zone.
- */
- if (purgeable_zone != NULL) {
- malloc_zone_unregister(purgeable_zone);
- malloc_zone_register(purgeable_zone);
- }
-
- zone = zone_default_get();
- } while (zone != &jemalloc_zone);
-}
-
-JEMALLOC_ATTR(constructor)
-void
-zone_register(void) {
- /*
- * If something else replaced the system default zone allocator, don't
- * register jemalloc's.
- */
- default_zone = zone_default_get();
- if (!default_zone->zone_name || strcmp(default_zone->zone_name,
- "DefaultMallocZone") != 0) {
- return;
- }
-
- /*
- * The default purgeable zone is created lazily by OSX's libc. It uses
- * the default zone when it is created for "small" allocations
- * (< 15 KiB), but assumes the default zone is a scalable_zone. This
- * obviously fails when the default zone is the jemalloc zone, so
- * malloc_default_purgeable_zone() is called beforehand so that the
- * default purgeable zone is created when the default zone is still
- * a scalable_zone. As purgeable zones only exist on >= 10.6, we need
- * to check for the existence of malloc_default_purgeable_zone() at
- * run time.
- */
- purgeable_zone = (malloc_default_purgeable_zone == NULL) ? NULL :
- malloc_default_purgeable_zone();
-
- /* Register the custom zone. At this point it won't be the default. */
- zone_init();
- malloc_zone_register(&jemalloc_zone);
-
- /* Promote the custom zone to be default. */
- zone_promote();
-}