Skip to content

Commit 8bb3198

Browse files
committed
Refactor/fix arenas manipulation.
Abstract arenas access to use arena_get() (or a0get() where appropriate) rather than directly reading e.g. arenas[ind]. Prior to the addition of the arenas.extend mallctl, the worst possible outcome of directly accessing arenas was a stale read, but arenas.extend may allocate and assign a new array to arenas. Add a tsd-based arenas_cache, which amortizes arenas reads. This introduces some subtle bootstrapping issues, with tsd_boot() now being split into tsd_boot[01]() to support tsd wrapper allocation bootstrapping, as well as an arenas_cache_bypass tsd variable which dynamically terminates allocation of arenas_cache itself. Promote a0malloc(), a0calloc(), and a0free() to be generally useful for internal allocation, and use them in several places (more may be appropriate). Abstract arena->nthreads management and fix a missing decrement during thread destruction (recent tsd refactoring left arenas_cleanup() unused). Change arena_choose() to propagate OOM, and handle OOM in all callers. This is important for providing consistent allocation behavior when the MALLOCX_ARENA() flag is being used. Prior to this fix, it was possible for an OOM to result in allocation silently allocating from a different arena than the one specified.
1 parent bf40641 commit 8bb3198

File tree

13 files changed

+740
-347
lines changed

13 files changed

+740
-347
lines changed

include/jemalloc/internal/arena.h

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -389,7 +389,7 @@ bool arena_dss_prec_set(arena_t *arena, dss_prec_t dss_prec);
389389
void arena_stats_merge(arena_t *arena, const char **dss, size_t *nactive,
390390
size_t *ndirty, arena_stats_t *astats, malloc_bin_stats_t *bstats,
391391
malloc_large_stats_t *lstats);
392-
bool arena_new(arena_t *arena, unsigned ind);
392+
arena_t *arena_new(unsigned ind);
393393
void arena_boot(void);
394394
void arena_prefork(arena_t *arena);
395395
void arena_postfork_parent(arena_t *arena);
@@ -924,8 +924,10 @@ arena_malloc(tsd_t *tsd, arena_t *arena, size_t size, bool zero,
924924
true)) != NULL))
925925
return (tcache_alloc_small(tcache, size, zero));
926926
else {
927-
return (arena_malloc_small(choose_arena(tsd, arena),
928-
size, zero));
927+
arena = arena_choose(tsd, arena);
928+
if (unlikely(arena == NULL))
929+
return (NULL);
930+
return (arena_malloc_small(arena, size, zero));
929931
}
930932
} else {
931933
/*
@@ -936,8 +938,10 @@ arena_malloc(tsd_t *tsd, arena_t *arena, size_t size, bool zero,
936938
tcache_get(tsd, true)) != NULL))
937939
return (tcache_alloc_large(tcache, size, zero));
938940
else {
939-
return (arena_malloc_large(choose_arena(tsd, arena),
940-
size, zero));
941+
arena = arena_choose(tsd, arena);
942+
if (unlikely(arena == NULL))
943+
return (NULL);
944+
return (arena_malloc_large(arena, size, zero));
941945
}
942946
}
943947
}

include/jemalloc/internal/jemalloc_internal.h.in

Lines changed: 54 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -386,20 +386,6 @@ extern bool in_valgrind;
386386
/* Number of CPUs. */
387387
extern unsigned ncpus;
388388

389-
/* Protects arenas initialization (arenas, arenas_total). */
390-
extern malloc_mutex_t arenas_lock;
391-
/*
392-
* Arenas that are used to service external requests. Not all elements of the
393-
* arenas array are necessarily used; arenas are created lazily as needed.
394-
*
395-
* arenas[0..narenas_auto) are used for automatic multiplexing of threads and
396-
* arenas. arenas[narenas_auto..narenas_total) are only used if the application
397-
* takes some action to create them and allocate from them.
398-
*/
399-
extern arena_t **arenas;
400-
extern unsigned narenas_total;
401-
extern unsigned narenas_auto; /* Read-only after initialization. */
402-
403389
/*
404390
* index2size_tab encodes the same information as could be computed (at
405391
* unacceptable cost in some code paths) by index2size_compute().
@@ -412,11 +398,23 @@ extern size_t const index2size_tab[NSIZES];
412398
*/
413399
extern uint8_t const size2index_tab[];
414400

401+
arena_t *a0get(void);
402+
void *a0malloc(size_t size);
403+
void *a0calloc(size_t num, size_t size);
404+
void a0free(void *ptr);
415405
arena_t *arenas_extend(unsigned ind);
416-
arena_t *choose_arena_hard(tsd_t *tsd);
406+
arena_t *arena_init(unsigned ind);
407+
unsigned narenas_total_get(void);
408+
arena_t *arena_get_hard(tsd_t *tsd, unsigned ind, bool init_if_missing);
409+
arena_t *arena_choose_hard(tsd_t *tsd);
410+
void arena_migrate(tsd_t *tsd, unsigned oldind, unsigned newind);
411+
unsigned arena_nbound(unsigned ind);
417412
void thread_allocated_cleanup(tsd_t *tsd);
418413
void thread_deallocated_cleanup(tsd_t *tsd);
419414
void arena_cleanup(tsd_t *tsd);
415+
void arenas_cache_cleanup(tsd_t *tsd);
416+
void narenas_cache_cleanup(tsd_t *tsd);
417+
void arenas_cache_bypass_cleanup(tsd_t *tsd);
420418
void jemalloc_prefork(void);
421419
void jemalloc_postfork_parent(void);
422420
void jemalloc_postfork_child(void);
@@ -475,8 +473,9 @@ size_t s2u_compute(size_t size);
475473
size_t s2u_lookup(size_t size);
476474
size_t s2u(size_t size);
477475
size_t sa2u(size_t size, size_t alignment);
478-
unsigned narenas_total_get(void);
479-
arena_t *choose_arena(tsd_t *tsd, arena_t *arena);
476+
arena_t *arena_choose(tsd_t *tsd, arena_t *arena);
477+
arena_t *arena_get(tsd_t *tsd, unsigned ind, bool init_if_missing,
478+
bool refresh_if_missing);
480479
#endif
481480

482481
#if (defined(JEMALLOC_ENABLE_INLINE) || defined(JEMALLOC_C_))
@@ -709,34 +708,51 @@ sa2u(size_t size, size_t alignment)
709708
return (usize);
710709
}
711710

