From 9e143468a244465e4b4a3822f4c1d8de42f39335 Mon Sep 17 00:00:00 2001 From: Slobodan Predolac Date: Thu, 21 May 2026 14:11:26 -0700 Subject: [PATCH] Refactor arena ctl helpers --- src/ctl.c | 141 +++++++++++++++++++++++++++++++----------------------- 1 file changed, 81 insertions(+), 60 deletions(-) diff --git a/src/ctl.c b/src/ctl.c index e048135a..0f0d1dd5 100644 --- a/src/ctl.c +++ b/src/ctl.c @@ -981,8 +981,41 @@ ctl_accum_atomic_zu(atomic_zu_t *dst, atomic_zu_t *src) { /******************************************************************************/ +/* + * Historical compatibility for treating arena. as the merged + * all-arenas entry. New code should use MALLCTL_ARENAS_ALL. + * + * `narenas` must be a snapshot of ctl_arenas->narenas taken while holding + * ctl_mtx; see ctl_narenas_get. + */ +static bool +ctl_arena_ind_is_deprecated_all(size_t i, unsigned narenas) { + return i == narenas; +} + +/* + * `narenas` must be a snapshot of ctl_arenas->narenas taken while holding + * ctl_mtx; see ctl_narenas_get. + */ +static bool +ctl_arena_ind_is_all(size_t i, unsigned narenas) { + return i == MALLCTL_ARENAS_ALL + || ctl_arena_ind_is_deprecated_all(i, narenas); +} + +/* + * ctl_arenas->narenas may grow concurrently (arena creation in + * ctl_arena_init); all reads must happen while ctl_mtx is held. This + * helper centralizes that requirement. + */ static unsigned -arenas_i2a_impl(size_t i, bool compat, bool validate) { +ctl_narenas_get(tsdn_t *tsdn) { + malloc_mutex_assert_owner(tsdn, &ctl_mtx); + return ctl_arenas->narenas; +} + +static unsigned +arenas_i2a_impl(size_t i, unsigned narenas, bool compat, bool validate) { unsigned a; switch (i) { @@ -993,7 +1026,7 @@ arenas_i2a_impl(size_t i, bool compat, bool validate) { a = 1; break; default: - if (compat && i == ctl_arenas->narenas) { + if (compat && ctl_arena_ind_is_deprecated_all(i, narenas)) { /* * Provide deprecated backward compatibility for * accessing the merged stats at index narenas rather @@ -1001,7 +1034,7 @@ arenas_i2a_impl(size_t i, bool compat, bool validate) { * removal in 6.0.0. */ a = 0; - } else if (validate && i >= ctl_arenas->narenas) { + } else if (validate && i >= narenas) { a = UINT_MAX; } else { /* @@ -1009,8 +1042,7 @@ arenas_i2a_impl(size_t i, bool compat, bool validate) { * more than one past the range of indices that have * initialized ctl data. */ - assert(i < ctl_arenas->narenas - || (!validate && i == ctl_arenas->narenas)); + assert(i < narenas || (!validate && i == narenas)); a = (unsigned)i + 2; } break; @@ -1020,8 +1052,8 @@ arenas_i2a_impl(size_t i, bool compat, bool validate) { } static unsigned -arenas_i2a(size_t i) { - return arenas_i2a_impl(i, true, false); +arenas_i2a(size_t i, unsigned narenas) { + return arenas_i2a_impl(i, narenas, true, false); } static ctl_arena_t * @@ -1029,8 +1061,9 @@ arenas_i_impl(tsd_t *tsd, size_t i, bool compat, bool init) { ctl_arena_t *ret; assert(!compat || !init); + unsigned narenas = ctl_narenas_get(tsd_tsdn(tsd)); - ret = ctl_arenas->arenas[arenas_i2a_impl(i, compat, false)]; + ret = ctl_arenas->arenas[arenas_i2a_impl(i, narenas, compat, false)]; if (init && ret == NULL) { if (config_stats) { struct container_s { @@ -1053,10 +1086,12 @@ arenas_i_impl(tsd_t *tsd, size_t i, bool compat, bool init) { } } ret->arena_ind = (unsigned)i; - ctl_arenas->arenas[arenas_i2a_impl(i, compat, false)] = ret; + ctl_arenas->arenas[arenas_i2a_impl(i, narenas, compat, false)] + = ret; } - assert(ret == NULL || arenas_i2a(ret->arena_ind) == arenas_i2a(i)); + assert(ret == NULL || + arenas_i2a(ret->arena_ind, narenas) == arenas_i2a(i, narenas)); return ret; } @@ -1309,6 +1344,8 @@ ctl_arena_init(tsd_t *tsd, const arena_config_t *config) { unsigned arena_ind; ctl_arena_t *ctl_arena; + malloc_mutex_assert_owner(tsd_tsdn(tsd), &ctl_mtx); + if ((ctl_arena = ql_last(&ctl_arenas->destroyed, destroyed_link)) != NULL) { ql_remove(&ctl_arenas->destroyed, ctl_arena, destroyed_link); @@ -2696,46 +2733,29 @@ label_return: static void arena_i_decay(tsdn_t *tsdn, unsigned arena_ind, bool all) { malloc_mutex_lock(tsdn, &ctl_mtx); - { - unsigned narenas = ctl_arenas->narenas; + unsigned narenas = ctl_narenas_get(tsdn); - /* - * 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_UNSAFE(arena_t *, tarenas, narenas); + /* + * Access via index narenas is deprecated, and scheduled for + * removal in 6.0.0. + */ + bool decay_all = ctl_arena_ind_is_all(arena_ind, narenas); + unsigned count = decay_all ? narenas : 1; + VARIABLE_ARRAY_UNSAFE(arena_t *, tarenas, count); - for (i = 0; i < narenas; i++) { - tarenas[i] = arena_get(tsdn, i, false); - } + if (decay_all) { + for (unsigned i = 0; i < narenas; i++) { + tarenas[i] = arena_get(tsdn, i, false); + } + } else { + assert(arena_ind < narenas); + tarenas[0] = arena_get(tsdn, arena_ind, false); + } + malloc_mutex_unlock(tsdn, &ctl_mtx); - /* - * 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); - } + for (unsigned i = 0; i < count; i++) { + if (tarenas[i] != NULL) { + arena_decay(tsdn, tarenas[i], false, all); } } } @@ -2920,8 +2940,8 @@ arena_i_dss_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, void *oldp, * 6.0.0. */ dss_prec_t dss_prec_old; - if (arena_ind == MALLCTL_ARENAS_ALL - || arena_ind == ctl_arenas->narenas) { + unsigned narenas = ctl_narenas_get(tsd_tsdn(tsd)); + if (ctl_arena_ind_is_all(arena_ind, narenas)) { if (dss_prec != dss_prec_limit && extent_dss_prec_set(dss_prec)) { ret = EFAULT; @@ -2996,7 +3016,7 @@ arena_i_decay_ms_ctl_impl(tsd_t *tsd, const size_t *mib, size_t miblen, 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); + ssize_t oldval = arena_decay_ms_get(arena, state); READ(oldval, ssize_t); } if (newp != NULL) { @@ -3141,8 +3161,9 @@ arena_i_name_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, void *oldp, malloc_mutex_lock(tsd_tsdn(tsd), &ctl_mtx); MIB_UNSIGNED(arena_ind, 1); - if (arena_ind == MALLCTL_ARENAS_ALL - || arena_ind >= ctl_arenas->narenas) { + unsigned narenas = ctl_narenas_get(tsd_tsdn(tsd)); + if (ctl_arena_ind_is_all(arena_ind, narenas) + || arena_ind > narenas) { ret = EINVAL; goto label_return; } @@ -3191,7 +3212,7 @@ arena_i_index(tsdn_t *tsdn, const size_t *mib, size_t miblen, size_t i) { case MALLCTL_ARENAS_DESTROYED: break; default: - if (i > ctl_arenas->narenas) { + if (i > ctl_narenas_get(tsdn)) { ret = NULL; goto label_return; } @@ -3214,7 +3235,7 @@ arenas_narenas_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, void *oldp, malloc_mutex_lock(tsd_tsdn(tsd), &ctl_mtx); READONLY(); - narenas = ctl_arenas->narenas; + narenas = ctl_narenas_get(tsd_tsdn(tsd)); READ(narenas, unsigned); ret = 0; @@ -3229,8 +3250,8 @@ arenas_decay_ms_ctl_impl(tsd_t *tsd, const size_t *mib, size_t miblen, int ret; if (oldp != NULL && oldlenp != NULL) { - size_t oldval = (dirty ? arena_dirty_decay_ms_default_get() - : arena_muzzy_decay_ms_default_get()); + ssize_t oldval = (dirty ? arena_dirty_decay_ms_default_get() + : arena_muzzy_decay_ms_default_get()); READ(oldval, ssize_t); } if (newp != NULL) { @@ -4254,8 +4275,8 @@ stats_arenas_i_hpa_shard_alloc_j_index( } static bool -ctl_arenas_i_verify(size_t i) { - size_t a = arenas_i2a_impl(i, true, true); +ctl_arenas_i_verify(size_t i, unsigned narenas) { + size_t a = arenas_i2a_impl(i, narenas, true, true); if (a == UINT_MAX || !ctl_arenas->arenas[a]->initialized) { return true; } @@ -4268,7 +4289,7 @@ 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)) { + if (ctl_arenas_i_verify(i, ctl_narenas_get(tsdn))) { ret = NULL; goto label_return; } @@ -4507,7 +4528,7 @@ experimental_arenas_i_index( const ctl_named_node_t *ret; malloc_mutex_lock(tsdn, &ctl_mtx); - if (ctl_arenas_i_verify(i)) { + if (ctl_arenas_i_verify(i, ctl_narenas_get(tsdn))) { ret = NULL; goto label_return; }