1*1208bc7eSAndroid Build Coastguard Worker #define JEMALLOC_EXTENT_C_
2*1208bc7eSAndroid Build Coastguard Worker #include "jemalloc/internal/jemalloc_preamble.h"
3*1208bc7eSAndroid Build Coastguard Worker #include "jemalloc/internal/jemalloc_internal_includes.h"
4*1208bc7eSAndroid Build Coastguard Worker
5*1208bc7eSAndroid Build Coastguard Worker #include "jemalloc/internal/assert.h"
6*1208bc7eSAndroid Build Coastguard Worker #include "jemalloc/internal/extent_dss.h"
7*1208bc7eSAndroid Build Coastguard Worker #include "jemalloc/internal/extent_mmap.h"
8*1208bc7eSAndroid Build Coastguard Worker #include "jemalloc/internal/ph.h"
9*1208bc7eSAndroid Build Coastguard Worker #include "jemalloc/internal/rtree.h"
10*1208bc7eSAndroid Build Coastguard Worker #include "jemalloc/internal/mutex.h"
11*1208bc7eSAndroid Build Coastguard Worker #include "jemalloc/internal/mutex_pool.h"
12*1208bc7eSAndroid Build Coastguard Worker
13*1208bc7eSAndroid Build Coastguard Worker /******************************************************************************/
14*1208bc7eSAndroid Build Coastguard Worker /* Data. */
15*1208bc7eSAndroid Build Coastguard Worker
16*1208bc7eSAndroid Build Coastguard Worker rtree_t extents_rtree;
17*1208bc7eSAndroid Build Coastguard Worker /* Keyed by the address of the extent_t being protected. */
18*1208bc7eSAndroid Build Coastguard Worker mutex_pool_t extent_mutex_pool;
19*1208bc7eSAndroid Build Coastguard Worker
20*1208bc7eSAndroid Build Coastguard Worker size_t opt_lg_extent_max_active_fit = LG_EXTENT_MAX_ACTIVE_FIT_DEFAULT;
21*1208bc7eSAndroid Build Coastguard Worker
22*1208bc7eSAndroid Build Coastguard Worker static const bitmap_info_t extents_bitmap_info =
23*1208bc7eSAndroid Build Coastguard Worker BITMAP_INFO_INITIALIZER(NPSIZES+1);
24*1208bc7eSAndroid Build Coastguard Worker
25*1208bc7eSAndroid Build Coastguard Worker static void *extent_alloc_default(extent_hooks_t *extent_hooks, void *new_addr,
26*1208bc7eSAndroid Build Coastguard Worker size_t size, size_t alignment, bool *zero, bool *commit,
27*1208bc7eSAndroid Build Coastguard Worker unsigned arena_ind);
28*1208bc7eSAndroid Build Coastguard Worker static bool extent_dalloc_default(extent_hooks_t *extent_hooks, void *addr,
29*1208bc7eSAndroid Build Coastguard Worker size_t size, bool committed, unsigned arena_ind);
30*1208bc7eSAndroid Build Coastguard Worker static void extent_destroy_default(extent_hooks_t *extent_hooks, void *addr,
31*1208bc7eSAndroid Build Coastguard Worker size_t size, bool committed, unsigned arena_ind);
32*1208bc7eSAndroid Build Coastguard Worker static bool extent_commit_default(extent_hooks_t *extent_hooks, void *addr,
33*1208bc7eSAndroid Build Coastguard Worker size_t size, size_t offset, size_t length, unsigned arena_ind);
34*1208bc7eSAndroid Build Coastguard Worker static bool extent_commit_impl(tsdn_t *tsdn, arena_t *arena,
35*1208bc7eSAndroid Build Coastguard Worker extent_hooks_t **r_extent_hooks, extent_t *extent, size_t offset,
36*1208bc7eSAndroid Build Coastguard Worker size_t length, bool growing_retained);
37*1208bc7eSAndroid Build Coastguard Worker static bool extent_decommit_default(extent_hooks_t *extent_hooks,
38*1208bc7eSAndroid Build Coastguard Worker void *addr, size_t size, size_t offset, size_t length, unsigned arena_ind);
39*1208bc7eSAndroid Build Coastguard Worker #ifdef PAGES_CAN_PURGE_LAZY
40*1208bc7eSAndroid Build Coastguard Worker static bool extent_purge_lazy_default(extent_hooks_t *extent_hooks, void *addr,
41*1208bc7eSAndroid Build Coastguard Worker size_t size, size_t offset, size_t length, unsigned arena_ind);
42*1208bc7eSAndroid Build Coastguard Worker #endif
43*1208bc7eSAndroid Build Coastguard Worker static bool extent_purge_lazy_impl(tsdn_t *tsdn, arena_t *arena,
44*1208bc7eSAndroid Build Coastguard Worker extent_hooks_t **r_extent_hooks, extent_t *extent, size_t offset,
45*1208bc7eSAndroid Build Coastguard Worker size_t length, bool growing_retained);
46*1208bc7eSAndroid Build Coastguard Worker #ifdef PAGES_CAN_PURGE_FORCED
47*1208bc7eSAndroid Build Coastguard Worker static bool extent_purge_forced_default(extent_hooks_t *extent_hooks,
48*1208bc7eSAndroid Build Coastguard Worker void *addr, size_t size, size_t offset, size_t length, unsigned arena_ind);
49*1208bc7eSAndroid Build Coastguard Worker #endif
50*1208bc7eSAndroid Build Coastguard Worker static bool extent_purge_forced_impl(tsdn_t *tsdn, arena_t *arena,
51*1208bc7eSAndroid Build Coastguard Worker extent_hooks_t **r_extent_hooks, extent_t *extent, size_t offset,
52*1208bc7eSAndroid Build Coastguard Worker size_t length, bool growing_retained);
53*1208bc7eSAndroid Build Coastguard Worker #ifdef JEMALLOC_MAPS_COALESCE
54*1208bc7eSAndroid Build Coastguard Worker static bool extent_split_default(extent_hooks_t *extent_hooks, void *addr,
55*1208bc7eSAndroid Build Coastguard Worker size_t size, size_t size_a, size_t size_b, bool committed,
56*1208bc7eSAndroid Build Coastguard Worker unsigned arena_ind);
57*1208bc7eSAndroid Build Coastguard Worker #endif
58*1208bc7eSAndroid Build Coastguard Worker static extent_t *extent_split_impl(tsdn_t *tsdn, arena_t *arena,
59*1208bc7eSAndroid Build Coastguard Worker extent_hooks_t **r_extent_hooks, extent_t *extent, size_t size_a,
60*1208bc7eSAndroid Build Coastguard Worker szind_t szind_a, bool slab_a, size_t size_b, szind_t szind_b, bool slab_b,
61*1208bc7eSAndroid Build Coastguard Worker bool growing_retained);
62*1208bc7eSAndroid Build Coastguard Worker #ifdef JEMALLOC_MAPS_COALESCE
63*1208bc7eSAndroid Build Coastguard Worker static bool extent_merge_default(extent_hooks_t *extent_hooks, void *addr_a,
64*1208bc7eSAndroid Build Coastguard Worker size_t size_a, void *addr_b, size_t size_b, bool committed,
65*1208bc7eSAndroid Build Coastguard Worker unsigned arena_ind);
66*1208bc7eSAndroid Build Coastguard Worker #endif
67*1208bc7eSAndroid Build Coastguard Worker static bool extent_merge_impl(tsdn_t *tsdn, arena_t *arena,
68*1208bc7eSAndroid Build Coastguard Worker extent_hooks_t **r_extent_hooks, extent_t *a, extent_t *b,
69*1208bc7eSAndroid Build Coastguard Worker bool growing_retained);
70*1208bc7eSAndroid Build Coastguard Worker
71*1208bc7eSAndroid Build Coastguard Worker const extent_hooks_t extent_hooks_default = {
72*1208bc7eSAndroid Build Coastguard Worker extent_alloc_default,
73*1208bc7eSAndroid Build Coastguard Worker extent_dalloc_default,
74*1208bc7eSAndroid Build Coastguard Worker extent_destroy_default,
75*1208bc7eSAndroid Build Coastguard Worker extent_commit_default,
76*1208bc7eSAndroid Build Coastguard Worker extent_decommit_default
77*1208bc7eSAndroid Build Coastguard Worker #ifdef PAGES_CAN_PURGE_LAZY
78*1208bc7eSAndroid Build Coastguard Worker ,
79*1208bc7eSAndroid Build Coastguard Worker extent_purge_lazy_default
80*1208bc7eSAndroid Build Coastguard Worker #else
81*1208bc7eSAndroid Build Coastguard Worker ,
82*1208bc7eSAndroid Build Coastguard Worker NULL
83*1208bc7eSAndroid Build Coastguard Worker #endif
84*1208bc7eSAndroid Build Coastguard Worker #ifdef PAGES_CAN_PURGE_FORCED
85*1208bc7eSAndroid Build Coastguard Worker ,
86*1208bc7eSAndroid Build Coastguard Worker extent_purge_forced_default
87*1208bc7eSAndroid Build Coastguard Worker #else
88*1208bc7eSAndroid Build Coastguard Worker ,
89*1208bc7eSAndroid Build Coastguard Worker NULL
90*1208bc7eSAndroid Build Coastguard Worker #endif
91*1208bc7eSAndroid Build Coastguard Worker #ifdef JEMALLOC_MAPS_COALESCE
92*1208bc7eSAndroid Build Coastguard Worker ,
93*1208bc7eSAndroid Build Coastguard Worker extent_split_default,
94*1208bc7eSAndroid Build Coastguard Worker extent_merge_default
95*1208bc7eSAndroid Build Coastguard Worker #endif
96*1208bc7eSAndroid Build Coastguard Worker };
97*1208bc7eSAndroid Build Coastguard Worker
98*1208bc7eSAndroid Build Coastguard Worker /* Used exclusively for gdump triggering. */
99*1208bc7eSAndroid Build Coastguard Worker static atomic_zu_t curpages;
100*1208bc7eSAndroid Build Coastguard Worker static atomic_zu_t highpages;
101*1208bc7eSAndroid Build Coastguard Worker
102*1208bc7eSAndroid Build Coastguard Worker /******************************************************************************/
103*1208bc7eSAndroid Build Coastguard Worker /*
104*1208bc7eSAndroid Build Coastguard Worker * Function prototypes for static functions that are referenced prior to
105*1208bc7eSAndroid Build Coastguard Worker * definition.
106*1208bc7eSAndroid Build Coastguard Worker */
107*1208bc7eSAndroid Build Coastguard Worker
108*1208bc7eSAndroid Build Coastguard Worker static void extent_deregister(tsdn_t *tsdn, extent_t *extent);
109*1208bc7eSAndroid Build Coastguard Worker static extent_t *extent_recycle(tsdn_t *tsdn, arena_t *arena,
110*1208bc7eSAndroid Build Coastguard Worker extent_hooks_t **r_extent_hooks, extents_t *extents, void *new_addr,
111*1208bc7eSAndroid Build Coastguard Worker size_t usize, size_t pad, size_t alignment, bool slab, szind_t szind,
112*1208bc7eSAndroid Build Coastguard Worker bool *zero, bool *commit, bool growing_retained);
113*1208bc7eSAndroid Build Coastguard Worker static extent_t *extent_try_coalesce(tsdn_t *tsdn, arena_t *arena,
114*1208bc7eSAndroid Build Coastguard Worker extent_hooks_t **r_extent_hooks, rtree_ctx_t *rtree_ctx, extents_t *extents,
115*1208bc7eSAndroid Build Coastguard Worker extent_t *extent, bool *coalesced, bool growing_retained);
116*1208bc7eSAndroid Build Coastguard Worker static void extent_record(tsdn_t *tsdn, arena_t *arena,
117*1208bc7eSAndroid Build Coastguard Worker extent_hooks_t **r_extent_hooks, extents_t *extents, extent_t *extent,
118*1208bc7eSAndroid Build Coastguard Worker bool growing_retained);
119*1208bc7eSAndroid Build Coastguard Worker
120*1208bc7eSAndroid Build Coastguard Worker /******************************************************************************/
121*1208bc7eSAndroid Build Coastguard Worker
122*1208bc7eSAndroid Build Coastguard Worker ph_gen(UNUSED, extent_avail_, extent_tree_t, extent_t, ph_link,
123*1208bc7eSAndroid Build Coastguard Worker extent_esnead_comp)
124*1208bc7eSAndroid Build Coastguard Worker
125*1208bc7eSAndroid Build Coastguard Worker typedef enum {
126*1208bc7eSAndroid Build Coastguard Worker lock_result_success,
127*1208bc7eSAndroid Build Coastguard Worker lock_result_failure,
128*1208bc7eSAndroid Build Coastguard Worker lock_result_no_extent
129*1208bc7eSAndroid Build Coastguard Worker } lock_result_t;
130*1208bc7eSAndroid Build Coastguard Worker
131*1208bc7eSAndroid Build Coastguard Worker static lock_result_t
extent_rtree_leaf_elm_try_lock(tsdn_t * tsdn,rtree_leaf_elm_t * elm,extent_t ** result)132*1208bc7eSAndroid Build Coastguard Worker extent_rtree_leaf_elm_try_lock(tsdn_t *tsdn, rtree_leaf_elm_t *elm,
133*1208bc7eSAndroid Build Coastguard Worker extent_t **result) {
134*1208bc7eSAndroid Build Coastguard Worker extent_t *extent1 = rtree_leaf_elm_extent_read(tsdn, &extents_rtree,
135*1208bc7eSAndroid Build Coastguard Worker elm, true);
136*1208bc7eSAndroid Build Coastguard Worker
137*1208bc7eSAndroid Build Coastguard Worker if (extent1 == NULL) {
138*1208bc7eSAndroid Build Coastguard Worker return lock_result_no_extent;
139*1208bc7eSAndroid Build Coastguard Worker }
140*1208bc7eSAndroid Build Coastguard Worker /*
141*1208bc7eSAndroid Build Coastguard Worker * It's possible that the extent changed out from under us, and with it
142*1208bc7eSAndroid Build Coastguard Worker * the leaf->extent mapping. We have to recheck while holding the lock.
143*1208bc7eSAndroid Build Coastguard Worker */
144*1208bc7eSAndroid Build Coastguard Worker extent_lock(tsdn, extent1);
145*1208bc7eSAndroid Build Coastguard Worker extent_t *extent2 = rtree_leaf_elm_extent_read(tsdn,
146*1208bc7eSAndroid Build Coastguard Worker &extents_rtree, elm, true);
147*1208bc7eSAndroid Build Coastguard Worker
148*1208bc7eSAndroid Build Coastguard Worker if (extent1 == extent2) {
149*1208bc7eSAndroid Build Coastguard Worker *result = extent1;
150*1208bc7eSAndroid Build Coastguard Worker return lock_result_success;
151*1208bc7eSAndroid Build Coastguard Worker } else {
152*1208bc7eSAndroid Build Coastguard Worker extent_unlock(tsdn, extent1);
153*1208bc7eSAndroid Build Coastguard Worker return lock_result_failure;
154*1208bc7eSAndroid Build Coastguard Worker }
155*1208bc7eSAndroid Build Coastguard Worker }
156*1208bc7eSAndroid Build Coastguard Worker
157*1208bc7eSAndroid Build Coastguard Worker /*
158*1208bc7eSAndroid Build Coastguard Worker * Returns a pool-locked extent_t * if there's one associated with the given
159*1208bc7eSAndroid Build Coastguard Worker * address, and NULL otherwise.
160*1208bc7eSAndroid Build Coastguard Worker */
161*1208bc7eSAndroid Build Coastguard Worker static extent_t *
extent_lock_from_addr(tsdn_t * tsdn,rtree_ctx_t * rtree_ctx,void * addr)162*1208bc7eSAndroid Build Coastguard Worker extent_lock_from_addr(tsdn_t *tsdn, rtree_ctx_t *rtree_ctx, void *addr) {
163*1208bc7eSAndroid Build Coastguard Worker extent_t *ret = NULL;
164*1208bc7eSAndroid Build Coastguard Worker rtree_leaf_elm_t *elm = rtree_leaf_elm_lookup(tsdn, &extents_rtree,
165*1208bc7eSAndroid Build Coastguard Worker rtree_ctx, (uintptr_t)addr, false, false);
166*1208bc7eSAndroid Build Coastguard Worker if (elm == NULL) {
167*1208bc7eSAndroid Build Coastguard Worker return NULL;
168*1208bc7eSAndroid Build Coastguard Worker }
169*1208bc7eSAndroid Build Coastguard Worker lock_result_t lock_result;
170*1208bc7eSAndroid Build Coastguard Worker do {
171*1208bc7eSAndroid Build Coastguard Worker lock_result = extent_rtree_leaf_elm_try_lock(tsdn, elm, &ret);
172*1208bc7eSAndroid Build Coastguard Worker } while (lock_result == lock_result_failure);
173*1208bc7eSAndroid Build Coastguard Worker return ret;
174*1208bc7eSAndroid Build Coastguard Worker }
175*1208bc7eSAndroid Build Coastguard Worker
176*1208bc7eSAndroid Build Coastguard Worker extent_t *
extent_alloc(tsdn_t * tsdn,arena_t * arena)177*1208bc7eSAndroid Build Coastguard Worker extent_alloc(tsdn_t *tsdn, arena_t *arena) {
178*1208bc7eSAndroid Build Coastguard Worker malloc_mutex_lock(tsdn, &arena->extent_avail_mtx);
179*1208bc7eSAndroid Build Coastguard Worker extent_t *extent = extent_avail_first(&arena->extent_avail);
180*1208bc7eSAndroid Build Coastguard Worker if (extent == NULL) {
181*1208bc7eSAndroid Build Coastguard Worker malloc_mutex_unlock(tsdn, &arena->extent_avail_mtx);
182*1208bc7eSAndroid Build Coastguard Worker return base_alloc_extent(tsdn, arena->base);
183*1208bc7eSAndroid Build Coastguard Worker }
184*1208bc7eSAndroid Build Coastguard Worker extent_avail_remove(&arena->extent_avail, extent);
185*1208bc7eSAndroid Build Coastguard Worker malloc_mutex_unlock(tsdn, &arena->extent_avail_mtx);
186*1208bc7eSAndroid Build Coastguard Worker return extent;
187*1208bc7eSAndroid Build Coastguard Worker }
188*1208bc7eSAndroid Build Coastguard Worker
189*1208bc7eSAndroid Build Coastguard Worker void
extent_dalloc(tsdn_t * tsdn,arena_t * arena,extent_t * extent)190*1208bc7eSAndroid Build Coastguard Worker extent_dalloc(tsdn_t *tsdn, arena_t *arena, extent_t *extent) {
191*1208bc7eSAndroid Build Coastguard Worker malloc_mutex_lock(tsdn, &arena->extent_avail_mtx);
192*1208bc7eSAndroid Build Coastguard Worker extent_avail_insert(&arena->extent_avail, extent);
193*1208bc7eSAndroid Build Coastguard Worker malloc_mutex_unlock(tsdn, &arena->extent_avail_mtx);
194*1208bc7eSAndroid Build Coastguard Worker }
195*1208bc7eSAndroid Build Coastguard Worker
196*1208bc7eSAndroid Build Coastguard Worker extent_hooks_t *
extent_hooks_get(arena_t * arena)197*1208bc7eSAndroid Build Coastguard Worker extent_hooks_get(arena_t *arena) {
198*1208bc7eSAndroid Build Coastguard Worker return base_extent_hooks_get(arena->base);
199*1208bc7eSAndroid Build Coastguard Worker }
200*1208bc7eSAndroid Build Coastguard Worker
201*1208bc7eSAndroid Build Coastguard Worker extent_hooks_t *
extent_hooks_set(tsd_t * tsd,arena_t * arena,extent_hooks_t * extent_hooks)202*1208bc7eSAndroid Build Coastguard Worker extent_hooks_set(tsd_t *tsd, arena_t *arena, extent_hooks_t *extent_hooks) {
203*1208bc7eSAndroid Build Coastguard Worker background_thread_info_t *info;
204*1208bc7eSAndroid Build Coastguard Worker if (have_background_thread) {
205*1208bc7eSAndroid Build Coastguard Worker info = arena_background_thread_info_get(arena);
206*1208bc7eSAndroid Build Coastguard Worker malloc_mutex_lock(tsd_tsdn(tsd), &info->mtx);
207*1208bc7eSAndroid Build Coastguard Worker }
208*1208bc7eSAndroid Build Coastguard Worker extent_hooks_t *ret = base_extent_hooks_set(arena->base, extent_hooks);
209*1208bc7eSAndroid Build Coastguard Worker if (have_background_thread) {
210*1208bc7eSAndroid Build Coastguard Worker malloc_mutex_unlock(tsd_tsdn(tsd), &info->mtx);
211*1208bc7eSAndroid Build Coastguard Worker }
212*1208bc7eSAndroid Build Coastguard Worker
213*1208bc7eSAndroid Build Coastguard Worker return ret;
214*1208bc7eSAndroid Build Coastguard Worker }
215*1208bc7eSAndroid Build Coastguard Worker
216*1208bc7eSAndroid Build Coastguard Worker static void
extent_hooks_assure_initialized(arena_t * arena,extent_hooks_t ** r_extent_hooks)217*1208bc7eSAndroid Build Coastguard Worker extent_hooks_assure_initialized(arena_t *arena,
218*1208bc7eSAndroid Build Coastguard Worker extent_hooks_t **r_extent_hooks) {
219*1208bc7eSAndroid Build Coastguard Worker if (*r_extent_hooks == EXTENT_HOOKS_INITIALIZER) {
220*1208bc7eSAndroid Build Coastguard Worker *r_extent_hooks = extent_hooks_get(arena);
221*1208bc7eSAndroid Build Coastguard Worker }
222*1208bc7eSAndroid Build Coastguard Worker }
223*1208bc7eSAndroid Build Coastguard Worker
224*1208bc7eSAndroid Build Coastguard Worker #ifndef JEMALLOC_JET
225*1208bc7eSAndroid Build Coastguard Worker static
226*1208bc7eSAndroid Build Coastguard Worker #endif
227*1208bc7eSAndroid Build Coastguard Worker size_t
extent_size_quantize_floor(size_t size)228*1208bc7eSAndroid Build Coastguard Worker extent_size_quantize_floor(size_t size) {
229*1208bc7eSAndroid Build Coastguard Worker size_t ret;
230*1208bc7eSAndroid Build Coastguard Worker pszind_t pind;
231*1208bc7eSAndroid Build Coastguard Worker
232*1208bc7eSAndroid Build Coastguard Worker assert(size > 0);
233*1208bc7eSAndroid Build Coastguard Worker assert((size & PAGE_MASK) == 0);
234*1208bc7eSAndroid Build Coastguard Worker
235*1208bc7eSAndroid Build Coastguard Worker pind = sz_psz2ind(size - sz_large_pad + 1);
236*1208bc7eSAndroid Build Coastguard Worker if (pind == 0) {
237*1208bc7eSAndroid Build Coastguard Worker /*
238*1208bc7eSAndroid Build Coastguard Worker * Avoid underflow. This short-circuit would also do the right
239*1208bc7eSAndroid Build Coastguard Worker * thing for all sizes in the range for which there are
240*1208bc7eSAndroid Build Coastguard Worker * PAGE-spaced size classes, but it's simplest to just handle
241*1208bc7eSAndroid Build Coastguard Worker * the one case that would cause erroneous results.
242*1208bc7eSAndroid Build Coastguard Worker */
243*1208bc7eSAndroid Build Coastguard Worker return size;
244*1208bc7eSAndroid Build Coastguard Worker }
245*1208bc7eSAndroid Build Coastguard Worker ret = sz_pind2sz(pind - 1) + sz_large_pad;
246*1208bc7eSAndroid Build Coastguard Worker assert(ret <= size);
247*1208bc7eSAndroid Build Coastguard Worker return ret;
248*1208bc7eSAndroid Build Coastguard Worker }
249*1208bc7eSAndroid Build Coastguard Worker
250*1208bc7eSAndroid Build Coastguard Worker #ifndef JEMALLOC_JET
251*1208bc7eSAndroid Build Coastguard Worker static
252*1208bc7eSAndroid Build Coastguard Worker #endif
253*1208bc7eSAndroid Build Coastguard Worker size_t
extent_size_quantize_ceil(size_t size)254*1208bc7eSAndroid Build Coastguard Worker extent_size_quantize_ceil(size_t size) {
255*1208bc7eSAndroid Build Coastguard Worker size_t ret;
256*1208bc7eSAndroid Build Coastguard Worker
257*1208bc7eSAndroid Build Coastguard Worker assert(size > 0);
258*1208bc7eSAndroid Build Coastguard Worker assert(size - sz_large_pad <= LARGE_MAXCLASS);
259*1208bc7eSAndroid Build Coastguard Worker assert((size & PAGE_MASK) == 0);
260*1208bc7eSAndroid Build Coastguard Worker
261*1208bc7eSAndroid Build Coastguard Worker ret = extent_size_quantize_floor(size);
262*1208bc7eSAndroid Build Coastguard Worker if (ret < size) {
263*1208bc7eSAndroid Build Coastguard Worker /*
264*1208bc7eSAndroid Build Coastguard Worker * Skip a quantization that may have an adequately large extent,
265*1208bc7eSAndroid Build Coastguard Worker * because under-sized extents may be mixed in. This only
266*1208bc7eSAndroid Build Coastguard Worker * happens when an unusual size is requested, i.e. for aligned
267*1208bc7eSAndroid Build Coastguard Worker * allocation, and is just one of several places where linear
268*1208bc7eSAndroid Build Coastguard Worker * search would potentially find sufficiently aligned available
269*1208bc7eSAndroid Build Coastguard Worker * memory somewhere lower.
270*1208bc7eSAndroid Build Coastguard Worker */
271*1208bc7eSAndroid Build Coastguard Worker ret = sz_pind2sz(sz_psz2ind(ret - sz_large_pad + 1)) +
272*1208bc7eSAndroid Build Coastguard Worker sz_large_pad;
273*1208bc7eSAndroid Build Coastguard Worker }
274*1208bc7eSAndroid Build Coastguard Worker return ret;
275*1208bc7eSAndroid Build Coastguard Worker }
276*1208bc7eSAndroid Build Coastguard Worker
277*1208bc7eSAndroid Build Coastguard Worker /* Generate pairing heap functions. */
278*1208bc7eSAndroid Build Coastguard Worker ph_gen(, extent_heap_, extent_heap_t, extent_t, ph_link, extent_snad_comp)
279*1208bc7eSAndroid Build Coastguard Worker
280*1208bc7eSAndroid Build Coastguard Worker bool
extents_init(tsdn_t * tsdn,extents_t * extents,extent_state_t state,bool delay_coalesce)281*1208bc7eSAndroid Build Coastguard Worker extents_init(tsdn_t *tsdn, extents_t *extents, extent_state_t state,
282*1208bc7eSAndroid Build Coastguard Worker bool delay_coalesce) {
283*1208bc7eSAndroid Build Coastguard Worker if (malloc_mutex_init(&extents->mtx, "extents", WITNESS_RANK_EXTENTS,
284*1208bc7eSAndroid Build Coastguard Worker malloc_mutex_rank_exclusive)) {
285*1208bc7eSAndroid Build Coastguard Worker return true;
286*1208bc7eSAndroid Build Coastguard Worker }
287*1208bc7eSAndroid Build Coastguard Worker for (unsigned i = 0; i < NPSIZES+1; i++) {
288*1208bc7eSAndroid Build Coastguard Worker extent_heap_new(&extents->heaps[i]);
289*1208bc7eSAndroid Build Coastguard Worker }
290*1208bc7eSAndroid Build Coastguard Worker bitmap_init(extents->bitmap, &extents_bitmap_info, true);
291*1208bc7eSAndroid Build Coastguard Worker extent_list_init(&extents->lru);
292*1208bc7eSAndroid Build Coastguard Worker atomic_store_zu(&extents->npages, 0, ATOMIC_RELAXED);
293*1208bc7eSAndroid Build Coastguard Worker extents->state = state;
294*1208bc7eSAndroid Build Coastguard Worker extents->delay_coalesce = delay_coalesce;
295*1208bc7eSAndroid Build Coastguard Worker return false;
296*1208bc7eSAndroid Build Coastguard Worker }
297*1208bc7eSAndroid Build Coastguard Worker
298*1208bc7eSAndroid Build Coastguard Worker extent_state_t
extents_state_get(const extents_t * extents)299*1208bc7eSAndroid Build Coastguard Worker extents_state_get(const extents_t *extents) {
300*1208bc7eSAndroid Build Coastguard Worker return extents->state;
301*1208bc7eSAndroid Build Coastguard Worker }
302*1208bc7eSAndroid Build Coastguard Worker
303*1208bc7eSAndroid Build Coastguard Worker size_t
extents_npages_get(extents_t * extents)304*1208bc7eSAndroid Build Coastguard Worker extents_npages_get(extents_t *extents) {
305*1208bc7eSAndroid Build Coastguard Worker return atomic_load_zu(&extents->npages, ATOMIC_RELAXED);
306*1208bc7eSAndroid Build Coastguard Worker }
307*1208bc7eSAndroid Build Coastguard Worker
308*1208bc7eSAndroid Build Coastguard Worker static void
extents_insert_locked(tsdn_t * tsdn,extents_t * extents,extent_t * extent)309*1208bc7eSAndroid Build Coastguard Worker extents_insert_locked(tsdn_t *tsdn, extents_t *extents, extent_t *extent) {
310*1208bc7eSAndroid Build Coastguard Worker malloc_mutex_assert_owner(tsdn, &extents->mtx);
311*1208bc7eSAndroid Build Coastguard Worker assert(extent_state_get(extent) == extents->state);
312*1208bc7eSAndroid Build Coastguard Worker
313*1208bc7eSAndroid Build Coastguard Worker size_t size = extent_size_get(extent);
314*1208bc7eSAndroid Build Coastguard Worker size_t psz = extent_size_quantize_floor(size);
315*1208bc7eSAndroid Build Coastguard Worker pszind_t pind = sz_psz2ind(psz);
316*1208bc7eSAndroid Build Coastguard Worker if (extent_heap_empty(&extents->heaps[pind])) {
317*1208bc7eSAndroid Build Coastguard Worker bitmap_unset(extents->bitmap, &extents_bitmap_info,
318*1208bc7eSAndroid Build Coastguard Worker (size_t)pind);
319*1208bc7eSAndroid Build Coastguard Worker }
320*1208bc7eSAndroid Build Coastguard Worker extent_heap_insert(&extents->heaps[pind], extent);
321*1208bc7eSAndroid Build Coastguard Worker extent_list_append(&extents->lru, extent);
322*1208bc7eSAndroid Build Coastguard Worker size_t npages = size >> LG_PAGE;
323*1208bc7eSAndroid Build Coastguard Worker /*
324*1208bc7eSAndroid Build Coastguard Worker * All modifications to npages hold the mutex (as asserted above), so we
325*1208bc7eSAndroid Build Coastguard Worker * don't need an atomic fetch-add; we can get by with a load followed by
326*1208bc7eSAndroid Build Coastguard Worker * a store.
327*1208bc7eSAndroid Build Coastguard Worker */
328*1208bc7eSAndroid Build Coastguard Worker size_t cur_extents_npages =
329*1208bc7eSAndroid Build Coastguard Worker atomic_load_zu(&extents->npages, ATOMIC_RELAXED);
330*1208bc7eSAndroid Build Coastguard Worker atomic_store_zu(&extents->npages, cur_extents_npages + npages,
331*1208bc7eSAndroid Build Coastguard Worker ATOMIC_RELAXED);
332*1208bc7eSAndroid Build Coastguard Worker }
333*1208bc7eSAndroid Build Coastguard Worker
334*1208bc7eSAndroid Build Coastguard Worker static void
extents_remove_locked(tsdn_t * tsdn,extents_t * extents,extent_t * extent)335*1208bc7eSAndroid Build Coastguard Worker extents_remove_locked(tsdn_t *tsdn, extents_t *extents, extent_t *extent) {
336*1208bc7eSAndroid Build Coastguard Worker malloc_mutex_assert_owner(tsdn, &extents->mtx);
337*1208bc7eSAndroid Build Coastguard Worker assert(extent_state_get(extent) == extents->state);
338*1208bc7eSAndroid Build Coastguard Worker
339*1208bc7eSAndroid Build Coastguard Worker size_t size = extent_size_get(extent);
340*1208bc7eSAndroid Build Coastguard Worker size_t psz = extent_size_quantize_floor(size);
341*1208bc7eSAndroid Build Coastguard Worker pszind_t pind = sz_psz2ind(psz);
342*1208bc7eSAndroid Build Coastguard Worker extent_heap_remove(&extents->heaps[pind], extent);
343*1208bc7eSAndroid Build Coastguard Worker if (extent_heap_empty(&extents->heaps[pind])) {
344*1208bc7eSAndroid Build Coastguard Worker bitmap_set(extents->bitmap, &extents_bitmap_info,
345*1208bc7eSAndroid Build Coastguard Worker (size_t)pind);
346*1208bc7eSAndroid Build Coastguard Worker }
347*1208bc7eSAndroid Build Coastguard Worker extent_list_remove(&extents->lru, extent);
348*1208bc7eSAndroid Build Coastguard Worker size_t npages = size >> LG_PAGE;
349*1208bc7eSAndroid Build Coastguard Worker /*
350*1208bc7eSAndroid Build Coastguard Worker * As in extents_insert_locked, we hold extents->mtx and so don't need
351*1208bc7eSAndroid Build Coastguard Worker * atomic operations for updating extents->npages.
352*1208bc7eSAndroid Build Coastguard Worker */
353*1208bc7eSAndroid Build Coastguard Worker size_t cur_extents_npages =
354*1208bc7eSAndroid Build Coastguard Worker atomic_load_zu(&extents->npages, ATOMIC_RELAXED);
355*1208bc7eSAndroid Build Coastguard Worker assert(cur_extents_npages >= npages);
356*1208bc7eSAndroid Build Coastguard Worker atomic_store_zu(&extents->npages,
357*1208bc7eSAndroid Build Coastguard Worker cur_extents_npages - (size >> LG_PAGE), ATOMIC_RELAXED);
358*1208bc7eSAndroid Build Coastguard Worker }
359*1208bc7eSAndroid Build Coastguard Worker
360*1208bc7eSAndroid Build Coastguard Worker /*
361*1208bc7eSAndroid Build Coastguard Worker * Find an extent with size [min_size, max_size) to satisfy the alignment
362*1208bc7eSAndroid Build Coastguard Worker * requirement. For each size, try only the first extent in the heap.
363*1208bc7eSAndroid Build Coastguard Worker */
364*1208bc7eSAndroid Build Coastguard Worker static extent_t *
extents_fit_alignment(extents_t * extents,size_t min_size,size_t max_size,size_t alignment)365*1208bc7eSAndroid Build Coastguard Worker extents_fit_alignment(extents_t *extents, size_t min_size, size_t max_size,
366*1208bc7eSAndroid Build Coastguard Worker size_t alignment) {
367*1208bc7eSAndroid Build Coastguard Worker pszind_t pind = sz_psz2ind(extent_size_quantize_ceil(min_size));
368*1208bc7eSAndroid Build Coastguard Worker pszind_t pind_max = sz_psz2ind(extent_size_quantize_ceil(max_size));
369*1208bc7eSAndroid Build Coastguard Worker
370*1208bc7eSAndroid Build Coastguard Worker for (pszind_t i = (pszind_t)bitmap_ffu(extents->bitmap,
371*1208bc7eSAndroid Build Coastguard Worker &extents_bitmap_info, (size_t)pind); i < pind_max; i =
372*1208bc7eSAndroid Build Coastguard Worker (pszind_t)bitmap_ffu(extents->bitmap, &extents_bitmap_info,
373*1208bc7eSAndroid Build Coastguard Worker (size_t)i+1)) {
374*1208bc7eSAndroid Build Coastguard Worker assert(i < NPSIZES);
375*1208bc7eSAndroid Build Coastguard Worker assert(!extent_heap_empty(&extents->heaps[i]));
376*1208bc7eSAndroid Build Coastguard Worker extent_t *extent = extent_heap_first(&extents->heaps[i]);
377*1208bc7eSAndroid Build Coastguard Worker uintptr_t base = (uintptr_t)extent_base_get(extent);
378*1208bc7eSAndroid Build Coastguard Worker size_t candidate_size = extent_size_get(extent);
379*1208bc7eSAndroid Build Coastguard Worker assert(candidate_size >= min_size);
380*1208bc7eSAndroid Build Coastguard Worker
381*1208bc7eSAndroid Build Coastguard Worker uintptr_t next_align = ALIGNMENT_CEILING((uintptr_t)base,
382*1208bc7eSAndroid Build Coastguard Worker PAGE_CEILING(alignment));
383*1208bc7eSAndroid Build Coastguard Worker if (base > next_align || base + candidate_size <= next_align) {
384*1208bc7eSAndroid Build Coastguard Worker /* Overflow or not crossing the next alignment. */
385*1208bc7eSAndroid Build Coastguard Worker continue;
386*1208bc7eSAndroid Build Coastguard Worker }
387*1208bc7eSAndroid Build Coastguard Worker
388*1208bc7eSAndroid Build Coastguard Worker size_t leadsize = next_align - base;
389*1208bc7eSAndroid Build Coastguard Worker if (candidate_size - leadsize >= min_size) {
390*1208bc7eSAndroid Build Coastguard Worker return extent;
391*1208bc7eSAndroid Build Coastguard Worker }
392*1208bc7eSAndroid Build Coastguard Worker }
393*1208bc7eSAndroid Build Coastguard Worker
394*1208bc7eSAndroid Build Coastguard Worker return NULL;
395*1208bc7eSAndroid Build Coastguard Worker }
396*1208bc7eSAndroid Build Coastguard Worker
397*1208bc7eSAndroid Build Coastguard Worker // ANDROID
398*1208bc7eSAndroid Build Coastguard Worker // The best-fit selection is reported to possiblity cause a memory leak.
399*1208bc7eSAndroid Build Coastguard Worker // This code has been completely removed from 5.2.0, so remove it from
400*1208bc7eSAndroid Build Coastguard Worker // our tree rather than risk a leak.
401*1208bc7eSAndroid Build Coastguard Worker // See https://github.com/jemalloc/jemalloc/issues/1454
402*1208bc7eSAndroid Build Coastguard Worker #if 0
403*1208bc7eSAndroid Build Coastguard Worker /* Do any-best-fit extent selection, i.e. select any extent that best fits. */
404*1208bc7eSAndroid Build Coastguard Worker static extent_t *
405*1208bc7eSAndroid Build Coastguard Worker extents_best_fit_locked(tsdn_t *tsdn, arena_t *arena, extents_t *extents,
406*1208bc7eSAndroid Build Coastguard Worker size_t size) {
407*1208bc7eSAndroid Build Coastguard Worker pszind_t pind = sz_psz2ind(extent_size_quantize_ceil(size));
408*1208bc7eSAndroid Build Coastguard Worker pszind_t i = (pszind_t)bitmap_ffu(extents->bitmap, &extents_bitmap_info,
409*1208bc7eSAndroid Build Coastguard Worker (size_t)pind);
410*1208bc7eSAndroid Build Coastguard Worker if (i < NPSIZES+1) {
411*1208bc7eSAndroid Build Coastguard Worker /*
412*1208bc7eSAndroid Build Coastguard Worker * In order to reduce fragmentation, avoid reusing and splitting
413*1208bc7eSAndroid Build Coastguard Worker * large extents for much smaller sizes.
414*1208bc7eSAndroid Build Coastguard Worker */
415*1208bc7eSAndroid Build Coastguard Worker if ((sz_pind2sz(i) >> opt_lg_extent_max_active_fit) > size) {
416*1208bc7eSAndroid Build Coastguard Worker return NULL;
417*1208bc7eSAndroid Build Coastguard Worker }
418*1208bc7eSAndroid Build Coastguard Worker assert(!extent_heap_empty(&extents->heaps[i]));
419*1208bc7eSAndroid Build Coastguard Worker extent_t *extent = extent_heap_first(&extents->heaps[i]);
420*1208bc7eSAndroid Build Coastguard Worker assert(extent_size_get(extent) >= size);
421*1208bc7eSAndroid Build Coastguard Worker return extent;
422*1208bc7eSAndroid Build Coastguard Worker }
423*1208bc7eSAndroid Build Coastguard Worker
424*1208bc7eSAndroid Build Coastguard Worker return NULL;
425*1208bc7eSAndroid Build Coastguard Worker }
426*1208bc7eSAndroid Build Coastguard Worker #endif
427*1208bc7eSAndroid Build Coastguard Worker
428*1208bc7eSAndroid Build Coastguard Worker /*
429*1208bc7eSAndroid Build Coastguard Worker * Do first-fit extent selection, i.e. select the oldest/lowest extent that is
430*1208bc7eSAndroid Build Coastguard Worker * large enough.
431*1208bc7eSAndroid Build Coastguard Worker */
432*1208bc7eSAndroid Build Coastguard Worker static extent_t *
extents_first_fit_locked(tsdn_t * tsdn,arena_t * arena,extents_t * extents,size_t size)433*1208bc7eSAndroid Build Coastguard Worker extents_first_fit_locked(tsdn_t *tsdn, arena_t *arena, extents_t *extents,
434*1208bc7eSAndroid Build Coastguard Worker size_t size) {
435*1208bc7eSAndroid Build Coastguard Worker extent_t *ret = NULL;
436*1208bc7eSAndroid Build Coastguard Worker
437*1208bc7eSAndroid Build Coastguard Worker pszind_t pind = sz_psz2ind(extent_size_quantize_ceil(size));
438*1208bc7eSAndroid Build Coastguard Worker for (pszind_t i = (pszind_t)bitmap_ffu(extents->bitmap,
439*1208bc7eSAndroid Build Coastguard Worker &extents_bitmap_info, (size_t)pind); i < NPSIZES+1; i =
440*1208bc7eSAndroid Build Coastguard Worker (pszind_t)bitmap_ffu(extents->bitmap, &extents_bitmap_info,
441*1208bc7eSAndroid Build Coastguard Worker (size_t)i+1)) {
442*1208bc7eSAndroid Build Coastguard Worker assert(!extent_heap_empty(&extents->heaps[i]));
443*1208bc7eSAndroid Build Coastguard Worker extent_t *extent = extent_heap_first(&extents->heaps[i]);
444*1208bc7eSAndroid Build Coastguard Worker assert(extent_size_get(extent) >= size);
445*1208bc7eSAndroid Build Coastguard Worker if (ret == NULL || extent_snad_comp(extent, ret) < 0) {
446*1208bc7eSAndroid Build Coastguard Worker ret = extent;
447*1208bc7eSAndroid Build Coastguard Worker }
448*1208bc7eSAndroid Build Coastguard Worker if (i == NPSIZES) {
449*1208bc7eSAndroid Build Coastguard Worker break;
450*1208bc7eSAndroid Build Coastguard Worker }
451*1208bc7eSAndroid Build Coastguard Worker assert(i < NPSIZES);
452*1208bc7eSAndroid Build Coastguard Worker }
453*1208bc7eSAndroid Build Coastguard Worker
454*1208bc7eSAndroid Build Coastguard Worker return ret;
455*1208bc7eSAndroid Build Coastguard Worker }
456*1208bc7eSAndroid Build Coastguard Worker
457*1208bc7eSAndroid Build Coastguard Worker /*
458*1208bc7eSAndroid Build Coastguard Worker * Do {best,first}-fit extent selection, where the selection policy choice is
459*1208bc7eSAndroid Build Coastguard Worker * based on extents->delay_coalesce. Best-fit selection requires less
460*1208bc7eSAndroid Build Coastguard Worker * searching, but its layout policy is less stable and may cause higher virtual
461*1208bc7eSAndroid Build Coastguard Worker * memory fragmentation as a side effect.
462*1208bc7eSAndroid Build Coastguard Worker */
463*1208bc7eSAndroid Build Coastguard Worker static extent_t *
extents_fit_locked(tsdn_t * tsdn,arena_t * arena,extents_t * extents,size_t esize,size_t alignment)464*1208bc7eSAndroid Build Coastguard Worker extents_fit_locked(tsdn_t *tsdn, arena_t *arena, extents_t *extents,
465*1208bc7eSAndroid Build Coastguard Worker size_t esize, size_t alignment) {
466*1208bc7eSAndroid Build Coastguard Worker malloc_mutex_assert_owner(tsdn, &extents->mtx);
467*1208bc7eSAndroid Build Coastguard Worker
468*1208bc7eSAndroid Build Coastguard Worker size_t max_size = esize + PAGE_CEILING(alignment) - PAGE;
469*1208bc7eSAndroid Build Coastguard Worker /* Beware size_t wrap-around. */
470*1208bc7eSAndroid Build Coastguard Worker if (max_size < esize) {
471*1208bc7eSAndroid Build Coastguard Worker return NULL;
472*1208bc7eSAndroid Build Coastguard Worker }
473*1208bc7eSAndroid Build Coastguard Worker
474*1208bc7eSAndroid Build Coastguard Worker // ANDROID
475*1208bc7eSAndroid Build Coastguard Worker // The best-fit selection is reported to possiblity cause a memory leak.
476*1208bc7eSAndroid Build Coastguard Worker // This code has been completely removed from 5.2.0, so remove it from
477*1208bc7eSAndroid Build Coastguard Worker // our tree rather than risk a leak.
478*1208bc7eSAndroid Build Coastguard Worker // See https://github.com/jemalloc/jemalloc/issues/1454
479*1208bc7eSAndroid Build Coastguard Worker #if 0
480*1208bc7eSAndroid Build Coastguard Worker extent_t *extent = extents->delay_coalesce ?
481*1208bc7eSAndroid Build Coastguard Worker extents_best_fit_locked(tsdn, arena, extents, max_size) :
482*1208bc7eSAndroid Build Coastguard Worker extents_first_fit_locked(tsdn, arena, extents, max_size);
483*1208bc7eSAndroid Build Coastguard Worker #endif
484*1208bc7eSAndroid Build Coastguard Worker extent_t *extent =
485*1208bc7eSAndroid Build Coastguard Worker extents_first_fit_locked(tsdn, arena, extents, max_size);
486*1208bc7eSAndroid Build Coastguard Worker
487*1208bc7eSAndroid Build Coastguard Worker if (alignment > PAGE && extent == NULL) {
488*1208bc7eSAndroid Build Coastguard Worker /*
489*1208bc7eSAndroid Build Coastguard Worker * max_size guarantees the alignment requirement but is rather
490*1208bc7eSAndroid Build Coastguard Worker * pessimistic. Next we try to satisfy the aligned allocation
491*1208bc7eSAndroid Build Coastguard Worker * with sizes in [esize, max_size).
492*1208bc7eSAndroid Build Coastguard Worker */
493*1208bc7eSAndroid Build Coastguard Worker extent = extents_fit_alignment(extents, esize, max_size,
494*1208bc7eSAndroid Build Coastguard Worker alignment);
495*1208bc7eSAndroid Build Coastguard Worker }
496*1208bc7eSAndroid Build Coastguard Worker
497*1208bc7eSAndroid Build Coastguard Worker return extent;
498*1208bc7eSAndroid Build Coastguard Worker }
499*1208bc7eSAndroid Build Coastguard Worker
500*1208bc7eSAndroid Build Coastguard Worker static bool
extent_try_delayed_coalesce(tsdn_t * tsdn,arena_t * arena,extent_hooks_t ** r_extent_hooks,rtree_ctx_t * rtree_ctx,extents_t * extents,extent_t * extent)501*1208bc7eSAndroid Build Coastguard Worker extent_try_delayed_coalesce(tsdn_t *tsdn, arena_t *arena,
502*1208bc7eSAndroid Build Coastguard Worker extent_hooks_t **r_extent_hooks, rtree_ctx_t *rtree_ctx, extents_t *extents,
503*1208bc7eSAndroid Build Coastguard Worker extent_t *extent) {
504*1208bc7eSAndroid Build Coastguard Worker extent_state_set(extent, extent_state_active);
505*1208bc7eSAndroid Build Coastguard Worker bool coalesced;
506*1208bc7eSAndroid Build Coastguard Worker extent = extent_try_coalesce(tsdn, arena, r_extent_hooks, rtree_ctx,
507*1208bc7eSAndroid Build Coastguard Worker extents, extent, &coalesced, false);
508*1208bc7eSAndroid Build Coastguard Worker extent_state_set(extent, extents_state_get(extents));
509*1208bc7eSAndroid Build Coastguard Worker
510*1208bc7eSAndroid Build Coastguard Worker if (!coalesced) {
511*1208bc7eSAndroid Build Coastguard Worker return true;
512*1208bc7eSAndroid Build Coastguard Worker }
513*1208bc7eSAndroid Build Coastguard Worker extents_insert_locked(tsdn, extents, extent);
514*1208bc7eSAndroid Build Coastguard Worker return false;
515*1208bc7eSAndroid Build Coastguard Worker }
516*1208bc7eSAndroid Build Coastguard Worker
517*1208bc7eSAndroid Build Coastguard Worker extent_t *
extents_alloc(tsdn_t * tsdn,arena_t * arena,extent_hooks_t ** r_extent_hooks,extents_t * extents,void * new_addr,size_t size,size_t pad,size_t alignment,bool slab,szind_t szind,bool * zero,bool * commit)518*1208bc7eSAndroid Build Coastguard Worker extents_alloc(tsdn_t *tsdn, arena_t *arena, extent_hooks_t **r_extent_hooks,
519*1208bc7eSAndroid Build Coastguard Worker extents_t *extents, void *new_addr, size_t size, size_t pad,
520*1208bc7eSAndroid Build Coastguard Worker size_t alignment, bool slab, szind_t szind, bool *zero, bool *commit) {
521*1208bc7eSAndroid Build Coastguard Worker assert(size + pad != 0);
522*1208bc7eSAndroid Build Coastguard Worker assert(alignment != 0);
523*1208bc7eSAndroid Build Coastguard Worker witness_assert_depth_to_rank(tsdn_witness_tsdp_get(tsdn),
524*1208bc7eSAndroid Build Coastguard Worker WITNESS_RANK_CORE, 0);
525*1208bc7eSAndroid Build Coastguard Worker
526*1208bc7eSAndroid Build Coastguard Worker extent_t *extent = extent_recycle(tsdn, arena, r_extent_hooks, extents,
527*1208bc7eSAndroid Build Coastguard Worker new_addr, size, pad, alignment, slab, szind, zero, commit, false);
528*1208bc7eSAndroid Build Coastguard Worker assert(extent == NULL || extent_dumpable_get(extent));
529*1208bc7eSAndroid Build Coastguard Worker return extent;
530*1208bc7eSAndroid Build Coastguard Worker }
531*1208bc7eSAndroid Build Coastguard Worker
532*1208bc7eSAndroid Build Coastguard Worker void
extents_dalloc(tsdn_t * tsdn,arena_t * arena,extent_hooks_t ** r_extent_hooks,extents_t * extents,extent_t * extent)533*1208bc7eSAndroid Build Coastguard Worker extents_dalloc(tsdn_t *tsdn, arena_t *arena, extent_hooks_t **r_extent_hooks,
534*1208bc7eSAndroid Build Coastguard Worker extents_t *extents, extent_t *extent) {
535*1208bc7eSAndroid Build Coastguard Worker assert(extent_base_get(extent) != NULL);
536*1208bc7eSAndroid Build Coastguard Worker assert(extent_size_get(extent) != 0);
537*1208bc7eSAndroid Build Coastguard Worker assert(extent_dumpable_get(extent));
538*1208bc7eSAndroid Build Coastguard Worker witness_assert_depth_to_rank(tsdn_witness_tsdp_get(tsdn),
539*1208bc7eSAndroid Build Coastguard Worker WITNESS_RANK_CORE, 0);
540*1208bc7eSAndroid Build Coastguard Worker
541*1208bc7eSAndroid Build Coastguard Worker extent_addr_set(extent, extent_base_get(extent));
542*1208bc7eSAndroid Build Coastguard Worker extent_zeroed_set(extent, false);
543*1208bc7eSAndroid Build Coastguard Worker
544*1208bc7eSAndroid Build Coastguard Worker extent_record(tsdn, arena, r_extent_hooks, extents, extent, false);
545*1208bc7eSAndroid Build Coastguard Worker }
546*1208bc7eSAndroid Build Coastguard Worker
547*1208bc7eSAndroid Build Coastguard Worker extent_t *
extents_evict(tsdn_t * tsdn,arena_t * arena,extent_hooks_t ** r_extent_hooks,extents_t * extents,size_t npages_min)548*1208bc7eSAndroid Build Coastguard Worker extents_evict(tsdn_t *tsdn, arena_t *arena, extent_hooks_t **r_extent_hooks,
549*1208bc7eSAndroid Build Coastguard Worker extents_t *extents, size_t npages_min) {
550*1208bc7eSAndroid Build Coastguard Worker rtree_ctx_t rtree_ctx_fallback;
551*1208bc7eSAndroid Build Coastguard Worker rtree_ctx_t *rtree_ctx = tsdn_rtree_ctx(tsdn, &rtree_ctx_fallback);
552*1208bc7eSAndroid Build Coastguard Worker
553*1208bc7eSAndroid Build Coastguard Worker malloc_mutex_lock(tsdn, &extents->mtx);
554*1208bc7eSAndroid Build Coastguard Worker
555*1208bc7eSAndroid Build Coastguard Worker /*
556*1208bc7eSAndroid Build Coastguard Worker * Get the LRU coalesced extent, if any. If coalescing was delayed,
557*1208bc7eSAndroid Build Coastguard Worker * the loop will iterate until the LRU extent is fully coalesced.
558*1208bc7eSAndroid Build Coastguard Worker */
559*1208bc7eSAndroid Build Coastguard Worker extent_t *extent;
560*1208bc7eSAndroid Build Coastguard Worker while (true) {
561*1208bc7eSAndroid Build Coastguard Worker /* Get the LRU extent, if any. */
562*1208bc7eSAndroid Build Coastguard Worker extent = extent_list_first(&extents->lru);
563*1208bc7eSAndroid Build Coastguard Worker if (extent == NULL) {
564*1208bc7eSAndroid Build Coastguard Worker goto label_return;
565*1208bc7eSAndroid Build Coastguard Worker }
566*1208bc7eSAndroid Build Coastguard Worker /* Check the eviction limit. */
567*1208bc7eSAndroid Build Coastguard Worker size_t extents_npages = atomic_load_zu(&extents->npages,
568*1208bc7eSAndroid Build Coastguard Worker ATOMIC_RELAXED);
569*1208bc7eSAndroid Build Coastguard Worker if (extents_npages <= npages_min) {
570*1208bc7eSAndroid Build Coastguard Worker extent = NULL;
571*1208bc7eSAndroid Build Coastguard Worker goto label_return;
572*1208bc7eSAndroid Build Coastguard Worker }
573*1208bc7eSAndroid Build Coastguard Worker extents_remove_locked(tsdn, extents, extent);
574*1208bc7eSAndroid Build Coastguard Worker if (!extents->delay_coalesce) {
575*1208bc7eSAndroid Build Coastguard Worker break;
576*1208bc7eSAndroid Build Coastguard Worker }
577*1208bc7eSAndroid Build Coastguard Worker /* Try to coalesce. */
578*1208bc7eSAndroid Build Coastguard Worker if (extent_try_delayed_coalesce(tsdn, arena, r_extent_hooks,
579*1208bc7eSAndroid Build Coastguard Worker rtree_ctx, extents, extent)) {
580*1208bc7eSAndroid Build Coastguard Worker break;
581*1208bc7eSAndroid Build Coastguard Worker }
582*1208bc7eSAndroid Build Coastguard Worker /*
583*1208bc7eSAndroid Build Coastguard Worker * The LRU extent was just coalesced and the result placed in
584*1208bc7eSAndroid Build Coastguard Worker * the LRU at its neighbor's position. Start over.
585*1208bc7eSAndroid Build Coastguard Worker */
586*1208bc7eSAndroid Build Coastguard Worker }
587*1208bc7eSAndroid Build Coastguard Worker
588*1208bc7eSAndroid Build Coastguard Worker /*
589*1208bc7eSAndroid Build Coastguard Worker * Either mark the extent active or deregister it to protect against
590*1208bc7eSAndroid Build Coastguard Worker * concurrent operations.
591*1208bc7eSAndroid Build Coastguard Worker */
592*1208bc7eSAndroid Build Coastguard Worker switch (extents_state_get(extents)) {
593*1208bc7eSAndroid Build Coastguard Worker case extent_state_active:
594*1208bc7eSAndroid Build Coastguard Worker not_reached();
595*1208bc7eSAndroid Build Coastguard Worker case extent_state_dirty:
596*1208bc7eSAndroid Build Coastguard Worker case extent_state_muzzy:
597*1208bc7eSAndroid Build Coastguard Worker extent_state_set(extent, extent_state_active);
598*1208bc7eSAndroid Build Coastguard Worker break;
599*1208bc7eSAndroid Build Coastguard Worker case extent_state_retained:
600*1208bc7eSAndroid Build Coastguard Worker extent_deregister(tsdn, extent);
601*1208bc7eSAndroid Build Coastguard Worker break;
602*1208bc7eSAndroid Build Coastguard Worker default:
603*1208bc7eSAndroid Build Coastguard Worker not_reached();
604*1208bc7eSAndroid Build Coastguard Worker }
605*1208bc7eSAndroid Build Coastguard Worker
606*1208bc7eSAndroid Build Coastguard Worker label_return:
607*1208bc7eSAndroid Build Coastguard Worker malloc_mutex_unlock(tsdn, &extents->mtx);
608*1208bc7eSAndroid Build Coastguard Worker return extent;
609*1208bc7eSAndroid Build Coastguard Worker }
610*1208bc7eSAndroid Build Coastguard Worker
611*1208bc7eSAndroid Build Coastguard Worker static void
extents_leak(tsdn_t * tsdn,arena_t * arena,extent_hooks_t ** r_extent_hooks,extents_t * extents,extent_t * extent,bool growing_retained)612*1208bc7eSAndroid Build Coastguard Worker extents_leak(tsdn_t *tsdn, arena_t *arena, extent_hooks_t **r_extent_hooks,
613*1208bc7eSAndroid Build Coastguard Worker extents_t *extents, extent_t *extent, bool growing_retained) {
614*1208bc7eSAndroid Build Coastguard Worker /*
615*1208bc7eSAndroid Build Coastguard Worker * Leak extent after making sure its pages have already been purged, so
616*1208bc7eSAndroid Build Coastguard Worker * that this is only a virtual memory leak.
617*1208bc7eSAndroid Build Coastguard Worker */
618*1208bc7eSAndroid Build Coastguard Worker if (extents_state_get(extents) == extent_state_dirty) {
619*1208bc7eSAndroid Build Coastguard Worker if (extent_purge_lazy_impl(tsdn, arena, r_extent_hooks,
620*1208bc7eSAndroid Build Coastguard Worker extent, 0, extent_size_get(extent), growing_retained)) {
621*1208bc7eSAndroid Build Coastguard Worker extent_purge_forced_impl(tsdn, arena, r_extent_hooks,
622*1208bc7eSAndroid Build Coastguard Worker extent, 0, extent_size_get(extent),
623*1208bc7eSAndroid Build Coastguard Worker growing_retained);
624*1208bc7eSAndroid Build Coastguard Worker }
625*1208bc7eSAndroid Build Coastguard Worker }
626*1208bc7eSAndroid Build Coastguard Worker extent_dalloc(tsdn, arena, extent);
627*1208bc7eSAndroid Build Coastguard Worker }
628*1208bc7eSAndroid Build Coastguard Worker
629*1208bc7eSAndroid Build Coastguard Worker void
extents_prefork(tsdn_t * tsdn,extents_t * extents)630*1208bc7eSAndroid Build Coastguard Worker extents_prefork(tsdn_t *tsdn, extents_t *extents) {
631*1208bc7eSAndroid Build Coastguard Worker malloc_mutex_prefork(tsdn, &extents->mtx);
632*1208bc7eSAndroid Build Coastguard Worker }
633*1208bc7eSAndroid Build Coastguard Worker
634*1208bc7eSAndroid Build Coastguard Worker void
extents_postfork_parent(tsdn_t * tsdn,extents_t * extents)635*1208bc7eSAndroid Build Coastguard Worker extents_postfork_parent(tsdn_t *tsdn, extents_t *extents) {
636*1208bc7eSAndroid Build Coastguard Worker malloc_mutex_postfork_parent(tsdn, &extents->mtx);
637*1208bc7eSAndroid Build Coastguard Worker }
638*1208bc7eSAndroid Build Coastguard Worker
639*1208bc7eSAndroid Build Coastguard Worker void
extents_postfork_child(tsdn_t * tsdn,extents_t * extents)640*1208bc7eSAndroid Build Coastguard Worker extents_postfork_child(tsdn_t *tsdn, extents_t *extents) {
641*1208bc7eSAndroid Build Coastguard Worker malloc_mutex_postfork_child(tsdn, &extents->mtx);
642*1208bc7eSAndroid Build Coastguard Worker }
643*1208bc7eSAndroid Build Coastguard Worker
644*1208bc7eSAndroid Build Coastguard Worker static void
extent_deactivate_locked(tsdn_t * tsdn,arena_t * arena,extents_t * extents,extent_t * extent)645*1208bc7eSAndroid Build Coastguard Worker extent_deactivate_locked(tsdn_t *tsdn, arena_t *arena, extents_t *extents,
646*1208bc7eSAndroid Build Coastguard Worker extent_t *extent) {
647*1208bc7eSAndroid Build Coastguard Worker assert(extent_arena_get(extent) == arena);
648*1208bc7eSAndroid Build Coastguard Worker assert(extent_state_get(extent) == extent_state_active);
649*1208bc7eSAndroid Build Coastguard Worker
650*1208bc7eSAndroid Build Coastguard Worker extent_state_set(extent, extents_state_get(extents));
651*1208bc7eSAndroid Build Coastguard Worker extents_insert_locked(tsdn, extents, extent);
652*1208bc7eSAndroid Build Coastguard Worker }
653*1208bc7eSAndroid Build Coastguard Worker
654*1208bc7eSAndroid Build Coastguard Worker static void
extent_deactivate(tsdn_t * tsdn,arena_t * arena,extents_t * extents,extent_t * extent)655*1208bc7eSAndroid Build Coastguard Worker extent_deactivate(tsdn_t *tsdn, arena_t *arena, extents_t *extents,
656*1208bc7eSAndroid Build Coastguard Worker extent_t *extent) {
657*1208bc7eSAndroid Build Coastguard Worker malloc_mutex_lock(tsdn, &extents->mtx);
658*1208bc7eSAndroid Build Coastguard Worker extent_deactivate_locked(tsdn, arena, extents, extent);
659*1208bc7eSAndroid Build Coastguard Worker malloc_mutex_unlock(tsdn, &extents->mtx);
660*1208bc7eSAndroid Build Coastguard Worker }
661*1208bc7eSAndroid Build Coastguard Worker
662*1208bc7eSAndroid Build Coastguard Worker static void
extent_activate_locked(tsdn_t * tsdn,arena_t * arena,extents_t * extents,extent_t * extent)663*1208bc7eSAndroid Build Coastguard Worker extent_activate_locked(tsdn_t *tsdn, arena_t *arena, extents_t *extents,
664*1208bc7eSAndroid Build Coastguard Worker extent_t *extent) {
665*1208bc7eSAndroid Build Coastguard Worker assert(extent_arena_get(extent) == arena);
666*1208bc7eSAndroid Build Coastguard Worker assert(extent_state_get(extent) == extents_state_get(extents));
667*1208bc7eSAndroid Build Coastguard Worker
668*1208bc7eSAndroid Build Coastguard Worker extents_remove_locked(tsdn, extents, extent);
669*1208bc7eSAndroid Build Coastguard Worker extent_state_set(extent, extent_state_active);
670*1208bc7eSAndroid Build Coastguard Worker }
671*1208bc7eSAndroid Build Coastguard Worker
672*1208bc7eSAndroid Build Coastguard Worker static bool
extent_rtree_leaf_elms_lookup(tsdn_t * tsdn,rtree_ctx_t * rtree_ctx,const extent_t * extent,bool dependent,bool init_missing,rtree_leaf_elm_t ** r_elm_a,rtree_leaf_elm_t ** r_elm_b)673*1208bc7eSAndroid Build Coastguard Worker extent_rtree_leaf_elms_lookup(tsdn_t *tsdn, rtree_ctx_t *rtree_ctx,
674*1208bc7eSAndroid Build Coastguard Worker const extent_t *extent, bool dependent, bool init_missing,
675*1208bc7eSAndroid Build Coastguard Worker rtree_leaf_elm_t **r_elm_a, rtree_leaf_elm_t **r_elm_b) {
676*1208bc7eSAndroid Build Coastguard Worker *r_elm_a = rtree_leaf_elm_lookup(tsdn, &extents_rtree, rtree_ctx,
677*1208bc7eSAndroid Build Coastguard Worker (uintptr_t)extent_base_get(extent), dependent, init_missing);
678*1208bc7eSAndroid Build Coastguard Worker if (!dependent && *r_elm_a == NULL) {
679*1208bc7eSAndroid Build Coastguard Worker return true;
680*1208bc7eSAndroid Build Coastguard Worker }
681*1208bc7eSAndroid Build Coastguard Worker assert(*r_elm_a != NULL);
682*1208bc7eSAndroid Build Coastguard Worker
683*1208bc7eSAndroid Build Coastguard Worker *r_elm_b = rtree_leaf_elm_lookup(tsdn, &extents_rtree, rtree_ctx,
684*1208bc7eSAndroid Build Coastguard Worker (uintptr_t)extent_last_get(extent), dependent, init_missing);
685*1208bc7eSAndroid Build Coastguard Worker if (!dependent && *r_elm_b == NULL) {
686*1208bc7eSAndroid Build Coastguard Worker return true;
687*1208bc7eSAndroid Build Coastguard Worker }
688*1208bc7eSAndroid Build Coastguard Worker assert(*r_elm_b != NULL);
689*1208bc7eSAndroid Build Coastguard Worker
690*1208bc7eSAndroid Build Coastguard Worker return false;
691*1208bc7eSAndroid Build Coastguard Worker }
692*1208bc7eSAndroid Build Coastguard Worker
693*1208bc7eSAndroid Build Coastguard Worker static void
extent_rtree_write_acquired(tsdn_t * tsdn,rtree_leaf_elm_t * elm_a,rtree_leaf_elm_t * elm_b,extent_t * extent,szind_t szind,bool slab)694*1208bc7eSAndroid Build Coastguard Worker extent_rtree_write_acquired(tsdn_t *tsdn, rtree_leaf_elm_t *elm_a,
695*1208bc7eSAndroid Build Coastguard Worker rtree_leaf_elm_t *elm_b, extent_t *extent, szind_t szind, bool slab) {
696*1208bc7eSAndroid Build Coastguard Worker rtree_leaf_elm_write(tsdn, &extents_rtree, elm_a, extent, szind, slab);
697*1208bc7eSAndroid Build Coastguard Worker if (elm_b != NULL) {
698*1208bc7eSAndroid Build Coastguard Worker rtree_leaf_elm_write(tsdn, &extents_rtree, elm_b, extent, szind,
699*1208bc7eSAndroid Build Coastguard Worker slab);
700*1208bc7eSAndroid Build Coastguard Worker }
701*1208bc7eSAndroid Build Coastguard Worker }
702*1208bc7eSAndroid Build Coastguard Worker
703*1208bc7eSAndroid Build Coastguard Worker static void
extent_interior_register(tsdn_t * tsdn,rtree_ctx_t * rtree_ctx,extent_t * extent,szind_t szind)704*1208bc7eSAndroid Build Coastguard Worker extent_interior_register(tsdn_t *tsdn, rtree_ctx_t *rtree_ctx, extent_t *extent,
705*1208bc7eSAndroid Build Coastguard Worker szind_t szind) {
706*1208bc7eSAndroid Build Coastguard Worker assert(extent_slab_get(extent));
707*1208bc7eSAndroid Build Coastguard Worker
708*1208bc7eSAndroid Build Coastguard Worker /* Register interior. */
709*1208bc7eSAndroid Build Coastguard Worker for (size_t i = 1; i < (extent_size_get(extent) >> LG_PAGE) - 1; i++) {
710*1208bc7eSAndroid Build Coastguard Worker rtree_write(tsdn, &extents_rtree, rtree_ctx,
711*1208bc7eSAndroid Build Coastguard Worker (uintptr_t)extent_base_get(extent) + (uintptr_t)(i <<
712*1208bc7eSAndroid Build Coastguard Worker LG_PAGE), extent, szind, true);
713*1208bc7eSAndroid Build Coastguard Worker }
714*1208bc7eSAndroid Build Coastguard Worker }
715*1208bc7eSAndroid Build Coastguard Worker
716*1208bc7eSAndroid Build Coastguard Worker static void
extent_gdump_add(tsdn_t * tsdn,const extent_t * extent)717*1208bc7eSAndroid Build Coastguard Worker extent_gdump_add(tsdn_t *tsdn, const extent_t *extent) {
718*1208bc7eSAndroid Build Coastguard Worker cassert(config_prof);
719*1208bc7eSAndroid Build Coastguard Worker /* prof_gdump() requirement. */
720*1208bc7eSAndroid Build Coastguard Worker witness_assert_depth_to_rank(tsdn_witness_tsdp_get(tsdn),
721*1208bc7eSAndroid Build Coastguard Worker WITNESS_RANK_CORE, 0);
722*1208bc7eSAndroid Build Coastguard Worker
723*1208bc7eSAndroid Build Coastguard Worker if (opt_prof && extent_state_get(extent) == extent_state_active) {
724*1208bc7eSAndroid Build Coastguard Worker size_t nadd = extent_size_get(extent) >> LG_PAGE;
725*1208bc7eSAndroid Build Coastguard Worker size_t cur = atomic_fetch_add_zu(&curpages, nadd,
726*1208bc7eSAndroid Build Coastguard Worker ATOMIC_RELAXED) + nadd;
727*1208bc7eSAndroid Build Coastguard Worker size_t high = atomic_load_zu(&highpages, ATOMIC_RELAXED);
728*1208bc7eSAndroid Build Coastguard Worker while (cur > high && !atomic_compare_exchange_weak_zu(
729*1208bc7eSAndroid Build Coastguard Worker &highpages, &high, cur, ATOMIC_RELAXED, ATOMIC_RELAXED)) {
730*1208bc7eSAndroid Build Coastguard Worker /*
731*1208bc7eSAndroid Build Coastguard Worker * Don't refresh cur, because it may have decreased
732*1208bc7eSAndroid Build Coastguard Worker * since this thread lost the highpages update race.
733*1208bc7eSAndroid Build Coastguard Worker * Note that high is updated in case of CAS failure.
734*1208bc7eSAndroid Build Coastguard Worker */
735*1208bc7eSAndroid Build Coastguard Worker }
736*1208bc7eSAndroid Build Coastguard Worker if (cur > high && prof_gdump_get_unlocked()) {
737*1208bc7eSAndroid Build Coastguard Worker prof_gdump(tsdn);
738*1208bc7eSAndroid Build Coastguard Worker }
739*1208bc7eSAndroid Build Coastguard Worker }
740*1208bc7eSAndroid Build Coastguard Worker }
741*1208bc7eSAndroid Build Coastguard Worker
742*1208bc7eSAndroid Build Coastguard Worker static void
extent_gdump_sub(tsdn_t * tsdn,const extent_t * extent)743*1208bc7eSAndroid Build Coastguard Worker extent_gdump_sub(tsdn_t *tsdn, const extent_t *extent) {
744*1208bc7eSAndroid Build Coastguard Worker cassert(config_prof);
745*1208bc7eSAndroid Build Coastguard Worker
746*1208bc7eSAndroid Build Coastguard Worker if (opt_prof && extent_state_get(extent) == extent_state_active) {
747*1208bc7eSAndroid Build Coastguard Worker size_t nsub = extent_size_get(extent) >> LG_PAGE;
748*1208bc7eSAndroid Build Coastguard Worker assert(atomic_load_zu(&curpages, ATOMIC_RELAXED) >= nsub);
749*1208bc7eSAndroid Build Coastguard Worker atomic_fetch_sub_zu(&curpages, nsub, ATOMIC_RELAXED);
750*1208bc7eSAndroid Build Coastguard Worker }
751*1208bc7eSAndroid Build Coastguard Worker }
752*1208bc7eSAndroid Build Coastguard Worker
753*1208bc7eSAndroid Build Coastguard Worker static bool
extent_register_impl(tsdn_t * tsdn,extent_t * extent,bool gdump_add)754*1208bc7eSAndroid Build Coastguard Worker extent_register_impl(tsdn_t *tsdn, extent_t *extent, bool gdump_add) {
755*1208bc7eSAndroid Build Coastguard Worker rtree_ctx_t rtree_ctx_fallback;
756*1208bc7eSAndroid Build Coastguard Worker rtree_ctx_t *rtree_ctx = tsdn_rtree_ctx(tsdn, &rtree_ctx_fallback);
757*1208bc7eSAndroid Build Coastguard Worker rtree_leaf_elm_t *elm_a, *elm_b;
758*1208bc7eSAndroid Build Coastguard Worker
759*1208bc7eSAndroid Build Coastguard Worker /*
760*1208bc7eSAndroid Build Coastguard Worker * We need to hold the lock to protect against a concurrent coalesce
761*1208bc7eSAndroid Build Coastguard Worker * operation that sees us in a partial state.
762*1208bc7eSAndroid Build Coastguard Worker */
763*1208bc7eSAndroid Build Coastguard Worker extent_lock(tsdn, extent);
764*1208bc7eSAndroid Build Coastguard Worker
765*1208bc7eSAndroid Build Coastguard Worker if (extent_rtree_leaf_elms_lookup(tsdn, rtree_ctx, extent, false, true,
766*1208bc7eSAndroid Build Coastguard Worker &elm_a, &elm_b)) {
767*1208bc7eSAndroid Build Coastguard Worker return true;
768*1208bc7eSAndroid Build Coastguard Worker }
769*1208bc7eSAndroid Build Coastguard Worker
770*1208bc7eSAndroid Build Coastguard Worker szind_t szind = extent_szind_get_maybe_invalid(extent);
771*1208bc7eSAndroid Build Coastguard Worker bool slab = extent_slab_get(extent);
772*1208bc7eSAndroid Build Coastguard Worker extent_rtree_write_acquired(tsdn, elm_a, elm_b, extent, szind, slab);
773*1208bc7eSAndroid Build Coastguard Worker if (slab) {
774*1208bc7eSAndroid Build Coastguard Worker extent_interior_register(tsdn, rtree_ctx, extent, szind);
775*1208bc7eSAndroid Build Coastguard Worker }
776*1208bc7eSAndroid Build Coastguard Worker
777*1208bc7eSAndroid Build Coastguard Worker extent_unlock(tsdn, extent);
778*1208bc7eSAndroid Build Coastguard Worker
779*1208bc7eSAndroid Build Coastguard Worker if (config_prof && gdump_add) {
780*1208bc7eSAndroid Build Coastguard Worker extent_gdump_add(tsdn, extent);
781*1208bc7eSAndroid Build Coastguard Worker }
782*1208bc7eSAndroid Build Coastguard Worker
783*1208bc7eSAndroid Build Coastguard Worker return false;
784*1208bc7eSAndroid Build Coastguard Worker }
785*1208bc7eSAndroid Build Coastguard Worker
786*1208bc7eSAndroid Build Coastguard Worker static bool
extent_register(tsdn_t * tsdn,extent_t * extent)787*1208bc7eSAndroid Build Coastguard Worker extent_register(tsdn_t *tsdn, extent_t *extent) {
788*1208bc7eSAndroid Build Coastguard Worker return extent_register_impl(tsdn, extent, true);
789*1208bc7eSAndroid Build Coastguard Worker }
790*1208bc7eSAndroid Build Coastguard Worker
791*1208bc7eSAndroid Build Coastguard Worker static bool
extent_register_no_gdump_add(tsdn_t * tsdn,extent_t * extent)792*1208bc7eSAndroid Build Coastguard Worker extent_register_no_gdump_add(tsdn_t *tsdn, extent_t *extent) {
793*1208bc7eSAndroid Build Coastguard Worker return extent_register_impl(tsdn, extent, false);
794*1208bc7eSAndroid Build Coastguard Worker }
795*1208bc7eSAndroid Build Coastguard Worker
796*1208bc7eSAndroid Build Coastguard Worker static void
extent_reregister(tsdn_t * tsdn,extent_t * extent)797*1208bc7eSAndroid Build Coastguard Worker extent_reregister(tsdn_t *tsdn, extent_t *extent) {
798*1208bc7eSAndroid Build Coastguard Worker bool err = extent_register(tsdn, extent);
799*1208bc7eSAndroid Build Coastguard Worker assert(!err);
800*1208bc7eSAndroid Build Coastguard Worker }
801*1208bc7eSAndroid Build Coastguard Worker
802*1208bc7eSAndroid Build Coastguard Worker /*
803*1208bc7eSAndroid Build Coastguard Worker * Removes all pointers to the given extent from the global rtree indices for
804*1208bc7eSAndroid Build Coastguard Worker * its interior. This is relevant for slab extents, for which we need to do
805*1208bc7eSAndroid Build Coastguard Worker * metadata lookups at places other than the head of the extent. We deregister
806*1208bc7eSAndroid Build Coastguard Worker * on the interior, then, when an extent moves from being an active slab to an
807*1208bc7eSAndroid Build Coastguard Worker * inactive state.
808*1208bc7eSAndroid Build Coastguard Worker */
809*1208bc7eSAndroid Build Coastguard Worker static void
extent_interior_deregister(tsdn_t * tsdn,rtree_ctx_t * rtree_ctx,extent_t * extent)810*1208bc7eSAndroid Build Coastguard Worker extent_interior_deregister(tsdn_t *tsdn, rtree_ctx_t *rtree_ctx,
811*1208bc7eSAndroid Build Coastguard Worker extent_t *extent) {
812*1208bc7eSAndroid Build Coastguard Worker size_t i;
813*1208bc7eSAndroid Build Coastguard Worker
814*1208bc7eSAndroid Build Coastguard Worker assert(extent_slab_get(extent));
815*1208bc7eSAndroid Build Coastguard Worker
816*1208bc7eSAndroid Build Coastguard Worker for (i = 1; i < (extent_size_get(extent) >> LG_PAGE) - 1; i++) {
817*1208bc7eSAndroid Build Coastguard Worker rtree_clear(tsdn, &extents_rtree, rtree_ctx,
818*1208bc7eSAndroid Build Coastguard Worker (uintptr_t)extent_base_get(extent) + (uintptr_t)(i <<
819*1208bc7eSAndroid Build Coastguard Worker LG_PAGE));
820*1208bc7eSAndroid Build Coastguard Worker }
821*1208bc7eSAndroid Build Coastguard Worker }
822*1208bc7eSAndroid Build Coastguard Worker
823*1208bc7eSAndroid Build Coastguard Worker /*
824*1208bc7eSAndroid Build Coastguard Worker * Removes all pointers to the given extent from the global rtree.
825*1208bc7eSAndroid Build Coastguard Worker */
826*1208bc7eSAndroid Build Coastguard Worker static void
extent_deregister_impl(tsdn_t * tsdn,extent_t * extent,bool gdump)827*1208bc7eSAndroid Build Coastguard Worker extent_deregister_impl(tsdn_t *tsdn, extent_t *extent, bool gdump) {
828*1208bc7eSAndroid Build Coastguard Worker rtree_ctx_t rtree_ctx_fallback;
829*1208bc7eSAndroid Build Coastguard Worker rtree_ctx_t *rtree_ctx = tsdn_rtree_ctx(tsdn, &rtree_ctx_fallback);
830*1208bc7eSAndroid Build Coastguard Worker rtree_leaf_elm_t *elm_a, *elm_b;
831*1208bc7eSAndroid Build Coastguard Worker extent_rtree_leaf_elms_lookup(tsdn, rtree_ctx, extent, true, false,
832*1208bc7eSAndroid Build Coastguard Worker &elm_a, &elm_b);
833*1208bc7eSAndroid Build Coastguard Worker
834*1208bc7eSAndroid Build Coastguard Worker extent_lock(tsdn, extent);
835*1208bc7eSAndroid Build Coastguard Worker
836*1208bc7eSAndroid Build Coastguard Worker extent_rtree_write_acquired(tsdn, elm_a, elm_b, NULL, NSIZES, false);
837*1208bc7eSAndroid Build Coastguard Worker if (extent_slab_get(extent)) {
838*1208bc7eSAndroid Build Coastguard Worker extent_interior_deregister(tsdn, rtree_ctx, extent);
839*1208bc7eSAndroid Build Coastguard Worker extent_slab_set(extent, false);
840*1208bc7eSAndroid Build Coastguard Worker }
841*1208bc7eSAndroid Build Coastguard Worker
842*1208bc7eSAndroid Build Coastguard Worker extent_unlock(tsdn, extent);
843*1208bc7eSAndroid Build Coastguard Worker
844*1208bc7eSAndroid Build Coastguard Worker if (config_prof && gdump) {
845*1208bc7eSAndroid Build Coastguard Worker extent_gdump_sub(tsdn, extent);
846*1208bc7eSAndroid Build Coastguard Worker }
847*1208bc7eSAndroid Build Coastguard Worker }
848*1208bc7eSAndroid Build Coastguard Worker
849*1208bc7eSAndroid Build Coastguard Worker static void
extent_deregister(tsdn_t * tsdn,extent_t * extent)850*1208bc7eSAndroid Build Coastguard Worker extent_deregister(tsdn_t *tsdn, extent_t *extent) {
851*1208bc7eSAndroid Build Coastguard Worker extent_deregister_impl(tsdn, extent, true);
852*1208bc7eSAndroid Build Coastguard Worker }
853*1208bc7eSAndroid Build Coastguard Worker
854*1208bc7eSAndroid Build Coastguard Worker static void
extent_deregister_no_gdump_sub(tsdn_t * tsdn,extent_t * extent)855*1208bc7eSAndroid Build Coastguard Worker extent_deregister_no_gdump_sub(tsdn_t *tsdn, extent_t *extent) {
856*1208bc7eSAndroid Build Coastguard Worker extent_deregister_impl(tsdn, extent, false);
857*1208bc7eSAndroid Build Coastguard Worker }
858*1208bc7eSAndroid Build Coastguard Worker
859*1208bc7eSAndroid Build Coastguard Worker /*
860*1208bc7eSAndroid Build Coastguard Worker * Tries to find and remove an extent from extents that can be used for the
861*1208bc7eSAndroid Build Coastguard Worker * given allocation request.
862*1208bc7eSAndroid Build Coastguard Worker */
863*1208bc7eSAndroid Build Coastguard Worker static extent_t *
extent_recycle_extract(tsdn_t * tsdn,arena_t * arena,extent_hooks_t ** r_extent_hooks,rtree_ctx_t * rtree_ctx,extents_t * extents,void * new_addr,size_t size,size_t pad,size_t alignment,bool slab,bool growing_retained)864*1208bc7eSAndroid Build Coastguard Worker extent_recycle_extract(tsdn_t *tsdn, arena_t *arena,
865*1208bc7eSAndroid Build Coastguard Worker extent_hooks_t **r_extent_hooks, rtree_ctx_t *rtree_ctx, extents_t *extents,
866*1208bc7eSAndroid Build Coastguard Worker void *new_addr, size_t size, size_t pad, size_t alignment, bool slab,
867*1208bc7eSAndroid Build Coastguard Worker bool growing_retained) {
868*1208bc7eSAndroid Build Coastguard Worker witness_assert_depth_to_rank(tsdn_witness_tsdp_get(tsdn),
869*1208bc7eSAndroid Build Coastguard Worker WITNESS_RANK_CORE, growing_retained ? 1 : 0);
870*1208bc7eSAndroid Build Coastguard Worker assert(alignment > 0);
871*1208bc7eSAndroid Build Coastguard Worker if (config_debug && new_addr != NULL) {
872*1208bc7eSAndroid Build Coastguard Worker /*
873*1208bc7eSAndroid Build Coastguard Worker * Non-NULL new_addr has two use cases:
874*1208bc7eSAndroid Build Coastguard Worker *
875*1208bc7eSAndroid Build Coastguard Worker * 1) Recycle a known-extant extent, e.g. during purging.
876*1208bc7eSAndroid Build Coastguard Worker * 2) Perform in-place expanding reallocation.
877*1208bc7eSAndroid Build Coastguard Worker *
878*1208bc7eSAndroid Build Coastguard Worker * Regardless of use case, new_addr must either refer to a
879*1208bc7eSAndroid Build Coastguard Worker * non-existing extent, or to the base of an extant extent,
880*1208bc7eSAndroid Build Coastguard Worker * since only active slabs support interior lookups (which of
881*1208bc7eSAndroid Build Coastguard Worker * course cannot be recycled).
882*1208bc7eSAndroid Build Coastguard Worker */
883*1208bc7eSAndroid Build Coastguard Worker assert(PAGE_ADDR2BASE(new_addr) == new_addr);
884*1208bc7eSAndroid Build Coastguard Worker assert(pad == 0);
885*1208bc7eSAndroid Build Coastguard Worker assert(alignment <= PAGE);
886*1208bc7eSAndroid Build Coastguard Worker }
887*1208bc7eSAndroid Build Coastguard Worker
888*1208bc7eSAndroid Build Coastguard Worker size_t esize = size + pad;
889*1208bc7eSAndroid Build Coastguard Worker malloc_mutex_lock(tsdn, &extents->mtx);
890*1208bc7eSAndroid Build Coastguard Worker extent_hooks_assure_initialized(arena, r_extent_hooks);
891*1208bc7eSAndroid Build Coastguard Worker extent_t *extent;
892*1208bc7eSAndroid Build Coastguard Worker if (new_addr != NULL) {
893*1208bc7eSAndroid Build Coastguard Worker extent = extent_lock_from_addr(tsdn, rtree_ctx, new_addr);
894*1208bc7eSAndroid Build Coastguard Worker if (extent != NULL) {
895*1208bc7eSAndroid Build Coastguard Worker /*
896*1208bc7eSAndroid Build Coastguard Worker * We might null-out extent to report an error, but we
897*1208bc7eSAndroid Build Coastguard Worker * still need to unlock the associated mutex after.
898*1208bc7eSAndroid Build Coastguard Worker */
899*1208bc7eSAndroid Build Coastguard Worker extent_t *unlock_extent = extent;
900*1208bc7eSAndroid Build Coastguard Worker assert(extent_base_get(extent) == new_addr);
901*1208bc7eSAndroid Build Coastguard Worker if (extent_arena_get(extent) != arena ||
902*1208bc7eSAndroid Build Coastguard Worker extent_size_get(extent) < esize ||
903*1208bc7eSAndroid Build Coastguard Worker extent_state_get(extent) !=
904*1208bc7eSAndroid Build Coastguard Worker extents_state_get(extents)) {
905*1208bc7eSAndroid Build Coastguard Worker extent = NULL;
906*1208bc7eSAndroid Build Coastguard Worker }
907*1208bc7eSAndroid Build Coastguard Worker extent_unlock(tsdn, unlock_extent);
908*1208bc7eSAndroid Build Coastguard Worker }
909*1208bc7eSAndroid Build Coastguard Worker } else {
910*1208bc7eSAndroid Build Coastguard Worker extent = extents_fit_locked(tsdn, arena, extents, esize,
911*1208bc7eSAndroid Build Coastguard Worker alignment);
912*1208bc7eSAndroid Build Coastguard Worker }
913*1208bc7eSAndroid Build Coastguard Worker if (extent == NULL) {
914*1208bc7eSAndroid Build Coastguard Worker malloc_mutex_unlock(tsdn, &extents->mtx);
915*1208bc7eSAndroid Build Coastguard Worker return NULL;
916*1208bc7eSAndroid Build Coastguard Worker }
917*1208bc7eSAndroid Build Coastguard Worker
918*1208bc7eSAndroid Build Coastguard Worker extent_activate_locked(tsdn, arena, extents, extent);
919*1208bc7eSAndroid Build Coastguard Worker malloc_mutex_unlock(tsdn, &extents->mtx);
920*1208bc7eSAndroid Build Coastguard Worker
921*1208bc7eSAndroid Build Coastguard Worker return extent;
922*1208bc7eSAndroid Build Coastguard Worker }
923*1208bc7eSAndroid Build Coastguard Worker
924*1208bc7eSAndroid Build Coastguard Worker /*
925*1208bc7eSAndroid Build Coastguard Worker * Given an allocation request and an extent guaranteed to be able to satisfy
926*1208bc7eSAndroid Build Coastguard Worker * it, this splits off lead and trail extents, leaving extent pointing to an
927*1208bc7eSAndroid Build Coastguard Worker * extent satisfying the allocation.
928*1208bc7eSAndroid Build Coastguard Worker * This function doesn't put lead or trail into any extents_t; it's the caller's
929*1208bc7eSAndroid Build Coastguard Worker * job to ensure that they can be reused.
930*1208bc7eSAndroid Build Coastguard Worker */
931*1208bc7eSAndroid Build Coastguard Worker typedef enum {
932*1208bc7eSAndroid Build Coastguard Worker /*
933*1208bc7eSAndroid Build Coastguard Worker * Split successfully. lead, extent, and trail, are modified to extents
934*1208bc7eSAndroid Build Coastguard Worker * describing the ranges before, in, and after the given allocation.
935*1208bc7eSAndroid Build Coastguard Worker */
936*1208bc7eSAndroid Build Coastguard Worker extent_split_interior_ok,
937*1208bc7eSAndroid Build Coastguard Worker /*
938*1208bc7eSAndroid Build Coastguard Worker * The extent can't satisfy the given allocation request. None of the
939*1208bc7eSAndroid Build Coastguard Worker * input extent_t *s are touched.
940*1208bc7eSAndroid Build Coastguard Worker */
941*1208bc7eSAndroid Build Coastguard Worker extent_split_interior_cant_alloc,
942*1208bc7eSAndroid Build Coastguard Worker /*
943*1208bc7eSAndroid Build Coastguard Worker * In a potentially invalid state. Must leak (if *to_leak is non-NULL),
944*1208bc7eSAndroid Build Coastguard Worker * and salvage what's still salvageable (if *to_salvage is non-NULL).
945*1208bc7eSAndroid Build Coastguard Worker * None of lead, extent, or trail are valid.
946*1208bc7eSAndroid Build Coastguard Worker */
947*1208bc7eSAndroid Build Coastguard Worker extent_split_interior_error
948*1208bc7eSAndroid Build Coastguard Worker } extent_split_interior_result_t;
949*1208bc7eSAndroid Build Coastguard Worker
950*1208bc7eSAndroid Build Coastguard Worker static extent_split_interior_result_t
extent_split_interior(tsdn_t * tsdn,arena_t * arena,extent_hooks_t ** r_extent_hooks,rtree_ctx_t * rtree_ctx,extent_t ** extent,extent_t ** lead,extent_t ** trail,extent_t ** to_leak,extent_t ** to_salvage,void * new_addr,size_t size,size_t pad,size_t alignment,bool slab,szind_t szind,bool growing_retained)951*1208bc7eSAndroid Build Coastguard Worker extent_split_interior(tsdn_t *tsdn, arena_t *arena,
952*1208bc7eSAndroid Build Coastguard Worker extent_hooks_t **r_extent_hooks, rtree_ctx_t *rtree_ctx,
953*1208bc7eSAndroid Build Coastguard Worker /* The result of splitting, in case of success. */
954*1208bc7eSAndroid Build Coastguard Worker extent_t **extent, extent_t **lead, extent_t **trail,
955*1208bc7eSAndroid Build Coastguard Worker /* The mess to clean up, in case of error. */
956*1208bc7eSAndroid Build Coastguard Worker extent_t **to_leak, extent_t **to_salvage,
957*1208bc7eSAndroid Build Coastguard Worker void *new_addr, size_t size, size_t pad, size_t alignment, bool slab,
958*1208bc7eSAndroid Build Coastguard Worker szind_t szind, bool growing_retained) {
959*1208bc7eSAndroid Build Coastguard Worker size_t esize = size + pad;
960*1208bc7eSAndroid Build Coastguard Worker size_t leadsize = ALIGNMENT_CEILING((uintptr_t)extent_base_get(*extent),
961*1208bc7eSAndroid Build Coastguard Worker PAGE_CEILING(alignment)) - (uintptr_t)extent_base_get(*extent);
962*1208bc7eSAndroid Build Coastguard Worker assert(new_addr == NULL || leadsize == 0);
963*1208bc7eSAndroid Build Coastguard Worker if (extent_size_get(*extent) < leadsize + esize) {
964*1208bc7eSAndroid Build Coastguard Worker return extent_split_interior_cant_alloc;
965*1208bc7eSAndroid Build Coastguard Worker }
966*1208bc7eSAndroid Build Coastguard Worker size_t trailsize = extent_size_get(*extent) - leadsize - esize;
967*1208bc7eSAndroid Build Coastguard Worker
968*1208bc7eSAndroid Build Coastguard Worker *lead = NULL;
969*1208bc7eSAndroid Build Coastguard Worker *trail = NULL;
970*1208bc7eSAndroid Build Coastguard Worker *to_leak = NULL;
971*1208bc7eSAndroid Build Coastguard Worker *to_salvage = NULL;
972*1208bc7eSAndroid Build Coastguard Worker
973*1208bc7eSAndroid Build Coastguard Worker /* Split the lead. */
974*1208bc7eSAndroid Build Coastguard Worker if (leadsize != 0) {
975*1208bc7eSAndroid Build Coastguard Worker *lead = *extent;
976*1208bc7eSAndroid Build Coastguard Worker *extent = extent_split_impl(tsdn, arena, r_extent_hooks,
977*1208bc7eSAndroid Build Coastguard Worker *lead, leadsize, NSIZES, false, esize + trailsize, szind,
978*1208bc7eSAndroid Build Coastguard Worker slab, growing_retained);
979*1208bc7eSAndroid Build Coastguard Worker if (*extent == NULL) {
980*1208bc7eSAndroid Build Coastguard Worker *to_leak = *lead;
981*1208bc7eSAndroid Build Coastguard Worker *lead = NULL;
982*1208bc7eSAndroid Build Coastguard Worker return extent_split_interior_error;
983*1208bc7eSAndroid Build Coastguard Worker }
984*1208bc7eSAndroid Build Coastguard Worker }
985*1208bc7eSAndroid Build Coastguard Worker
986*1208bc7eSAndroid Build Coastguard Worker /* Split the trail. */
987*1208bc7eSAndroid Build Coastguard Worker if (trailsize != 0) {
988*1208bc7eSAndroid Build Coastguard Worker *trail = extent_split_impl(tsdn, arena, r_extent_hooks, *extent,
989*1208bc7eSAndroid Build Coastguard Worker esize, szind, slab, trailsize, NSIZES, false,
990*1208bc7eSAndroid Build Coastguard Worker growing_retained);
991*1208bc7eSAndroid Build Coastguard Worker if (*trail == NULL) {
992*1208bc7eSAndroid Build Coastguard Worker *to_leak = *extent;
993*1208bc7eSAndroid Build Coastguard Worker *to_salvage = *lead;
994*1208bc7eSAndroid Build Coastguard Worker *lead = NULL;
995*1208bc7eSAndroid Build Coastguard Worker *extent = NULL;
996*1208bc7eSAndroid Build Coastguard Worker return extent_split_interior_error;
997*1208bc7eSAndroid Build Coastguard Worker }
998*1208bc7eSAndroid Build Coastguard Worker }
999*1208bc7eSAndroid Build Coastguard Worker
1000*1208bc7eSAndroid Build Coastguard Worker if (leadsize == 0 && trailsize == 0) {
1001*1208bc7eSAndroid Build Coastguard Worker /*
1002*1208bc7eSAndroid Build Coastguard Worker * Splitting causes szind to be set as a side effect, but no
1003*1208bc7eSAndroid Build Coastguard Worker * splitting occurred.
1004*1208bc7eSAndroid Build Coastguard Worker */
1005*1208bc7eSAndroid Build Coastguard Worker extent_szind_set(*extent, szind);
1006*1208bc7eSAndroid Build Coastguard Worker if (szind != NSIZES) {
1007*1208bc7eSAndroid Build Coastguard Worker rtree_szind_slab_update(tsdn, &extents_rtree, rtree_ctx,
1008*1208bc7eSAndroid Build Coastguard Worker (uintptr_t)extent_addr_get(*extent), szind, slab);
1009*1208bc7eSAndroid Build Coastguard Worker if (slab && extent_size_get(*extent) > PAGE) {
1010*1208bc7eSAndroid Build Coastguard Worker rtree_szind_slab_update(tsdn, &extents_rtree,
1011*1208bc7eSAndroid Build Coastguard Worker rtree_ctx,
1012*1208bc7eSAndroid Build Coastguard Worker (uintptr_t)extent_past_get(*extent) -
1013*1208bc7eSAndroid Build Coastguard Worker (uintptr_t)PAGE, szind, slab);
1014*1208bc7eSAndroid Build Coastguard Worker }
1015*1208bc7eSAndroid Build Coastguard Worker }
1016*1208bc7eSAndroid Build Coastguard Worker }
1017*1208bc7eSAndroid Build Coastguard Worker
1018*1208bc7eSAndroid Build Coastguard Worker return extent_split_interior_ok;
1019*1208bc7eSAndroid Build Coastguard Worker }
1020*1208bc7eSAndroid Build Coastguard Worker
1021*1208bc7eSAndroid Build Coastguard Worker /*
1022*1208bc7eSAndroid Build Coastguard Worker * This fulfills the indicated allocation request out of the given extent (which
1023*1208bc7eSAndroid Build Coastguard Worker * the caller should have ensured was big enough). If there's any unused space
1024*1208bc7eSAndroid Build Coastguard Worker * before or after the resulting allocation, that space is given its own extent
1025*1208bc7eSAndroid Build Coastguard Worker * and put back into extents.
1026*1208bc7eSAndroid Build Coastguard Worker */
1027*1208bc7eSAndroid Build Coastguard Worker static extent_t *
extent_recycle_split(tsdn_t * tsdn,arena_t * arena,extent_hooks_t ** r_extent_hooks,rtree_ctx_t * rtree_ctx,extents_t * extents,void * new_addr,size_t size,size_t pad,size_t alignment,bool slab,szind_t szind,extent_t * extent,bool growing_retained)1028*1208bc7eSAndroid Build Coastguard Worker extent_recycle_split(tsdn_t *tsdn, arena_t *arena,
1029*1208bc7eSAndroid Build Coastguard Worker extent_hooks_t **r_extent_hooks, rtree_ctx_t *rtree_ctx, extents_t *extents,
1030*1208bc7eSAndroid Build Coastguard Worker void *new_addr, size_t size, size_t pad, size_t alignment, bool slab,
1031*1208bc7eSAndroid Build Coastguard Worker szind_t szind, extent_t *extent, bool growing_retained) {
1032*1208bc7eSAndroid Build Coastguard Worker extent_t *lead;
1033*1208bc7eSAndroid Build Coastguard Worker extent_t *trail;
1034*1208bc7eSAndroid Build Coastguard Worker extent_t *to_leak;
1035*1208bc7eSAndroid Build Coastguard Worker extent_t *to_salvage;
1036*1208bc7eSAndroid Build Coastguard Worker
1037*1208bc7eSAndroid Build Coastguard Worker extent_split_interior_result_t result = extent_split_interior(
1038*1208bc7eSAndroid Build Coastguard Worker tsdn, arena, r_extent_hooks, rtree_ctx, &extent, &lead, &trail,
1039*1208bc7eSAndroid Build Coastguard Worker &to_leak, &to_salvage, new_addr, size, pad, alignment, slab, szind,
1040*1208bc7eSAndroid Build Coastguard Worker growing_retained);
1041*1208bc7eSAndroid Build Coastguard Worker
1042*1208bc7eSAndroid Build Coastguard Worker if (result == extent_split_interior_ok) {
1043*1208bc7eSAndroid Build Coastguard Worker if (lead != NULL) {
1044*1208bc7eSAndroid Build Coastguard Worker extent_deactivate(tsdn, arena, extents, lead);
1045*1208bc7eSAndroid Build Coastguard Worker }
1046*1208bc7eSAndroid Build Coastguard Worker if (trail != NULL) {
1047*1208bc7eSAndroid Build Coastguard Worker extent_deactivate(tsdn, arena, extents, trail);
1048*1208bc7eSAndroid Build Coastguard Worker }
1049*1208bc7eSAndroid Build Coastguard Worker return extent;
1050*1208bc7eSAndroid Build Coastguard Worker } else {
1051*1208bc7eSAndroid Build Coastguard Worker /*
1052*1208bc7eSAndroid Build Coastguard Worker * We should have picked an extent that was large enough to
1053*1208bc7eSAndroid Build Coastguard Worker * fulfill our allocation request.
1054*1208bc7eSAndroid Build Coastguard Worker */
1055*1208bc7eSAndroid Build Coastguard Worker assert(result == extent_split_interior_error);
1056*1208bc7eSAndroid Build Coastguard Worker if (to_salvage != NULL) {
1057*1208bc7eSAndroid Build Coastguard Worker extent_deregister(tsdn, to_salvage);
1058*1208bc7eSAndroid Build Coastguard Worker }
1059*1208bc7eSAndroid Build Coastguard Worker if (to_leak != NULL) {
1060*1208bc7eSAndroid Build Coastguard Worker void *leak = extent_base_get(to_leak);
1061*1208bc7eSAndroid Build Coastguard Worker extent_deregister_no_gdump_sub(tsdn, to_leak);
1062*1208bc7eSAndroid Build Coastguard Worker extents_leak(tsdn, arena, r_extent_hooks, extents,
1063*1208bc7eSAndroid Build Coastguard Worker to_leak, growing_retained);
1064*1208bc7eSAndroid Build Coastguard Worker assert(extent_lock_from_addr(tsdn, rtree_ctx, leak)
1065*1208bc7eSAndroid Build Coastguard Worker == NULL);
1066*1208bc7eSAndroid Build Coastguard Worker }
1067*1208bc7eSAndroid Build Coastguard Worker return NULL;
1068*1208bc7eSAndroid Build Coastguard Worker }
1069*1208bc7eSAndroid Build Coastguard Worker unreachable();
1070*1208bc7eSAndroid Build Coastguard Worker }
1071*1208bc7eSAndroid Build Coastguard Worker
1072*1208bc7eSAndroid Build Coastguard Worker /*
1073*1208bc7eSAndroid Build Coastguard Worker * Tries to satisfy the given allocation request by reusing one of the extents
1074*1208bc7eSAndroid Build Coastguard Worker * in the given extents_t.
1075*1208bc7eSAndroid Build Coastguard Worker */
1076*1208bc7eSAndroid Build Coastguard Worker static extent_t *
extent_recycle(tsdn_t * tsdn,arena_t * arena,extent_hooks_t ** r_extent_hooks,extents_t * extents,void * new_addr,size_t size,size_t pad,size_t alignment,bool slab,szind_t szind,bool * zero,bool * commit,bool growing_retained)1077*1208bc7eSAndroid Build Coastguard Worker extent_recycle(tsdn_t *tsdn, arena_t *arena, extent_hooks_t **r_extent_hooks,
1078*1208bc7eSAndroid Build Coastguard Worker extents_t *extents, void *new_addr, size_t size, size_t pad,
1079*1208bc7eSAndroid Build Coastguard Worker size_t alignment, bool slab, szind_t szind, bool *zero, bool *commit,
1080*1208bc7eSAndroid Build Coastguard Worker bool growing_retained) {
1081*1208bc7eSAndroid Build Coastguard Worker witness_assert_depth_to_rank(tsdn_witness_tsdp_get(tsdn),
1082*1208bc7eSAndroid Build Coastguard Worker WITNESS_RANK_CORE, growing_retained ? 1 : 0);
1083*1208bc7eSAndroid Build Coastguard Worker assert(new_addr == NULL || !slab);
1084*1208bc7eSAndroid Build Coastguard Worker assert(pad == 0 || !slab);
1085*1208bc7eSAndroid Build Coastguard Worker assert(!*zero || !slab);
1086*1208bc7eSAndroid Build Coastguard Worker
1087*1208bc7eSAndroid Build Coastguard Worker rtree_ctx_t rtree_ctx_fallback;
1088*1208bc7eSAndroid Build Coastguard Worker rtree_ctx_t *rtree_ctx = tsdn_rtree_ctx(tsdn, &rtree_ctx_fallback);
1089*1208bc7eSAndroid Build Coastguard Worker
1090*1208bc7eSAndroid Build Coastguard Worker extent_t *extent = extent_recycle_extract(tsdn, arena, r_extent_hooks,
1091*1208bc7eSAndroid Build Coastguard Worker rtree_ctx, extents, new_addr, size, pad, alignment, slab,
1092*1208bc7eSAndroid Build Coastguard Worker growing_retained);
1093*1208bc7eSAndroid Build Coastguard Worker if (extent == NULL) {
1094*1208bc7eSAndroid Build Coastguard Worker return NULL;
1095*1208bc7eSAndroid Build Coastguard Worker }
1096*1208bc7eSAndroid Build Coastguard Worker
1097*1208bc7eSAndroid Build Coastguard Worker extent = extent_recycle_split(tsdn, arena, r_extent_hooks, rtree_ctx,
1098*1208bc7eSAndroid Build Coastguard Worker extents, new_addr, size, pad, alignment, slab, szind, extent,
1099*1208bc7eSAndroid Build Coastguard Worker growing_retained);
1100*1208bc7eSAndroid Build Coastguard Worker if (extent == NULL) {
1101*1208bc7eSAndroid Build Coastguard Worker return NULL;
1102*1208bc7eSAndroid Build Coastguard Worker }
1103*1208bc7eSAndroid Build Coastguard Worker
1104*1208bc7eSAndroid Build Coastguard Worker if (*commit && !extent_committed_get(extent)) {
1105*1208bc7eSAndroid Build Coastguard Worker if (extent_commit_impl(tsdn, arena, r_extent_hooks, extent,
1106*1208bc7eSAndroid Build Coastguard Worker 0, extent_size_get(extent), growing_retained)) {
1107*1208bc7eSAndroid Build Coastguard Worker extent_record(tsdn, arena, r_extent_hooks, extents,
1108*1208bc7eSAndroid Build Coastguard Worker extent, growing_retained);
1109*1208bc7eSAndroid Build Coastguard Worker return NULL;
1110*1208bc7eSAndroid Build Coastguard Worker }
1111*1208bc7eSAndroid Build Coastguard Worker extent_zeroed_set(extent, true);
1112*1208bc7eSAndroid Build Coastguard Worker }
1113*1208bc7eSAndroid Build Coastguard Worker
1114*1208bc7eSAndroid Build Coastguard Worker if (extent_committed_get(extent)) {
1115*1208bc7eSAndroid Build Coastguard Worker *commit = true;
1116*1208bc7eSAndroid Build Coastguard Worker }
1117*1208bc7eSAndroid Build Coastguard Worker if (extent_zeroed_get(extent)) {
1118*1208bc7eSAndroid Build Coastguard Worker *zero = true;
1119*1208bc7eSAndroid Build Coastguard Worker }
1120*1208bc7eSAndroid Build Coastguard Worker
1121*1208bc7eSAndroid Build Coastguard Worker if (pad != 0) {
1122*1208bc7eSAndroid Build Coastguard Worker extent_addr_randomize(tsdn, extent, alignment);
1123*1208bc7eSAndroid Build Coastguard Worker }
1124*1208bc7eSAndroid Build Coastguard Worker assert(extent_state_get(extent) == extent_state_active);
1125*1208bc7eSAndroid Build Coastguard Worker if (slab) {
1126*1208bc7eSAndroid Build Coastguard Worker extent_slab_set(extent, slab);
1127*1208bc7eSAndroid Build Coastguard Worker extent_interior_register(tsdn, rtree_ctx, extent, szind);
1128*1208bc7eSAndroid Build Coastguard Worker }
1129*1208bc7eSAndroid Build Coastguard Worker
1130*1208bc7eSAndroid Build Coastguard Worker if (*zero) {
1131*1208bc7eSAndroid Build Coastguard Worker void *addr = extent_base_get(extent);
1132*1208bc7eSAndroid Build Coastguard Worker size_t size = extent_size_get(extent);
1133*1208bc7eSAndroid Build Coastguard Worker if (!extent_zeroed_get(extent)) {
1134*1208bc7eSAndroid Build Coastguard Worker if (pages_purge_forced(addr, size)) {
1135*1208bc7eSAndroid Build Coastguard Worker memset(addr, 0, size);
1136*1208bc7eSAndroid Build Coastguard Worker }
1137*1208bc7eSAndroid Build Coastguard Worker } else if (config_debug) {
1138*1208bc7eSAndroid Build Coastguard Worker size_t *p = (size_t *)(uintptr_t)addr;
1139*1208bc7eSAndroid Build Coastguard Worker for (size_t i = 0; i < size / sizeof(size_t); i++) {
1140*1208bc7eSAndroid Build Coastguard Worker assert(p[i] == 0);
1141*1208bc7eSAndroid Build Coastguard Worker }
1142*1208bc7eSAndroid Build Coastguard Worker }
1143*1208bc7eSAndroid Build Coastguard Worker }
1144*1208bc7eSAndroid Build Coastguard Worker return extent;
1145*1208bc7eSAndroid Build Coastguard Worker }
1146*1208bc7eSAndroid Build Coastguard Worker
1147*1208bc7eSAndroid Build Coastguard Worker /*
1148*1208bc7eSAndroid Build Coastguard Worker * If the caller specifies (!*zero), it is still possible to receive zeroed
1149*1208bc7eSAndroid Build Coastguard Worker * memory, in which case *zero is toggled to true. arena_extent_alloc() takes
1150*1208bc7eSAndroid Build Coastguard Worker * advantage of this to avoid demanding zeroed extents, but taking advantage of
1151*1208bc7eSAndroid Build Coastguard Worker * them if they are returned.
1152*1208bc7eSAndroid Build Coastguard Worker */
1153*1208bc7eSAndroid Build Coastguard Worker 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)1154*1208bc7eSAndroid Build Coastguard Worker extent_alloc_core(tsdn_t *tsdn, arena_t *arena, void *new_addr, size_t size,
1155*1208bc7eSAndroid Build Coastguard Worker size_t alignment, bool *zero, bool *commit, dss_prec_t dss_prec) {
1156*1208bc7eSAndroid Build Coastguard Worker void *ret;
1157*1208bc7eSAndroid Build Coastguard Worker
1158*1208bc7eSAndroid Build Coastguard Worker assert(size != 0);
1159*1208bc7eSAndroid Build Coastguard Worker assert(alignment != 0);
1160*1208bc7eSAndroid Build Coastguard Worker
1161*1208bc7eSAndroid Build Coastguard Worker /* "primary" dss. */
1162*1208bc7eSAndroid Build Coastguard Worker if (have_dss && dss_prec == dss_prec_primary && (ret =
1163*1208bc7eSAndroid Build Coastguard Worker extent_alloc_dss(tsdn, arena, new_addr, size, alignment, zero,
1164*1208bc7eSAndroid Build Coastguard Worker commit)) != NULL) {
1165*1208bc7eSAndroid Build Coastguard Worker return ret;
1166*1208bc7eSAndroid Build Coastguard Worker }
1167*1208bc7eSAndroid Build Coastguard Worker /* mmap. */
1168*1208bc7eSAndroid Build Coastguard Worker if ((ret = extent_alloc_mmap(new_addr, size, alignment, zero, commit))
1169*1208bc7eSAndroid Build Coastguard Worker != NULL) {
1170*1208bc7eSAndroid Build Coastguard Worker return ret;
1171*1208bc7eSAndroid Build Coastguard Worker }
1172*1208bc7eSAndroid Build Coastguard Worker /* "secondary" dss. */
1173*1208bc7eSAndroid Build Coastguard Worker if (have_dss && dss_prec == dss_prec_secondary && (ret =
1174*1208bc7eSAndroid Build Coastguard Worker extent_alloc_dss(tsdn, arena, new_addr, size, alignment, zero,
1175*1208bc7eSAndroid Build Coastguard Worker commit)) != NULL) {
1176*1208bc7eSAndroid Build Coastguard Worker return ret;
1177*1208bc7eSAndroid Build Coastguard Worker }
1178*1208bc7eSAndroid Build Coastguard Worker
1179*1208bc7eSAndroid Build Coastguard Worker /* All strategies for allocation failed. */
1180*1208bc7eSAndroid Build Coastguard Worker return NULL;
1181*1208bc7eSAndroid Build Coastguard Worker }
1182*1208bc7eSAndroid Build Coastguard Worker
1183*1208bc7eSAndroid Build Coastguard Worker static void *
extent_alloc_default_impl(tsdn_t * tsdn,arena_t * arena,void * new_addr,size_t size,size_t alignment,bool * zero,bool * commit)1184*1208bc7eSAndroid Build Coastguard Worker extent_alloc_default_impl(tsdn_t *tsdn, arena_t *arena, void *new_addr,
1185*1208bc7eSAndroid Build Coastguard Worker size_t size, size_t alignment, bool *zero, bool *commit) {
1186*1208bc7eSAndroid Build Coastguard Worker void *ret = extent_alloc_core(tsdn, arena, new_addr, size, alignment, zero,
1187*1208bc7eSAndroid Build Coastguard Worker commit, (dss_prec_t)atomic_load_u(&arena->dss_prec,
1188*1208bc7eSAndroid Build Coastguard Worker ATOMIC_RELAXED));
1189*1208bc7eSAndroid Build Coastguard Worker if (have_madvise_huge && ret) {
1190*1208bc7eSAndroid Build Coastguard Worker pages_set_thp_state(ret, size);
1191*1208bc7eSAndroid Build Coastguard Worker }
1192*1208bc7eSAndroid Build Coastguard Worker return ret;
1193*1208bc7eSAndroid Build Coastguard Worker }
1194*1208bc7eSAndroid Build Coastguard Worker
1195*1208bc7eSAndroid Build Coastguard Worker static void *
extent_alloc_default(extent_hooks_t * extent_hooks,void * new_addr,size_t size,size_t alignment,bool * zero,bool * commit,unsigned arena_ind)1196*1208bc7eSAndroid Build Coastguard Worker extent_alloc_default(extent_hooks_t *extent_hooks, void *new_addr, size_t size,
1197*1208bc7eSAndroid Build Coastguard Worker size_t alignment, bool *zero, bool *commit, unsigned arena_ind) {
1198*1208bc7eSAndroid Build Coastguard Worker tsdn_t *tsdn;
1199*1208bc7eSAndroid Build Coastguard Worker arena_t *arena;
1200*1208bc7eSAndroid Build Coastguard Worker
1201*1208bc7eSAndroid Build Coastguard Worker tsdn = tsdn_fetch();
1202*1208bc7eSAndroid Build Coastguard Worker arena = arena_get(tsdn, arena_ind, false);
1203*1208bc7eSAndroid Build Coastguard Worker /*
1204*1208bc7eSAndroid Build Coastguard Worker * The arena we're allocating on behalf of must have been initialized
1205*1208bc7eSAndroid Build Coastguard Worker * already.
1206*1208bc7eSAndroid Build Coastguard Worker */
1207*1208bc7eSAndroid Build Coastguard Worker assert(arena != NULL);
1208*1208bc7eSAndroid Build Coastguard Worker
1209*1208bc7eSAndroid Build Coastguard Worker return extent_alloc_default_impl(tsdn, arena, new_addr, size,
1210*1208bc7eSAndroid Build Coastguard Worker alignment, zero, commit);
1211*1208bc7eSAndroid Build Coastguard Worker }
1212*1208bc7eSAndroid Build Coastguard Worker
1213*1208bc7eSAndroid Build Coastguard Worker static void
extent_hook_pre_reentrancy(tsdn_t * tsdn,arena_t * arena)1214*1208bc7eSAndroid Build Coastguard Worker extent_hook_pre_reentrancy(tsdn_t *tsdn, arena_t *arena) {
1215*1208bc7eSAndroid Build Coastguard Worker tsd_t *tsd = tsdn_null(tsdn) ? tsd_fetch() : tsdn_tsd(tsdn);
1216*1208bc7eSAndroid Build Coastguard Worker if (arena == arena_get(tsd_tsdn(tsd), 0, false)) {
1217*1208bc7eSAndroid Build Coastguard Worker /*
1218*1208bc7eSAndroid Build Coastguard Worker * The only legitimate case of customized extent hooks for a0 is
1219*1208bc7eSAndroid Build Coastguard Worker * hooks with no allocation activities. One such example is to
1220*1208bc7eSAndroid Build Coastguard Worker * place metadata on pre-allocated resources such as huge pages.
1221*1208bc7eSAndroid Build Coastguard Worker * In that case, rely on reentrancy_level checks to catch
1222*1208bc7eSAndroid Build Coastguard Worker * infinite recursions.
1223*1208bc7eSAndroid Build Coastguard Worker */
1224*1208bc7eSAndroid Build Coastguard Worker pre_reentrancy(tsd, NULL);
1225*1208bc7eSAndroid Build Coastguard Worker } else {
1226*1208bc7eSAndroid Build Coastguard Worker pre_reentrancy(tsd, arena);
1227*1208bc7eSAndroid Build Coastguard Worker }
1228*1208bc7eSAndroid Build Coastguard Worker }
1229*1208bc7eSAndroid Build Coastguard Worker
1230*1208bc7eSAndroid Build Coastguard Worker static void
extent_hook_post_reentrancy(tsdn_t * tsdn)1231*1208bc7eSAndroid Build Coastguard Worker extent_hook_post_reentrancy(tsdn_t *tsdn) {
1232*1208bc7eSAndroid Build Coastguard Worker tsd_t *tsd = tsdn_null(tsdn) ? tsd_fetch() : tsdn_tsd(tsdn);
1233*1208bc7eSAndroid Build Coastguard Worker post_reentrancy(tsd);
1234*1208bc7eSAndroid Build Coastguard Worker }
1235*1208bc7eSAndroid Build Coastguard Worker
1236*1208bc7eSAndroid Build Coastguard Worker /*
1237*1208bc7eSAndroid Build Coastguard Worker * If virtual memory is retained, create increasingly larger extents from which
1238*1208bc7eSAndroid Build Coastguard Worker * to split requested extents in order to limit the total number of disjoint
1239*1208bc7eSAndroid Build Coastguard Worker * virtual memory ranges retained by each arena.
1240*1208bc7eSAndroid Build Coastguard Worker */
1241*1208bc7eSAndroid Build Coastguard Worker static extent_t *
extent_grow_retained(tsdn_t * tsdn,arena_t * arena,extent_hooks_t ** r_extent_hooks,size_t size,size_t pad,size_t alignment,bool slab,szind_t szind,bool * zero,bool * commit)1242*1208bc7eSAndroid Build Coastguard Worker extent_grow_retained(tsdn_t *tsdn, arena_t *arena,
1243*1208bc7eSAndroid Build Coastguard Worker extent_hooks_t **r_extent_hooks, size_t size, size_t pad, size_t alignment,
1244*1208bc7eSAndroid Build Coastguard Worker bool slab, szind_t szind, bool *zero, bool *commit) {
1245*1208bc7eSAndroid Build Coastguard Worker malloc_mutex_assert_owner(tsdn, &arena->extent_grow_mtx);
1246*1208bc7eSAndroid Build Coastguard Worker assert(pad == 0 || !slab);
1247*1208bc7eSAndroid Build Coastguard Worker assert(!*zero || !slab);
1248*1208bc7eSAndroid Build Coastguard Worker
1249*1208bc7eSAndroid Build Coastguard Worker size_t esize = size + pad;
1250*1208bc7eSAndroid Build Coastguard Worker size_t alloc_size_min = esize + PAGE_CEILING(alignment) - PAGE;
1251*1208bc7eSAndroid Build Coastguard Worker /* Beware size_t wrap-around. */
1252*1208bc7eSAndroid Build Coastguard Worker if (alloc_size_min < esize) {
1253*1208bc7eSAndroid Build Coastguard Worker goto label_err;
1254*1208bc7eSAndroid Build Coastguard Worker }
1255*1208bc7eSAndroid Build Coastguard Worker /*
1256*1208bc7eSAndroid Build Coastguard Worker * Find the next extent size in the series that would be large enough to
1257*1208bc7eSAndroid Build Coastguard Worker * satisfy this request.
1258*1208bc7eSAndroid Build Coastguard Worker */
1259*1208bc7eSAndroid Build Coastguard Worker pszind_t egn_skip = 0;
1260*1208bc7eSAndroid Build Coastguard Worker size_t alloc_size = sz_pind2sz(arena->extent_grow_next + egn_skip);
1261*1208bc7eSAndroid Build Coastguard Worker while (alloc_size < alloc_size_min) {
1262*1208bc7eSAndroid Build Coastguard Worker egn_skip++;
1263*1208bc7eSAndroid Build Coastguard Worker if (arena->extent_grow_next + egn_skip == NPSIZES) {
1264*1208bc7eSAndroid Build Coastguard Worker /* Outside legal range. */
1265*1208bc7eSAndroid Build Coastguard Worker goto label_err;
1266*1208bc7eSAndroid Build Coastguard Worker }
1267*1208bc7eSAndroid Build Coastguard Worker assert(arena->extent_grow_next + egn_skip < NPSIZES);
1268*1208bc7eSAndroid Build Coastguard Worker alloc_size = sz_pind2sz(arena->extent_grow_next + egn_skip);
1269*1208bc7eSAndroid Build Coastguard Worker }
1270*1208bc7eSAndroid Build Coastguard Worker
1271*1208bc7eSAndroid Build Coastguard Worker extent_t *extent = extent_alloc(tsdn, arena);
1272*1208bc7eSAndroid Build Coastguard Worker if (extent == NULL) {
1273*1208bc7eSAndroid Build Coastguard Worker goto label_err;
1274*1208bc7eSAndroid Build Coastguard Worker }
1275*1208bc7eSAndroid Build Coastguard Worker bool zeroed = false;
1276*1208bc7eSAndroid Build Coastguard Worker bool committed = false;
1277*1208bc7eSAndroid Build Coastguard Worker
1278*1208bc7eSAndroid Build Coastguard Worker void *ptr;
1279*1208bc7eSAndroid Build Coastguard Worker if (*r_extent_hooks == &extent_hooks_default) {
1280*1208bc7eSAndroid Build Coastguard Worker ptr = extent_alloc_default_impl(tsdn, arena, NULL,
1281*1208bc7eSAndroid Build Coastguard Worker alloc_size, PAGE, &zeroed, &committed);
1282*1208bc7eSAndroid Build Coastguard Worker } else {
1283*1208bc7eSAndroid Build Coastguard Worker extent_hook_pre_reentrancy(tsdn, arena);
1284*1208bc7eSAndroid Build Coastguard Worker ptr = (*r_extent_hooks)->alloc(*r_extent_hooks, NULL,
1285*1208bc7eSAndroid Build Coastguard Worker alloc_size, PAGE, &zeroed, &committed,
1286*1208bc7eSAndroid Build Coastguard Worker arena_ind_get(arena));
1287*1208bc7eSAndroid Build Coastguard Worker extent_hook_post_reentrancy(tsdn);
1288*1208bc7eSAndroid Build Coastguard Worker }
1289*1208bc7eSAndroid Build Coastguard Worker
1290*1208bc7eSAndroid Build Coastguard Worker extent_init(extent, arena, ptr, alloc_size, false, NSIZES,
1291*1208bc7eSAndroid Build Coastguard Worker arena_extent_sn_next(arena), extent_state_active, zeroed,
1292*1208bc7eSAndroid Build Coastguard Worker committed, true);
1293*1208bc7eSAndroid Build Coastguard Worker if (ptr == NULL) {
1294*1208bc7eSAndroid Build Coastguard Worker extent_dalloc(tsdn, arena, extent);
1295*1208bc7eSAndroid Build Coastguard Worker goto label_err;
1296*1208bc7eSAndroid Build Coastguard Worker }
1297*1208bc7eSAndroid Build Coastguard Worker
1298*1208bc7eSAndroid Build Coastguard Worker if (extent_register_no_gdump_add(tsdn, extent)) {
1299*1208bc7eSAndroid Build Coastguard Worker extents_leak(tsdn, arena, r_extent_hooks,
1300*1208bc7eSAndroid Build Coastguard Worker &arena->extents_retained, extent, true);
1301*1208bc7eSAndroid Build Coastguard Worker goto label_err;
1302*1208bc7eSAndroid Build Coastguard Worker }
1303*1208bc7eSAndroid Build Coastguard Worker
1304*1208bc7eSAndroid Build Coastguard Worker if (extent_zeroed_get(extent) && extent_committed_get(extent)) {
1305*1208bc7eSAndroid Build Coastguard Worker *zero = true;
1306*1208bc7eSAndroid Build Coastguard Worker }
1307*1208bc7eSAndroid Build Coastguard Worker if (extent_committed_get(extent)) {
1308*1208bc7eSAndroid Build Coastguard Worker *commit = true;
1309*1208bc7eSAndroid Build Coastguard Worker }
1310*1208bc7eSAndroid Build Coastguard Worker
1311*1208bc7eSAndroid Build Coastguard Worker rtree_ctx_t rtree_ctx_fallback;
1312*1208bc7eSAndroid Build Coastguard Worker rtree_ctx_t *rtree_ctx = tsdn_rtree_ctx(tsdn, &rtree_ctx_fallback);
1313*1208bc7eSAndroid Build Coastguard Worker
1314*1208bc7eSAndroid Build Coastguard Worker extent_t *lead;
1315*1208bc7eSAndroid Build Coastguard Worker extent_t *trail;
1316*1208bc7eSAndroid Build Coastguard Worker extent_t *to_leak;
1317*1208bc7eSAndroid Build Coastguard Worker extent_t *to_salvage;
1318*1208bc7eSAndroid Build Coastguard Worker extent_split_interior_result_t result = extent_split_interior(
1319*1208bc7eSAndroid Build Coastguard Worker tsdn, arena, r_extent_hooks, rtree_ctx, &extent, &lead, &trail,
1320*1208bc7eSAndroid Build Coastguard Worker &to_leak, &to_salvage, NULL, size, pad, alignment, slab, szind,
1321*1208bc7eSAndroid Build Coastguard Worker true);
1322*1208bc7eSAndroid Build Coastguard Worker
1323*1208bc7eSAndroid Build Coastguard Worker if (result == extent_split_interior_ok) {
1324*1208bc7eSAndroid Build Coastguard Worker if (lead != NULL) {
1325*1208bc7eSAndroid Build Coastguard Worker extent_record(tsdn, arena, r_extent_hooks,
1326*1208bc7eSAndroid Build Coastguard Worker &arena->extents_retained, lead, true);
1327*1208bc7eSAndroid Build Coastguard Worker }
1328*1208bc7eSAndroid Build Coastguard Worker if (trail != NULL) {
1329*1208bc7eSAndroid Build Coastguard Worker extent_record(tsdn, arena, r_extent_hooks,
1330*1208bc7eSAndroid Build Coastguard Worker &arena->extents_retained, trail, true);
1331*1208bc7eSAndroid Build Coastguard Worker }
1332*1208bc7eSAndroid Build Coastguard Worker } else {
1333*1208bc7eSAndroid Build Coastguard Worker /*
1334*1208bc7eSAndroid Build Coastguard Worker * We should have allocated a sufficiently large extent; the
1335*1208bc7eSAndroid Build Coastguard Worker * cant_alloc case should not occur.
1336*1208bc7eSAndroid Build Coastguard Worker */
1337*1208bc7eSAndroid Build Coastguard Worker assert(result == extent_split_interior_error);
1338*1208bc7eSAndroid Build Coastguard Worker if (to_salvage != NULL) {
1339*1208bc7eSAndroid Build Coastguard Worker if (config_prof) {
1340*1208bc7eSAndroid Build Coastguard Worker extent_gdump_add(tsdn, to_salvage);
1341*1208bc7eSAndroid Build Coastguard Worker }
1342*1208bc7eSAndroid Build Coastguard Worker extent_record(tsdn, arena, r_extent_hooks,
1343*1208bc7eSAndroid Build Coastguard Worker &arena->extents_retained, to_salvage, true);
1344*1208bc7eSAndroid Build Coastguard Worker }
1345*1208bc7eSAndroid Build Coastguard Worker if (to_leak != NULL) {
1346*1208bc7eSAndroid Build Coastguard Worker extent_deregister_no_gdump_sub(tsdn, to_leak);
1347*1208bc7eSAndroid Build Coastguard Worker extents_leak(tsdn, arena, r_extent_hooks,
1348*1208bc7eSAndroid Build Coastguard Worker &arena->extents_retained, to_leak, true);
1349*1208bc7eSAndroid Build Coastguard Worker }
1350*1208bc7eSAndroid Build Coastguard Worker goto label_err;
1351*1208bc7eSAndroid Build Coastguard Worker }
1352*1208bc7eSAndroid Build Coastguard Worker
1353*1208bc7eSAndroid Build Coastguard Worker if (*commit && !extent_committed_get(extent)) {
1354*1208bc7eSAndroid Build Coastguard Worker if (extent_commit_impl(tsdn, arena, r_extent_hooks, extent, 0,
1355*1208bc7eSAndroid Build Coastguard Worker extent_size_get(extent), true)) {
1356*1208bc7eSAndroid Build Coastguard Worker extent_record(tsdn, arena, r_extent_hooks,
1357*1208bc7eSAndroid Build Coastguard Worker &arena->extents_retained, extent, true);
1358*1208bc7eSAndroid Build Coastguard Worker goto label_err;
1359*1208bc7eSAndroid Build Coastguard Worker }
1360*1208bc7eSAndroid Build Coastguard Worker extent_zeroed_set(extent, true);
1361*1208bc7eSAndroid Build Coastguard Worker }
1362*1208bc7eSAndroid Build Coastguard Worker
1363*1208bc7eSAndroid Build Coastguard Worker /*
1364*1208bc7eSAndroid Build Coastguard Worker * Increment extent_grow_next if doing so wouldn't exceed the allowed
1365*1208bc7eSAndroid Build Coastguard Worker * range.
1366*1208bc7eSAndroid Build Coastguard Worker */
1367*1208bc7eSAndroid Build Coastguard Worker if (arena->extent_grow_next + egn_skip + 1 <=
1368*1208bc7eSAndroid Build Coastguard Worker arena->retain_grow_limit) {
1369*1208bc7eSAndroid Build Coastguard Worker arena->extent_grow_next += egn_skip + 1;
1370*1208bc7eSAndroid Build Coastguard Worker } else {
1371*1208bc7eSAndroid Build Coastguard Worker arena->extent_grow_next = arena->retain_grow_limit;
1372*1208bc7eSAndroid Build Coastguard Worker }
1373*1208bc7eSAndroid Build Coastguard Worker /* All opportunities for failure are past. */
1374*1208bc7eSAndroid Build Coastguard Worker malloc_mutex_unlock(tsdn, &arena->extent_grow_mtx);
1375*1208bc7eSAndroid Build Coastguard Worker
1376*1208bc7eSAndroid Build Coastguard Worker if (config_prof) {
1377*1208bc7eSAndroid Build Coastguard Worker /* Adjust gdump stats now that extent is final size. */
1378*1208bc7eSAndroid Build Coastguard Worker extent_gdump_add(tsdn, extent);
1379*1208bc7eSAndroid Build Coastguard Worker }
1380*1208bc7eSAndroid Build Coastguard Worker if (pad != 0) {
1381*1208bc7eSAndroid Build Coastguard Worker extent_addr_randomize(tsdn, extent, alignment);
1382*1208bc7eSAndroid Build Coastguard Worker }
1383*1208bc7eSAndroid Build Coastguard Worker if (slab) {
1384*1208bc7eSAndroid Build Coastguard Worker rtree_ctx_t rtree_ctx_fallback;
1385*1208bc7eSAndroid Build Coastguard Worker rtree_ctx_t *rtree_ctx = tsdn_rtree_ctx(tsdn,
1386*1208bc7eSAndroid Build Coastguard Worker &rtree_ctx_fallback);
1387*1208bc7eSAndroid Build Coastguard Worker
1388*1208bc7eSAndroid Build Coastguard Worker extent_slab_set(extent, true);
1389*1208bc7eSAndroid Build Coastguard Worker extent_interior_register(tsdn, rtree_ctx, extent, szind);
1390*1208bc7eSAndroid Build Coastguard Worker }
1391*1208bc7eSAndroid Build Coastguard Worker if (*zero && !extent_zeroed_get(extent)) {
1392*1208bc7eSAndroid Build Coastguard Worker void *addr = extent_base_get(extent);
1393*1208bc7eSAndroid Build Coastguard Worker size_t size = extent_size_get(extent);
1394*1208bc7eSAndroid Build Coastguard Worker if (pages_purge_forced(addr, size)) {
1395*1208bc7eSAndroid Build Coastguard Worker memset(addr, 0, size);
1396*1208bc7eSAndroid Build Coastguard Worker }
1397*1208bc7eSAndroid Build Coastguard Worker }
1398*1208bc7eSAndroid Build Coastguard Worker
1399*1208bc7eSAndroid Build Coastguard Worker return extent;
1400*1208bc7eSAndroid Build Coastguard Worker label_err:
1401*1208bc7eSAndroid Build Coastguard Worker malloc_mutex_unlock(tsdn, &arena->extent_grow_mtx);
1402*1208bc7eSAndroid Build Coastguard Worker return NULL;
1403*1208bc7eSAndroid Build Coastguard Worker }
1404*1208bc7eSAndroid Build Coastguard Worker
1405*1208bc7eSAndroid Build Coastguard Worker static extent_t *
extent_alloc_retained(tsdn_t * tsdn,arena_t * arena,extent_hooks_t ** r_extent_hooks,void * new_addr,size_t size,size_t pad,size_t alignment,bool slab,szind_t szind,bool * zero,bool * commit)1406*1208bc7eSAndroid Build Coastguard Worker extent_alloc_retained(tsdn_t *tsdn, arena_t *arena,
1407*1208bc7eSAndroid Build Coastguard Worker extent_hooks_t **r_extent_hooks, void *new_addr, size_t size, size_t pad,
1408*1208bc7eSAndroid Build Coastguard Worker size_t alignment, bool slab, szind_t szind, bool *zero, bool *commit) {
1409*1208bc7eSAndroid Build Coastguard Worker assert(size != 0);
1410*1208bc7eSAndroid Build Coastguard Worker assert(alignment != 0);
1411*1208bc7eSAndroid Build Coastguard Worker
1412*1208bc7eSAndroid Build Coastguard Worker malloc_mutex_lock(tsdn, &arena->extent_grow_mtx);
1413*1208bc7eSAndroid Build Coastguard Worker
1414*1208bc7eSAndroid Build Coastguard Worker extent_t *extent = extent_recycle(tsdn, arena, r_extent_hooks,
1415*1208bc7eSAndroid Build Coastguard Worker &arena->extents_retained, new_addr, size, pad, alignment, slab,
1416*1208bc7eSAndroid Build Coastguard Worker szind, zero, commit, true);
1417*1208bc7eSAndroid Build Coastguard Worker if (extent != NULL) {
1418*1208bc7eSAndroid Build Coastguard Worker malloc_mutex_unlock(tsdn, &arena->extent_grow_mtx);
1419*1208bc7eSAndroid Build Coastguard Worker if (config_prof) {
1420*1208bc7eSAndroid Build Coastguard Worker extent_gdump_add(tsdn, extent);
1421*1208bc7eSAndroid Build Coastguard Worker }
1422*1208bc7eSAndroid Build Coastguard Worker } else if (opt_retain && new_addr == NULL) {
1423*1208bc7eSAndroid Build Coastguard Worker extent = extent_grow_retained(tsdn, arena, r_extent_hooks, size,
1424*1208bc7eSAndroid Build Coastguard Worker pad, alignment, slab, szind, zero, commit);
1425*1208bc7eSAndroid Build Coastguard Worker /* extent_grow_retained() always releases extent_grow_mtx. */
1426*1208bc7eSAndroid Build Coastguard Worker } else {
1427*1208bc7eSAndroid Build Coastguard Worker malloc_mutex_unlock(tsdn, &arena->extent_grow_mtx);
1428*1208bc7eSAndroid Build Coastguard Worker }
1429*1208bc7eSAndroid Build Coastguard Worker malloc_mutex_assert_not_owner(tsdn, &arena->extent_grow_mtx);
1430*1208bc7eSAndroid Build Coastguard Worker
1431*1208bc7eSAndroid Build Coastguard Worker return extent;
1432*1208bc7eSAndroid Build Coastguard Worker }
1433*1208bc7eSAndroid Build Coastguard Worker
1434*1208bc7eSAndroid Build Coastguard Worker static extent_t *
extent_alloc_wrapper_hard(tsdn_t * tsdn,arena_t * arena,extent_hooks_t ** r_extent_hooks,void * new_addr,size_t size,size_t pad,size_t alignment,bool slab,szind_t szind,bool * zero,bool * commit)1435*1208bc7eSAndroid Build Coastguard Worker extent_alloc_wrapper_hard(tsdn_t *tsdn, arena_t *arena,
1436*1208bc7eSAndroid Build Coastguard Worker extent_hooks_t **r_extent_hooks, void *new_addr, size_t size, size_t pad,
1437*1208bc7eSAndroid Build Coastguard Worker size_t alignment, bool slab, szind_t szind, bool *zero, bool *commit) {
1438*1208bc7eSAndroid Build Coastguard Worker size_t esize = size + pad;
1439*1208bc7eSAndroid Build Coastguard Worker extent_t *extent = extent_alloc(tsdn, arena);
1440*1208bc7eSAndroid Build Coastguard Worker if (extent == NULL) {
1441*1208bc7eSAndroid Build Coastguard Worker return NULL;
1442*1208bc7eSAndroid Build Coastguard Worker }
1443*1208bc7eSAndroid Build Coastguard Worker void *addr;
1444*1208bc7eSAndroid Build Coastguard Worker if (*r_extent_hooks == &extent_hooks_default) {
1445*1208bc7eSAndroid Build Coastguard Worker /* Call directly to propagate tsdn. */
1446*1208bc7eSAndroid Build Coastguard Worker addr = extent_alloc_default_impl(tsdn, arena, new_addr, esize,
1447*1208bc7eSAndroid Build Coastguard Worker alignment, zero, commit);
1448*1208bc7eSAndroid Build Coastguard Worker } else {
1449*1208bc7eSAndroid Build Coastguard Worker extent_hook_pre_reentrancy(tsdn, arena);
1450*1208bc7eSAndroid Build Coastguard Worker addr = (*r_extent_hooks)->alloc(*r_extent_hooks, new_addr,
1451*1208bc7eSAndroid Build Coastguard Worker esize, alignment, zero, commit, arena_ind_get(arena));
1452*1208bc7eSAndroid Build Coastguard Worker extent_hook_post_reentrancy(tsdn);
1453*1208bc7eSAndroid Build Coastguard Worker }
1454*1208bc7eSAndroid Build Coastguard Worker if (addr == NULL) {
1455*1208bc7eSAndroid Build Coastguard Worker extent_dalloc(tsdn, arena, extent);
1456*1208bc7eSAndroid Build Coastguard Worker return NULL;
1457*1208bc7eSAndroid Build Coastguard Worker }
1458*1208bc7eSAndroid Build Coastguard Worker extent_init(extent, arena, addr, esize, slab, szind,
1459*1208bc7eSAndroid Build Coastguard Worker arena_extent_sn_next(arena), extent_state_active, *zero, *commit,
1460*1208bc7eSAndroid Build Coastguard Worker true);
1461*1208bc7eSAndroid Build Coastguard Worker if (pad != 0) {
1462*1208bc7eSAndroid Build Coastguard Worker extent_addr_randomize(tsdn, extent, alignment);
1463*1208bc7eSAndroid Build Coastguard Worker }
1464*1208bc7eSAndroid Build Coastguard Worker if (extent_register(tsdn, extent)) {
1465*1208bc7eSAndroid Build Coastguard Worker extents_leak(tsdn, arena, r_extent_hooks,
1466*1208bc7eSAndroid Build Coastguard Worker &arena->extents_retained, extent, false);
1467*1208bc7eSAndroid Build Coastguard Worker return NULL;
1468*1208bc7eSAndroid Build Coastguard Worker }
1469*1208bc7eSAndroid Build Coastguard Worker
1470*1208bc7eSAndroid Build Coastguard Worker return extent;
1471*1208bc7eSAndroid Build Coastguard Worker }
1472*1208bc7eSAndroid Build Coastguard Worker
1473*1208bc7eSAndroid Build Coastguard Worker extent_t *
extent_alloc_wrapper(tsdn_t * tsdn,arena_t * arena,extent_hooks_t ** r_extent_hooks,void * new_addr,size_t size,size_t pad,size_t alignment,bool slab,szind_t szind,bool * zero,bool * commit)1474*1208bc7eSAndroid Build Coastguard Worker extent_alloc_wrapper(tsdn_t *tsdn, arena_t *arena,
1475*1208bc7eSAndroid Build Coastguard Worker extent_hooks_t **r_extent_hooks, void *new_addr, size_t size, size_t pad,
1476*1208bc7eSAndroid Build Coastguard Worker size_t alignment, bool slab, szind_t szind, bool *zero, bool *commit) {
1477*1208bc7eSAndroid Build Coastguard Worker witness_assert_depth_to_rank(tsdn_witness_tsdp_get(tsdn),
1478*1208bc7eSAndroid Build Coastguard Worker WITNESS_RANK_CORE, 0);
1479*1208bc7eSAndroid Build Coastguard Worker
1480*1208bc7eSAndroid Build Coastguard Worker extent_hooks_assure_initialized(arena, r_extent_hooks);
1481*1208bc7eSAndroid Build Coastguard Worker
1482*1208bc7eSAndroid Build Coastguard Worker extent_t *extent = extent_alloc_retained(tsdn, arena, r_extent_hooks,
1483*1208bc7eSAndroid Build Coastguard Worker new_addr, size, pad, alignment, slab, szind, zero, commit);
1484*1208bc7eSAndroid Build Coastguard Worker if (extent == NULL) {
1485*1208bc7eSAndroid Build Coastguard Worker if (opt_retain && new_addr != NULL) {
1486*1208bc7eSAndroid Build Coastguard Worker /*
1487*1208bc7eSAndroid Build Coastguard Worker * When retain is enabled and new_addr is set, we do not
1488*1208bc7eSAndroid Build Coastguard Worker * attempt extent_alloc_wrapper_hard which does mmap
1489*1208bc7eSAndroid Build Coastguard Worker * that is very unlikely to succeed (unless it happens
1490*1208bc7eSAndroid Build Coastguard Worker * to be at the end).
1491*1208bc7eSAndroid Build Coastguard Worker */
1492*1208bc7eSAndroid Build Coastguard Worker return NULL;
1493*1208bc7eSAndroid Build Coastguard Worker }
1494*1208bc7eSAndroid Build Coastguard Worker extent = extent_alloc_wrapper_hard(tsdn, arena, r_extent_hooks,
1495*1208bc7eSAndroid Build Coastguard Worker new_addr, size, pad, alignment, slab, szind, zero, commit);
1496*1208bc7eSAndroid Build Coastguard Worker }
1497*1208bc7eSAndroid Build Coastguard Worker
1498*1208bc7eSAndroid Build Coastguard Worker assert(extent == NULL || extent_dumpable_get(extent));
1499*1208bc7eSAndroid Build Coastguard Worker return extent;
1500*1208bc7eSAndroid Build Coastguard Worker }
1501*1208bc7eSAndroid Build Coastguard Worker
1502*1208bc7eSAndroid Build Coastguard Worker static bool
extent_can_coalesce(arena_t * arena,extents_t * extents,const extent_t * inner,const extent_t * outer)1503*1208bc7eSAndroid Build Coastguard Worker extent_can_coalesce(arena_t *arena, extents_t *extents, const extent_t *inner,
1504*1208bc7eSAndroid Build Coastguard Worker const extent_t *outer) {
1505*1208bc7eSAndroid Build Coastguard Worker assert(extent_arena_get(inner) == arena);
1506*1208bc7eSAndroid Build Coastguard Worker if (extent_arena_get(outer) != arena) {
1507*1208bc7eSAndroid Build Coastguard Worker return false;
1508*1208bc7eSAndroid Build Coastguard Worker }
1509*1208bc7eSAndroid Build Coastguard Worker
1510*1208bc7eSAndroid Build Coastguard Worker assert(extent_state_get(inner) == extent_state_active);
1511*1208bc7eSAndroid Build Coastguard Worker if (extent_state_get(outer) != extents->state) {
1512*1208bc7eSAndroid Build Coastguard Worker return false;
1513*1208bc7eSAndroid Build Coastguard Worker }
1514*1208bc7eSAndroid Build Coastguard Worker
1515*1208bc7eSAndroid Build Coastguard Worker if (extent_committed_get(inner) != extent_committed_get(outer)) {
1516*1208bc7eSAndroid Build Coastguard Worker return false;
1517*1208bc7eSAndroid Build Coastguard Worker }
1518*1208bc7eSAndroid Build Coastguard Worker
1519*1208bc7eSAndroid Build Coastguard Worker return true;
1520*1208bc7eSAndroid Build Coastguard Worker }
1521*1208bc7eSAndroid Build Coastguard Worker
1522*1208bc7eSAndroid Build Coastguard Worker static bool
extent_coalesce(tsdn_t * tsdn,arena_t * arena,extent_hooks_t ** r_extent_hooks,extents_t * extents,extent_t * inner,extent_t * outer,bool forward,bool growing_retained)1523*1208bc7eSAndroid Build Coastguard Worker extent_coalesce(tsdn_t *tsdn, arena_t *arena, extent_hooks_t **r_extent_hooks,
1524*1208bc7eSAndroid Build Coastguard Worker extents_t *extents, extent_t *inner, extent_t *outer, bool forward,
1525*1208bc7eSAndroid Build Coastguard Worker bool growing_retained) {
1526*1208bc7eSAndroid Build Coastguard Worker assert(extent_can_coalesce(arena, extents, inner, outer));
1527*1208bc7eSAndroid Build Coastguard Worker
1528*1208bc7eSAndroid Build Coastguard Worker extent_activate_locked(tsdn, arena, extents, outer);
1529*1208bc7eSAndroid Build Coastguard Worker
1530*1208bc7eSAndroid Build Coastguard Worker malloc_mutex_unlock(tsdn, &extents->mtx);
1531*1208bc7eSAndroid Build Coastguard Worker bool err = extent_merge_impl(tsdn, arena, r_extent_hooks,
1532*1208bc7eSAndroid Build Coastguard Worker forward ? inner : outer, forward ? outer : inner, growing_retained);
1533*1208bc7eSAndroid Build Coastguard Worker malloc_mutex_lock(tsdn, &extents->mtx);
1534*1208bc7eSAndroid Build Coastguard Worker
1535*1208bc7eSAndroid Build Coastguard Worker if (err) {
1536*1208bc7eSAndroid Build Coastguard Worker extent_deactivate_locked(tsdn, arena, extents, outer);
1537*1208bc7eSAndroid Build Coastguard Worker }
1538*1208bc7eSAndroid Build Coastguard Worker
1539*1208bc7eSAndroid Build Coastguard Worker return err;
1540*1208bc7eSAndroid Build Coastguard Worker }
1541*1208bc7eSAndroid Build Coastguard Worker
1542*1208bc7eSAndroid Build Coastguard Worker static extent_t *
extent_try_coalesce(tsdn_t * tsdn,arena_t * arena,extent_hooks_t ** r_extent_hooks,rtree_ctx_t * rtree_ctx,extents_t * extents,extent_t * extent,bool * coalesced,bool growing_retained)1543*1208bc7eSAndroid Build Coastguard Worker extent_try_coalesce(tsdn_t *tsdn, arena_t *arena,
1544*1208bc7eSAndroid Build Coastguard Worker extent_hooks_t **r_extent_hooks, rtree_ctx_t *rtree_ctx, extents_t *extents,
1545*1208bc7eSAndroid Build Coastguard Worker extent_t *extent, bool *coalesced, bool growing_retained) {
1546*1208bc7eSAndroid Build Coastguard Worker /*
1547*1208bc7eSAndroid Build Coastguard Worker * Continue attempting to coalesce until failure, to protect against
1548*1208bc7eSAndroid Build Coastguard Worker * races with other threads that are thwarted by this one.
1549*1208bc7eSAndroid Build Coastguard Worker */
1550*1208bc7eSAndroid Build Coastguard Worker bool again;
1551*1208bc7eSAndroid Build Coastguard Worker do {
1552*1208bc7eSAndroid Build Coastguard Worker again = false;
1553*1208bc7eSAndroid Build Coastguard Worker
1554*1208bc7eSAndroid Build Coastguard Worker /* Try to coalesce forward. */
1555*1208bc7eSAndroid Build Coastguard Worker extent_t *next = extent_lock_from_addr(tsdn, rtree_ctx,
1556*1208bc7eSAndroid Build Coastguard Worker extent_past_get(extent));
1557*1208bc7eSAndroid Build Coastguard Worker if (next != NULL) {
1558*1208bc7eSAndroid Build Coastguard Worker /*
1559*1208bc7eSAndroid Build Coastguard Worker * extents->mtx only protects against races for
1560*1208bc7eSAndroid Build Coastguard Worker * like-state extents, so call extent_can_coalesce()
1561*1208bc7eSAndroid Build Coastguard Worker * before releasing next's pool lock.
1562*1208bc7eSAndroid Build Coastguard Worker */
1563*1208bc7eSAndroid Build Coastguard Worker bool can_coalesce = extent_can_coalesce(arena, extents,
1564*1208bc7eSAndroid Build Coastguard Worker extent, next);
1565*1208bc7eSAndroid Build Coastguard Worker
1566*1208bc7eSAndroid Build Coastguard Worker extent_unlock(tsdn, next);
1567*1208bc7eSAndroid Build Coastguard Worker
1568*1208bc7eSAndroid Build Coastguard Worker if (can_coalesce && !extent_coalesce(tsdn, arena,
1569*1208bc7eSAndroid Build Coastguard Worker r_extent_hooks, extents, extent, next, true,
1570*1208bc7eSAndroid Build Coastguard Worker growing_retained)) {
1571*1208bc7eSAndroid Build Coastguard Worker if (extents->delay_coalesce) {
1572*1208bc7eSAndroid Build Coastguard Worker /* Do minimal coalescing. */
1573*1208bc7eSAndroid Build Coastguard Worker *coalesced = true;
1574*1208bc7eSAndroid Build Coastguard Worker return extent;
1575*1208bc7eSAndroid Build Coastguard Worker }
1576*1208bc7eSAndroid Build Coastguard Worker again = true;
1577*1208bc7eSAndroid Build Coastguard Worker }
1578*1208bc7eSAndroid Build Coastguard Worker }
1579*1208bc7eSAndroid Build Coastguard Worker
1580*1208bc7eSAndroid Build Coastguard Worker /* Try to coalesce backward. */
1581*1208bc7eSAndroid Build Coastguard Worker extent_t *prev = extent_lock_from_addr(tsdn, rtree_ctx,
1582*1208bc7eSAndroid Build Coastguard Worker extent_before_get(extent));
1583*1208bc7eSAndroid Build Coastguard Worker if (prev != NULL) {
1584*1208bc7eSAndroid Build Coastguard Worker bool can_coalesce = extent_can_coalesce(arena, extents,
1585*1208bc7eSAndroid Build Coastguard Worker extent, prev);
1586*1208bc7eSAndroid Build Coastguard Worker extent_unlock(tsdn, prev);
1587*1208bc7eSAndroid Build Coastguard Worker
1588*1208bc7eSAndroid Build Coastguard Worker if (can_coalesce && !extent_coalesce(tsdn, arena,
1589*1208bc7eSAndroid Build Coastguard Worker r_extent_hooks, extents, extent, prev, false,
1590*1208bc7eSAndroid Build Coastguard Worker growing_retained)) {
1591*1208bc7eSAndroid Build Coastguard Worker extent = prev;
1592*1208bc7eSAndroid Build Coastguard Worker if (extents->delay_coalesce) {
1593*1208bc7eSAndroid Build Coastguard Worker /* Do minimal coalescing. */
1594*1208bc7eSAndroid Build Coastguard Worker *coalesced = true;
1595*1208bc7eSAndroid Build Coastguard Worker return extent;
1596*1208bc7eSAndroid Build Coastguard Worker }
1597*1208bc7eSAndroid Build Coastguard Worker again = true;
1598*1208bc7eSAndroid Build Coastguard Worker }
1599*1208bc7eSAndroid Build Coastguard Worker }
1600*1208bc7eSAndroid Build Coastguard Worker } while (again);
1601*1208bc7eSAndroid Build Coastguard Worker
1602*1208bc7eSAndroid Build Coastguard Worker if (extents->delay_coalesce) {
1603*1208bc7eSAndroid Build Coastguard Worker *coalesced = false;
1604*1208bc7eSAndroid Build Coastguard Worker }
1605*1208bc7eSAndroid Build Coastguard Worker return extent;
1606*1208bc7eSAndroid Build Coastguard Worker }
1607*1208bc7eSAndroid Build Coastguard Worker
1608*1208bc7eSAndroid Build Coastguard Worker /*
1609*1208bc7eSAndroid Build Coastguard Worker * Does the metadata management portions of putting an unused extent into the
1610*1208bc7eSAndroid Build Coastguard Worker * given extents_t (coalesces, deregisters slab interiors, the heap operations).
1611*1208bc7eSAndroid Build Coastguard Worker */
1612*1208bc7eSAndroid Build Coastguard Worker static void
extent_record(tsdn_t * tsdn,arena_t * arena,extent_hooks_t ** r_extent_hooks,extents_t * extents,extent_t * extent,bool growing_retained)1613*1208bc7eSAndroid Build Coastguard Worker extent_record(tsdn_t *tsdn, arena_t *arena, extent_hooks_t **r_extent_hooks,
1614*1208bc7eSAndroid Build Coastguard Worker extents_t *extents, extent_t *extent, bool growing_retained) {
1615*1208bc7eSAndroid Build Coastguard Worker rtree_ctx_t rtree_ctx_fallback;
1616*1208bc7eSAndroid Build Coastguard Worker rtree_ctx_t *rtree_ctx = tsdn_rtree_ctx(tsdn, &rtree_ctx_fallback);
1617*1208bc7eSAndroid Build Coastguard Worker
1618*1208bc7eSAndroid Build Coastguard Worker assert((extents_state_get(extents) != extent_state_dirty &&
1619*1208bc7eSAndroid Build Coastguard Worker extents_state_get(extents) != extent_state_muzzy) ||
1620*1208bc7eSAndroid Build Coastguard Worker !extent_zeroed_get(extent));
1621*1208bc7eSAndroid Build Coastguard Worker
1622*1208bc7eSAndroid Build Coastguard Worker malloc_mutex_lock(tsdn, &extents->mtx);
1623*1208bc7eSAndroid Build Coastguard Worker extent_hooks_assure_initialized(arena, r_extent_hooks);
1624*1208bc7eSAndroid Build Coastguard Worker
1625*1208bc7eSAndroid Build Coastguard Worker extent_szind_set(extent, NSIZES);
1626*1208bc7eSAndroid Build Coastguard Worker if (extent_slab_get(extent)) {
1627*1208bc7eSAndroid Build Coastguard Worker extent_interior_deregister(tsdn, rtree_ctx, extent);
1628*1208bc7eSAndroid Build Coastguard Worker extent_slab_set(extent, false);
1629*1208bc7eSAndroid Build Coastguard Worker }
1630*1208bc7eSAndroid Build Coastguard Worker
1631*1208bc7eSAndroid Build Coastguard Worker assert(rtree_extent_read(tsdn, &extents_rtree, rtree_ctx,
1632*1208bc7eSAndroid Build Coastguard Worker (uintptr_t)extent_base_get(extent), true) == extent);
1633*1208bc7eSAndroid Build Coastguard Worker
1634*1208bc7eSAndroid Build Coastguard Worker if (!extents->delay_coalesce) {
1635*1208bc7eSAndroid Build Coastguard Worker extent = extent_try_coalesce(tsdn, arena, r_extent_hooks,
1636*1208bc7eSAndroid Build Coastguard Worker rtree_ctx, extents, extent, NULL, growing_retained);
1637*1208bc7eSAndroid Build Coastguard Worker } else if (extent_size_get(extent) >= LARGE_MINCLASS) {
1638*1208bc7eSAndroid Build Coastguard Worker /* Always coalesce large extents eagerly. */
1639*1208bc7eSAndroid Build Coastguard Worker bool coalesced;
1640*1208bc7eSAndroid Build Coastguard Worker size_t prev_size;
1641*1208bc7eSAndroid Build Coastguard Worker do {
1642*1208bc7eSAndroid Build Coastguard Worker prev_size = extent_size_get(extent);
1643*1208bc7eSAndroid Build Coastguard Worker assert(extent_state_get(extent) == extent_state_active);
1644*1208bc7eSAndroid Build Coastguard Worker extent = extent_try_coalesce(tsdn, arena,
1645*1208bc7eSAndroid Build Coastguard Worker r_extent_hooks, rtree_ctx, extents, extent,
1646*1208bc7eSAndroid Build Coastguard Worker &coalesced, growing_retained);
1647*1208bc7eSAndroid Build Coastguard Worker } while (coalesced &&
1648*1208bc7eSAndroid Build Coastguard Worker extent_size_get(extent) >= prev_size + LARGE_MINCLASS);
1649*1208bc7eSAndroid Build Coastguard Worker }
1650*1208bc7eSAndroid Build Coastguard Worker extent_deactivate_locked(tsdn, arena, extents, extent);
1651*1208bc7eSAndroid Build Coastguard Worker
1652*1208bc7eSAndroid Build Coastguard Worker malloc_mutex_unlock(tsdn, &extents->mtx);
1653*1208bc7eSAndroid Build Coastguard Worker }
1654*1208bc7eSAndroid Build Coastguard Worker
1655*1208bc7eSAndroid Build Coastguard Worker void
extent_dalloc_gap(tsdn_t * tsdn,arena_t * arena,extent_t * extent)1656*1208bc7eSAndroid Build Coastguard Worker extent_dalloc_gap(tsdn_t *tsdn, arena_t *arena, extent_t *extent) {
1657*1208bc7eSAndroid Build Coastguard Worker extent_hooks_t *extent_hooks = EXTENT_HOOKS_INITIALIZER;
1658*1208bc7eSAndroid Build Coastguard Worker
1659*1208bc7eSAndroid Build Coastguard Worker witness_assert_depth_to_rank(tsdn_witness_tsdp_get(tsdn),
1660*1208bc7eSAndroid Build Coastguard Worker WITNESS_RANK_CORE, 0);
1661*1208bc7eSAndroid Build Coastguard Worker
1662*1208bc7eSAndroid Build Coastguard Worker if (extent_register(tsdn, extent)) {
1663*1208bc7eSAndroid Build Coastguard Worker extents_leak(tsdn, arena, &extent_hooks,
1664*1208bc7eSAndroid Build Coastguard Worker &arena->extents_retained, extent, false);
1665*1208bc7eSAndroid Build Coastguard Worker return;
1666*1208bc7eSAndroid Build Coastguard Worker }
1667*1208bc7eSAndroid Build Coastguard Worker extent_dalloc_wrapper(tsdn, arena, &extent_hooks, extent);
1668*1208bc7eSAndroid Build Coastguard Worker }
1669*1208bc7eSAndroid Build Coastguard Worker
1670*1208bc7eSAndroid Build Coastguard Worker static bool
extent_dalloc_default_impl(void * addr,size_t size)1671*1208bc7eSAndroid Build Coastguard Worker extent_dalloc_default_impl(void *addr, size_t size) {
1672*1208bc7eSAndroid Build Coastguard Worker if (!have_dss || !extent_in_dss(addr)) {
1673*1208bc7eSAndroid Build Coastguard Worker return extent_dalloc_mmap(addr, size);
1674*1208bc7eSAndroid Build Coastguard Worker }
1675*1208bc7eSAndroid Build Coastguard Worker return true;
1676*1208bc7eSAndroid Build Coastguard Worker }
1677*1208bc7eSAndroid Build Coastguard Worker
1678*1208bc7eSAndroid Build Coastguard Worker static bool
extent_dalloc_default(extent_hooks_t * extent_hooks,void * addr,size_t size,bool committed,unsigned arena_ind)1679*1208bc7eSAndroid Build Coastguard Worker extent_dalloc_default(extent_hooks_t *extent_hooks, void *addr, size_t size,
1680*1208bc7eSAndroid Build Coastguard Worker bool committed, unsigned arena_ind) {
1681*1208bc7eSAndroid Build Coastguard Worker return extent_dalloc_default_impl(addr, size);
1682*1208bc7eSAndroid Build Coastguard Worker }
1683*1208bc7eSAndroid Build Coastguard Worker
1684*1208bc7eSAndroid Build Coastguard Worker static bool
extent_dalloc_wrapper_try(tsdn_t * tsdn,arena_t * arena,extent_hooks_t ** r_extent_hooks,extent_t * extent)1685*1208bc7eSAndroid Build Coastguard Worker extent_dalloc_wrapper_try(tsdn_t *tsdn, arena_t *arena,
1686*1208bc7eSAndroid Build Coastguard Worker extent_hooks_t **r_extent_hooks, extent_t *extent) {
1687*1208bc7eSAndroid Build Coastguard Worker bool err;
1688*1208bc7eSAndroid Build Coastguard Worker
1689*1208bc7eSAndroid Build Coastguard Worker assert(extent_base_get(extent) != NULL);
1690*1208bc7eSAndroid Build Coastguard Worker assert(extent_size_get(extent) != 0);
1691*1208bc7eSAndroid Build Coastguard Worker witness_assert_depth_to_rank(tsdn_witness_tsdp_get(tsdn),
1692*1208bc7eSAndroid Build Coastguard Worker WITNESS_RANK_CORE, 0);
1693*1208bc7eSAndroid Build Coastguard Worker
1694*1208bc7eSAndroid Build Coastguard Worker extent_addr_set(extent, extent_base_get(extent));
1695*1208bc7eSAndroid Build Coastguard Worker
1696*1208bc7eSAndroid Build Coastguard Worker extent_hooks_assure_initialized(arena, r_extent_hooks);
1697*1208bc7eSAndroid Build Coastguard Worker /* Try to deallocate. */
1698*1208bc7eSAndroid Build Coastguard Worker if (*r_extent_hooks == &extent_hooks_default) {
1699*1208bc7eSAndroid Build Coastguard Worker /* Call directly to propagate tsdn. */
1700*1208bc7eSAndroid Build Coastguard Worker err = extent_dalloc_default_impl(extent_base_get(extent),
1701*1208bc7eSAndroid Build Coastguard Worker extent_size_get(extent));
1702*1208bc7eSAndroid Build Coastguard Worker } else {
1703*1208bc7eSAndroid Build Coastguard Worker extent_hook_pre_reentrancy(tsdn, arena);
1704*1208bc7eSAndroid Build Coastguard Worker err = ((*r_extent_hooks)->dalloc == NULL ||
1705*1208bc7eSAndroid Build Coastguard Worker (*r_extent_hooks)->dalloc(*r_extent_hooks,
1706*1208bc7eSAndroid Build Coastguard Worker extent_base_get(extent), extent_size_get(extent),
1707*1208bc7eSAndroid Build Coastguard Worker extent_committed_get(extent), arena_ind_get(arena)));
1708*1208bc7eSAndroid Build Coastguard Worker extent_hook_post_reentrancy(tsdn);
1709*1208bc7eSAndroid Build Coastguard Worker }
1710*1208bc7eSAndroid Build Coastguard Worker
1711*1208bc7eSAndroid Build Coastguard Worker if (!err) {
1712*1208bc7eSAndroid Build Coastguard Worker extent_dalloc(tsdn, arena, extent);
1713*1208bc7eSAndroid Build Coastguard Worker }
1714*1208bc7eSAndroid Build Coastguard Worker
1715*1208bc7eSAndroid Build Coastguard Worker return err;
1716*1208bc7eSAndroid Build Coastguard Worker }
1717*1208bc7eSAndroid Build Coastguard Worker
1718*1208bc7eSAndroid Build Coastguard Worker void
extent_dalloc_wrapper(tsdn_t * tsdn,arena_t * arena,extent_hooks_t ** r_extent_hooks,extent_t * extent)1719*1208bc7eSAndroid Build Coastguard Worker extent_dalloc_wrapper(tsdn_t *tsdn, arena_t *arena,
1720*1208bc7eSAndroid Build Coastguard Worker extent_hooks_t **r_extent_hooks, extent_t *extent) {
1721*1208bc7eSAndroid Build Coastguard Worker assert(extent_dumpable_get(extent));
1722*1208bc7eSAndroid Build Coastguard Worker witness_assert_depth_to_rank(tsdn_witness_tsdp_get(tsdn),
1723*1208bc7eSAndroid Build Coastguard Worker WITNESS_RANK_CORE, 0);
1724*1208bc7eSAndroid Build Coastguard Worker
1725*1208bc7eSAndroid Build Coastguard Worker /*
1726*1208bc7eSAndroid Build Coastguard Worker * Deregister first to avoid a race with other allocating threads, and
1727*1208bc7eSAndroid Build Coastguard Worker * reregister if deallocation fails.
1728*1208bc7eSAndroid Build Coastguard Worker */
1729*1208bc7eSAndroid Build Coastguard Worker extent_deregister(tsdn, extent);
1730*1208bc7eSAndroid Build Coastguard Worker if (!extent_dalloc_wrapper_try(tsdn, arena, r_extent_hooks, extent)) {
1731*1208bc7eSAndroid Build Coastguard Worker return;
1732*1208bc7eSAndroid Build Coastguard Worker }
1733*1208bc7eSAndroid Build Coastguard Worker
1734*1208bc7eSAndroid Build Coastguard Worker extent_reregister(tsdn, extent);
1735*1208bc7eSAndroid Build Coastguard Worker if (*r_extent_hooks != &extent_hooks_default) {
1736*1208bc7eSAndroid Build Coastguard Worker extent_hook_pre_reentrancy(tsdn, arena);
1737*1208bc7eSAndroid Build Coastguard Worker }
1738*1208bc7eSAndroid Build Coastguard Worker /* Try to decommit; purge if that fails. */
1739*1208bc7eSAndroid Build Coastguard Worker bool zeroed;
1740*1208bc7eSAndroid Build Coastguard Worker if (!extent_committed_get(extent)) {
1741*1208bc7eSAndroid Build Coastguard Worker zeroed = true;
1742*1208bc7eSAndroid Build Coastguard Worker } else if (!extent_decommit_wrapper(tsdn, arena, r_extent_hooks, extent,
1743*1208bc7eSAndroid Build Coastguard Worker 0, extent_size_get(extent))) {
1744*1208bc7eSAndroid Build Coastguard Worker zeroed = true;
1745*1208bc7eSAndroid Build Coastguard Worker } else if ((*r_extent_hooks)->purge_forced != NULL &&
1746*1208bc7eSAndroid Build Coastguard Worker !(*r_extent_hooks)->purge_forced(*r_extent_hooks,
1747*1208bc7eSAndroid Build Coastguard Worker extent_base_get(extent), extent_size_get(extent), 0,
1748*1208bc7eSAndroid Build Coastguard Worker extent_size_get(extent), arena_ind_get(arena))) {
1749*1208bc7eSAndroid Build Coastguard Worker zeroed = true;
1750*1208bc7eSAndroid Build Coastguard Worker } else if (extent_state_get(extent) == extent_state_muzzy ||
1751*1208bc7eSAndroid Build Coastguard Worker ((*r_extent_hooks)->purge_lazy != NULL &&
1752*1208bc7eSAndroid Build Coastguard Worker !(*r_extent_hooks)->purge_lazy(*r_extent_hooks,
1753*1208bc7eSAndroid Build Coastguard Worker extent_base_get(extent), extent_size_get(extent), 0,
1754*1208bc7eSAndroid Build Coastguard Worker extent_size_get(extent), arena_ind_get(arena)))) {
1755*1208bc7eSAndroid Build Coastguard Worker zeroed = false;
1756*1208bc7eSAndroid Build Coastguard Worker } else {
1757*1208bc7eSAndroid Build Coastguard Worker zeroed = false;
1758*1208bc7eSAndroid Build Coastguard Worker }
1759*1208bc7eSAndroid Build Coastguard Worker if (*r_extent_hooks != &extent_hooks_default) {
1760*1208bc7eSAndroid Build Coastguard Worker extent_hook_post_reentrancy(tsdn);
1761*1208bc7eSAndroid Build Coastguard Worker }
1762*1208bc7eSAndroid Build Coastguard Worker extent_zeroed_set(extent, zeroed);
1763*1208bc7eSAndroid Build Coastguard Worker
1764*1208bc7eSAndroid Build Coastguard Worker if (config_prof) {
1765*1208bc7eSAndroid Build Coastguard Worker extent_gdump_sub(tsdn, extent);
1766*1208bc7eSAndroid Build Coastguard Worker }
1767*1208bc7eSAndroid Build Coastguard Worker
1768*1208bc7eSAndroid Build Coastguard Worker extent_record(tsdn, arena, r_extent_hooks, &arena->extents_retained,
1769*1208bc7eSAndroid Build Coastguard Worker extent, false);
1770*1208bc7eSAndroid Build Coastguard Worker }
1771*1208bc7eSAndroid Build Coastguard Worker
1772*1208bc7eSAndroid Build Coastguard Worker static void
extent_destroy_default_impl(void * addr,size_t size)1773*1208bc7eSAndroid Build Coastguard Worker extent_destroy_default_impl(void *addr, size_t size) {
1774*1208bc7eSAndroid Build Coastguard Worker if (!have_dss || !extent_in_dss(addr)) {
1775*1208bc7eSAndroid Build Coastguard Worker pages_unmap(addr, size);
1776*1208bc7eSAndroid Build Coastguard Worker }
1777*1208bc7eSAndroid Build Coastguard Worker }
1778*1208bc7eSAndroid Build Coastguard Worker
1779*1208bc7eSAndroid Build Coastguard Worker static void
extent_destroy_default(extent_hooks_t * extent_hooks,void * addr,size_t size,bool committed,unsigned arena_ind)1780*1208bc7eSAndroid Build Coastguard Worker extent_destroy_default(extent_hooks_t *extent_hooks, void *addr, size_t size,
1781*1208bc7eSAndroid Build Coastguard Worker bool committed, unsigned arena_ind) {
1782*1208bc7eSAndroid Build Coastguard Worker extent_destroy_default_impl(addr, size);
1783*1208bc7eSAndroid Build Coastguard Worker }
1784*1208bc7eSAndroid Build Coastguard Worker
1785*1208bc7eSAndroid Build Coastguard Worker void
extent_destroy_wrapper(tsdn_t * tsdn,arena_t * arena,extent_hooks_t ** r_extent_hooks,extent_t * extent)1786*1208bc7eSAndroid Build Coastguard Worker extent_destroy_wrapper(tsdn_t *tsdn, arena_t *arena,
1787*1208bc7eSAndroid Build Coastguard Worker extent_hooks_t **r_extent_hooks, extent_t *extent) {
1788*1208bc7eSAndroid Build Coastguard Worker assert(extent_base_get(extent) != NULL);
1789*1208bc7eSAndroid Build Coastguard Worker assert(extent_size_get(extent) != 0);
1790*1208bc7eSAndroid Build Coastguard Worker witness_assert_depth_to_rank(tsdn_witness_tsdp_get(tsdn),
1791*1208bc7eSAndroid Build Coastguard Worker WITNESS_RANK_CORE, 0);
1792*1208bc7eSAndroid Build Coastguard Worker
1793*1208bc7eSAndroid Build Coastguard Worker /* Deregister first to avoid a race with other allocating threads. */
1794*1208bc7eSAndroid Build Coastguard Worker extent_deregister(tsdn, extent);
1795*1208bc7eSAndroid Build Coastguard Worker
1796*1208bc7eSAndroid Build Coastguard Worker extent_addr_set(extent, extent_base_get(extent));
1797*1208bc7eSAndroid Build Coastguard Worker
1798*1208bc7eSAndroid Build Coastguard Worker extent_hooks_assure_initialized(arena, r_extent_hooks);
1799*1208bc7eSAndroid Build Coastguard Worker /* Try to destroy; silently fail otherwise. */
1800*1208bc7eSAndroid Build Coastguard Worker if (*r_extent_hooks == &extent_hooks_default) {
1801*1208bc7eSAndroid Build Coastguard Worker /* Call directly to propagate tsdn. */
1802*1208bc7eSAndroid Build Coastguard Worker extent_destroy_default_impl(extent_base_get(extent),
1803*1208bc7eSAndroid Build Coastguard Worker extent_size_get(extent));
1804*1208bc7eSAndroid Build Coastguard Worker } else if ((*r_extent_hooks)->destroy != NULL) {
1805*1208bc7eSAndroid Build Coastguard Worker extent_hook_pre_reentrancy(tsdn, arena);
1806*1208bc7eSAndroid Build Coastguard Worker (*r_extent_hooks)->destroy(*r_extent_hooks,
1807*1208bc7eSAndroid Build Coastguard Worker extent_base_get(extent), extent_size_get(extent),
1808*1208bc7eSAndroid Build Coastguard Worker extent_committed_get(extent), arena_ind_get(arena));
1809*1208bc7eSAndroid Build Coastguard Worker extent_hook_post_reentrancy(tsdn);
1810*1208bc7eSAndroid Build Coastguard Worker }
1811*1208bc7eSAndroid Build Coastguard Worker
1812*1208bc7eSAndroid Build Coastguard Worker extent_dalloc(tsdn, arena, extent);
1813*1208bc7eSAndroid Build Coastguard Worker }
1814*1208bc7eSAndroid Build Coastguard Worker
1815*1208bc7eSAndroid Build Coastguard Worker static bool
extent_commit_default(extent_hooks_t * extent_hooks,void * addr,size_t size,size_t offset,size_t length,unsigned arena_ind)1816*1208bc7eSAndroid Build Coastguard Worker extent_commit_default(extent_hooks_t *extent_hooks, void *addr, size_t size,
1817*1208bc7eSAndroid Build Coastguard Worker size_t offset, size_t length, unsigned arena_ind) {
1818*1208bc7eSAndroid Build Coastguard Worker return pages_commit((void *)((uintptr_t)addr + (uintptr_t)offset),
1819*1208bc7eSAndroid Build Coastguard Worker length);
1820*1208bc7eSAndroid Build Coastguard Worker }
1821*1208bc7eSAndroid Build Coastguard Worker
1822*1208bc7eSAndroid Build Coastguard Worker static bool
extent_commit_impl(tsdn_t * tsdn,arena_t * arena,extent_hooks_t ** r_extent_hooks,extent_t * extent,size_t offset,size_t length,bool growing_retained)1823*1208bc7eSAndroid Build Coastguard Worker extent_commit_impl(tsdn_t *tsdn, arena_t *arena,
1824*1208bc7eSAndroid Build Coastguard Worker extent_hooks_t **r_extent_hooks, extent_t *extent, size_t offset,
1825*1208bc7eSAndroid Build Coastguard Worker size_t length, bool growing_retained) {
1826*1208bc7eSAndroid Build Coastguard Worker witness_assert_depth_to_rank(tsdn_witness_tsdp_get(tsdn),
1827*1208bc7eSAndroid Build Coastguard Worker WITNESS_RANK_CORE, growing_retained ? 1 : 0);
1828*1208bc7eSAndroid Build Coastguard Worker
1829*1208bc7eSAndroid Build Coastguard Worker extent_hooks_assure_initialized(arena, r_extent_hooks);
1830*1208bc7eSAndroid Build Coastguard Worker if (*r_extent_hooks != &extent_hooks_default) {
1831*1208bc7eSAndroid Build Coastguard Worker extent_hook_pre_reentrancy(tsdn, arena);
1832*1208bc7eSAndroid Build Coastguard Worker }
1833*1208bc7eSAndroid Build Coastguard Worker bool err = ((*r_extent_hooks)->commit == NULL ||
1834*1208bc7eSAndroid Build Coastguard Worker (*r_extent_hooks)->commit(*r_extent_hooks, extent_base_get(extent),
1835*1208bc7eSAndroid Build Coastguard Worker extent_size_get(extent), offset, length, arena_ind_get(arena)));
1836*1208bc7eSAndroid Build Coastguard Worker if (*r_extent_hooks != &extent_hooks_default) {
1837*1208bc7eSAndroid Build Coastguard Worker extent_hook_post_reentrancy(tsdn);
1838*1208bc7eSAndroid Build Coastguard Worker }
1839*1208bc7eSAndroid Build Coastguard Worker extent_committed_set(extent, extent_committed_get(extent) || !err);
1840*1208bc7eSAndroid Build Coastguard Worker return err;
1841*1208bc7eSAndroid Build Coastguard Worker }
1842*1208bc7eSAndroid Build Coastguard Worker
1843*1208bc7eSAndroid Build Coastguard Worker bool
extent_commit_wrapper(tsdn_t * tsdn,arena_t * arena,extent_hooks_t ** r_extent_hooks,extent_t * extent,size_t offset,size_t length)1844*1208bc7eSAndroid Build Coastguard Worker extent_commit_wrapper(tsdn_t *tsdn, arena_t *arena,
1845*1208bc7eSAndroid Build Coastguard Worker extent_hooks_t **r_extent_hooks, extent_t *extent, size_t offset,
1846*1208bc7eSAndroid Build Coastguard Worker size_t length) {
1847*1208bc7eSAndroid Build Coastguard Worker return extent_commit_impl(tsdn, arena, r_extent_hooks, extent, offset,
1848*1208bc7eSAndroid Build Coastguard Worker length, false);
1849*1208bc7eSAndroid Build Coastguard Worker }
1850*1208bc7eSAndroid Build Coastguard Worker
1851*1208bc7eSAndroid Build Coastguard Worker static bool
extent_decommit_default(extent_hooks_t * extent_hooks,void * addr,size_t size,size_t offset,size_t length,unsigned arena_ind)1852*1208bc7eSAndroid Build Coastguard Worker extent_decommit_default(extent_hooks_t *extent_hooks, void *addr, size_t size,
1853*1208bc7eSAndroid Build Coastguard Worker size_t offset, size_t length, unsigned arena_ind) {
1854*1208bc7eSAndroid Build Coastguard Worker return pages_decommit((void *)((uintptr_t)addr + (uintptr_t)offset),
1855*1208bc7eSAndroid Build Coastguard Worker length);
1856*1208bc7eSAndroid Build Coastguard Worker }
1857*1208bc7eSAndroid Build Coastguard Worker
1858*1208bc7eSAndroid Build Coastguard Worker bool
extent_decommit_wrapper(tsdn_t * tsdn,arena_t * arena,extent_hooks_t ** r_extent_hooks,extent_t * extent,size_t offset,size_t length)1859*1208bc7eSAndroid Build Coastguard Worker extent_decommit_wrapper(tsdn_t *tsdn, arena_t *arena,
1860*1208bc7eSAndroid Build Coastguard Worker extent_hooks_t **r_extent_hooks, extent_t *extent, size_t offset,
1861*1208bc7eSAndroid Build Coastguard Worker size_t length) {
1862*1208bc7eSAndroid Build Coastguard Worker witness_assert_depth_to_rank(tsdn_witness_tsdp_get(tsdn),
1863*1208bc7eSAndroid Build Coastguard Worker WITNESS_RANK_CORE, 0);
1864*1208bc7eSAndroid Build Coastguard Worker
1865*1208bc7eSAndroid Build Coastguard Worker extent_hooks_assure_initialized(arena, r_extent_hooks);
1866*1208bc7eSAndroid Build Coastguard Worker
1867*1208bc7eSAndroid Build Coastguard Worker if (*r_extent_hooks != &extent_hooks_default) {
1868*1208bc7eSAndroid Build Coastguard Worker extent_hook_pre_reentrancy(tsdn, arena);
1869*1208bc7eSAndroid Build Coastguard Worker }
1870*1208bc7eSAndroid Build Coastguard Worker bool err = ((*r_extent_hooks)->decommit == NULL ||
1871*1208bc7eSAndroid Build Coastguard Worker (*r_extent_hooks)->decommit(*r_extent_hooks,
1872*1208bc7eSAndroid Build Coastguard Worker extent_base_get(extent), extent_size_get(extent), offset, length,
1873*1208bc7eSAndroid Build Coastguard Worker arena_ind_get(arena)));
1874*1208bc7eSAndroid Build Coastguard Worker if (*r_extent_hooks != &extent_hooks_default) {
1875*1208bc7eSAndroid Build Coastguard Worker extent_hook_post_reentrancy(tsdn);
1876*1208bc7eSAndroid Build Coastguard Worker }
1877*1208bc7eSAndroid Build Coastguard Worker extent_committed_set(extent, extent_committed_get(extent) && err);
1878*1208bc7eSAndroid Build Coastguard Worker return err;
1879*1208bc7eSAndroid Build Coastguard Worker }
1880*1208bc7eSAndroid Build Coastguard Worker
1881*1208bc7eSAndroid Build Coastguard Worker #ifdef PAGES_CAN_PURGE_LAZY
1882*1208bc7eSAndroid Build Coastguard Worker static bool
extent_purge_lazy_default(extent_hooks_t * extent_hooks,void * addr,size_t size,size_t offset,size_t length,unsigned arena_ind)1883*1208bc7eSAndroid Build Coastguard Worker extent_purge_lazy_default(extent_hooks_t *extent_hooks, void *addr, size_t size,
1884*1208bc7eSAndroid Build Coastguard Worker size_t offset, size_t length, unsigned arena_ind) {
1885*1208bc7eSAndroid Build Coastguard Worker assert(addr != NULL);
1886*1208bc7eSAndroid Build Coastguard Worker assert((offset & PAGE_MASK) == 0);
1887*1208bc7eSAndroid Build Coastguard Worker assert(length != 0);
1888*1208bc7eSAndroid Build Coastguard Worker assert((length & PAGE_MASK) == 0);
1889*1208bc7eSAndroid Build Coastguard Worker
1890*1208bc7eSAndroid Build Coastguard Worker return pages_purge_lazy((void *)((uintptr_t)addr + (uintptr_t)offset),
1891*1208bc7eSAndroid Build Coastguard Worker length);
1892*1208bc7eSAndroid Build Coastguard Worker }
1893*1208bc7eSAndroid Build Coastguard Worker #endif
1894*1208bc7eSAndroid Build Coastguard Worker
1895*1208bc7eSAndroid Build Coastguard Worker static bool
extent_purge_lazy_impl(tsdn_t * tsdn,arena_t * arena,extent_hooks_t ** r_extent_hooks,extent_t * extent,size_t offset,size_t length,bool growing_retained)1896*1208bc7eSAndroid Build Coastguard Worker extent_purge_lazy_impl(tsdn_t *tsdn, arena_t *arena,
1897*1208bc7eSAndroid Build Coastguard Worker extent_hooks_t **r_extent_hooks, extent_t *extent, size_t offset,
1898*1208bc7eSAndroid Build Coastguard Worker size_t length, bool growing_retained) {
1899*1208bc7eSAndroid Build Coastguard Worker witness_assert_depth_to_rank(tsdn_witness_tsdp_get(tsdn),
1900*1208bc7eSAndroid Build Coastguard Worker WITNESS_RANK_CORE, growing_retained ? 1 : 0);
1901*1208bc7eSAndroid Build Coastguard Worker
1902*1208bc7eSAndroid Build Coastguard Worker extent_hooks_assure_initialized(arena, r_extent_hooks);
1903*1208bc7eSAndroid Build Coastguard Worker
1904*1208bc7eSAndroid Build Coastguard Worker if ((*r_extent_hooks)->purge_lazy == NULL) {
1905*1208bc7eSAndroid Build Coastguard Worker return true;
1906*1208bc7eSAndroid Build Coastguard Worker }
1907*1208bc7eSAndroid Build Coastguard Worker if (*r_extent_hooks != &extent_hooks_default) {
1908*1208bc7eSAndroid Build Coastguard Worker extent_hook_pre_reentrancy(tsdn, arena);
1909*1208bc7eSAndroid Build Coastguard Worker }
1910*1208bc7eSAndroid Build Coastguard Worker bool err = (*r_extent_hooks)->purge_lazy(*r_extent_hooks,
1911*1208bc7eSAndroid Build Coastguard Worker extent_base_get(extent), extent_size_get(extent), offset, length,
1912*1208bc7eSAndroid Build Coastguard Worker arena_ind_get(arena));
1913*1208bc7eSAndroid Build Coastguard Worker if (*r_extent_hooks != &extent_hooks_default) {
1914*1208bc7eSAndroid Build Coastguard Worker extent_hook_post_reentrancy(tsdn);
1915*1208bc7eSAndroid Build Coastguard Worker }
1916*1208bc7eSAndroid Build Coastguard Worker
1917*1208bc7eSAndroid Build Coastguard Worker return err;
1918*1208bc7eSAndroid Build Coastguard Worker }
1919*1208bc7eSAndroid Build Coastguard Worker
1920*1208bc7eSAndroid Build Coastguard Worker bool
extent_purge_lazy_wrapper(tsdn_t * tsdn,arena_t * arena,extent_hooks_t ** r_extent_hooks,extent_t * extent,size_t offset,size_t length)1921*1208bc7eSAndroid Build Coastguard Worker extent_purge_lazy_wrapper(tsdn_t *tsdn, arena_t *arena,
1922*1208bc7eSAndroid Build Coastguard Worker extent_hooks_t **r_extent_hooks, extent_t *extent, size_t offset,
1923*1208bc7eSAndroid Build Coastguard Worker size_t length) {
1924*1208bc7eSAndroid Build Coastguard Worker return extent_purge_lazy_impl(tsdn, arena, r_extent_hooks, extent,
1925*1208bc7eSAndroid Build Coastguard Worker offset, length, false);
1926*1208bc7eSAndroid Build Coastguard Worker }
1927*1208bc7eSAndroid Build Coastguard Worker
1928*1208bc7eSAndroid Build Coastguard Worker #ifdef PAGES_CAN_PURGE_FORCED
1929*1208bc7eSAndroid Build Coastguard Worker static bool
extent_purge_forced_default(extent_hooks_t * extent_hooks,void * addr,size_t size,size_t offset,size_t length,unsigned arena_ind)1930*1208bc7eSAndroid Build Coastguard Worker extent_purge_forced_default(extent_hooks_t *extent_hooks, void *addr,
1931*1208bc7eSAndroid Build Coastguard Worker size_t size, size_t offset, size_t length, unsigned arena_ind) {
1932*1208bc7eSAndroid Build Coastguard Worker assert(addr != NULL);
1933*1208bc7eSAndroid Build Coastguard Worker assert((offset & PAGE_MASK) == 0);
1934*1208bc7eSAndroid Build Coastguard Worker assert(length != 0);
1935*1208bc7eSAndroid Build Coastguard Worker assert((length & PAGE_MASK) == 0);
1936*1208bc7eSAndroid Build Coastguard Worker
1937*1208bc7eSAndroid Build Coastguard Worker return pages_purge_forced((void *)((uintptr_t)addr +
1938*1208bc7eSAndroid Build Coastguard Worker (uintptr_t)offset), length);
1939*1208bc7eSAndroid Build Coastguard Worker }
1940*1208bc7eSAndroid Build Coastguard Worker #endif
1941*1208bc7eSAndroid Build Coastguard Worker
1942*1208bc7eSAndroid Build Coastguard Worker static bool
extent_purge_forced_impl(tsdn_t * tsdn,arena_t * arena,extent_hooks_t ** r_extent_hooks,extent_t * extent,size_t offset,size_t length,bool growing_retained)1943*1208bc7eSAndroid Build Coastguard Worker extent_purge_forced_impl(tsdn_t *tsdn, arena_t *arena,
1944*1208bc7eSAndroid Build Coastguard Worker extent_hooks_t **r_extent_hooks, extent_t *extent, size_t offset,
1945*1208bc7eSAndroid Build Coastguard Worker size_t length, bool growing_retained) {
1946*1208bc7eSAndroid Build Coastguard Worker witness_assert_depth_to_rank(tsdn_witness_tsdp_get(tsdn),
1947*1208bc7eSAndroid Build Coastguard Worker WITNESS_RANK_CORE, growing_retained ? 1 : 0);
1948*1208bc7eSAndroid Build Coastguard Worker
1949*1208bc7eSAndroid Build Coastguard Worker extent_hooks_assure_initialized(arena, r_extent_hooks);
1950*1208bc7eSAndroid Build Coastguard Worker
1951*1208bc7eSAndroid Build Coastguard Worker if ((*r_extent_hooks)->purge_forced == NULL) {
1952*1208bc7eSAndroid Build Coastguard Worker return true;
1953*1208bc7eSAndroid Build Coastguard Worker }
1954*1208bc7eSAndroid Build Coastguard Worker if (*r_extent_hooks != &extent_hooks_default) {
1955*1208bc7eSAndroid Build Coastguard Worker extent_hook_pre_reentrancy(tsdn, arena);
1956*1208bc7eSAndroid Build Coastguard Worker }
1957*1208bc7eSAndroid Build Coastguard Worker bool err = (*r_extent_hooks)->purge_forced(*r_extent_hooks,
1958*1208bc7eSAndroid Build Coastguard Worker extent_base_get(extent), extent_size_get(extent), offset, length,
1959*1208bc7eSAndroid Build Coastguard Worker arena_ind_get(arena));
1960*1208bc7eSAndroid Build Coastguard Worker if (*r_extent_hooks != &extent_hooks_default) {
1961*1208bc7eSAndroid Build Coastguard Worker extent_hook_post_reentrancy(tsdn);
1962*1208bc7eSAndroid Build Coastguard Worker }
1963*1208bc7eSAndroid Build Coastguard Worker return err;
1964*1208bc7eSAndroid Build Coastguard Worker }
1965*1208bc7eSAndroid Build Coastguard Worker
1966*1208bc7eSAndroid Build Coastguard Worker bool
extent_purge_forced_wrapper(tsdn_t * tsdn,arena_t * arena,extent_hooks_t ** r_extent_hooks,extent_t * extent,size_t offset,size_t length)1967*1208bc7eSAndroid Build Coastguard Worker extent_purge_forced_wrapper(tsdn_t *tsdn, arena_t *arena,
1968*1208bc7eSAndroid Build Coastguard Worker extent_hooks_t **r_extent_hooks, extent_t *extent, size_t offset,
1969*1208bc7eSAndroid Build Coastguard Worker size_t length) {
1970*1208bc7eSAndroid Build Coastguard Worker return extent_purge_forced_impl(tsdn, arena, r_extent_hooks, extent,
1971*1208bc7eSAndroid Build Coastguard Worker offset, length, false);
1972*1208bc7eSAndroid Build Coastguard Worker }
1973*1208bc7eSAndroid Build Coastguard Worker
1974*1208bc7eSAndroid Build Coastguard Worker #ifdef JEMALLOC_MAPS_COALESCE
1975*1208bc7eSAndroid Build Coastguard Worker static bool
extent_split_default(extent_hooks_t * extent_hooks,void * addr,size_t size,size_t size_a,size_t size_b,bool committed,unsigned arena_ind)1976*1208bc7eSAndroid Build Coastguard Worker extent_split_default(extent_hooks_t *extent_hooks, void *addr, size_t size,
1977*1208bc7eSAndroid Build Coastguard Worker size_t size_a, size_t size_b, bool committed, unsigned arena_ind) {
1978*1208bc7eSAndroid Build Coastguard Worker return !maps_coalesce;
1979*1208bc7eSAndroid Build Coastguard Worker }
1980*1208bc7eSAndroid Build Coastguard Worker #endif
1981*1208bc7eSAndroid Build Coastguard Worker
1982*1208bc7eSAndroid Build Coastguard Worker /*
1983*1208bc7eSAndroid Build Coastguard Worker * Accepts the extent to split, and the characteristics of each side of the
1984*1208bc7eSAndroid Build Coastguard Worker * split. The 'a' parameters go with the 'lead' of the resulting pair of
1985*1208bc7eSAndroid Build Coastguard Worker * extents (the lower addressed portion of the split), and the 'b' parameters go
1986*1208bc7eSAndroid Build Coastguard Worker * with the trail (the higher addressed portion). This makes 'extent' the lead,
1987*1208bc7eSAndroid Build Coastguard Worker * and returns the trail (except in case of error).
1988*1208bc7eSAndroid Build Coastguard Worker */
1989*1208bc7eSAndroid Build Coastguard Worker static extent_t *
extent_split_impl(tsdn_t * tsdn,arena_t * arena,extent_hooks_t ** r_extent_hooks,extent_t * extent,size_t size_a,szind_t szind_a,bool slab_a,size_t size_b,szind_t szind_b,bool slab_b,bool growing_retained)1990*1208bc7eSAndroid Build Coastguard Worker extent_split_impl(tsdn_t *tsdn, arena_t *arena,
1991*1208bc7eSAndroid Build Coastguard Worker extent_hooks_t **r_extent_hooks, extent_t *extent, size_t size_a,
1992*1208bc7eSAndroid Build Coastguard Worker szind_t szind_a, bool slab_a, size_t size_b, szind_t szind_b, bool slab_b,
1993*1208bc7eSAndroid Build Coastguard Worker bool growing_retained) {
1994*1208bc7eSAndroid Build Coastguard Worker assert(extent_size_get(extent) == size_a + size_b);
1995*1208bc7eSAndroid Build Coastguard Worker witness_assert_depth_to_rank(tsdn_witness_tsdp_get(tsdn),
1996*1208bc7eSAndroid Build Coastguard Worker WITNESS_RANK_CORE, growing_retained ? 1 : 0);
1997*1208bc7eSAndroid Build Coastguard Worker
1998*1208bc7eSAndroid Build Coastguard Worker extent_hooks_assure_initialized(arena, r_extent_hooks);
1999*1208bc7eSAndroid Build Coastguard Worker
2000*1208bc7eSAndroid Build Coastguard Worker if ((*r_extent_hooks)->split == NULL) {
2001*1208bc7eSAndroid Build Coastguard Worker return NULL;
2002*1208bc7eSAndroid Build Coastguard Worker }
2003*1208bc7eSAndroid Build Coastguard Worker
2004*1208bc7eSAndroid Build Coastguard Worker extent_t *trail = extent_alloc(tsdn, arena);
2005*1208bc7eSAndroid Build Coastguard Worker if (trail == NULL) {
2006*1208bc7eSAndroid Build Coastguard Worker goto label_error_a;
2007*1208bc7eSAndroid Build Coastguard Worker }
2008*1208bc7eSAndroid Build Coastguard Worker
2009*1208bc7eSAndroid Build Coastguard Worker extent_init(trail, arena, (void *)((uintptr_t)extent_base_get(extent) +
2010*1208bc7eSAndroid Build Coastguard Worker size_a), size_b, slab_b, szind_b, extent_sn_get(extent),
2011*1208bc7eSAndroid Build Coastguard Worker extent_state_get(extent), extent_zeroed_get(extent),
2012*1208bc7eSAndroid Build Coastguard Worker extent_committed_get(extent), extent_dumpable_get(extent));
2013*1208bc7eSAndroid Build Coastguard Worker
2014*1208bc7eSAndroid Build Coastguard Worker rtree_ctx_t rtree_ctx_fallback;
2015*1208bc7eSAndroid Build Coastguard Worker rtree_ctx_t *rtree_ctx = tsdn_rtree_ctx(tsdn, &rtree_ctx_fallback);
2016*1208bc7eSAndroid Build Coastguard Worker rtree_leaf_elm_t *lead_elm_a, *lead_elm_b;
2017*1208bc7eSAndroid Build Coastguard Worker {
2018*1208bc7eSAndroid Build Coastguard Worker extent_t lead;
2019*1208bc7eSAndroid Build Coastguard Worker
2020*1208bc7eSAndroid Build Coastguard Worker extent_init(&lead, arena, extent_addr_get(extent), size_a,
2021*1208bc7eSAndroid Build Coastguard Worker slab_a, szind_a, extent_sn_get(extent),
2022*1208bc7eSAndroid Build Coastguard Worker extent_state_get(extent), extent_zeroed_get(extent),
2023*1208bc7eSAndroid Build Coastguard Worker extent_committed_get(extent), extent_dumpable_get(extent));
2024*1208bc7eSAndroid Build Coastguard Worker
2025*1208bc7eSAndroid Build Coastguard Worker extent_rtree_leaf_elms_lookup(tsdn, rtree_ctx, &lead, false,
2026*1208bc7eSAndroid Build Coastguard Worker true, &lead_elm_a, &lead_elm_b);
2027*1208bc7eSAndroid Build Coastguard Worker }
2028*1208bc7eSAndroid Build Coastguard Worker rtree_leaf_elm_t *trail_elm_a, *trail_elm_b;
2029*1208bc7eSAndroid Build Coastguard Worker extent_rtree_leaf_elms_lookup(tsdn, rtree_ctx, trail, false, true,
2030*1208bc7eSAndroid Build Coastguard Worker &trail_elm_a, &trail_elm_b);
2031*1208bc7eSAndroid Build Coastguard Worker
2032*1208bc7eSAndroid Build Coastguard Worker if (lead_elm_a == NULL || lead_elm_b == NULL || trail_elm_a == NULL
2033*1208bc7eSAndroid Build Coastguard Worker || trail_elm_b == NULL) {
2034*1208bc7eSAndroid Build Coastguard Worker goto label_error_b;
2035*1208bc7eSAndroid Build Coastguard Worker }
2036*1208bc7eSAndroid Build Coastguard Worker
2037*1208bc7eSAndroid Build Coastguard Worker extent_lock2(tsdn, extent, trail);
2038*1208bc7eSAndroid Build Coastguard Worker
2039*1208bc7eSAndroid Build Coastguard Worker if (*r_extent_hooks != &extent_hooks_default) {
2040*1208bc7eSAndroid Build Coastguard Worker extent_hook_pre_reentrancy(tsdn, arena);
2041*1208bc7eSAndroid Build Coastguard Worker }
2042*1208bc7eSAndroid Build Coastguard Worker bool err = (*r_extent_hooks)->split(*r_extent_hooks, extent_base_get(extent),
2043*1208bc7eSAndroid Build Coastguard Worker size_a + size_b, size_a, size_b, extent_committed_get(extent),
2044*1208bc7eSAndroid Build Coastguard Worker arena_ind_get(arena));
2045*1208bc7eSAndroid Build Coastguard Worker if (*r_extent_hooks != &extent_hooks_default) {
2046*1208bc7eSAndroid Build Coastguard Worker extent_hook_post_reentrancy(tsdn);
2047*1208bc7eSAndroid Build Coastguard Worker }
2048*1208bc7eSAndroid Build Coastguard Worker if (err) {
2049*1208bc7eSAndroid Build Coastguard Worker goto label_error_c;
2050*1208bc7eSAndroid Build Coastguard Worker }
2051*1208bc7eSAndroid Build Coastguard Worker
2052*1208bc7eSAndroid Build Coastguard Worker extent_size_set(extent, size_a);
2053*1208bc7eSAndroid Build Coastguard Worker extent_szind_set(extent, szind_a);
2054*1208bc7eSAndroid Build Coastguard Worker
2055*1208bc7eSAndroid Build Coastguard Worker extent_rtree_write_acquired(tsdn, lead_elm_a, lead_elm_b, extent,
2056*1208bc7eSAndroid Build Coastguard Worker szind_a, slab_a);
2057*1208bc7eSAndroid Build Coastguard Worker extent_rtree_write_acquired(tsdn, trail_elm_a, trail_elm_b, trail,
2058*1208bc7eSAndroid Build Coastguard Worker szind_b, slab_b);
2059*1208bc7eSAndroid Build Coastguard Worker
2060*1208bc7eSAndroid Build Coastguard Worker extent_unlock2(tsdn, extent, trail);
2061*1208bc7eSAndroid Build Coastguard Worker
2062*1208bc7eSAndroid Build Coastguard Worker return trail;
2063*1208bc7eSAndroid Build Coastguard Worker label_error_c:
2064*1208bc7eSAndroid Build Coastguard Worker extent_unlock2(tsdn, extent, trail);
2065*1208bc7eSAndroid Build Coastguard Worker label_error_b:
2066*1208bc7eSAndroid Build Coastguard Worker extent_dalloc(tsdn, arena, trail);
2067*1208bc7eSAndroid Build Coastguard Worker label_error_a:
2068*1208bc7eSAndroid Build Coastguard Worker return NULL;
2069*1208bc7eSAndroid Build Coastguard Worker }
2070*1208bc7eSAndroid Build Coastguard Worker
2071*1208bc7eSAndroid Build Coastguard Worker extent_t *
extent_split_wrapper(tsdn_t * tsdn,arena_t * arena,extent_hooks_t ** r_extent_hooks,extent_t * extent,size_t size_a,szind_t szind_a,bool slab_a,size_t size_b,szind_t szind_b,bool slab_b)2072*1208bc7eSAndroid Build Coastguard Worker extent_split_wrapper(tsdn_t *tsdn, arena_t *arena,
2073*1208bc7eSAndroid Build Coastguard Worker extent_hooks_t **r_extent_hooks, extent_t *extent, size_t size_a,
2074*1208bc7eSAndroid Build Coastguard Worker szind_t szind_a, bool slab_a, size_t size_b, szind_t szind_b, bool slab_b) {
2075*1208bc7eSAndroid Build Coastguard Worker return extent_split_impl(tsdn, arena, r_extent_hooks, extent, size_a,
2076*1208bc7eSAndroid Build Coastguard Worker szind_a, slab_a, size_b, szind_b, slab_b, false);
2077*1208bc7eSAndroid Build Coastguard Worker }
2078*1208bc7eSAndroid Build Coastguard Worker
2079*1208bc7eSAndroid Build Coastguard Worker static bool
extent_merge_default_impl(void * addr_a,void * addr_b)2080*1208bc7eSAndroid Build Coastguard Worker extent_merge_default_impl(void *addr_a, void *addr_b) {
2081*1208bc7eSAndroid Build Coastguard Worker if (!maps_coalesce) {
2082*1208bc7eSAndroid Build Coastguard Worker return true;
2083*1208bc7eSAndroid Build Coastguard Worker }
2084*1208bc7eSAndroid Build Coastguard Worker if (have_dss && !extent_dss_mergeable(addr_a, addr_b)) {
2085*1208bc7eSAndroid Build Coastguard Worker return true;
2086*1208bc7eSAndroid Build Coastguard Worker }
2087*1208bc7eSAndroid Build Coastguard Worker
2088*1208bc7eSAndroid Build Coastguard Worker return false;
2089*1208bc7eSAndroid Build Coastguard Worker }
2090*1208bc7eSAndroid Build Coastguard Worker
2091*1208bc7eSAndroid Build Coastguard Worker #ifdef JEMALLOC_MAPS_COALESCE
2092*1208bc7eSAndroid Build Coastguard Worker static bool
extent_merge_default(extent_hooks_t * extent_hooks,void * addr_a,size_t size_a,void * addr_b,size_t size_b,bool committed,unsigned arena_ind)2093*1208bc7eSAndroid Build Coastguard Worker extent_merge_default(extent_hooks_t *extent_hooks, void *addr_a, size_t size_a,
2094*1208bc7eSAndroid Build Coastguard Worker void *addr_b, size_t size_b, bool committed, unsigned arena_ind) {
2095*1208bc7eSAndroid Build Coastguard Worker return extent_merge_default_impl(addr_a, addr_b);
2096*1208bc7eSAndroid Build Coastguard Worker }
2097*1208bc7eSAndroid Build Coastguard Worker #endif
2098*1208bc7eSAndroid Build Coastguard Worker
2099*1208bc7eSAndroid Build Coastguard Worker static bool
extent_merge_impl(tsdn_t * tsdn,arena_t * arena,extent_hooks_t ** r_extent_hooks,extent_t * a,extent_t * b,bool growing_retained)2100*1208bc7eSAndroid Build Coastguard Worker extent_merge_impl(tsdn_t *tsdn, arena_t *arena,
2101*1208bc7eSAndroid Build Coastguard Worker extent_hooks_t **r_extent_hooks, extent_t *a, extent_t *b,
2102*1208bc7eSAndroid Build Coastguard Worker bool growing_retained) {
2103*1208bc7eSAndroid Build Coastguard Worker witness_assert_depth_to_rank(tsdn_witness_tsdp_get(tsdn),
2104*1208bc7eSAndroid Build Coastguard Worker WITNESS_RANK_CORE, growing_retained ? 1 : 0);
2105*1208bc7eSAndroid Build Coastguard Worker
2106*1208bc7eSAndroid Build Coastguard Worker extent_hooks_assure_initialized(arena, r_extent_hooks);
2107*1208bc7eSAndroid Build Coastguard Worker
2108*1208bc7eSAndroid Build Coastguard Worker if ((*r_extent_hooks)->merge == NULL) {
2109*1208bc7eSAndroid Build Coastguard Worker return true;
2110*1208bc7eSAndroid Build Coastguard Worker }
2111*1208bc7eSAndroid Build Coastguard Worker
2112*1208bc7eSAndroid Build Coastguard Worker bool err;
2113*1208bc7eSAndroid Build Coastguard Worker if (*r_extent_hooks == &extent_hooks_default) {
2114*1208bc7eSAndroid Build Coastguard Worker /* Call directly to propagate tsdn. */
2115*1208bc7eSAndroid Build Coastguard Worker err = extent_merge_default_impl(extent_base_get(a),
2116*1208bc7eSAndroid Build Coastguard Worker extent_base_get(b));
2117*1208bc7eSAndroid Build Coastguard Worker } else {
2118*1208bc7eSAndroid Build Coastguard Worker extent_hook_pre_reentrancy(tsdn, arena);
2119*1208bc7eSAndroid Build Coastguard Worker err = (*r_extent_hooks)->merge(*r_extent_hooks,
2120*1208bc7eSAndroid Build Coastguard Worker extent_base_get(a), extent_size_get(a), extent_base_get(b),
2121*1208bc7eSAndroid Build Coastguard Worker extent_size_get(b), extent_committed_get(a),
2122*1208bc7eSAndroid Build Coastguard Worker arena_ind_get(arena));
2123*1208bc7eSAndroid Build Coastguard Worker extent_hook_post_reentrancy(tsdn);
2124*1208bc7eSAndroid Build Coastguard Worker }
2125*1208bc7eSAndroid Build Coastguard Worker
2126*1208bc7eSAndroid Build Coastguard Worker if (err) {
2127*1208bc7eSAndroid Build Coastguard Worker return true;
2128*1208bc7eSAndroid Build Coastguard Worker }
2129*1208bc7eSAndroid Build Coastguard Worker
2130*1208bc7eSAndroid Build Coastguard Worker /*
2131*1208bc7eSAndroid Build Coastguard Worker * The rtree writes must happen while all the relevant elements are
2132*1208bc7eSAndroid Build Coastguard Worker * owned, so the following code uses decomposed helper functions rather
2133*1208bc7eSAndroid Build Coastguard Worker * than extent_{,de}register() to do things in the right order.
2134*1208bc7eSAndroid Build Coastguard Worker */
2135*1208bc7eSAndroid Build Coastguard Worker rtree_ctx_t rtree_ctx_fallback;
2136*1208bc7eSAndroid Build Coastguard Worker rtree_ctx_t *rtree_ctx = tsdn_rtree_ctx(tsdn, &rtree_ctx_fallback);
2137*1208bc7eSAndroid Build Coastguard Worker rtree_leaf_elm_t *a_elm_a, *a_elm_b, *b_elm_a, *b_elm_b;
2138*1208bc7eSAndroid Build Coastguard Worker extent_rtree_leaf_elms_lookup(tsdn, rtree_ctx, a, true, false, &a_elm_a,
2139*1208bc7eSAndroid Build Coastguard Worker &a_elm_b);
2140*1208bc7eSAndroid Build Coastguard Worker extent_rtree_leaf_elms_lookup(tsdn, rtree_ctx, b, true, false, &b_elm_a,
2141*1208bc7eSAndroid Build Coastguard Worker &b_elm_b);
2142*1208bc7eSAndroid Build Coastguard Worker
2143*1208bc7eSAndroid Build Coastguard Worker extent_lock2(tsdn, a, b);
2144*1208bc7eSAndroid Build Coastguard Worker
2145*1208bc7eSAndroid Build Coastguard Worker if (a_elm_b != NULL) {
2146*1208bc7eSAndroid Build Coastguard Worker rtree_leaf_elm_write(tsdn, &extents_rtree, a_elm_b, NULL,
2147*1208bc7eSAndroid Build Coastguard Worker NSIZES, false);
2148*1208bc7eSAndroid Build Coastguard Worker }
2149*1208bc7eSAndroid Build Coastguard Worker if (b_elm_b != NULL) {
2150*1208bc7eSAndroid Build Coastguard Worker rtree_leaf_elm_write(tsdn, &extents_rtree, b_elm_a, NULL,
2151*1208bc7eSAndroid Build Coastguard Worker NSIZES, false);
2152*1208bc7eSAndroid Build Coastguard Worker } else {
2153*1208bc7eSAndroid Build Coastguard Worker b_elm_b = b_elm_a;
2154*1208bc7eSAndroid Build Coastguard Worker }
2155*1208bc7eSAndroid Build Coastguard Worker
2156*1208bc7eSAndroid Build Coastguard Worker extent_size_set(a, extent_size_get(a) + extent_size_get(b));
2157*1208bc7eSAndroid Build Coastguard Worker extent_szind_set(a, NSIZES);
2158*1208bc7eSAndroid Build Coastguard Worker extent_sn_set(a, (extent_sn_get(a) < extent_sn_get(b)) ?
2159*1208bc7eSAndroid Build Coastguard Worker extent_sn_get(a) : extent_sn_get(b));
2160*1208bc7eSAndroid Build Coastguard Worker extent_zeroed_set(a, extent_zeroed_get(a) && extent_zeroed_get(b));
2161*1208bc7eSAndroid Build Coastguard Worker
2162*1208bc7eSAndroid Build Coastguard Worker extent_rtree_write_acquired(tsdn, a_elm_a, b_elm_b, a, NSIZES, false);
2163*1208bc7eSAndroid Build Coastguard Worker
2164*1208bc7eSAndroid Build Coastguard Worker extent_unlock2(tsdn, a, b);
2165*1208bc7eSAndroid Build Coastguard Worker
2166*1208bc7eSAndroid Build Coastguard Worker extent_dalloc(tsdn, extent_arena_get(b), b);
2167*1208bc7eSAndroid Build Coastguard Worker
2168*1208bc7eSAndroid Build Coastguard Worker return false;
2169*1208bc7eSAndroid Build Coastguard Worker }
2170*1208bc7eSAndroid Build Coastguard Worker
2171*1208bc7eSAndroid Build Coastguard Worker bool
extent_merge_wrapper(tsdn_t * tsdn,arena_t * arena,extent_hooks_t ** r_extent_hooks,extent_t * a,extent_t * b)2172*1208bc7eSAndroid Build Coastguard Worker extent_merge_wrapper(tsdn_t *tsdn, arena_t *arena,
2173*1208bc7eSAndroid Build Coastguard Worker extent_hooks_t **r_extent_hooks, extent_t *a, extent_t *b) {
2174*1208bc7eSAndroid Build Coastguard Worker return extent_merge_impl(tsdn, arena, r_extent_hooks, a, b, false);
2175*1208bc7eSAndroid Build Coastguard Worker }
2176*1208bc7eSAndroid Build Coastguard Worker
2177*1208bc7eSAndroid Build Coastguard Worker bool
extent_boot(void)2178*1208bc7eSAndroid Build Coastguard Worker extent_boot(void) {
2179*1208bc7eSAndroid Build Coastguard Worker if (rtree_new(&extents_rtree, true)) {
2180*1208bc7eSAndroid Build Coastguard Worker return true;
2181*1208bc7eSAndroid Build Coastguard Worker }
2182*1208bc7eSAndroid Build Coastguard Worker
2183*1208bc7eSAndroid Build Coastguard Worker if (mutex_pool_init(&extent_mutex_pool, "extent_mutex_pool",
2184*1208bc7eSAndroid Build Coastguard Worker WITNESS_RANK_EXTENT_POOL)) {
2185*1208bc7eSAndroid Build Coastguard Worker return true;
2186*1208bc7eSAndroid Build Coastguard Worker }
2187*1208bc7eSAndroid Build Coastguard Worker
2188*1208bc7eSAndroid Build Coastguard Worker if (have_dss) {
2189*1208bc7eSAndroid Build Coastguard Worker extent_dss_boot();
2190*1208bc7eSAndroid Build Coastguard Worker }
2191*1208bc7eSAndroid Build Coastguard Worker
2192*1208bc7eSAndroid Build Coastguard Worker return false;
2193*1208bc7eSAndroid Build Coastguard Worker }
2194*1208bc7eSAndroid Build Coastguard Worker
2195*1208bc7eSAndroid Build Coastguard Worker void
extent_postfork_child(tsdn_t * tsdn)2196*1208bc7eSAndroid Build Coastguard Worker extent_postfork_child(tsdn_t *tsdn) {
2197*1208bc7eSAndroid Build Coastguard Worker // There is the possibility that a thread is holding one of these locks
2198*1208bc7eSAndroid Build Coastguard Worker // when forking, but all of the other locks acquired during the prefork
2199*1208bc7eSAndroid Build Coastguard Worker // should prevent any corruption if this code resets the locks.
2200*1208bc7eSAndroid Build Coastguard Worker mutex_pool_init(&extent_mutex_pool, "extent_mutex_pool",
2201*1208bc7eSAndroid Build Coastguard Worker WITNESS_RANK_EXTENT_POOL);
2202*1208bc7eSAndroid Build Coastguard Worker
2203*1208bc7eSAndroid Build Coastguard Worker malloc_mutex_init(&extents_rtree.init_lock, "rtree", WITNESS_RANK_RTREE, malloc_mutex_rank_exclusive);
2204*1208bc7eSAndroid Build Coastguard Worker }
2205