712-
JEMALLOC_INLINE unsigned
713-
narenas_total_get(void)
714-
{
715-
unsigned narenas;
716-
717-
malloc_mutex_lock(&arenas_lock);
718-
narenas = narenas_total;
719-
malloc_mutex_unlock(&arenas_lock);
720-
721-
return (narenas);
722-
}
723-
724711
/* Choose an arena based on a per-thread value. */
725712
JEMALLOC_INLINE arena_t *
726-
choose_arena(tsd_t *tsd, arena_t *arena)
713+
arena_choose(tsd_t *tsd, arena_t *arena)
727714
{
728715
arena_t *ret;
729716

730717
if (arena != NULL)
731718
return (arena);
732719

733-
if (unlikely((ret = tsd_arena_get(tsd)) == NULL)) {
734-
ret = choose_arena_hard(tsd);
735-
assert(ret != NULL);
736-
}
720+
if (unlikely((ret = tsd_arena_get(tsd)) == NULL))
721+
ret = arena_choose_hard(tsd);
737722

738723
return (ret);
739724
}
725+
726+
JEMALLOC_INLINE arena_t *
727+
arena_get(tsd_t *tsd, unsigned ind, bool init_if_missing,
728+
bool refresh_if_missing)
729+
{
730+
arena_t *arena;
731+
arena_t **arenas_cache = tsd_arenas_cache_get(tsd);
732+
733+
/* init_if_missing requires refresh_if_missing. */
734+
assert(!init_if_missing || refresh_if_missing);
735+
736+
if (unlikely(arenas_cache == NULL)) {
737+
/* arenas_cache hasn't been initialized yet. */
738+
return (arena_get_hard(tsd, ind, init_if_missing));
739+
}
740+
if (unlikely(ind >= tsd_narenas_cache_get(tsd))) {
741+
/*
742+
* ind is invalid, cache is old (too small), or arena to be
743+
* initialized.
744+
*/
745+
return (refresh_if_missing ? arena_get_hard(tsd, ind,
746+
init_if_missing) : NULL);
747+
}
748+
arena = arenas_cache[ind];
749+
if (likely(arena != NULL) || !refresh_if_missing)
750+
return (arena);
751+
if (init_if_missing)
752+
return (arena_get_hard(tsd, ind, init_if_missing));
753+
else
754+
return (NULL);
755+
}
740756
#endif
741757

