xref: /aosp_15_r20/external/jemalloc_new/src/extent.c (revision 1208bc7e437ced7eb82efac44ba17e3beba411da)
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