742758
#include "jemalloc/internal/bitmap.h"
@@ -833,8 +849,10 @@ ipalloct(tsd_t *tsd, size_t usize, size_t alignment, bool zero, bool try_tcache,
833849
ret = arena_malloc(tsd, arena, usize, zero, try_tcache);
834850
else {
835851
if (usize <= arena_maxclass) {
836-
ret = arena_palloc(choose_arena(tsd, arena), usize,
837-
alignment, zero);
852+
arena = arena_choose(tsd, arena);
853+
if (unlikely(arena == NULL))
854+
return (NULL);
855+
ret = arena_palloc(arena, usize, alignment, zero);
838856
} else if (alignment <= chunksize)
839857
ret = huge_malloc(tsd, arena, usize, zero);
840858
else

include/jemalloc/internal/private_symbols.txt

Lines changed: 18 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,16 @@
11
a0calloc
22
a0free
3+
a0get
34
a0malloc
5+
arena_get
6+
arena_get_hard
47
arena_alloc_junk_small
58
arena_bin_index
69
arena_bin_info
710
arena_bitselm_get
811
arena_boot
12+
arena_choose
13+
arena_choose_hard
914
arena_chunk_alloc_huge
1015
arena_chunk_dalloc_huge
1116
arena_cleanup
@@ -19,6 +24,7 @@ arena_dalloc_large_locked
1924
arena_dalloc_small
2025
arena_dss_prec_get
2126
arena_dss_prec_set
27+
arena_init
2228
arena_malloc
2329
arena_malloc_large
2430
arena_malloc_small
@@ -42,9 +48,11 @@ arena_mapbitsp_read
4248
arena_mapbitsp_write
4349
arena_maxclass
4450
arena_maxrun
51+
arena_migrate
4552
arena_miscelm_get
4653
arena_miscelm_to_pageind
4754
arena_miscelm_to_rpages
55+
arena_nbound
4856
arena_new
4957
arena_palloc
5058
arena_postfork_child
@@ -69,10 +77,8 @@ arena_salloc
6977
arena_sdalloc
7078
arena_stats_merge
7179
arena_tcache_fill_small
72-
arenas
73-
arenas_cleanup
74-
arenas_extend
75-
arenas_lock
80+
arenas_cache_bypass_cleanup
81+
arenas_cache_cleanup
7682
atomic_add_u
7783
atomic_add_uint32
7884
atomic_add_uint64
@@ -100,8 +106,6 @@ bitmap_size
100106
bitmap_unset
101107
bt_init
102108
buferror
103-
choose_arena
104-
choose_arena_hard
105109
chunk_alloc_arena
106110
chunk_alloc_base
107111
chunk_alloc_default
@@ -247,7 +251,8 @@ malloc_mutex_unlock
247251
malloc_printf
248252
malloc_snprintf
249253
malloc_strtoumax
250-
malloc_tsd_boot
254+
malloc_tsd_boot0
255+
malloc_tsd_boot1
251256
malloc_tsd_cleanup_register
252257
malloc_tsd_dalloc
253258
malloc_tsd_malloc
@@ -259,8 +264,7 @@ map_bias
259264
map_misc_offset
260265
mb_write
261266
mutex_boot
262-
narenas_auto
263-
narenas_total
267+
narenas_cache_cleanup
264268
narenas_total_get
265269
ncpus
266270
nhbins
@@ -363,6 +367,7 @@ tcache_alloc_small
363367
tcache_alloc_small_hard
364368
tcache_arena_associate
365369
tcache_arena_dissociate
370+
tcache_arena_reassociate
366371
tcache_bin_flush_large
367372
tcache_bin_flush_small
368373
tcache_bin_info
@@ -388,11 +393,14 @@ tsd_booted
388393
tsd_arena_get
389394
tsd_arena_set
390395
tsd_boot
396+
tsd_boot0
397+
tsd_boot1
391398
tsd_cleanup
392399
tsd_cleanup_wrapper
393400
tsd_fetch
394401
tsd_get
395-
tsd_get_wrapper
402+
tsd_wrapper_get
403+
tsd_wrapper_set
396404
tsd_initialized
397405
tsd_init_check_recursion
398406
tsd_init_finish

include/jemalloc/internal/tcache.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,7 @@ void tcache_bin_flush_small(tcache_bin_t *tbin, index_t binind, unsigned rem,
109109
void tcache_bin_flush_large(tcache_bin_t *tbin, index_t binind, unsigned rem,
110110
tcache_t *tcache);
111111
void tcache_arena_associate(tcache_t *tcache, arena_t *arena);
112+
void tcache_arena_reassociate(tcache_t *tcache, arena_t *arena);
112113
void tcache_arena_dissociate(tcache_t *tcache);
113114
tcache_t *tcache_get_hard(tsd_t *tsd);
114115
tcache_t *tcache_create(arena_t *arena);

0 commit comments

Comments
 (0)