xref: /aosp_15_r20/external/jemalloc_new/src/jemalloc.c (revision 1208bc7e437ced7eb82efac44ba17e3beba411da)
1*1208bc7eSAndroid Build Coastguard Worker #define JEMALLOC_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/atomic.h"
7*1208bc7eSAndroid Build Coastguard Worker #include "jemalloc/internal/ctl.h"
8*1208bc7eSAndroid Build Coastguard Worker #include "jemalloc/internal/extent_dss.h"
9*1208bc7eSAndroid Build Coastguard Worker #include "jemalloc/internal/extent_mmap.h"
10*1208bc7eSAndroid Build Coastguard Worker #include "jemalloc/internal/jemalloc_internal_types.h"
11*1208bc7eSAndroid Build Coastguard Worker #include "jemalloc/internal/log.h"
12*1208bc7eSAndroid Build Coastguard Worker #include "jemalloc/internal/malloc_io.h"
13*1208bc7eSAndroid Build Coastguard Worker #include "jemalloc/internal/mutex.h"
14*1208bc7eSAndroid Build Coastguard Worker #include "jemalloc/internal/rtree.h"
15*1208bc7eSAndroid Build Coastguard Worker #include "jemalloc/internal/size_classes.h"
16*1208bc7eSAndroid Build Coastguard Worker #include "jemalloc/internal/spin.h"
17*1208bc7eSAndroid Build Coastguard Worker #include "jemalloc/internal/sz.h"
18*1208bc7eSAndroid Build Coastguard Worker #include "jemalloc/internal/ticker.h"
19*1208bc7eSAndroid Build Coastguard Worker #include "jemalloc/internal/util.h"
20*1208bc7eSAndroid Build Coastguard Worker 
21*1208bc7eSAndroid Build Coastguard Worker /******************************************************************************/
22*1208bc7eSAndroid Build Coastguard Worker /* Data. */
23*1208bc7eSAndroid Build Coastguard Worker 
24*1208bc7eSAndroid Build Coastguard Worker /* Runtime configuration options. */
25*1208bc7eSAndroid Build Coastguard Worker const char	*je_malloc_conf
26*1208bc7eSAndroid Build Coastguard Worker #ifndef _WIN32
27*1208bc7eSAndroid Build Coastguard Worker     JEMALLOC_ATTR(weak)
28*1208bc7eSAndroid Build Coastguard Worker #endif
29*1208bc7eSAndroid Build Coastguard Worker     ;
30*1208bc7eSAndroid Build Coastguard Worker bool	opt_abort =
31*1208bc7eSAndroid Build Coastguard Worker #ifdef JEMALLOC_DEBUG
32*1208bc7eSAndroid Build Coastguard Worker     true
33*1208bc7eSAndroid Build Coastguard Worker #else
34*1208bc7eSAndroid Build Coastguard Worker     false
35*1208bc7eSAndroid Build Coastguard Worker #endif
36*1208bc7eSAndroid Build Coastguard Worker     ;
37*1208bc7eSAndroid Build Coastguard Worker bool	opt_abort_conf =
38*1208bc7eSAndroid Build Coastguard Worker #ifdef JEMALLOC_DEBUG
39*1208bc7eSAndroid Build Coastguard Worker     true
40*1208bc7eSAndroid Build Coastguard Worker #else
41*1208bc7eSAndroid Build Coastguard Worker     false
42*1208bc7eSAndroid Build Coastguard Worker #endif
43*1208bc7eSAndroid Build Coastguard Worker     ;
44*1208bc7eSAndroid Build Coastguard Worker const char	*opt_junk =
45*1208bc7eSAndroid Build Coastguard Worker #if (defined(JEMALLOC_DEBUG) && defined(JEMALLOC_FILL))
46*1208bc7eSAndroid Build Coastguard Worker     "true"
47*1208bc7eSAndroid Build Coastguard Worker #else
48*1208bc7eSAndroid Build Coastguard Worker     "false"
49*1208bc7eSAndroid Build Coastguard Worker #endif
50*1208bc7eSAndroid Build Coastguard Worker     ;
51*1208bc7eSAndroid Build Coastguard Worker bool	opt_junk_alloc =
52*1208bc7eSAndroid Build Coastguard Worker #if (defined(JEMALLOC_DEBUG) && defined(JEMALLOC_FILL))
53*1208bc7eSAndroid Build Coastguard Worker     true
54*1208bc7eSAndroid Build Coastguard Worker #else
55*1208bc7eSAndroid Build Coastguard Worker     false
56*1208bc7eSAndroid Build Coastguard Worker #endif
57*1208bc7eSAndroid Build Coastguard Worker     ;
58*1208bc7eSAndroid Build Coastguard Worker bool	opt_junk_free =
59*1208bc7eSAndroid Build Coastguard Worker #if (defined(JEMALLOC_DEBUG) && defined(JEMALLOC_FILL))
60*1208bc7eSAndroid Build Coastguard Worker     true
61*1208bc7eSAndroid Build Coastguard Worker #else
62*1208bc7eSAndroid Build Coastguard Worker     false
63*1208bc7eSAndroid Build Coastguard Worker #endif
64*1208bc7eSAndroid Build Coastguard Worker     ;
65*1208bc7eSAndroid Build Coastguard Worker 
66*1208bc7eSAndroid Build Coastguard Worker bool	opt_utrace = false;
67*1208bc7eSAndroid Build Coastguard Worker bool	opt_xmalloc = false;
68*1208bc7eSAndroid Build Coastguard Worker bool	opt_zero = false;
69*1208bc7eSAndroid Build Coastguard Worker unsigned	opt_narenas = 0;
70*1208bc7eSAndroid Build Coastguard Worker 
71*1208bc7eSAndroid Build Coastguard Worker unsigned	ncpus;
72*1208bc7eSAndroid Build Coastguard Worker 
73*1208bc7eSAndroid Build Coastguard Worker /* Protects arenas initialization. */
74*1208bc7eSAndroid Build Coastguard Worker malloc_mutex_t arenas_lock;
75*1208bc7eSAndroid Build Coastguard Worker /*
76*1208bc7eSAndroid Build Coastguard Worker  * Arenas that are used to service external requests.  Not all elements of the
77*1208bc7eSAndroid Build Coastguard Worker  * arenas array are necessarily used; arenas are created lazily as needed.
78*1208bc7eSAndroid Build Coastguard Worker  *
79*1208bc7eSAndroid Build Coastguard Worker  * arenas[0..narenas_auto) are used for automatic multiplexing of threads and
80*1208bc7eSAndroid Build Coastguard Worker  * arenas.  arenas[narenas_auto..narenas_total) are only used if the application
81*1208bc7eSAndroid Build Coastguard Worker  * takes some action to create them and allocate from them.
82*1208bc7eSAndroid Build Coastguard Worker  *
83*1208bc7eSAndroid Build Coastguard Worker  * Points to an arena_t.
84*1208bc7eSAndroid Build Coastguard Worker  */
85*1208bc7eSAndroid Build Coastguard Worker JEMALLOC_ALIGNED(CACHELINE)
86*1208bc7eSAndroid Build Coastguard Worker atomic_p_t		arenas[MALLOCX_ARENA_LIMIT];
87*1208bc7eSAndroid Build Coastguard Worker static atomic_u_t	narenas_total; /* Use narenas_total_*(). */
88*1208bc7eSAndroid Build Coastguard Worker static arena_t		*a0; /* arenas[0]; read-only after initialization. */
89*1208bc7eSAndroid Build Coastguard Worker unsigned		narenas_auto; /* Read-only after initialization. */
90*1208bc7eSAndroid Build Coastguard Worker 
91*1208bc7eSAndroid Build Coastguard Worker typedef enum {
92*1208bc7eSAndroid Build Coastguard Worker 	malloc_init_uninitialized	= 3,
93*1208bc7eSAndroid Build Coastguard Worker 	malloc_init_a0_initialized	= 2,
94*1208bc7eSAndroid Build Coastguard Worker 	malloc_init_recursible		= 1,
95*1208bc7eSAndroid Build Coastguard Worker 	malloc_init_initialized		= 0 /* Common case --> jnz. */
96*1208bc7eSAndroid Build Coastguard Worker } malloc_init_t;
97*1208bc7eSAndroid Build Coastguard Worker static malloc_init_t	malloc_init_state = malloc_init_uninitialized;
98*1208bc7eSAndroid Build Coastguard Worker 
99*1208bc7eSAndroid Build Coastguard Worker /* False should be the common case.  Set to true to trigger initialization. */
100*1208bc7eSAndroid Build Coastguard Worker bool			malloc_slow = true;
101*1208bc7eSAndroid Build Coastguard Worker 
102*1208bc7eSAndroid Build Coastguard Worker /* When malloc_slow is true, set the corresponding bits for sanity check. */
103*1208bc7eSAndroid Build Coastguard Worker enum {
104*1208bc7eSAndroid Build Coastguard Worker 	flag_opt_junk_alloc	= (1U),
105*1208bc7eSAndroid Build Coastguard Worker 	flag_opt_junk_free	= (1U << 1),
106*1208bc7eSAndroid Build Coastguard Worker 	flag_opt_zero		= (1U << 2),
107*1208bc7eSAndroid Build Coastguard Worker 	flag_opt_utrace		= (1U << 3),
108*1208bc7eSAndroid Build Coastguard Worker 	flag_opt_xmalloc	= (1U << 4)
109*1208bc7eSAndroid Build Coastguard Worker };
110*1208bc7eSAndroid Build Coastguard Worker static uint8_t	malloc_slow_flags;
111*1208bc7eSAndroid Build Coastguard Worker 
112*1208bc7eSAndroid Build Coastguard Worker #ifdef JEMALLOC_THREADED_INIT
113*1208bc7eSAndroid Build Coastguard Worker /* Used to let the initializing thread recursively allocate. */
114*1208bc7eSAndroid Build Coastguard Worker #  define NO_INITIALIZER	((pthread_t)0)
115*1208bc7eSAndroid Build Coastguard Worker #  define INITIALIZER		pthread_self()
116*1208bc7eSAndroid Build Coastguard Worker #  define IS_INITIALIZER	(malloc_initializer == pthread_self())
117*1208bc7eSAndroid Build Coastguard Worker static pthread_t		malloc_initializer = NO_INITIALIZER;
118*1208bc7eSAndroid Build Coastguard Worker #else
119*1208bc7eSAndroid Build Coastguard Worker #  define NO_INITIALIZER	false
120*1208bc7eSAndroid Build Coastguard Worker #  define INITIALIZER		true
121*1208bc7eSAndroid Build Coastguard Worker #  define IS_INITIALIZER	malloc_initializer
122*1208bc7eSAndroid Build Coastguard Worker static bool			malloc_initializer = NO_INITIALIZER;
123*1208bc7eSAndroid Build Coastguard Worker #endif
124*1208bc7eSAndroid Build Coastguard Worker 
125*1208bc7eSAndroid Build Coastguard Worker /* Used to avoid initialization races. */
126*1208bc7eSAndroid Build Coastguard Worker #ifdef _WIN32
127*1208bc7eSAndroid Build Coastguard Worker #if _WIN32_WINNT >= 0x0600
128*1208bc7eSAndroid Build Coastguard Worker static malloc_mutex_t	init_lock = SRWLOCK_INIT;
129*1208bc7eSAndroid Build Coastguard Worker #else
130*1208bc7eSAndroid Build Coastguard Worker static malloc_mutex_t	init_lock;
131*1208bc7eSAndroid Build Coastguard Worker static bool init_lock_initialized = false;
132*1208bc7eSAndroid Build Coastguard Worker 
JEMALLOC_ATTR(constructor)133*1208bc7eSAndroid Build Coastguard Worker JEMALLOC_ATTR(constructor)
134*1208bc7eSAndroid Build Coastguard Worker static void WINAPI
135*1208bc7eSAndroid Build Coastguard Worker _init_init_lock(void) {
136*1208bc7eSAndroid Build Coastguard Worker 	/*
137*1208bc7eSAndroid Build Coastguard Worker 	 * If another constructor in the same binary is using mallctl to e.g.
138*1208bc7eSAndroid Build Coastguard Worker 	 * set up extent hooks, it may end up running before this one, and
139*1208bc7eSAndroid Build Coastguard Worker 	 * malloc_init_hard will crash trying to lock the uninitialized lock. So
140*1208bc7eSAndroid Build Coastguard Worker 	 * we force an initialization of the lock in malloc_init_hard as well.
141*1208bc7eSAndroid Build Coastguard Worker 	 * We don't try to care about atomicity of the accessed to the
142*1208bc7eSAndroid Build Coastguard Worker 	 * init_lock_initialized boolean, since it really only matters early in
143*1208bc7eSAndroid Build Coastguard Worker 	 * the process creation, before any separate thread normally starts
144*1208bc7eSAndroid Build Coastguard Worker 	 * doing anything.
145*1208bc7eSAndroid Build Coastguard Worker 	 */
146*1208bc7eSAndroid Build Coastguard Worker 	if (!init_lock_initialized) {
147*1208bc7eSAndroid Build Coastguard Worker 		malloc_mutex_init(&init_lock, "init", WITNESS_RANK_INIT,
148*1208bc7eSAndroid Build Coastguard Worker 		    malloc_mutex_rank_exclusive);
149*1208bc7eSAndroid Build Coastguard Worker 	}
150*1208bc7eSAndroid Build Coastguard Worker 	init_lock_initialized = true;
151*1208bc7eSAndroid Build Coastguard Worker }
152*1208bc7eSAndroid Build Coastguard Worker 
153*1208bc7eSAndroid Build Coastguard Worker #ifdef _MSC_VER
154*1208bc7eSAndroid Build Coastguard Worker #  pragma section(".CRT$XCU", read)
155*1208bc7eSAndroid Build Coastguard Worker JEMALLOC_SECTION(".CRT$XCU") JEMALLOC_ATTR(used)
156*1208bc7eSAndroid Build Coastguard Worker static const void (WINAPI *init_init_lock)(void) = _init_init_lock;
157*1208bc7eSAndroid Build Coastguard Worker #endif
158*1208bc7eSAndroid Build Coastguard Worker #endif
159*1208bc7eSAndroid Build Coastguard Worker #else
160*1208bc7eSAndroid Build Coastguard Worker static malloc_mutex_t	init_lock = MALLOC_MUTEX_INITIALIZER;
161*1208bc7eSAndroid Build Coastguard Worker #endif
162*1208bc7eSAndroid Build Coastguard Worker 
163*1208bc7eSAndroid Build Coastguard Worker typedef struct {
164*1208bc7eSAndroid Build Coastguard Worker 	void	*p;	/* Input pointer (as in realloc(p, s)). */
165*1208bc7eSAndroid Build Coastguard Worker 	size_t	s;	/* Request size. */
166*1208bc7eSAndroid Build Coastguard Worker 	void	*r;	/* Result pointer. */
167*1208bc7eSAndroid Build Coastguard Worker } malloc_utrace_t;
168*1208bc7eSAndroid Build Coastguard Worker 
169*1208bc7eSAndroid Build Coastguard Worker #ifdef JEMALLOC_UTRACE
170*1208bc7eSAndroid Build Coastguard Worker #  define UTRACE(a, b, c) do {						\
171*1208bc7eSAndroid Build Coastguard Worker 	if (unlikely(opt_utrace)) {					\
172*1208bc7eSAndroid Build Coastguard Worker 		int utrace_serrno = errno;				\
173*1208bc7eSAndroid Build Coastguard Worker 		malloc_utrace_t ut;					\
174*1208bc7eSAndroid Build Coastguard Worker 		ut.p = (a);						\
175*1208bc7eSAndroid Build Coastguard Worker 		ut.s = (b);						\
176*1208bc7eSAndroid Build Coastguard Worker 		ut.r = (c);						\
177*1208bc7eSAndroid Build Coastguard Worker 		utrace(&ut, sizeof(ut));				\
178*1208bc7eSAndroid Build Coastguard Worker 		errno = utrace_serrno;					\
179*1208bc7eSAndroid Build Coastguard Worker 	}								\
180*1208bc7eSAndroid Build Coastguard Worker } while (0)
181*1208bc7eSAndroid Build Coastguard Worker #else
182*1208bc7eSAndroid Build Coastguard Worker #  define UTRACE(a, b, c)
183*1208bc7eSAndroid Build Coastguard Worker #endif
184*1208bc7eSAndroid Build Coastguard Worker 
185*1208bc7eSAndroid Build Coastguard Worker /* Whether encountered any invalid config options. */
186*1208bc7eSAndroid Build Coastguard Worker static bool had_conf_error = false;
187*1208bc7eSAndroid Build Coastguard Worker 
188*1208bc7eSAndroid Build Coastguard Worker /******************************************************************************/
189*1208bc7eSAndroid Build Coastguard Worker /*
190*1208bc7eSAndroid Build Coastguard Worker  * Function prototypes for static functions that are referenced prior to
191*1208bc7eSAndroid Build Coastguard Worker  * definition.
192*1208bc7eSAndroid Build Coastguard Worker  */
193*1208bc7eSAndroid Build Coastguard Worker 
194*1208bc7eSAndroid Build Coastguard Worker static bool	malloc_init_hard_a0(void);
195*1208bc7eSAndroid Build Coastguard Worker static bool	malloc_init_hard(void);
196*1208bc7eSAndroid Build Coastguard Worker 
197*1208bc7eSAndroid Build Coastguard Worker /******************************************************************************/
198*1208bc7eSAndroid Build Coastguard Worker /*
199*1208bc7eSAndroid Build Coastguard Worker  * Begin miscellaneous support functions.
200*1208bc7eSAndroid Build Coastguard Worker  */
201*1208bc7eSAndroid Build Coastguard Worker 
202*1208bc7eSAndroid Build Coastguard Worker bool
malloc_initialized(void)203*1208bc7eSAndroid Build Coastguard Worker malloc_initialized(void) {
204*1208bc7eSAndroid Build Coastguard Worker 	return (malloc_init_state == malloc_init_initialized);
205*1208bc7eSAndroid Build Coastguard Worker }
206*1208bc7eSAndroid Build Coastguard Worker 
207*1208bc7eSAndroid Build Coastguard Worker JEMALLOC_ALWAYS_INLINE bool
malloc_init_a0(void)208*1208bc7eSAndroid Build Coastguard Worker malloc_init_a0(void) {
209*1208bc7eSAndroid Build Coastguard Worker 	if (unlikely(malloc_init_state == malloc_init_uninitialized)) {
210*1208bc7eSAndroid Build Coastguard Worker 		return malloc_init_hard_a0();
211*1208bc7eSAndroid Build Coastguard Worker 	}
212*1208bc7eSAndroid Build Coastguard Worker 	return false;
213*1208bc7eSAndroid Build Coastguard Worker }
214*1208bc7eSAndroid Build Coastguard Worker 
215*1208bc7eSAndroid Build Coastguard Worker JEMALLOC_ALWAYS_INLINE bool
malloc_init(void)216*1208bc7eSAndroid Build Coastguard Worker malloc_init(void) {
217*1208bc7eSAndroid Build Coastguard Worker 	if (unlikely(!malloc_initialized()) && malloc_init_hard()) {
218*1208bc7eSAndroid Build Coastguard Worker 		return true;
219*1208bc7eSAndroid Build Coastguard Worker 	}
220*1208bc7eSAndroid Build Coastguard Worker 	return false;
221*1208bc7eSAndroid Build Coastguard Worker }
222*1208bc7eSAndroid Build Coastguard Worker 
223*1208bc7eSAndroid Build Coastguard Worker /*
224*1208bc7eSAndroid Build Coastguard Worker  * The a0*() functions are used instead of i{d,}alloc() in situations that
225*1208bc7eSAndroid Build Coastguard Worker  * cannot tolerate TLS variable access.
226*1208bc7eSAndroid Build Coastguard Worker  */
227*1208bc7eSAndroid Build Coastguard Worker 
228*1208bc7eSAndroid Build Coastguard Worker static void *
a0ialloc(size_t size,bool zero,bool is_internal)229*1208bc7eSAndroid Build Coastguard Worker a0ialloc(size_t size, bool zero, bool is_internal) {
230*1208bc7eSAndroid Build Coastguard Worker 	if (unlikely(malloc_init_a0())) {
231*1208bc7eSAndroid Build Coastguard Worker 		return NULL;
232*1208bc7eSAndroid Build Coastguard Worker 	}
233*1208bc7eSAndroid Build Coastguard Worker 
234*1208bc7eSAndroid Build Coastguard Worker 	return iallocztm(TSDN_NULL, size, sz_size2index(size), zero, NULL,
235*1208bc7eSAndroid Build Coastguard Worker 	    is_internal, arena_get(TSDN_NULL, 0, true), true);
236*1208bc7eSAndroid Build Coastguard Worker }
237*1208bc7eSAndroid Build Coastguard Worker 
238*1208bc7eSAndroid Build Coastguard Worker static void
a0idalloc(void * ptr,bool is_internal)239*1208bc7eSAndroid Build Coastguard Worker a0idalloc(void *ptr, bool is_internal) {
240*1208bc7eSAndroid Build Coastguard Worker 	idalloctm(TSDN_NULL, ptr, NULL, NULL, is_internal, true);
241*1208bc7eSAndroid Build Coastguard Worker }
242*1208bc7eSAndroid Build Coastguard Worker 
243*1208bc7eSAndroid Build Coastguard Worker void *
a0malloc(size_t size)244*1208bc7eSAndroid Build Coastguard Worker a0malloc(size_t size) {
245*1208bc7eSAndroid Build Coastguard Worker 	return a0ialloc(size, false, true);
246*1208bc7eSAndroid Build Coastguard Worker }
247*1208bc7eSAndroid Build Coastguard Worker 
248*1208bc7eSAndroid Build Coastguard Worker void
a0dalloc(void * ptr)249*1208bc7eSAndroid Build Coastguard Worker a0dalloc(void *ptr) {
250*1208bc7eSAndroid Build Coastguard Worker 	a0idalloc(ptr, true);
251*1208bc7eSAndroid Build Coastguard Worker }
252*1208bc7eSAndroid Build Coastguard Worker 
253*1208bc7eSAndroid Build Coastguard Worker /*
254*1208bc7eSAndroid Build Coastguard Worker  * FreeBSD's libc uses the bootstrap_*() functions in bootstrap-senstive
255*1208bc7eSAndroid Build Coastguard Worker  * situations that cannot tolerate TLS variable access (TLS allocation and very
256*1208bc7eSAndroid Build Coastguard Worker  * early internal data structure initialization).
257*1208bc7eSAndroid Build Coastguard Worker  */
258*1208bc7eSAndroid Build Coastguard Worker 
259*1208bc7eSAndroid Build Coastguard Worker void *
bootstrap_malloc(size_t size)260*1208bc7eSAndroid Build Coastguard Worker bootstrap_malloc(size_t size) {
261*1208bc7eSAndroid Build Coastguard Worker 	if (unlikely(size == 0)) {
262*1208bc7eSAndroid Build Coastguard Worker 		size = 1;
263*1208bc7eSAndroid Build Coastguard Worker 	}
264*1208bc7eSAndroid Build Coastguard Worker 
265*1208bc7eSAndroid Build Coastguard Worker 	return a0ialloc(size, false, false);
266*1208bc7eSAndroid Build Coastguard Worker }
267*1208bc7eSAndroid Build Coastguard Worker 
268*1208bc7eSAndroid Build Coastguard Worker void *
bootstrap_calloc(size_t num,size_t size)269*1208bc7eSAndroid Build Coastguard Worker bootstrap_calloc(size_t num, size_t size) {
270*1208bc7eSAndroid Build Coastguard Worker 	size_t num_size;
271*1208bc7eSAndroid Build Coastguard Worker 
272*1208bc7eSAndroid Build Coastguard Worker 	num_size = num * size;
273*1208bc7eSAndroid Build Coastguard Worker 	if (unlikely(num_size == 0)) {
274*1208bc7eSAndroid Build Coastguard Worker 		assert(num == 0 || size == 0);
275*1208bc7eSAndroid Build Coastguard Worker 		num_size = 1;
276*1208bc7eSAndroid Build Coastguard Worker 	}
277*1208bc7eSAndroid Build Coastguard Worker 
278*1208bc7eSAndroid Build Coastguard Worker 	return a0ialloc(num_size, true, false);
279*1208bc7eSAndroid Build Coastguard Worker }
280*1208bc7eSAndroid Build Coastguard Worker 
281*1208bc7eSAndroid Build Coastguard Worker void
bootstrap_free(void * ptr)282*1208bc7eSAndroid Build Coastguard Worker bootstrap_free(void *ptr) {
283*1208bc7eSAndroid Build Coastguard Worker 	if (unlikely(ptr == NULL)) {
284*1208bc7eSAndroid Build Coastguard Worker 		return;
285*1208bc7eSAndroid Build Coastguard Worker 	}
286*1208bc7eSAndroid Build Coastguard Worker 
287*1208bc7eSAndroid Build Coastguard Worker 	a0idalloc(ptr, false);
288*1208bc7eSAndroid Build Coastguard Worker }
289*1208bc7eSAndroid Build Coastguard Worker 
290*1208bc7eSAndroid Build Coastguard Worker void
arena_set(unsigned ind,arena_t * arena)291*1208bc7eSAndroid Build Coastguard Worker arena_set(unsigned ind, arena_t *arena) {
292*1208bc7eSAndroid Build Coastguard Worker 	atomic_store_p(&arenas[ind], arena, ATOMIC_RELEASE);
293*1208bc7eSAndroid Build Coastguard Worker }
294*1208bc7eSAndroid Build Coastguard Worker 
295*1208bc7eSAndroid Build Coastguard Worker static void
narenas_total_set(unsigned narenas)296*1208bc7eSAndroid Build Coastguard Worker narenas_total_set(unsigned narenas) {
297*1208bc7eSAndroid Build Coastguard Worker 	atomic_store_u(&narenas_total, narenas, ATOMIC_RELEASE);
298*1208bc7eSAndroid Build Coastguard Worker }
299*1208bc7eSAndroid Build Coastguard Worker 
300*1208bc7eSAndroid Build Coastguard Worker static void
narenas_total_inc(void)301*1208bc7eSAndroid Build Coastguard Worker narenas_total_inc(void) {
302*1208bc7eSAndroid Build Coastguard Worker 	atomic_fetch_add_u(&narenas_total, 1, ATOMIC_RELEASE);
303*1208bc7eSAndroid Build Coastguard Worker }
304*1208bc7eSAndroid Build Coastguard Worker 
305*1208bc7eSAndroid Build Coastguard Worker unsigned
narenas_total_get(void)306*1208bc7eSAndroid Build Coastguard Worker narenas_total_get(void) {
307*1208bc7eSAndroid Build Coastguard Worker 	return atomic_load_u(&narenas_total, ATOMIC_ACQUIRE);
308*1208bc7eSAndroid Build Coastguard Worker }
309*1208bc7eSAndroid Build Coastguard Worker 
310*1208bc7eSAndroid Build Coastguard Worker /* Create a new arena and insert it into the arenas array at index ind. */
311*1208bc7eSAndroid Build Coastguard Worker static arena_t *
arena_init_locked(tsdn_t * tsdn,unsigned ind,extent_hooks_t * extent_hooks)312*1208bc7eSAndroid Build Coastguard Worker arena_init_locked(tsdn_t *tsdn, unsigned ind, extent_hooks_t *extent_hooks) {
313*1208bc7eSAndroid Build Coastguard Worker 	arena_t *arena;
314*1208bc7eSAndroid Build Coastguard Worker 
315*1208bc7eSAndroid Build Coastguard Worker 	assert(ind <= narenas_total_get());
316*1208bc7eSAndroid Build Coastguard Worker 	if (ind >= MALLOCX_ARENA_LIMIT) {
317*1208bc7eSAndroid Build Coastguard Worker 		return NULL;
318*1208bc7eSAndroid Build Coastguard Worker 	}
319*1208bc7eSAndroid Build Coastguard Worker 	if (ind == narenas_total_get()) {
320*1208bc7eSAndroid Build Coastguard Worker 		narenas_total_inc();
321*1208bc7eSAndroid Build Coastguard Worker 	}
322*1208bc7eSAndroid Build Coastguard Worker 
323*1208bc7eSAndroid Build Coastguard Worker 	/*
324*1208bc7eSAndroid Build Coastguard Worker 	 * Another thread may have already initialized arenas[ind] if it's an
325*1208bc7eSAndroid Build Coastguard Worker 	 * auto arena.
326*1208bc7eSAndroid Build Coastguard Worker 	 */
327*1208bc7eSAndroid Build Coastguard Worker 	arena = arena_get(tsdn, ind, false);
328*1208bc7eSAndroid Build Coastguard Worker 	if (arena != NULL) {
329*1208bc7eSAndroid Build Coastguard Worker 		assert(ind < narenas_auto);
330*1208bc7eSAndroid Build Coastguard Worker 		return arena;
331*1208bc7eSAndroid Build Coastguard Worker 	}
332*1208bc7eSAndroid Build Coastguard Worker 
333*1208bc7eSAndroid Build Coastguard Worker 	/* Actually initialize the arena. */
334*1208bc7eSAndroid Build Coastguard Worker 	arena = arena_new(tsdn, ind, extent_hooks);
335*1208bc7eSAndroid Build Coastguard Worker 
336*1208bc7eSAndroid Build Coastguard Worker 	return arena;
337*1208bc7eSAndroid Build Coastguard Worker }
338*1208bc7eSAndroid Build Coastguard Worker 
339*1208bc7eSAndroid Build Coastguard Worker static void
arena_new_create_background_thread(tsdn_t * tsdn,unsigned ind)340*1208bc7eSAndroid Build Coastguard Worker arena_new_create_background_thread(tsdn_t *tsdn, unsigned ind) {
341*1208bc7eSAndroid Build Coastguard Worker 	if (ind == 0) {
342*1208bc7eSAndroid Build Coastguard Worker 		return;
343*1208bc7eSAndroid Build Coastguard Worker 	}
344*1208bc7eSAndroid Build Coastguard Worker 	if (have_background_thread) {
345*1208bc7eSAndroid Build Coastguard Worker 		bool err;
346*1208bc7eSAndroid Build Coastguard Worker 		malloc_mutex_lock(tsdn, &background_thread_lock);
347*1208bc7eSAndroid Build Coastguard Worker 		err = background_thread_create(tsdn_tsd(tsdn), ind);
348*1208bc7eSAndroid Build Coastguard Worker 		malloc_mutex_unlock(tsdn, &background_thread_lock);
349*1208bc7eSAndroid Build Coastguard Worker 		if (err) {
350*1208bc7eSAndroid Build Coastguard Worker 			malloc_printf("<jemalloc>: error in background thread "
351*1208bc7eSAndroid Build Coastguard Worker 				      "creation for arena %u. Abort.\n", ind);
352*1208bc7eSAndroid Build Coastguard Worker 			abort();
353*1208bc7eSAndroid Build Coastguard Worker 		}
354*1208bc7eSAndroid Build Coastguard Worker 	}
355*1208bc7eSAndroid Build Coastguard Worker }
356*1208bc7eSAndroid Build Coastguard Worker 
357*1208bc7eSAndroid Build Coastguard Worker arena_t *
arena_init(tsdn_t * tsdn,unsigned ind,extent_hooks_t * extent_hooks)358*1208bc7eSAndroid Build Coastguard Worker arena_init(tsdn_t *tsdn, unsigned ind, extent_hooks_t *extent_hooks) {
359*1208bc7eSAndroid Build Coastguard Worker 	arena_t *arena;
360*1208bc7eSAndroid Build Coastguard Worker 
361*1208bc7eSAndroid Build Coastguard Worker 	malloc_mutex_lock(tsdn, &arenas_lock);
362*1208bc7eSAndroid Build Coastguard Worker 	arena = arena_init_locked(tsdn, ind, extent_hooks);
363*1208bc7eSAndroid Build Coastguard Worker 	malloc_mutex_unlock(tsdn, &arenas_lock);
364*1208bc7eSAndroid Build Coastguard Worker 
365*1208bc7eSAndroid Build Coastguard Worker 	arena_new_create_background_thread(tsdn, ind);
366*1208bc7eSAndroid Build Coastguard Worker 
367*1208bc7eSAndroid Build Coastguard Worker 	return arena;
368*1208bc7eSAndroid Build Coastguard Worker }
369*1208bc7eSAndroid Build Coastguard Worker 
370*1208bc7eSAndroid Build Coastguard Worker static void
arena_bind(tsd_t * tsd,unsigned ind,bool internal)371*1208bc7eSAndroid Build Coastguard Worker arena_bind(tsd_t *tsd, unsigned ind, bool internal) {
372*1208bc7eSAndroid Build Coastguard Worker 	arena_t *arena = arena_get(tsd_tsdn(tsd), ind, false);
373*1208bc7eSAndroid Build Coastguard Worker 	arena_nthreads_inc(arena, internal);
374*1208bc7eSAndroid Build Coastguard Worker 
375*1208bc7eSAndroid Build Coastguard Worker 	if (internal) {
376*1208bc7eSAndroid Build Coastguard Worker 		tsd_iarena_set(tsd, arena);
377*1208bc7eSAndroid Build Coastguard Worker 	} else {
378*1208bc7eSAndroid Build Coastguard Worker 		tsd_arena_set(tsd, arena);
379*1208bc7eSAndroid Build Coastguard Worker 	}
380*1208bc7eSAndroid Build Coastguard Worker }
381*1208bc7eSAndroid Build Coastguard Worker 
382*1208bc7eSAndroid Build Coastguard Worker void
arena_migrate(tsd_t * tsd,unsigned oldind,unsigned newind)383*1208bc7eSAndroid Build Coastguard Worker arena_migrate(tsd_t *tsd, unsigned oldind, unsigned newind) {
384*1208bc7eSAndroid Build Coastguard Worker 	arena_t *oldarena, *newarena;
385*1208bc7eSAndroid Build Coastguard Worker 
386*1208bc7eSAndroid Build Coastguard Worker 	oldarena = arena_get(tsd_tsdn(tsd), oldind, false);
387*1208bc7eSAndroid Build Coastguard Worker 	newarena = arena_get(tsd_tsdn(tsd), newind, false);
388*1208bc7eSAndroid Build Coastguard Worker 	arena_nthreads_dec(oldarena, false);
389*1208bc7eSAndroid Build Coastguard Worker 	arena_nthreads_inc(newarena, false);
390*1208bc7eSAndroid Build Coastguard Worker 	tsd_arena_set(tsd, newarena);
391*1208bc7eSAndroid Build Coastguard Worker }
392*1208bc7eSAndroid Build Coastguard Worker 
393*1208bc7eSAndroid Build Coastguard Worker static void
arena_unbind(tsd_t * tsd,unsigned ind,bool internal)394*1208bc7eSAndroid Build Coastguard Worker arena_unbind(tsd_t *tsd, unsigned ind, bool internal) {
395*1208bc7eSAndroid Build Coastguard Worker 	arena_t *arena;
396*1208bc7eSAndroid Build Coastguard Worker 
397*1208bc7eSAndroid Build Coastguard Worker 	arena = arena_get(tsd_tsdn(tsd), ind, false);
398*1208bc7eSAndroid Build Coastguard Worker 	arena_nthreads_dec(arena, internal);
399*1208bc7eSAndroid Build Coastguard Worker 
400*1208bc7eSAndroid Build Coastguard Worker 	if (internal) {
401*1208bc7eSAndroid Build Coastguard Worker 		tsd_iarena_set(tsd, NULL);
402*1208bc7eSAndroid Build Coastguard Worker 	} else {
403*1208bc7eSAndroid Build Coastguard Worker 		tsd_arena_set(tsd, NULL);
404*1208bc7eSAndroid Build Coastguard Worker 	}
405*1208bc7eSAndroid Build Coastguard Worker }
406*1208bc7eSAndroid Build Coastguard Worker 
407*1208bc7eSAndroid Build Coastguard Worker arena_tdata_t *
arena_tdata_get_hard(tsd_t * tsd,unsigned ind)408*1208bc7eSAndroid Build Coastguard Worker arena_tdata_get_hard(tsd_t *tsd, unsigned ind) {
409*1208bc7eSAndroid Build Coastguard Worker 	arena_tdata_t *tdata, *arenas_tdata_old;
410*1208bc7eSAndroid Build Coastguard Worker 	arena_tdata_t *arenas_tdata = tsd_arenas_tdata_get(tsd);
411*1208bc7eSAndroid Build Coastguard Worker 	unsigned narenas_tdata_old, i;
412*1208bc7eSAndroid Build Coastguard Worker 	unsigned narenas_tdata = tsd_narenas_tdata_get(tsd);
413*1208bc7eSAndroid Build Coastguard Worker 	unsigned narenas_actual = narenas_total_get();
414*1208bc7eSAndroid Build Coastguard Worker 
415*1208bc7eSAndroid Build Coastguard Worker 	/*
416*1208bc7eSAndroid Build Coastguard Worker 	 * Dissociate old tdata array (and set up for deallocation upon return)
417*1208bc7eSAndroid Build Coastguard Worker 	 * if it's too small.
418*1208bc7eSAndroid Build Coastguard Worker 	 */
419*1208bc7eSAndroid Build Coastguard Worker 	if (arenas_tdata != NULL && narenas_tdata < narenas_actual) {
420*1208bc7eSAndroid Build Coastguard Worker 		arenas_tdata_old = arenas_tdata;
421*1208bc7eSAndroid Build Coastguard Worker 		narenas_tdata_old = narenas_tdata;
422*1208bc7eSAndroid Build Coastguard Worker 		arenas_tdata = NULL;
423*1208bc7eSAndroid Build Coastguard Worker 		narenas_tdata = 0;
424*1208bc7eSAndroid Build Coastguard Worker 		tsd_arenas_tdata_set(tsd, arenas_tdata);
425*1208bc7eSAndroid Build Coastguard Worker 		tsd_narenas_tdata_set(tsd, narenas_tdata);
426*1208bc7eSAndroid Build Coastguard Worker 	} else {
427*1208bc7eSAndroid Build Coastguard Worker 		arenas_tdata_old = NULL;
428*1208bc7eSAndroid Build Coastguard Worker 		narenas_tdata_old = 0;
429*1208bc7eSAndroid Build Coastguard Worker 	}
430*1208bc7eSAndroid Build Coastguard Worker 
431*1208bc7eSAndroid Build Coastguard Worker 	/* Allocate tdata array if it's missing. */
432*1208bc7eSAndroid Build Coastguard Worker 	if (arenas_tdata == NULL) {
433*1208bc7eSAndroid Build Coastguard Worker 		bool *arenas_tdata_bypassp = tsd_arenas_tdata_bypassp_get(tsd);
434*1208bc7eSAndroid Build Coastguard Worker 		narenas_tdata = (ind < narenas_actual) ? narenas_actual : ind+1;
435*1208bc7eSAndroid Build Coastguard Worker 
436*1208bc7eSAndroid Build Coastguard Worker 		if (tsd_nominal(tsd) && !*arenas_tdata_bypassp) {
437*1208bc7eSAndroid Build Coastguard Worker 			*arenas_tdata_bypassp = true;
438*1208bc7eSAndroid Build Coastguard Worker 			arenas_tdata = (arena_tdata_t *)a0malloc(
439*1208bc7eSAndroid Build Coastguard Worker 			    sizeof(arena_tdata_t) * narenas_tdata);
440*1208bc7eSAndroid Build Coastguard Worker 			*arenas_tdata_bypassp = false;
441*1208bc7eSAndroid Build Coastguard Worker 		}
442*1208bc7eSAndroid Build Coastguard Worker 		if (arenas_tdata == NULL) {
443*1208bc7eSAndroid Build Coastguard Worker 			tdata = NULL;
444*1208bc7eSAndroid Build Coastguard Worker 			goto label_return;
445*1208bc7eSAndroid Build Coastguard Worker 		}
446*1208bc7eSAndroid Build Coastguard Worker 		assert(tsd_nominal(tsd) && !*arenas_tdata_bypassp);
447*1208bc7eSAndroid Build Coastguard Worker 		tsd_arenas_tdata_set(tsd, arenas_tdata);
448*1208bc7eSAndroid Build Coastguard Worker 		tsd_narenas_tdata_set(tsd, narenas_tdata);
449*1208bc7eSAndroid Build Coastguard Worker 	}
450*1208bc7eSAndroid Build Coastguard Worker 
451*1208bc7eSAndroid Build Coastguard Worker 	/*
452*1208bc7eSAndroid Build Coastguard Worker 	 * Copy to tdata array.  It's possible that the actual number of arenas
453*1208bc7eSAndroid Build Coastguard Worker 	 * has increased since narenas_total_get() was called above, but that
454*1208bc7eSAndroid Build Coastguard Worker 	 * causes no correctness issues unless two threads concurrently execute
455*1208bc7eSAndroid Build Coastguard Worker 	 * the arenas.create mallctl, which we trust mallctl synchronization to
456*1208bc7eSAndroid Build Coastguard Worker 	 * prevent.
457*1208bc7eSAndroid Build Coastguard Worker 	 */
458*1208bc7eSAndroid Build Coastguard Worker 
459*1208bc7eSAndroid Build Coastguard Worker 	/* Copy/initialize tickers. */
460*1208bc7eSAndroid Build Coastguard Worker 	for (i = 0; i < narenas_actual; i++) {
461*1208bc7eSAndroid Build Coastguard Worker 		if (i < narenas_tdata_old) {
462*1208bc7eSAndroid Build Coastguard Worker 			ticker_copy(&arenas_tdata[i].decay_ticker,
463*1208bc7eSAndroid Build Coastguard Worker 			    &arenas_tdata_old[i].decay_ticker);
464*1208bc7eSAndroid Build Coastguard Worker 		} else {
465*1208bc7eSAndroid Build Coastguard Worker 			ticker_init(&arenas_tdata[i].decay_ticker,
466*1208bc7eSAndroid Build Coastguard Worker 			    DECAY_NTICKS_PER_UPDATE);
467*1208bc7eSAndroid Build Coastguard Worker 		}
468*1208bc7eSAndroid Build Coastguard Worker 	}
469*1208bc7eSAndroid Build Coastguard Worker 	if (narenas_tdata > narenas_actual) {
470*1208bc7eSAndroid Build Coastguard Worker 		memset(&arenas_tdata[narenas_actual], 0, sizeof(arena_tdata_t)
471*1208bc7eSAndroid Build Coastguard Worker 		    * (narenas_tdata - narenas_actual));
472*1208bc7eSAndroid Build Coastguard Worker 	}
473*1208bc7eSAndroid Build Coastguard Worker 
474*1208bc7eSAndroid Build Coastguard Worker 	/* Read the refreshed tdata array. */
475*1208bc7eSAndroid Build Coastguard Worker 	tdata = &arenas_tdata[ind];
476*1208bc7eSAndroid Build Coastguard Worker label_return:
477*1208bc7eSAndroid Build Coastguard Worker 	if (arenas_tdata_old != NULL) {
478*1208bc7eSAndroid Build Coastguard Worker 		a0dalloc(arenas_tdata_old);
479*1208bc7eSAndroid Build Coastguard Worker 	}
480*1208bc7eSAndroid Build Coastguard Worker 	return tdata;
481*1208bc7eSAndroid Build Coastguard Worker }
482*1208bc7eSAndroid Build Coastguard Worker 
483*1208bc7eSAndroid Build Coastguard Worker /* Slow path, called only by arena_choose(). */
484*1208bc7eSAndroid Build Coastguard Worker arena_t *
arena_choose_hard(tsd_t * tsd,bool internal)485*1208bc7eSAndroid Build Coastguard Worker arena_choose_hard(tsd_t *tsd, bool internal) {
486*1208bc7eSAndroid Build Coastguard Worker 	arena_t *ret JEMALLOC_CC_SILENCE_INIT(NULL);
487*1208bc7eSAndroid Build Coastguard Worker 
488*1208bc7eSAndroid Build Coastguard Worker 	if (have_percpu_arena && PERCPU_ARENA_ENABLED(opt_percpu_arena)) {
489*1208bc7eSAndroid Build Coastguard Worker 		unsigned choose = percpu_arena_choose();
490*1208bc7eSAndroid Build Coastguard Worker 		ret = arena_get(tsd_tsdn(tsd), choose, true);
491*1208bc7eSAndroid Build Coastguard Worker 		assert(ret != NULL);
492*1208bc7eSAndroid Build Coastguard Worker 		arena_bind(tsd, arena_ind_get(ret), false);
493*1208bc7eSAndroid Build Coastguard Worker 		arena_bind(tsd, arena_ind_get(ret), true);
494*1208bc7eSAndroid Build Coastguard Worker 
495*1208bc7eSAndroid Build Coastguard Worker 		return ret;
496*1208bc7eSAndroid Build Coastguard Worker 	}
497*1208bc7eSAndroid Build Coastguard Worker 
498*1208bc7eSAndroid Build Coastguard Worker 	if (narenas_auto > 1) {
499*1208bc7eSAndroid Build Coastguard Worker 		unsigned i, j, choose[2], first_null;
500*1208bc7eSAndroid Build Coastguard Worker 		bool is_new_arena[2];
501*1208bc7eSAndroid Build Coastguard Worker 
502*1208bc7eSAndroid Build Coastguard Worker 		/*
503*1208bc7eSAndroid Build Coastguard Worker 		 * Determine binding for both non-internal and internal
504*1208bc7eSAndroid Build Coastguard Worker 		 * allocation.
505*1208bc7eSAndroid Build Coastguard Worker 		 *
506*1208bc7eSAndroid Build Coastguard Worker 		 *   choose[0]: For application allocation.
507*1208bc7eSAndroid Build Coastguard Worker 		 *   choose[1]: For internal metadata allocation.
508*1208bc7eSAndroid Build Coastguard Worker 		 */
509*1208bc7eSAndroid Build Coastguard Worker 
510*1208bc7eSAndroid Build Coastguard Worker 		for (j = 0; j < 2; j++) {
511*1208bc7eSAndroid Build Coastguard Worker 			choose[j] = 0;
512*1208bc7eSAndroid Build Coastguard Worker 			is_new_arena[j] = false;
513*1208bc7eSAndroid Build Coastguard Worker 		}
514*1208bc7eSAndroid Build Coastguard Worker 
515*1208bc7eSAndroid Build Coastguard Worker 		first_null = narenas_auto;
516*1208bc7eSAndroid Build Coastguard Worker 		malloc_mutex_lock(tsd_tsdn(tsd), &arenas_lock);
517*1208bc7eSAndroid Build Coastguard Worker 		assert(arena_get(tsd_tsdn(tsd), 0, false) != NULL);
518*1208bc7eSAndroid Build Coastguard Worker 		for (i = 1; i < narenas_auto; i++) {
519*1208bc7eSAndroid Build Coastguard Worker 			if (arena_get(tsd_tsdn(tsd), i, false) != NULL) {
520*1208bc7eSAndroid Build Coastguard Worker 				/*
521*1208bc7eSAndroid Build Coastguard Worker 				 * Choose the first arena that has the lowest
522*1208bc7eSAndroid Build Coastguard Worker 				 * number of threads assigned to it.
523*1208bc7eSAndroid Build Coastguard Worker 				 */
524*1208bc7eSAndroid Build Coastguard Worker 				for (j = 0; j < 2; j++) {
525*1208bc7eSAndroid Build Coastguard Worker 					if (arena_nthreads_get(arena_get(
526*1208bc7eSAndroid Build Coastguard Worker 					    tsd_tsdn(tsd), i, false), !!j) <
527*1208bc7eSAndroid Build Coastguard Worker 					    arena_nthreads_get(arena_get(
528*1208bc7eSAndroid Build Coastguard Worker 					    tsd_tsdn(tsd), choose[j], false),
529*1208bc7eSAndroid Build Coastguard Worker 					    !!j)) {
530*1208bc7eSAndroid Build Coastguard Worker 						choose[j] = i;
531*1208bc7eSAndroid Build Coastguard Worker 					}
532*1208bc7eSAndroid Build Coastguard Worker 				}
533*1208bc7eSAndroid Build Coastguard Worker 			} else if (first_null == narenas_auto) {
534*1208bc7eSAndroid Build Coastguard Worker 				/*
535*1208bc7eSAndroid Build Coastguard Worker 				 * Record the index of the first uninitialized
536*1208bc7eSAndroid Build Coastguard Worker 				 * arena, in case all extant arenas are in use.
537*1208bc7eSAndroid Build Coastguard Worker 				 *
538*1208bc7eSAndroid Build Coastguard Worker 				 * NB: It is possible for there to be
539*1208bc7eSAndroid Build Coastguard Worker 				 * discontinuities in terms of initialized
540*1208bc7eSAndroid Build Coastguard Worker 				 * versus uninitialized arenas, due to the
541*1208bc7eSAndroid Build Coastguard Worker 				 * "thread.arena" mallctl.
542*1208bc7eSAndroid Build Coastguard Worker 				 */
543*1208bc7eSAndroid Build Coastguard Worker 				first_null = i;
544*1208bc7eSAndroid Build Coastguard Worker 			}
545*1208bc7eSAndroid Build Coastguard Worker 		}
546*1208bc7eSAndroid Build Coastguard Worker 
547*1208bc7eSAndroid Build Coastguard Worker 		for (j = 0; j < 2; j++) {
548*1208bc7eSAndroid Build Coastguard Worker 			if (arena_nthreads_get(arena_get(tsd_tsdn(tsd),
549*1208bc7eSAndroid Build Coastguard Worker 			    choose[j], false), !!j) == 0 || first_null ==
550*1208bc7eSAndroid Build Coastguard Worker 			    narenas_auto) {
551*1208bc7eSAndroid Build Coastguard Worker 				/*
552*1208bc7eSAndroid Build Coastguard Worker 				 * Use an unloaded arena, or the least loaded
553*1208bc7eSAndroid Build Coastguard Worker 				 * arena if all arenas are already initialized.
554*1208bc7eSAndroid Build Coastguard Worker 				 */
555*1208bc7eSAndroid Build Coastguard Worker 				if (!!j == internal) {
556*1208bc7eSAndroid Build Coastguard Worker 					ret = arena_get(tsd_tsdn(tsd),
557*1208bc7eSAndroid Build Coastguard Worker 					    choose[j], false);
558*1208bc7eSAndroid Build Coastguard Worker 				}
559*1208bc7eSAndroid Build Coastguard Worker 			} else {
560*1208bc7eSAndroid Build Coastguard Worker 				arena_t *arena;
561*1208bc7eSAndroid Build Coastguard Worker 
562*1208bc7eSAndroid Build Coastguard Worker 				/* Initialize a new arena. */
563*1208bc7eSAndroid Build Coastguard Worker 				choose[j] = first_null;
564*1208bc7eSAndroid Build Coastguard Worker 				arena = arena_init_locked(tsd_tsdn(tsd),
565*1208bc7eSAndroid Build Coastguard Worker 				    choose[j],
566*1208bc7eSAndroid Build Coastguard Worker 				    (extent_hooks_t *)&extent_hooks_default);
567*1208bc7eSAndroid Build Coastguard Worker 				if (arena == NULL) {
568*1208bc7eSAndroid Build Coastguard Worker 					malloc_mutex_unlock(tsd_tsdn(tsd),
569*1208bc7eSAndroid Build Coastguard Worker 					    &arenas_lock);
570*1208bc7eSAndroid Build Coastguard Worker 					return NULL;
571*1208bc7eSAndroid Build Coastguard Worker 				}
572*1208bc7eSAndroid Build Coastguard Worker 				is_new_arena[j] = true;
573*1208bc7eSAndroid Build Coastguard Worker 				if (!!j == internal) {
574*1208bc7eSAndroid Build Coastguard Worker 					ret = arena;
575*1208bc7eSAndroid Build Coastguard Worker 				}
576*1208bc7eSAndroid Build Coastguard Worker 			}
577*1208bc7eSAndroid Build Coastguard Worker 			arena_bind(tsd, choose[j], !!j);
578*1208bc7eSAndroid Build Coastguard Worker 		}
579*1208bc7eSAndroid Build Coastguard Worker 		malloc_mutex_unlock(tsd_tsdn(tsd), &arenas_lock);
580*1208bc7eSAndroid Build Coastguard Worker 
581*1208bc7eSAndroid Build Coastguard Worker 		for (j = 0; j < 2; j++) {
582*1208bc7eSAndroid Build Coastguard Worker 			if (is_new_arena[j]) {
583*1208bc7eSAndroid Build Coastguard Worker 				assert(choose[j] > 0);
584*1208bc7eSAndroid Build Coastguard Worker 				arena_new_create_background_thread(
585*1208bc7eSAndroid Build Coastguard Worker 				    tsd_tsdn(tsd), choose[j]);
586*1208bc7eSAndroid Build Coastguard Worker 			}
587*1208bc7eSAndroid Build Coastguard Worker 		}
588*1208bc7eSAndroid Build Coastguard Worker 
589*1208bc7eSAndroid Build Coastguard Worker 	} else {
590*1208bc7eSAndroid Build Coastguard Worker 		ret = arena_get(tsd_tsdn(tsd), 0, false);
591*1208bc7eSAndroid Build Coastguard Worker 		arena_bind(tsd, 0, false);
592*1208bc7eSAndroid Build Coastguard Worker 		arena_bind(tsd, 0, true);
593*1208bc7eSAndroid Build Coastguard Worker 	}
594*1208bc7eSAndroid Build Coastguard Worker 
595*1208bc7eSAndroid Build Coastguard Worker 	return ret;
596*1208bc7eSAndroid Build Coastguard Worker }
597*1208bc7eSAndroid Build Coastguard Worker 
598*1208bc7eSAndroid Build Coastguard Worker void
iarena_cleanup(tsd_t * tsd)599*1208bc7eSAndroid Build Coastguard Worker iarena_cleanup(tsd_t *tsd) {
600*1208bc7eSAndroid Build Coastguard Worker 	arena_t *iarena;
601*1208bc7eSAndroid Build Coastguard Worker 
602*1208bc7eSAndroid Build Coastguard Worker 	iarena = tsd_iarena_get(tsd);
603*1208bc7eSAndroid Build Coastguard Worker 	if (iarena != NULL) {
604*1208bc7eSAndroid Build Coastguard Worker 		arena_unbind(tsd, arena_ind_get(iarena), true);
605*1208bc7eSAndroid Build Coastguard Worker 	}
606*1208bc7eSAndroid Build Coastguard Worker }
607*1208bc7eSAndroid Build Coastguard Worker 
608*1208bc7eSAndroid Build Coastguard Worker void
arena_cleanup(tsd_t * tsd)609*1208bc7eSAndroid Build Coastguard Worker arena_cleanup(tsd_t *tsd) {
610*1208bc7eSAndroid Build Coastguard Worker 	arena_t *arena;
611*1208bc7eSAndroid Build Coastguard Worker 
612*1208bc7eSAndroid Build Coastguard Worker 	arena = tsd_arena_get(tsd);
613*1208bc7eSAndroid Build Coastguard Worker 	if (arena != NULL) {
614*1208bc7eSAndroid Build Coastguard Worker 		arena_unbind(tsd, arena_ind_get(arena), false);
615*1208bc7eSAndroid Build Coastguard Worker 	}
616*1208bc7eSAndroid Build Coastguard Worker }
617*1208bc7eSAndroid Build Coastguard Worker 
618*1208bc7eSAndroid Build Coastguard Worker void
arenas_tdata_cleanup(tsd_t * tsd)619*1208bc7eSAndroid Build Coastguard Worker arenas_tdata_cleanup(tsd_t *tsd) {
620*1208bc7eSAndroid Build Coastguard Worker 	arena_tdata_t *arenas_tdata;
621*1208bc7eSAndroid Build Coastguard Worker 
622*1208bc7eSAndroid Build Coastguard Worker 	/* Prevent tsd->arenas_tdata from being (re)created. */
623*1208bc7eSAndroid Build Coastguard Worker 	*tsd_arenas_tdata_bypassp_get(tsd) = true;
624*1208bc7eSAndroid Build Coastguard Worker 
625*1208bc7eSAndroid Build Coastguard Worker 	arenas_tdata = tsd_arenas_tdata_get(tsd);
626*1208bc7eSAndroid Build Coastguard Worker 	if (arenas_tdata != NULL) {
627*1208bc7eSAndroid Build Coastguard Worker 		tsd_arenas_tdata_set(tsd, NULL);
628*1208bc7eSAndroid Build Coastguard Worker 		a0dalloc(arenas_tdata);
629*1208bc7eSAndroid Build Coastguard Worker 	}
630*1208bc7eSAndroid Build Coastguard Worker }
631*1208bc7eSAndroid Build Coastguard Worker 
632*1208bc7eSAndroid Build Coastguard Worker static void
stats_print_atexit(void)633*1208bc7eSAndroid Build Coastguard Worker stats_print_atexit(void) {
634*1208bc7eSAndroid Build Coastguard Worker #if defined(ANDROID_ENABLE_TCACHE)
635*1208bc7eSAndroid Build Coastguard Worker 	if (config_stats) {
636*1208bc7eSAndroid Build Coastguard Worker 		tsdn_t *tsdn;
637*1208bc7eSAndroid Build Coastguard Worker 		unsigned narenas, i;
638*1208bc7eSAndroid Build Coastguard Worker 
639*1208bc7eSAndroid Build Coastguard Worker 		tsdn = tsdn_fetch();
640*1208bc7eSAndroid Build Coastguard Worker 
641*1208bc7eSAndroid Build Coastguard Worker 		/*
642*1208bc7eSAndroid Build Coastguard Worker 		 * Merge stats from extant threads.  This is racy, since
643*1208bc7eSAndroid Build Coastguard Worker 		 * individual threads do not lock when recording tcache stats
644*1208bc7eSAndroid Build Coastguard Worker 		 * events.  As a consequence, the final stats may be slightly
645*1208bc7eSAndroid Build Coastguard Worker 		 * out of date by the time they are reported, if other threads
646*1208bc7eSAndroid Build Coastguard Worker 		 * continue to allocate.
647*1208bc7eSAndroid Build Coastguard Worker 		 */
648*1208bc7eSAndroid Build Coastguard Worker 		for (i = 0, narenas = narenas_total_get(); i < narenas; i++) {
649*1208bc7eSAndroid Build Coastguard Worker 			arena_t *arena = arena_get(tsdn, i, false);
650*1208bc7eSAndroid Build Coastguard Worker 			if (arena != NULL) {
651*1208bc7eSAndroid Build Coastguard Worker 				tcache_t *tcache;
652*1208bc7eSAndroid Build Coastguard Worker 
653*1208bc7eSAndroid Build Coastguard Worker 				malloc_mutex_lock(tsdn, &arena->tcache_ql_mtx);
654*1208bc7eSAndroid Build Coastguard Worker 				ql_foreach(tcache, &arena->tcache_ql, link) {
655*1208bc7eSAndroid Build Coastguard Worker 					tcache_stats_merge(tsdn, tcache, arena);
656*1208bc7eSAndroid Build Coastguard Worker 				}
657*1208bc7eSAndroid Build Coastguard Worker 				malloc_mutex_unlock(tsdn,
658*1208bc7eSAndroid Build Coastguard Worker 				    &arena->tcache_ql_mtx);
659*1208bc7eSAndroid Build Coastguard Worker 			}
660*1208bc7eSAndroid Build Coastguard Worker 		}
661*1208bc7eSAndroid Build Coastguard Worker 	}
662*1208bc7eSAndroid Build Coastguard Worker #endif
663*1208bc7eSAndroid Build Coastguard Worker 	je_malloc_stats_print(NULL, NULL, opt_stats_print_opts);
664*1208bc7eSAndroid Build Coastguard Worker }
665*1208bc7eSAndroid Build Coastguard Worker 
666*1208bc7eSAndroid Build Coastguard Worker /*
667*1208bc7eSAndroid Build Coastguard Worker  * Ensure that we don't hold any locks upon entry to or exit from allocator
668*1208bc7eSAndroid Build Coastguard Worker  * code (in a "broad" sense that doesn't count a reentrant allocation as an
669*1208bc7eSAndroid Build Coastguard Worker  * entrance or exit).
670*1208bc7eSAndroid Build Coastguard Worker  */
671*1208bc7eSAndroid Build Coastguard Worker JEMALLOC_ALWAYS_INLINE void
check_entry_exit_locking(tsdn_t * tsdn)672*1208bc7eSAndroid Build Coastguard Worker check_entry_exit_locking(tsdn_t *tsdn) {
673*1208bc7eSAndroid Build Coastguard Worker 	if (!config_debug) {
674*1208bc7eSAndroid Build Coastguard Worker 		return;
675*1208bc7eSAndroid Build Coastguard Worker 	}
676*1208bc7eSAndroid Build Coastguard Worker 	if (tsdn_null(tsdn)) {
677*1208bc7eSAndroid Build Coastguard Worker 		return;
678*1208bc7eSAndroid Build Coastguard Worker 	}
679*1208bc7eSAndroid Build Coastguard Worker 	tsd_t *tsd = tsdn_tsd(tsdn);
680*1208bc7eSAndroid Build Coastguard Worker 	/*
681*1208bc7eSAndroid Build Coastguard Worker 	 * It's possible we hold locks at entry/exit if we're in a nested
682*1208bc7eSAndroid Build Coastguard Worker 	 * allocation.
683*1208bc7eSAndroid Build Coastguard Worker 	 */
684*1208bc7eSAndroid Build Coastguard Worker 	int8_t reentrancy_level = tsd_reentrancy_level_get(tsd);
685*1208bc7eSAndroid Build Coastguard Worker 	if (reentrancy_level != 0) {
686*1208bc7eSAndroid Build Coastguard Worker 		return;
687*1208bc7eSAndroid Build Coastguard Worker 	}
688*1208bc7eSAndroid Build Coastguard Worker 	witness_assert_lockless(tsdn_witness_tsdp_get(tsdn));
689*1208bc7eSAndroid Build Coastguard Worker }
690*1208bc7eSAndroid Build Coastguard Worker 
691*1208bc7eSAndroid Build Coastguard Worker /*
692*1208bc7eSAndroid Build Coastguard Worker  * End miscellaneous support functions.
693*1208bc7eSAndroid Build Coastguard Worker  */
694*1208bc7eSAndroid Build Coastguard Worker /******************************************************************************/
695*1208bc7eSAndroid Build Coastguard Worker /*
696*1208bc7eSAndroid Build Coastguard Worker  * Begin initialization functions.
697*1208bc7eSAndroid Build Coastguard Worker  */
698*1208bc7eSAndroid Build Coastguard Worker 
699*1208bc7eSAndroid Build Coastguard Worker static char *
jemalloc_secure_getenv(const char * name)700*1208bc7eSAndroid Build Coastguard Worker jemalloc_secure_getenv(const char *name) {
701*1208bc7eSAndroid Build Coastguard Worker #ifdef JEMALLOC_HAVE_SECURE_GETENV
702*1208bc7eSAndroid Build Coastguard Worker 	return secure_getenv(name);
703*1208bc7eSAndroid Build Coastguard Worker #else
704*1208bc7eSAndroid Build Coastguard Worker #  ifdef JEMALLOC_HAVE_ISSETUGID
705*1208bc7eSAndroid Build Coastguard Worker 	if (issetugid() != 0) {
706*1208bc7eSAndroid Build Coastguard Worker 		return NULL;
707*1208bc7eSAndroid Build Coastguard Worker 	}
708*1208bc7eSAndroid Build Coastguard Worker #  endif
709*1208bc7eSAndroid Build Coastguard Worker 	return getenv(name);
710*1208bc7eSAndroid Build Coastguard Worker #endif
711*1208bc7eSAndroid Build Coastguard Worker }
712*1208bc7eSAndroid Build Coastguard Worker 
713*1208bc7eSAndroid Build Coastguard Worker static unsigned
malloc_ncpus(void)714*1208bc7eSAndroid Build Coastguard Worker malloc_ncpus(void) {
715*1208bc7eSAndroid Build Coastguard Worker 	long result;
716*1208bc7eSAndroid Build Coastguard Worker 
717*1208bc7eSAndroid Build Coastguard Worker #ifdef _WIN32
718*1208bc7eSAndroid Build Coastguard Worker 	SYSTEM_INFO si;
719*1208bc7eSAndroid Build Coastguard Worker 	GetSystemInfo(&si);
720*1208bc7eSAndroid Build Coastguard Worker 	result = si.dwNumberOfProcessors;
721*1208bc7eSAndroid Build Coastguard Worker #elif defined(JEMALLOC_GLIBC_MALLOC_HOOK) && defined(CPU_COUNT)
722*1208bc7eSAndroid Build Coastguard Worker 	/*
723*1208bc7eSAndroid Build Coastguard Worker 	 * glibc >= 2.6 has the CPU_COUNT macro.
724*1208bc7eSAndroid Build Coastguard Worker 	 *
725*1208bc7eSAndroid Build Coastguard Worker 	 * glibc's sysconf() uses isspace().  glibc allocates for the first time
726*1208bc7eSAndroid Build Coastguard Worker 	 * *before* setting up the isspace tables.  Therefore we need a
727*1208bc7eSAndroid Build Coastguard Worker 	 * different method to get the number of CPUs.
728*1208bc7eSAndroid Build Coastguard Worker 	 */
729*1208bc7eSAndroid Build Coastguard Worker 	{
730*1208bc7eSAndroid Build Coastguard Worker 		cpu_set_t set;
731*1208bc7eSAndroid Build Coastguard Worker 
732*1208bc7eSAndroid Build Coastguard Worker 		pthread_getaffinity_np(pthread_self(), sizeof(set), &set);
733*1208bc7eSAndroid Build Coastguard Worker 		result = CPU_COUNT(&set);
734*1208bc7eSAndroid Build Coastguard Worker 	}
735*1208bc7eSAndroid Build Coastguard Worker #else
736*1208bc7eSAndroid Build Coastguard Worker 	result = sysconf(_SC_NPROCESSORS_ONLN);
737*1208bc7eSAndroid Build Coastguard Worker #endif
738*1208bc7eSAndroid Build Coastguard Worker 	return ((result == -1) ? 1 : (unsigned)result);
739*1208bc7eSAndroid Build Coastguard Worker }
740*1208bc7eSAndroid Build Coastguard Worker 
741*1208bc7eSAndroid Build Coastguard Worker static void
init_opt_stats_print_opts(const char * v,size_t vlen)742*1208bc7eSAndroid Build Coastguard Worker init_opt_stats_print_opts(const char *v, size_t vlen) {
743*1208bc7eSAndroid Build Coastguard Worker 	size_t opts_len = strlen(opt_stats_print_opts);
744*1208bc7eSAndroid Build Coastguard Worker 	assert(opts_len <= stats_print_tot_num_options);
745*1208bc7eSAndroid Build Coastguard Worker 
746*1208bc7eSAndroid Build Coastguard Worker 	for (size_t i = 0; i < vlen; i++) {
747*1208bc7eSAndroid Build Coastguard Worker 		switch (v[i]) {
748*1208bc7eSAndroid Build Coastguard Worker #define OPTION(o, v, d, s) case o: break;
749*1208bc7eSAndroid Build Coastguard Worker 			STATS_PRINT_OPTIONS
750*1208bc7eSAndroid Build Coastguard Worker #undef OPTION
751*1208bc7eSAndroid Build Coastguard Worker 		default: continue;
752*1208bc7eSAndroid Build Coastguard Worker 		}
753*1208bc7eSAndroid Build Coastguard Worker 
754*1208bc7eSAndroid Build Coastguard Worker 		if (strchr(opt_stats_print_opts, v[i]) != NULL) {
755*1208bc7eSAndroid Build Coastguard Worker 			/* Ignore repeated. */
756*1208bc7eSAndroid Build Coastguard Worker 			continue;
757*1208bc7eSAndroid Build Coastguard Worker 		}
758*1208bc7eSAndroid Build Coastguard Worker 
759*1208bc7eSAndroid Build Coastguard Worker 		opt_stats_print_opts[opts_len++] = v[i];
760*1208bc7eSAndroid Build Coastguard Worker 		opt_stats_print_opts[opts_len] = '\0';
761*1208bc7eSAndroid Build Coastguard Worker 		assert(opts_len <= stats_print_tot_num_options);
762*1208bc7eSAndroid Build Coastguard Worker 	}
763*1208bc7eSAndroid Build Coastguard Worker 	assert(opts_len == strlen(opt_stats_print_opts));
764*1208bc7eSAndroid Build Coastguard Worker }
765*1208bc7eSAndroid Build Coastguard Worker 
766*1208bc7eSAndroid Build Coastguard Worker static bool
malloc_conf_next(char const ** opts_p,char const ** k_p,size_t * klen_p,char const ** v_p,size_t * vlen_p)767*1208bc7eSAndroid Build Coastguard Worker malloc_conf_next(char const **opts_p, char const **k_p, size_t *klen_p,
768*1208bc7eSAndroid Build Coastguard Worker     char const **v_p, size_t *vlen_p) {
769*1208bc7eSAndroid Build Coastguard Worker 	bool accept;
770*1208bc7eSAndroid Build Coastguard Worker 	const char *opts = *opts_p;
771*1208bc7eSAndroid Build Coastguard Worker 
772*1208bc7eSAndroid Build Coastguard Worker 	*k_p = opts;
773*1208bc7eSAndroid Build Coastguard Worker 
774*1208bc7eSAndroid Build Coastguard Worker 	for (accept = false; !accept;) {
775*1208bc7eSAndroid Build Coastguard Worker 		switch (*opts) {
776*1208bc7eSAndroid Build Coastguard Worker 		case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
777*1208bc7eSAndroid Build Coastguard Worker 		case 'G': case 'H': case 'I': case 'J': case 'K': case 'L':
778*1208bc7eSAndroid Build Coastguard Worker 		case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R':
779*1208bc7eSAndroid Build Coastguard Worker 		case 'S': case 'T': case 'U': case 'V': case 'W': case 'X':
780*1208bc7eSAndroid Build Coastguard Worker 		case 'Y': case 'Z':
781*1208bc7eSAndroid Build Coastguard Worker 		case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
782*1208bc7eSAndroid Build Coastguard Worker 		case 'g': case 'h': case 'i': case 'j': case 'k': case 'l':
783*1208bc7eSAndroid Build Coastguard Worker 		case 'm': case 'n': case 'o': case 'p': case 'q': case 'r':
784*1208bc7eSAndroid Build Coastguard Worker 		case 's': case 't': case 'u': case 'v': case 'w': case 'x':
785*1208bc7eSAndroid Build Coastguard Worker 		case 'y': case 'z':
786*1208bc7eSAndroid Build Coastguard Worker 		case '0': case '1': case '2': case '3': case '4': case '5':
787*1208bc7eSAndroid Build Coastguard Worker 		case '6': case '7': case '8': case '9':
788*1208bc7eSAndroid Build Coastguard Worker 		case '_':
789*1208bc7eSAndroid Build Coastguard Worker 			opts++;
790*1208bc7eSAndroid Build Coastguard Worker 			break;
791*1208bc7eSAndroid Build Coastguard Worker 		case ':':
792*1208bc7eSAndroid Build Coastguard Worker 			opts++;
793*1208bc7eSAndroid Build Coastguard Worker 			*klen_p = (uintptr_t)opts - 1 - (uintptr_t)*k_p;
794*1208bc7eSAndroid Build Coastguard Worker 			*v_p = opts;
795*1208bc7eSAndroid Build Coastguard Worker 			accept = true;
796*1208bc7eSAndroid Build Coastguard Worker 			break;
797*1208bc7eSAndroid Build Coastguard Worker 		case '\0':
798*1208bc7eSAndroid Build Coastguard Worker 			if (opts != *opts_p) {
799*1208bc7eSAndroid Build Coastguard Worker 				malloc_write("<jemalloc>: Conf string ends "
800*1208bc7eSAndroid Build Coastguard Worker 				    "with key\n");
801*1208bc7eSAndroid Build Coastguard Worker 			}
802*1208bc7eSAndroid Build Coastguard Worker 			return true;
803*1208bc7eSAndroid Build Coastguard Worker 		default:
804*1208bc7eSAndroid Build Coastguard Worker 			malloc_write("<jemalloc>: Malformed conf string\n");
805*1208bc7eSAndroid Build Coastguard Worker 			return true;
806*1208bc7eSAndroid Build Coastguard Worker 		}
807*1208bc7eSAndroid Build Coastguard Worker 	}
808*1208bc7eSAndroid Build Coastguard Worker 
809*1208bc7eSAndroid Build Coastguard Worker 	for (accept = false; !accept;) {
810*1208bc7eSAndroid Build Coastguard Worker 		switch (*opts) {
811*1208bc7eSAndroid Build Coastguard Worker 		case ',':
812*1208bc7eSAndroid Build Coastguard Worker 			opts++;
813*1208bc7eSAndroid Build Coastguard Worker 			/*
814*1208bc7eSAndroid Build Coastguard Worker 			 * Look ahead one character here, because the next time
815*1208bc7eSAndroid Build Coastguard Worker 			 * this function is called, it will assume that end of
816*1208bc7eSAndroid Build Coastguard Worker 			 * input has been cleanly reached if no input remains,
817*1208bc7eSAndroid Build Coastguard Worker 			 * but we have optimistically already consumed the
818*1208bc7eSAndroid Build Coastguard Worker 			 * comma if one exists.
819*1208bc7eSAndroid Build Coastguard Worker 			 */
820*1208bc7eSAndroid Build Coastguard Worker 			if (*opts == '\0') {
821*1208bc7eSAndroid Build Coastguard Worker 				malloc_write("<jemalloc>: Conf string ends "
822*1208bc7eSAndroid Build Coastguard Worker 				    "with comma\n");
823*1208bc7eSAndroid Build Coastguard Worker 			}
824*1208bc7eSAndroid Build Coastguard Worker 			*vlen_p = (uintptr_t)opts - 1 - (uintptr_t)*v_p;
825*1208bc7eSAndroid Build Coastguard Worker 			accept = true;
826*1208bc7eSAndroid Build Coastguard Worker 			break;
827*1208bc7eSAndroid Build Coastguard Worker 		case '\0':
828*1208bc7eSAndroid Build Coastguard Worker 			*vlen_p = (uintptr_t)opts - (uintptr_t)*v_p;
829*1208bc7eSAndroid Build Coastguard Worker 			accept = true;
830*1208bc7eSAndroid Build Coastguard Worker 			break;
831*1208bc7eSAndroid Build Coastguard Worker 		default:
832*1208bc7eSAndroid Build Coastguard Worker 			opts++;
833*1208bc7eSAndroid Build Coastguard Worker 			break;
834*1208bc7eSAndroid Build Coastguard Worker 		}
835*1208bc7eSAndroid Build Coastguard Worker 	}
836*1208bc7eSAndroid Build Coastguard Worker 
837*1208bc7eSAndroid Build Coastguard Worker 	*opts_p = opts;
838*1208bc7eSAndroid Build Coastguard Worker 	return false;
839*1208bc7eSAndroid Build Coastguard Worker }
840*1208bc7eSAndroid Build Coastguard Worker 
841*1208bc7eSAndroid Build Coastguard Worker static void
malloc_abort_invalid_conf(void)842*1208bc7eSAndroid Build Coastguard Worker malloc_abort_invalid_conf(void) {
843*1208bc7eSAndroid Build Coastguard Worker 	assert(opt_abort_conf);
844*1208bc7eSAndroid Build Coastguard Worker 	malloc_printf("<jemalloc>: Abort (abort_conf:true) on invalid conf "
845*1208bc7eSAndroid Build Coastguard Worker 	    "value (see above).\n");
846*1208bc7eSAndroid Build Coastguard Worker 	abort();
847*1208bc7eSAndroid Build Coastguard Worker }
848*1208bc7eSAndroid Build Coastguard Worker 
849*1208bc7eSAndroid Build Coastguard Worker static void
malloc_conf_error(const char * msg,const char * k,size_t klen,const char * v,size_t vlen)850*1208bc7eSAndroid Build Coastguard Worker malloc_conf_error(const char *msg, const char *k, size_t klen, const char *v,
851*1208bc7eSAndroid Build Coastguard Worker     size_t vlen) {
852*1208bc7eSAndroid Build Coastguard Worker 	malloc_printf("<jemalloc>: %s: %.*s:%.*s\n", msg, (int)klen, k,
853*1208bc7eSAndroid Build Coastguard Worker 	    (int)vlen, v);
854*1208bc7eSAndroid Build Coastguard Worker 	/* If abort_conf is set, error out after processing all options. */
855*1208bc7eSAndroid Build Coastguard Worker 	had_conf_error = true;
856*1208bc7eSAndroid Build Coastguard Worker }
857*1208bc7eSAndroid Build Coastguard Worker 
858*1208bc7eSAndroid Build Coastguard Worker static void
malloc_slow_flag_init(void)859*1208bc7eSAndroid Build Coastguard Worker malloc_slow_flag_init(void) {
860*1208bc7eSAndroid Build Coastguard Worker 	/*
861*1208bc7eSAndroid Build Coastguard Worker 	 * Combine the runtime options into malloc_slow for fast path.  Called
862*1208bc7eSAndroid Build Coastguard Worker 	 * after processing all the options.
863*1208bc7eSAndroid Build Coastguard Worker 	 */
864*1208bc7eSAndroid Build Coastguard Worker 	malloc_slow_flags |= (opt_junk_alloc ? flag_opt_junk_alloc : 0)
865*1208bc7eSAndroid Build Coastguard Worker 	    | (opt_junk_free ? flag_opt_junk_free : 0)
866*1208bc7eSAndroid Build Coastguard Worker 	    | (opt_zero ? flag_opt_zero : 0)
867*1208bc7eSAndroid Build Coastguard Worker 	    | (opt_utrace ? flag_opt_utrace : 0)
868*1208bc7eSAndroid Build Coastguard Worker 	    | (opt_xmalloc ? flag_opt_xmalloc : 0);
869*1208bc7eSAndroid Build Coastguard Worker 
870*1208bc7eSAndroid Build Coastguard Worker 	malloc_slow = (malloc_slow_flags != 0);
871*1208bc7eSAndroid Build Coastguard Worker }
872*1208bc7eSAndroid Build Coastguard Worker 
873*1208bc7eSAndroid Build Coastguard Worker static void
malloc_conf_init(void)874*1208bc7eSAndroid Build Coastguard Worker malloc_conf_init(void) {
875*1208bc7eSAndroid Build Coastguard Worker 	unsigned i;
876*1208bc7eSAndroid Build Coastguard Worker 	char buf[PATH_MAX + 1];
877*1208bc7eSAndroid Build Coastguard Worker 	const char *opts, *k, *v;
878*1208bc7eSAndroid Build Coastguard Worker 	size_t klen, vlen;
879*1208bc7eSAndroid Build Coastguard Worker 
880*1208bc7eSAndroid Build Coastguard Worker #if defined(__BIONIC__)
881*1208bc7eSAndroid Build Coastguard Worker 	/* For Android, do not look at files nor environment variables for
882*1208bc7eSAndroid Build Coastguard Worker 	 * config data.
883*1208bc7eSAndroid Build Coastguard Worker 	 */
884*1208bc7eSAndroid Build Coastguard Worker 	for (i = 0; i < 2; i++) {
885*1208bc7eSAndroid Build Coastguard Worker #else
886*1208bc7eSAndroid Build Coastguard Worker 	for (i = 0; i < 4; i++) {
887*1208bc7eSAndroid Build Coastguard Worker #endif
888*1208bc7eSAndroid Build Coastguard Worker 		/* Get runtime configuration. */
889*1208bc7eSAndroid Build Coastguard Worker 		switch (i) {
890*1208bc7eSAndroid Build Coastguard Worker 		case 0:
891*1208bc7eSAndroid Build Coastguard Worker 			opts = config_malloc_conf;
892*1208bc7eSAndroid Build Coastguard Worker 			break;
893*1208bc7eSAndroid Build Coastguard Worker 		case 1:
894*1208bc7eSAndroid Build Coastguard Worker 			if (je_malloc_conf != NULL) {
895*1208bc7eSAndroid Build Coastguard Worker 				/*
896*1208bc7eSAndroid Build Coastguard Worker 				 * Use options that were compiled into the
897*1208bc7eSAndroid Build Coastguard Worker 				 * program.
898*1208bc7eSAndroid Build Coastguard Worker 				 */
899*1208bc7eSAndroid Build Coastguard Worker 				opts = je_malloc_conf;
900*1208bc7eSAndroid Build Coastguard Worker 			} else {
901*1208bc7eSAndroid Build Coastguard Worker 				/* No configuration specified. */
902*1208bc7eSAndroid Build Coastguard Worker 				buf[0] = '\0';
903*1208bc7eSAndroid Build Coastguard Worker 				opts = buf;
904*1208bc7eSAndroid Build Coastguard Worker 			}
905*1208bc7eSAndroid Build Coastguard Worker 			break;
906*1208bc7eSAndroid Build Coastguard Worker 		case 2: {
907*1208bc7eSAndroid Build Coastguard Worker 			ssize_t linklen = 0;
908*1208bc7eSAndroid Build Coastguard Worker #ifndef _WIN32
909*1208bc7eSAndroid Build Coastguard Worker 			int saved_errno = errno;
910*1208bc7eSAndroid Build Coastguard Worker 			const char *linkname =
911*1208bc7eSAndroid Build Coastguard Worker #  ifdef JEMALLOC_PREFIX
912*1208bc7eSAndroid Build Coastguard Worker 			    "/etc/"JEMALLOC_PREFIX"malloc.conf"
913*1208bc7eSAndroid Build Coastguard Worker #  else
914*1208bc7eSAndroid Build Coastguard Worker 			    "/etc/malloc.conf"
915*1208bc7eSAndroid Build Coastguard Worker #  endif
916*1208bc7eSAndroid Build Coastguard Worker 			    ;
917*1208bc7eSAndroid Build Coastguard Worker 
918*1208bc7eSAndroid Build Coastguard Worker 			/*
919*1208bc7eSAndroid Build Coastguard Worker 			 * Try to use the contents of the "/etc/malloc.conf"
920*1208bc7eSAndroid Build Coastguard Worker 			 * symbolic link's name.
921*1208bc7eSAndroid Build Coastguard Worker 			 */
922*1208bc7eSAndroid Build Coastguard Worker 			linklen = readlink(linkname, buf, sizeof(buf) - 1);
923*1208bc7eSAndroid Build Coastguard Worker 			if (linklen == -1) {
924*1208bc7eSAndroid Build Coastguard Worker 				/* No configuration specified. */
925*1208bc7eSAndroid Build Coastguard Worker 				linklen = 0;
926*1208bc7eSAndroid Build Coastguard Worker 				/* Restore errno. */
927*1208bc7eSAndroid Build Coastguard Worker 				set_errno(saved_errno);
928*1208bc7eSAndroid Build Coastguard Worker 			}
929*1208bc7eSAndroid Build Coastguard Worker #endif
930*1208bc7eSAndroid Build Coastguard Worker 			buf[linklen] = '\0';
931*1208bc7eSAndroid Build Coastguard Worker 			opts = buf;
932*1208bc7eSAndroid Build Coastguard Worker 			break;
933*1208bc7eSAndroid Build Coastguard Worker 		} case 3: {
934*1208bc7eSAndroid Build Coastguard Worker 			const char *envname =
935*1208bc7eSAndroid Build Coastguard Worker #ifdef JEMALLOC_PREFIX
936*1208bc7eSAndroid Build Coastguard Worker 			    JEMALLOC_CPREFIX"MALLOC_CONF"
937*1208bc7eSAndroid Build Coastguard Worker #else
938*1208bc7eSAndroid Build Coastguard Worker 			    "MALLOC_CONF"
939*1208bc7eSAndroid Build Coastguard Worker #endif
940*1208bc7eSAndroid Build Coastguard Worker 			    ;
941*1208bc7eSAndroid Build Coastguard Worker 
942*1208bc7eSAndroid Build Coastguard Worker 			if ((opts = jemalloc_secure_getenv(envname)) != NULL) {
943*1208bc7eSAndroid Build Coastguard Worker 				/*
944*1208bc7eSAndroid Build Coastguard Worker 				 * Do nothing; opts is already initialized to
945*1208bc7eSAndroid Build Coastguard Worker 				 * the value of the MALLOC_CONF environment
946*1208bc7eSAndroid Build Coastguard Worker 				 * variable.
947*1208bc7eSAndroid Build Coastguard Worker 				 */
948*1208bc7eSAndroid Build Coastguard Worker 			} else {
949*1208bc7eSAndroid Build Coastguard Worker 				/* No configuration specified. */
950*1208bc7eSAndroid Build Coastguard Worker 				buf[0] = '\0';
951*1208bc7eSAndroid Build Coastguard Worker 				opts = buf;
952*1208bc7eSAndroid Build Coastguard Worker 			}
953*1208bc7eSAndroid Build Coastguard Worker 			break;
954*1208bc7eSAndroid Build Coastguard Worker 		} default:
955*1208bc7eSAndroid Build Coastguard Worker 			not_reached();
956*1208bc7eSAndroid Build Coastguard Worker 			buf[0] = '\0';
957*1208bc7eSAndroid Build Coastguard Worker 			opts = buf;
958*1208bc7eSAndroid Build Coastguard Worker 		}
959*1208bc7eSAndroid Build Coastguard Worker 
960*1208bc7eSAndroid Build Coastguard Worker 		while (*opts != '\0' && !malloc_conf_next(&opts, &k, &klen, &v,
961*1208bc7eSAndroid Build Coastguard Worker 		    &vlen)) {
962*1208bc7eSAndroid Build Coastguard Worker #define CONF_MATCH(n)							\
963*1208bc7eSAndroid Build Coastguard Worker 	(sizeof(n)-1 == klen && strncmp(n, k, klen) == 0)
964*1208bc7eSAndroid Build Coastguard Worker #define CONF_MATCH_VALUE(n)						\
965*1208bc7eSAndroid Build Coastguard Worker 	(sizeof(n)-1 == vlen && strncmp(n, v, vlen) == 0)
966*1208bc7eSAndroid Build Coastguard Worker #define CONF_HANDLE_BOOL(o, n)						\
967*1208bc7eSAndroid Build Coastguard Worker 			if (CONF_MATCH(n)) {				\
968*1208bc7eSAndroid Build Coastguard Worker 				if (CONF_MATCH_VALUE("true")) {		\
969*1208bc7eSAndroid Build Coastguard Worker 					o = true;			\
970*1208bc7eSAndroid Build Coastguard Worker 				} else if (CONF_MATCH_VALUE("false")) {	\
971*1208bc7eSAndroid Build Coastguard Worker 					o = false;			\
972*1208bc7eSAndroid Build Coastguard Worker 				} else {				\
973*1208bc7eSAndroid Build Coastguard Worker 					malloc_conf_error(		\
974*1208bc7eSAndroid Build Coastguard Worker 					    "Invalid conf value",	\
975*1208bc7eSAndroid Build Coastguard Worker 					    k, klen, v, vlen);		\
976*1208bc7eSAndroid Build Coastguard Worker 				}					\
977*1208bc7eSAndroid Build Coastguard Worker 				continue;				\
978*1208bc7eSAndroid Build Coastguard Worker 			}
979*1208bc7eSAndroid Build Coastguard Worker #define CONF_MIN_no(um, min)	false
980*1208bc7eSAndroid Build Coastguard Worker #define CONF_MIN_yes(um, min)	((um) < (min))
981*1208bc7eSAndroid Build Coastguard Worker #define CONF_MAX_no(um, max)	false
982*1208bc7eSAndroid Build Coastguard Worker #define CONF_MAX_yes(um, max)	((um) > (max))
983*1208bc7eSAndroid Build Coastguard Worker #define CONF_HANDLE_T_U(t, o, n, min, max, check_min, check_max, clip)	\
984*1208bc7eSAndroid Build Coastguard Worker 			if (CONF_MATCH(n)) {				\
985*1208bc7eSAndroid Build Coastguard Worker 				uintmax_t um;				\
986*1208bc7eSAndroid Build Coastguard Worker 				char *end;				\
987*1208bc7eSAndroid Build Coastguard Worker 									\
988*1208bc7eSAndroid Build Coastguard Worker 				set_errno(0);				\
989*1208bc7eSAndroid Build Coastguard Worker 				um = malloc_strtoumax(v, &end, 0);	\
990*1208bc7eSAndroid Build Coastguard Worker 				if (get_errno() != 0 || (uintptr_t)end -\
991*1208bc7eSAndroid Build Coastguard Worker 				    (uintptr_t)v != vlen) {		\
992*1208bc7eSAndroid Build Coastguard Worker 					malloc_conf_error(		\
993*1208bc7eSAndroid Build Coastguard Worker 					    "Invalid conf value",	\
994*1208bc7eSAndroid Build Coastguard Worker 					    k, klen, v, vlen);		\
995*1208bc7eSAndroid Build Coastguard Worker 				} else if (clip) {			\
996*1208bc7eSAndroid Build Coastguard Worker 					if (CONF_MIN_##check_min(um,	\
997*1208bc7eSAndroid Build Coastguard Worker 					    (t)(min))) {		\
998*1208bc7eSAndroid Build Coastguard Worker 						o = (t)(min);		\
999*1208bc7eSAndroid Build Coastguard Worker 					} else if (			\
1000*1208bc7eSAndroid Build Coastguard Worker 					    CONF_MAX_##check_max(um,	\
1001*1208bc7eSAndroid Build Coastguard Worker 					    (t)(max))) {		\
1002*1208bc7eSAndroid Build Coastguard Worker 						o = (t)(max);		\
1003*1208bc7eSAndroid Build Coastguard Worker 					} else {			\
1004*1208bc7eSAndroid Build Coastguard Worker 						o = (t)um;		\
1005*1208bc7eSAndroid Build Coastguard Worker 					}				\
1006*1208bc7eSAndroid Build Coastguard Worker 				} else {				\
1007*1208bc7eSAndroid Build Coastguard Worker 					if (CONF_MIN_##check_min(um,	\
1008*1208bc7eSAndroid Build Coastguard Worker 					    (t)(min)) ||		\
1009*1208bc7eSAndroid Build Coastguard Worker 					    CONF_MAX_##check_max(um,	\
1010*1208bc7eSAndroid Build Coastguard Worker 					    (t)(max))) {		\
1011*1208bc7eSAndroid Build Coastguard Worker 						malloc_conf_error(	\
1012*1208bc7eSAndroid Build Coastguard Worker 						    "Out-of-range "	\
1013*1208bc7eSAndroid Build Coastguard Worker 						    "conf value",	\
1014*1208bc7eSAndroid Build Coastguard Worker 						    k, klen, v, vlen);	\
1015*1208bc7eSAndroid Build Coastguard Worker 					} else {			\
1016*1208bc7eSAndroid Build Coastguard Worker 						o = (t)um;		\
1017*1208bc7eSAndroid Build Coastguard Worker 					}				\
1018*1208bc7eSAndroid Build Coastguard Worker 				}					\
1019*1208bc7eSAndroid Build Coastguard Worker 				continue;				\
1020*1208bc7eSAndroid Build Coastguard Worker 			}
1021*1208bc7eSAndroid Build Coastguard Worker #define CONF_HANDLE_UNSIGNED(o, n, min, max, check_min, check_max,	\
1022*1208bc7eSAndroid Build Coastguard Worker     clip)								\
1023*1208bc7eSAndroid Build Coastguard Worker 			CONF_HANDLE_T_U(unsigned, o, n, min, max,	\
1024*1208bc7eSAndroid Build Coastguard Worker 			    check_min, check_max, clip)
1025*1208bc7eSAndroid Build Coastguard Worker #define CONF_HANDLE_SIZE_T(o, n, min, max, check_min, check_max, clip)	\
1026*1208bc7eSAndroid Build Coastguard Worker 			CONF_HANDLE_T_U(size_t, o, n, min, max,		\
1027*1208bc7eSAndroid Build Coastguard Worker 			    check_min, check_max, clip)
1028*1208bc7eSAndroid Build Coastguard Worker #define CONF_HANDLE_SSIZE_T(o, n, min, max)				\
1029*1208bc7eSAndroid Build Coastguard Worker 			if (CONF_MATCH(n)) {				\
1030*1208bc7eSAndroid Build Coastguard Worker 				long l;					\
1031*1208bc7eSAndroid Build Coastguard Worker 				char *end;				\
1032*1208bc7eSAndroid Build Coastguard Worker 									\
1033*1208bc7eSAndroid Build Coastguard Worker 				set_errno(0);				\
1034*1208bc7eSAndroid Build Coastguard Worker 				l = strtol(v, &end, 0);			\
1035*1208bc7eSAndroid Build Coastguard Worker 				if (get_errno() != 0 || (uintptr_t)end -\
1036*1208bc7eSAndroid Build Coastguard Worker 				    (uintptr_t)v != vlen) {		\
1037*1208bc7eSAndroid Build Coastguard Worker 					malloc_conf_error(		\
1038*1208bc7eSAndroid Build Coastguard Worker 					    "Invalid conf value",	\
1039*1208bc7eSAndroid Build Coastguard Worker 					    k, klen, v, vlen);		\
1040*1208bc7eSAndroid Build Coastguard Worker 				} else if (l < (ssize_t)(min) || l >	\
1041*1208bc7eSAndroid Build Coastguard Worker 				    (ssize_t)(max)) {			\
1042*1208bc7eSAndroid Build Coastguard Worker 					malloc_conf_error(		\
1043*1208bc7eSAndroid Build Coastguard Worker 					    "Out-of-range conf value",	\
1044*1208bc7eSAndroid Build Coastguard Worker 					    k, klen, v, vlen);		\
1045*1208bc7eSAndroid Build Coastguard Worker 				} else {				\
1046*1208bc7eSAndroid Build Coastguard Worker 					o = l;				\
1047*1208bc7eSAndroid Build Coastguard Worker 				}					\
1048*1208bc7eSAndroid Build Coastguard Worker 				continue;				\
1049*1208bc7eSAndroid Build Coastguard Worker 			}
1050*1208bc7eSAndroid Build Coastguard Worker #define CONF_HANDLE_CHAR_P(o, n, d)					\
1051*1208bc7eSAndroid Build Coastguard Worker 			if (CONF_MATCH(n)) {				\
1052*1208bc7eSAndroid Build Coastguard Worker 				size_t cpylen = (vlen <=		\
1053*1208bc7eSAndroid Build Coastguard Worker 				    sizeof(o)-1) ? vlen :		\
1054*1208bc7eSAndroid Build Coastguard Worker 				    sizeof(o)-1;			\
1055*1208bc7eSAndroid Build Coastguard Worker 				strncpy(o, v, cpylen);			\
1056*1208bc7eSAndroid Build Coastguard Worker 				o[cpylen] = '\0';			\
1057*1208bc7eSAndroid Build Coastguard Worker 				continue;				\
1058*1208bc7eSAndroid Build Coastguard Worker 			}
1059*1208bc7eSAndroid Build Coastguard Worker 
1060*1208bc7eSAndroid Build Coastguard Worker 			CONF_HANDLE_BOOL(opt_abort, "abort")
1061*1208bc7eSAndroid Build Coastguard Worker 			CONF_HANDLE_BOOL(opt_abort_conf, "abort_conf")
1062*1208bc7eSAndroid Build Coastguard Worker 			if (strncmp("metadata_thp", k, klen) == 0) {
1063*1208bc7eSAndroid Build Coastguard Worker 				int i;
1064*1208bc7eSAndroid Build Coastguard Worker 				bool match = false;
1065*1208bc7eSAndroid Build Coastguard Worker 				for (i = 0; i < metadata_thp_mode_limit; i++) {
1066*1208bc7eSAndroid Build Coastguard Worker 					if (strncmp(metadata_thp_mode_names[i],
1067*1208bc7eSAndroid Build Coastguard Worker 					    v, vlen) == 0) {
1068*1208bc7eSAndroid Build Coastguard Worker 						opt_metadata_thp = i;
1069*1208bc7eSAndroid Build Coastguard Worker 						match = true;
1070*1208bc7eSAndroid Build Coastguard Worker 						break;
1071*1208bc7eSAndroid Build Coastguard Worker 					}
1072*1208bc7eSAndroid Build Coastguard Worker 				}
1073*1208bc7eSAndroid Build Coastguard Worker 				if (!match) {
1074*1208bc7eSAndroid Build Coastguard Worker 					malloc_conf_error("Invalid conf value",
1075*1208bc7eSAndroid Build Coastguard Worker 					    k, klen, v, vlen);
1076*1208bc7eSAndroid Build Coastguard Worker 				}
1077*1208bc7eSAndroid Build Coastguard Worker 				continue;
1078*1208bc7eSAndroid Build Coastguard Worker 			}
1079*1208bc7eSAndroid Build Coastguard Worker 			CONF_HANDLE_BOOL(opt_retain, "retain")
1080*1208bc7eSAndroid Build Coastguard Worker 			if (strncmp("dss", k, klen) == 0) {
1081*1208bc7eSAndroid Build Coastguard Worker 				int i;
1082*1208bc7eSAndroid Build Coastguard Worker 				bool match = false;
1083*1208bc7eSAndroid Build Coastguard Worker 				for (i = 0; i < dss_prec_limit; i++) {
1084*1208bc7eSAndroid Build Coastguard Worker 					if (strncmp(dss_prec_names[i], v, vlen)
1085*1208bc7eSAndroid Build Coastguard Worker 					    == 0) {
1086*1208bc7eSAndroid Build Coastguard Worker 						if (extent_dss_prec_set(i)) {
1087*1208bc7eSAndroid Build Coastguard Worker 							malloc_conf_error(
1088*1208bc7eSAndroid Build Coastguard Worker 							    "Error setting dss",
1089*1208bc7eSAndroid Build Coastguard Worker 							    k, klen, v, vlen);
1090*1208bc7eSAndroid Build Coastguard Worker 						} else {
1091*1208bc7eSAndroid Build Coastguard Worker 							opt_dss =
1092*1208bc7eSAndroid Build Coastguard Worker 							    dss_prec_names[i];
1093*1208bc7eSAndroid Build Coastguard Worker 							match = true;
1094*1208bc7eSAndroid Build Coastguard Worker 							break;
1095*1208bc7eSAndroid Build Coastguard Worker 						}
1096*1208bc7eSAndroid Build Coastguard Worker 					}
1097*1208bc7eSAndroid Build Coastguard Worker 				}
1098*1208bc7eSAndroid Build Coastguard Worker 				if (!match) {
1099*1208bc7eSAndroid Build Coastguard Worker 					malloc_conf_error("Invalid conf value",
1100*1208bc7eSAndroid Build Coastguard Worker 					    k, klen, v, vlen);
1101*1208bc7eSAndroid Build Coastguard Worker 				}
1102*1208bc7eSAndroid Build Coastguard Worker 				continue;
1103*1208bc7eSAndroid Build Coastguard Worker 			}
1104*1208bc7eSAndroid Build Coastguard Worker 			CONF_HANDLE_UNSIGNED(opt_narenas, "narenas", 1,
1105*1208bc7eSAndroid Build Coastguard Worker 			    UINT_MAX, yes, no, false)
1106*1208bc7eSAndroid Build Coastguard Worker 			CONF_HANDLE_SSIZE_T(opt_dirty_decay_ms,
1107*1208bc7eSAndroid Build Coastguard Worker 			    "dirty_decay_ms", -1, NSTIME_SEC_MAX * KQU(1000) <
1108*1208bc7eSAndroid Build Coastguard Worker 			    QU(SSIZE_MAX) ? NSTIME_SEC_MAX * KQU(1000) :
1109*1208bc7eSAndroid Build Coastguard Worker 			    SSIZE_MAX);
1110*1208bc7eSAndroid Build Coastguard Worker 			CONF_HANDLE_SSIZE_T(opt_muzzy_decay_ms,
1111*1208bc7eSAndroid Build Coastguard Worker 			    "muzzy_decay_ms", -1, NSTIME_SEC_MAX * KQU(1000) <
1112*1208bc7eSAndroid Build Coastguard Worker 			    QU(SSIZE_MAX) ? NSTIME_SEC_MAX * KQU(1000) :
1113*1208bc7eSAndroid Build Coastguard Worker 			    SSIZE_MAX);
1114*1208bc7eSAndroid Build Coastguard Worker 			CONF_HANDLE_BOOL(opt_stats_print, "stats_print")
1115*1208bc7eSAndroid Build Coastguard Worker 			if (CONF_MATCH("stats_print_opts")) {
1116*1208bc7eSAndroid Build Coastguard Worker 				init_opt_stats_print_opts(v, vlen);
1117*1208bc7eSAndroid Build Coastguard Worker 				continue;
1118*1208bc7eSAndroid Build Coastguard Worker 			}
1119*1208bc7eSAndroid Build Coastguard Worker 			if (config_fill) {
1120*1208bc7eSAndroid Build Coastguard Worker 				if (CONF_MATCH("junk")) {
1121*1208bc7eSAndroid Build Coastguard Worker 					if (CONF_MATCH_VALUE("true")) {
1122*1208bc7eSAndroid Build Coastguard Worker 						opt_junk = "true";
1123*1208bc7eSAndroid Build Coastguard Worker 						opt_junk_alloc = opt_junk_free =
1124*1208bc7eSAndroid Build Coastguard Worker 						    true;
1125*1208bc7eSAndroid Build Coastguard Worker 					} else if (CONF_MATCH_VALUE("false")) {
1126*1208bc7eSAndroid Build Coastguard Worker 						opt_junk = "false";
1127*1208bc7eSAndroid Build Coastguard Worker 						opt_junk_alloc = opt_junk_free =
1128*1208bc7eSAndroid Build Coastguard Worker 						    false;
1129*1208bc7eSAndroid Build Coastguard Worker 					} else if (CONF_MATCH_VALUE("alloc")) {
1130*1208bc7eSAndroid Build Coastguard Worker 						opt_junk = "alloc";
1131*1208bc7eSAndroid Build Coastguard Worker 						opt_junk_alloc = true;
1132*1208bc7eSAndroid Build Coastguard Worker 						opt_junk_free = false;
1133*1208bc7eSAndroid Build Coastguard Worker 					} else if (CONF_MATCH_VALUE("free")) {
1134*1208bc7eSAndroid Build Coastguard Worker 						opt_junk = "free";
1135*1208bc7eSAndroid Build Coastguard Worker 						opt_junk_alloc = false;
1136*1208bc7eSAndroid Build Coastguard Worker 						opt_junk_free = true;
1137*1208bc7eSAndroid Build Coastguard Worker 					} else {
1138*1208bc7eSAndroid Build Coastguard Worker 						malloc_conf_error(
1139*1208bc7eSAndroid Build Coastguard Worker 						    "Invalid conf value", k,
1140*1208bc7eSAndroid Build Coastguard Worker 						    klen, v, vlen);
1141*1208bc7eSAndroid Build Coastguard Worker 					}
1142*1208bc7eSAndroid Build Coastguard Worker 					continue;
1143*1208bc7eSAndroid Build Coastguard Worker 				}
1144*1208bc7eSAndroid Build Coastguard Worker 				CONF_HANDLE_BOOL(opt_zero, "zero")
1145*1208bc7eSAndroid Build Coastguard Worker 			}
1146*1208bc7eSAndroid Build Coastguard Worker 			if (config_utrace) {
1147*1208bc7eSAndroid Build Coastguard Worker 				CONF_HANDLE_BOOL(opt_utrace, "utrace")
1148*1208bc7eSAndroid Build Coastguard Worker 			}
1149*1208bc7eSAndroid Build Coastguard Worker 			if (config_xmalloc) {
1150*1208bc7eSAndroid Build Coastguard Worker 				CONF_HANDLE_BOOL(opt_xmalloc, "xmalloc")
1151*1208bc7eSAndroid Build Coastguard Worker 			}
1152*1208bc7eSAndroid Build Coastguard Worker 			CONF_HANDLE_BOOL(opt_tcache, "tcache")
1153*1208bc7eSAndroid Build Coastguard Worker 			CONF_HANDLE_SIZE_T(opt_lg_extent_max_active_fit,
1154*1208bc7eSAndroid Build Coastguard Worker 			    "lg_extent_max_active_fit", 0,
1155*1208bc7eSAndroid Build Coastguard Worker 			    (sizeof(size_t) << 3), yes, yes, false)
1156*1208bc7eSAndroid Build Coastguard Worker 			CONF_HANDLE_SSIZE_T(opt_lg_tcache_max, "lg_tcache_max",
1157*1208bc7eSAndroid Build Coastguard Worker 			    -1, (sizeof(size_t) << 3) - 1)
1158*1208bc7eSAndroid Build Coastguard Worker 			if (strncmp("percpu_arena", k, klen) == 0) {
1159*1208bc7eSAndroid Build Coastguard Worker 				bool match = false;
1160*1208bc7eSAndroid Build Coastguard Worker 				for (int i = percpu_arena_mode_names_base; i <
1161*1208bc7eSAndroid Build Coastguard Worker 				    percpu_arena_mode_names_limit; i++) {
1162*1208bc7eSAndroid Build Coastguard Worker 					if (strncmp(percpu_arena_mode_names[i],
1163*1208bc7eSAndroid Build Coastguard Worker 					    v, vlen) == 0) {
1164*1208bc7eSAndroid Build Coastguard Worker 						if (!have_percpu_arena) {
1165*1208bc7eSAndroid Build Coastguard Worker 							malloc_conf_error(
1166*1208bc7eSAndroid Build Coastguard Worker 							    "No getcpu support",
1167*1208bc7eSAndroid Build Coastguard Worker 							    k, klen, v, vlen);
1168*1208bc7eSAndroid Build Coastguard Worker 						}
1169*1208bc7eSAndroid Build Coastguard Worker 						opt_percpu_arena = i;
1170*1208bc7eSAndroid Build Coastguard Worker 						match = true;
1171*1208bc7eSAndroid Build Coastguard Worker 						break;
1172*1208bc7eSAndroid Build Coastguard Worker 					}
1173*1208bc7eSAndroid Build Coastguard Worker 				}
1174*1208bc7eSAndroid Build Coastguard Worker 				if (!match) {
1175*1208bc7eSAndroid Build Coastguard Worker 					malloc_conf_error("Invalid conf value",
1176*1208bc7eSAndroid Build Coastguard Worker 					    k, klen, v, vlen);
1177*1208bc7eSAndroid Build Coastguard Worker 				}
1178*1208bc7eSAndroid Build Coastguard Worker 				continue;
1179*1208bc7eSAndroid Build Coastguard Worker 			}
1180*1208bc7eSAndroid Build Coastguard Worker 			CONF_HANDLE_BOOL(opt_background_thread,
1181*1208bc7eSAndroid Build Coastguard Worker 			    "background_thread");
1182*1208bc7eSAndroid Build Coastguard Worker 			CONF_HANDLE_SIZE_T(opt_max_background_threads,
1183*1208bc7eSAndroid Build Coastguard Worker 					   "max_background_threads", 1,
1184*1208bc7eSAndroid Build Coastguard Worker 					   opt_max_background_threads, yes, yes,
1185*1208bc7eSAndroid Build Coastguard Worker 					   true);
1186*1208bc7eSAndroid Build Coastguard Worker 			if (config_prof) {
1187*1208bc7eSAndroid Build Coastguard Worker 				CONF_HANDLE_BOOL(opt_prof, "prof")
1188*1208bc7eSAndroid Build Coastguard Worker 				CONF_HANDLE_CHAR_P(opt_prof_prefix,
1189*1208bc7eSAndroid Build Coastguard Worker 				    "prof_prefix", "jeprof")
1190*1208bc7eSAndroid Build Coastguard Worker 				CONF_HANDLE_BOOL(opt_prof_active, "prof_active")
1191*1208bc7eSAndroid Build Coastguard Worker 				CONF_HANDLE_BOOL(opt_prof_thread_active_init,
1192*1208bc7eSAndroid Build Coastguard Worker 				    "prof_thread_active_init")
1193*1208bc7eSAndroid Build Coastguard Worker 				CONF_HANDLE_SIZE_T(opt_lg_prof_sample,
1194*1208bc7eSAndroid Build Coastguard Worker 				    "lg_prof_sample", 0, (sizeof(uint64_t) << 3)
1195*1208bc7eSAndroid Build Coastguard Worker 				    - 1, no, yes, true)
1196*1208bc7eSAndroid Build Coastguard Worker 				CONF_HANDLE_BOOL(opt_prof_accum, "prof_accum")
1197*1208bc7eSAndroid Build Coastguard Worker 				CONF_HANDLE_SSIZE_T(opt_lg_prof_interval,
1198*1208bc7eSAndroid Build Coastguard Worker 				    "lg_prof_interval", -1,
1199*1208bc7eSAndroid Build Coastguard Worker 				    (sizeof(uint64_t) << 3) - 1)
1200*1208bc7eSAndroid Build Coastguard Worker 				CONF_HANDLE_BOOL(opt_prof_gdump, "prof_gdump")
1201*1208bc7eSAndroid Build Coastguard Worker 				CONF_HANDLE_BOOL(opt_prof_final, "prof_final")
1202*1208bc7eSAndroid Build Coastguard Worker 				CONF_HANDLE_BOOL(opt_prof_leak, "prof_leak")
1203*1208bc7eSAndroid Build Coastguard Worker 			}
1204*1208bc7eSAndroid Build Coastguard Worker 			if (config_log) {
1205*1208bc7eSAndroid Build Coastguard Worker 				if (CONF_MATCH("log")) {
1206*1208bc7eSAndroid Build Coastguard Worker 					size_t cpylen = (
1207*1208bc7eSAndroid Build Coastguard Worker 					    vlen <= sizeof(log_var_names) ?
1208*1208bc7eSAndroid Build Coastguard Worker 					    vlen : sizeof(log_var_names) - 1);
1209*1208bc7eSAndroid Build Coastguard Worker 					strncpy(log_var_names, v, cpylen);
1210*1208bc7eSAndroid Build Coastguard Worker 					log_var_names[cpylen] = '\0';
1211*1208bc7eSAndroid Build Coastguard Worker 					continue;
1212*1208bc7eSAndroid Build Coastguard Worker 				}
1213*1208bc7eSAndroid Build Coastguard Worker 			}
1214*1208bc7eSAndroid Build Coastguard Worker 			if (CONF_MATCH("thp")) {
1215*1208bc7eSAndroid Build Coastguard Worker 				bool match = false;
1216*1208bc7eSAndroid Build Coastguard Worker 				for (int i = 0; i < thp_mode_names_limit; i++) {
1217*1208bc7eSAndroid Build Coastguard Worker 					if (strncmp(thp_mode_names[i],v, vlen)
1218*1208bc7eSAndroid Build Coastguard Worker 					    == 0) {
1219*1208bc7eSAndroid Build Coastguard Worker 						if (!have_madvise_huge) {
1220*1208bc7eSAndroid Build Coastguard Worker 							malloc_conf_error(
1221*1208bc7eSAndroid Build Coastguard Worker 							    "No THP support",
1222*1208bc7eSAndroid Build Coastguard Worker 							    k, klen, v, vlen);
1223*1208bc7eSAndroid Build Coastguard Worker 						}
1224*1208bc7eSAndroid Build Coastguard Worker 						opt_thp = i;
1225*1208bc7eSAndroid Build Coastguard Worker 						match = true;
1226*1208bc7eSAndroid Build Coastguard Worker 						break;
1227*1208bc7eSAndroid Build Coastguard Worker 					}
1228*1208bc7eSAndroid Build Coastguard Worker 				}
1229*1208bc7eSAndroid Build Coastguard Worker 				if (!match) {
1230*1208bc7eSAndroid Build Coastguard Worker 					malloc_conf_error("Invalid conf value",
1231*1208bc7eSAndroid Build Coastguard Worker 					    k, klen, v, vlen);
1232*1208bc7eSAndroid Build Coastguard Worker 				}
1233*1208bc7eSAndroid Build Coastguard Worker 				continue;
1234*1208bc7eSAndroid Build Coastguard Worker 			}
1235*1208bc7eSAndroid Build Coastguard Worker 			malloc_conf_error("Invalid conf pair", k, klen, v,
1236*1208bc7eSAndroid Build Coastguard Worker 			    vlen);
1237*1208bc7eSAndroid Build Coastguard Worker #undef CONF_MATCH
1238*1208bc7eSAndroid Build Coastguard Worker #undef CONF_MATCH_VALUE
1239*1208bc7eSAndroid Build Coastguard Worker #undef CONF_HANDLE_BOOL
1240*1208bc7eSAndroid Build Coastguard Worker #undef CONF_MIN_no
1241*1208bc7eSAndroid Build Coastguard Worker #undef CONF_MIN_yes
1242*1208bc7eSAndroid Build Coastguard Worker #undef CONF_MAX_no
1243*1208bc7eSAndroid Build Coastguard Worker #undef CONF_MAX_yes
1244*1208bc7eSAndroid Build Coastguard Worker #undef CONF_HANDLE_T_U
1245*1208bc7eSAndroid Build Coastguard Worker #undef CONF_HANDLE_UNSIGNED
1246*1208bc7eSAndroid Build Coastguard Worker #undef CONF_HANDLE_SIZE_T
1247*1208bc7eSAndroid Build Coastguard Worker #undef CONF_HANDLE_SSIZE_T
1248*1208bc7eSAndroid Build Coastguard Worker #undef CONF_HANDLE_CHAR_P
1249*1208bc7eSAndroid Build Coastguard Worker 		}
1250*1208bc7eSAndroid Build Coastguard Worker 		if (opt_abort_conf && had_conf_error) {
1251*1208bc7eSAndroid Build Coastguard Worker 			malloc_abort_invalid_conf();
1252*1208bc7eSAndroid Build Coastguard Worker 		}
1253*1208bc7eSAndroid Build Coastguard Worker 	}
1254*1208bc7eSAndroid Build Coastguard Worker 	atomic_store_b(&log_init_done, true, ATOMIC_RELEASE);
1255*1208bc7eSAndroid Build Coastguard Worker }
1256*1208bc7eSAndroid Build Coastguard Worker 
1257*1208bc7eSAndroid Build Coastguard Worker static bool
1258*1208bc7eSAndroid Build Coastguard Worker malloc_init_hard_needed(void) {
1259*1208bc7eSAndroid Build Coastguard Worker 	if (malloc_initialized() || (IS_INITIALIZER && malloc_init_state ==
1260*1208bc7eSAndroid Build Coastguard Worker 	    malloc_init_recursible)) {
1261*1208bc7eSAndroid Build Coastguard Worker 		/*
1262*1208bc7eSAndroid Build Coastguard Worker 		 * Another thread initialized the allocator before this one
1263*1208bc7eSAndroid Build Coastguard Worker 		 * acquired init_lock, or this thread is the initializing
1264*1208bc7eSAndroid Build Coastguard Worker 		 * thread, and it is recursively allocating.
1265*1208bc7eSAndroid Build Coastguard Worker 		 */
1266*1208bc7eSAndroid Build Coastguard Worker 		return false;
1267*1208bc7eSAndroid Build Coastguard Worker 	}
1268*1208bc7eSAndroid Build Coastguard Worker #ifdef JEMALLOC_THREADED_INIT
1269*1208bc7eSAndroid Build Coastguard Worker 	if (malloc_initializer != NO_INITIALIZER && !IS_INITIALIZER) {
1270*1208bc7eSAndroid Build Coastguard Worker 		/* Busy-wait until the initializing thread completes. */
1271*1208bc7eSAndroid Build Coastguard Worker 		spin_t spinner = SPIN_INITIALIZER;
1272*1208bc7eSAndroid Build Coastguard Worker 		do {
1273*1208bc7eSAndroid Build Coastguard Worker 			malloc_mutex_unlock(TSDN_NULL, &init_lock);
1274*1208bc7eSAndroid Build Coastguard Worker 			spin_adaptive(&spinner);
1275*1208bc7eSAndroid Build Coastguard Worker 			malloc_mutex_lock(TSDN_NULL, &init_lock);
1276*1208bc7eSAndroid Build Coastguard Worker 		} while (!malloc_initialized());
1277*1208bc7eSAndroid Build Coastguard Worker 		return false;
1278*1208bc7eSAndroid Build Coastguard Worker 	}
1279*1208bc7eSAndroid Build Coastguard Worker #endif
1280*1208bc7eSAndroid Build Coastguard Worker 	return true;
1281*1208bc7eSAndroid Build Coastguard Worker }
1282*1208bc7eSAndroid Build Coastguard Worker 
1283*1208bc7eSAndroid Build Coastguard Worker static bool
1284*1208bc7eSAndroid Build Coastguard Worker malloc_init_hard_a0_locked() {
1285*1208bc7eSAndroid Build Coastguard Worker 	malloc_initializer = INITIALIZER;
1286*1208bc7eSAndroid Build Coastguard Worker 
1287*1208bc7eSAndroid Build Coastguard Worker 	if (config_prof) {
1288*1208bc7eSAndroid Build Coastguard Worker 		prof_boot0();
1289*1208bc7eSAndroid Build Coastguard Worker 	}
1290*1208bc7eSAndroid Build Coastguard Worker 	malloc_conf_init();
1291*1208bc7eSAndroid Build Coastguard Worker 	if (opt_stats_print) {
1292*1208bc7eSAndroid Build Coastguard Worker 		/* Print statistics at exit. */
1293*1208bc7eSAndroid Build Coastguard Worker 		if (atexit(stats_print_atexit) != 0) {
1294*1208bc7eSAndroid Build Coastguard Worker 			malloc_write("<jemalloc>: Error in atexit()\n");
1295*1208bc7eSAndroid Build Coastguard Worker 			if (opt_abort) {
1296*1208bc7eSAndroid Build Coastguard Worker 				abort();
1297*1208bc7eSAndroid Build Coastguard Worker 			}
1298*1208bc7eSAndroid Build Coastguard Worker 		}
1299*1208bc7eSAndroid Build Coastguard Worker 	}
1300*1208bc7eSAndroid Build Coastguard Worker 	if (pages_boot()) {
1301*1208bc7eSAndroid Build Coastguard Worker 		return true;
1302*1208bc7eSAndroid Build Coastguard Worker 	}
1303*1208bc7eSAndroid Build Coastguard Worker 	if (base_boot(TSDN_NULL)) {
1304*1208bc7eSAndroid Build Coastguard Worker 		return true;
1305*1208bc7eSAndroid Build Coastguard Worker 	}
1306*1208bc7eSAndroid Build Coastguard Worker 	if (extent_boot()) {
1307*1208bc7eSAndroid Build Coastguard Worker 		return true;
1308*1208bc7eSAndroid Build Coastguard Worker 	}
1309*1208bc7eSAndroid Build Coastguard Worker 	if (ctl_boot()) {
1310*1208bc7eSAndroid Build Coastguard Worker 		return true;
1311*1208bc7eSAndroid Build Coastguard Worker 	}
1312*1208bc7eSAndroid Build Coastguard Worker 	if (config_prof) {
1313*1208bc7eSAndroid Build Coastguard Worker 		prof_boot1();
1314*1208bc7eSAndroid Build Coastguard Worker 	}
1315*1208bc7eSAndroid Build Coastguard Worker 	arena_boot();
1316*1208bc7eSAndroid Build Coastguard Worker 	if (tcache_boot(TSDN_NULL)) {
1317*1208bc7eSAndroid Build Coastguard Worker 		return true;
1318*1208bc7eSAndroid Build Coastguard Worker 	}
1319*1208bc7eSAndroid Build Coastguard Worker 	if (malloc_mutex_init(&arenas_lock, "arenas", WITNESS_RANK_ARENAS,
1320*1208bc7eSAndroid Build Coastguard Worker 	    malloc_mutex_rank_exclusive)) {
1321*1208bc7eSAndroid Build Coastguard Worker 		return true;
1322*1208bc7eSAndroid Build Coastguard Worker 	}
1323*1208bc7eSAndroid Build Coastguard Worker 	/*
1324*1208bc7eSAndroid Build Coastguard Worker 	 * Create enough scaffolding to allow recursive allocation in
1325*1208bc7eSAndroid Build Coastguard Worker 	 * malloc_ncpus().
1326*1208bc7eSAndroid Build Coastguard Worker 	 */
1327*1208bc7eSAndroid Build Coastguard Worker 	narenas_auto = 1;
1328*1208bc7eSAndroid Build Coastguard Worker 	memset(arenas, 0, sizeof(arena_t *) * narenas_auto);
1329*1208bc7eSAndroid Build Coastguard Worker 	/*
1330*1208bc7eSAndroid Build Coastguard Worker 	 * Initialize one arena here.  The rest are lazily created in
1331*1208bc7eSAndroid Build Coastguard Worker 	 * arena_choose_hard().
1332*1208bc7eSAndroid Build Coastguard Worker 	 */
1333*1208bc7eSAndroid Build Coastguard Worker 	if (arena_init(TSDN_NULL, 0, (extent_hooks_t *)&extent_hooks_default)
1334*1208bc7eSAndroid Build Coastguard Worker 	    == NULL) {
1335*1208bc7eSAndroid Build Coastguard Worker 		return true;
1336*1208bc7eSAndroid Build Coastguard Worker 	}
1337*1208bc7eSAndroid Build Coastguard Worker 	a0 = arena_get(TSDN_NULL, 0, false);
1338*1208bc7eSAndroid Build Coastguard Worker 	malloc_init_state = malloc_init_a0_initialized;
1339*1208bc7eSAndroid Build Coastguard Worker 
1340*1208bc7eSAndroid Build Coastguard Worker 	return false;
1341*1208bc7eSAndroid Build Coastguard Worker }
1342*1208bc7eSAndroid Build Coastguard Worker 
1343*1208bc7eSAndroid Build Coastguard Worker static bool
1344*1208bc7eSAndroid Build Coastguard Worker malloc_init_hard_a0(void) {
1345*1208bc7eSAndroid Build Coastguard Worker 	bool ret;
1346*1208bc7eSAndroid Build Coastguard Worker 
1347*1208bc7eSAndroid Build Coastguard Worker 	malloc_mutex_lock(TSDN_NULL, &init_lock);
1348*1208bc7eSAndroid Build Coastguard Worker 	ret = malloc_init_hard_a0_locked();
1349*1208bc7eSAndroid Build Coastguard Worker 	malloc_mutex_unlock(TSDN_NULL, &init_lock);
1350*1208bc7eSAndroid Build Coastguard Worker 	return ret;
1351*1208bc7eSAndroid Build Coastguard Worker }
1352*1208bc7eSAndroid Build Coastguard Worker 
1353*1208bc7eSAndroid Build Coastguard Worker /* Initialize data structures which may trigger recursive allocation. */
1354*1208bc7eSAndroid Build Coastguard Worker static bool
1355*1208bc7eSAndroid Build Coastguard Worker malloc_init_hard_recursible(void) {
1356*1208bc7eSAndroid Build Coastguard Worker 	malloc_init_state = malloc_init_recursible;
1357*1208bc7eSAndroid Build Coastguard Worker 
1358*1208bc7eSAndroid Build Coastguard Worker #if defined(__BIONIC__) && defined(ANDROID_NUM_ARENAS)
1359*1208bc7eSAndroid Build Coastguard Worker 	/* Hardcode since this value won't be used. */
1360*1208bc7eSAndroid Build Coastguard Worker 	ncpus = 2;
1361*1208bc7eSAndroid Build Coastguard Worker #else
1362*1208bc7eSAndroid Build Coastguard Worker 	ncpus = malloc_ncpus();
1363*1208bc7eSAndroid Build Coastguard Worker #endif
1364*1208bc7eSAndroid Build Coastguard Worker 
1365*1208bc7eSAndroid Build Coastguard Worker #if (defined(JEMALLOC_HAVE_PTHREAD_ATFORK) && !defined(JEMALLOC_MUTEX_INIT_CB) \
1366*1208bc7eSAndroid Build Coastguard Worker     && !defined(JEMALLOC_ZONE) && !defined(_WIN32) && \
1367*1208bc7eSAndroid Build Coastguard Worker     !defined(__native_client__))
1368*1208bc7eSAndroid Build Coastguard Worker 	/* LinuxThreads' pthread_atfork() allocates. */
1369*1208bc7eSAndroid Build Coastguard Worker 	if (pthread_atfork(jemalloc_prefork, jemalloc_postfork_parent,
1370*1208bc7eSAndroid Build Coastguard Worker 	    jemalloc_postfork_child) != 0) {
1371*1208bc7eSAndroid Build Coastguard Worker 		malloc_write("<jemalloc>: Error in pthread_atfork()\n");
1372*1208bc7eSAndroid Build Coastguard Worker 		if (opt_abort) {
1373*1208bc7eSAndroid Build Coastguard Worker 			abort();
1374*1208bc7eSAndroid Build Coastguard Worker 		}
1375*1208bc7eSAndroid Build Coastguard Worker 		return true;
1376*1208bc7eSAndroid Build Coastguard Worker 	}
1377*1208bc7eSAndroid Build Coastguard Worker #endif
1378*1208bc7eSAndroid Build Coastguard Worker 
1379*1208bc7eSAndroid Build Coastguard Worker 	if (background_thread_boot0()) {
1380*1208bc7eSAndroid Build Coastguard Worker 		return true;
1381*1208bc7eSAndroid Build Coastguard Worker 	}
1382*1208bc7eSAndroid Build Coastguard Worker 
1383*1208bc7eSAndroid Build Coastguard Worker 	return false;
1384*1208bc7eSAndroid Build Coastguard Worker }
1385*1208bc7eSAndroid Build Coastguard Worker 
1386*1208bc7eSAndroid Build Coastguard Worker static unsigned
1387*1208bc7eSAndroid Build Coastguard Worker malloc_narenas_default(void) {
1388*1208bc7eSAndroid Build Coastguard Worker #if defined(ANDROID_NUM_ARENAS)
1389*1208bc7eSAndroid Build Coastguard Worker 	return ANDROID_NUM_ARENAS;
1390*1208bc7eSAndroid Build Coastguard Worker #else
1391*1208bc7eSAndroid Build Coastguard Worker 	assert(ncpus > 0);
1392*1208bc7eSAndroid Build Coastguard Worker 	/*
1393*1208bc7eSAndroid Build Coastguard Worker 	 * For SMP systems, create more than one arena per CPU by
1394*1208bc7eSAndroid Build Coastguard Worker 	 * default.
1395*1208bc7eSAndroid Build Coastguard Worker 	 */
1396*1208bc7eSAndroid Build Coastguard Worker 	if (ncpus > 1) {
1397*1208bc7eSAndroid Build Coastguard Worker 		return ncpus << 2;
1398*1208bc7eSAndroid Build Coastguard Worker 	} else {
1399*1208bc7eSAndroid Build Coastguard Worker 		return 1;
1400*1208bc7eSAndroid Build Coastguard Worker 	}
1401*1208bc7eSAndroid Build Coastguard Worker #endif
1402*1208bc7eSAndroid Build Coastguard Worker }
1403*1208bc7eSAndroid Build Coastguard Worker 
1404*1208bc7eSAndroid Build Coastguard Worker static percpu_arena_mode_t
1405*1208bc7eSAndroid Build Coastguard Worker percpu_arena_as_initialized(percpu_arena_mode_t mode) {
1406*1208bc7eSAndroid Build Coastguard Worker 	assert(!malloc_initialized());
1407*1208bc7eSAndroid Build Coastguard Worker 	assert(mode <= percpu_arena_disabled);
1408*1208bc7eSAndroid Build Coastguard Worker 
1409*1208bc7eSAndroid Build Coastguard Worker 	if (mode != percpu_arena_disabled) {
1410*1208bc7eSAndroid Build Coastguard Worker 		mode += percpu_arena_mode_enabled_base;
1411*1208bc7eSAndroid Build Coastguard Worker 	}
1412*1208bc7eSAndroid Build Coastguard Worker 
1413*1208bc7eSAndroid Build Coastguard Worker 	return mode;
1414*1208bc7eSAndroid Build Coastguard Worker }
1415*1208bc7eSAndroid Build Coastguard Worker 
1416*1208bc7eSAndroid Build Coastguard Worker static bool
1417*1208bc7eSAndroid Build Coastguard Worker malloc_init_narenas(void) {
1418*1208bc7eSAndroid Build Coastguard Worker 	assert(ncpus > 0);
1419*1208bc7eSAndroid Build Coastguard Worker 
1420*1208bc7eSAndroid Build Coastguard Worker 	if (opt_percpu_arena != percpu_arena_disabled) {
1421*1208bc7eSAndroid Build Coastguard Worker 		if (!have_percpu_arena || malloc_getcpu() < 0) {
1422*1208bc7eSAndroid Build Coastguard Worker 			opt_percpu_arena = percpu_arena_disabled;
1423*1208bc7eSAndroid Build Coastguard Worker 			malloc_printf("<jemalloc>: perCPU arena getcpu() not "
1424*1208bc7eSAndroid Build Coastguard Worker 			    "available. Setting narenas to %u.\n", opt_narenas ?
1425*1208bc7eSAndroid Build Coastguard Worker 			    opt_narenas : malloc_narenas_default());
1426*1208bc7eSAndroid Build Coastguard Worker 			if (opt_abort) {
1427*1208bc7eSAndroid Build Coastguard Worker 				abort();
1428*1208bc7eSAndroid Build Coastguard Worker 			}
1429*1208bc7eSAndroid Build Coastguard Worker 		} else {
1430*1208bc7eSAndroid Build Coastguard Worker 			if (ncpus >= MALLOCX_ARENA_LIMIT) {
1431*1208bc7eSAndroid Build Coastguard Worker 				malloc_printf("<jemalloc>: narenas w/ percpu"
1432*1208bc7eSAndroid Build Coastguard Worker 				    "arena beyond limit (%d)\n", ncpus);
1433*1208bc7eSAndroid Build Coastguard Worker 				if (opt_abort) {
1434*1208bc7eSAndroid Build Coastguard Worker 					abort();
1435*1208bc7eSAndroid Build Coastguard Worker 				}
1436*1208bc7eSAndroid Build Coastguard Worker 				return true;
1437*1208bc7eSAndroid Build Coastguard Worker 			}
1438*1208bc7eSAndroid Build Coastguard Worker 			/* NB: opt_percpu_arena isn't fully initialized yet. */
1439*1208bc7eSAndroid Build Coastguard Worker 			if (percpu_arena_as_initialized(opt_percpu_arena) ==
1440*1208bc7eSAndroid Build Coastguard Worker 			    per_phycpu_arena && ncpus % 2 != 0) {
1441*1208bc7eSAndroid Build Coastguard Worker 				malloc_printf("<jemalloc>: invalid "
1442*1208bc7eSAndroid Build Coastguard Worker 				    "configuration -- per physical CPU arena "
1443*1208bc7eSAndroid Build Coastguard Worker 				    "with odd number (%u) of CPUs (no hyper "
1444*1208bc7eSAndroid Build Coastguard Worker 				    "threading?).\n", ncpus);
1445*1208bc7eSAndroid Build Coastguard Worker 				if (opt_abort)
1446*1208bc7eSAndroid Build Coastguard Worker 					abort();
1447*1208bc7eSAndroid Build Coastguard Worker 			}
1448*1208bc7eSAndroid Build Coastguard Worker 			unsigned n = percpu_arena_ind_limit(
1449*1208bc7eSAndroid Build Coastguard Worker 			    percpu_arena_as_initialized(opt_percpu_arena));
1450*1208bc7eSAndroid Build Coastguard Worker 			if (opt_narenas < n) {
1451*1208bc7eSAndroid Build Coastguard Worker 				/*
1452*1208bc7eSAndroid Build Coastguard Worker 				 * If narenas is specified with percpu_arena
1453*1208bc7eSAndroid Build Coastguard Worker 				 * enabled, actual narenas is set as the greater
1454*1208bc7eSAndroid Build Coastguard Worker 				 * of the two. percpu_arena_choose will be free
1455*1208bc7eSAndroid Build Coastguard Worker 				 * to use any of the arenas based on CPU
1456*1208bc7eSAndroid Build Coastguard Worker 				 * id. This is conservative (at a small cost)
1457*1208bc7eSAndroid Build Coastguard Worker 				 * but ensures correctness.
1458*1208bc7eSAndroid Build Coastguard Worker 				 *
1459*1208bc7eSAndroid Build Coastguard Worker 				 * If for some reason the ncpus determined at
1460*1208bc7eSAndroid Build Coastguard Worker 				 * boot is not the actual number (e.g. because
1461*1208bc7eSAndroid Build Coastguard Worker 				 * of affinity setting from numactl), reserving
1462*1208bc7eSAndroid Build Coastguard Worker 				 * narenas this way provides a workaround for
1463*1208bc7eSAndroid Build Coastguard Worker 				 * percpu_arena.
1464*1208bc7eSAndroid Build Coastguard Worker 				 */
1465*1208bc7eSAndroid Build Coastguard Worker 				opt_narenas = n;
1466*1208bc7eSAndroid Build Coastguard Worker 			}
1467*1208bc7eSAndroid Build Coastguard Worker 		}
1468*1208bc7eSAndroid Build Coastguard Worker 	}
1469*1208bc7eSAndroid Build Coastguard Worker 	if (opt_narenas == 0) {
1470*1208bc7eSAndroid Build Coastguard Worker 		opt_narenas = malloc_narenas_default();
1471*1208bc7eSAndroid Build Coastguard Worker 	}
1472*1208bc7eSAndroid Build Coastguard Worker 	assert(opt_narenas > 0);
1473*1208bc7eSAndroid Build Coastguard Worker 
1474*1208bc7eSAndroid Build Coastguard Worker 	narenas_auto = opt_narenas;
1475*1208bc7eSAndroid Build Coastguard Worker 	/*
1476*1208bc7eSAndroid Build Coastguard Worker 	 * Limit the number of arenas to the indexing range of MALLOCX_ARENA().
1477*1208bc7eSAndroid Build Coastguard Worker 	 */
1478*1208bc7eSAndroid Build Coastguard Worker 	if (narenas_auto >= MALLOCX_ARENA_LIMIT) {
1479*1208bc7eSAndroid Build Coastguard Worker 		narenas_auto = MALLOCX_ARENA_LIMIT - 1;
1480*1208bc7eSAndroid Build Coastguard Worker 		malloc_printf("<jemalloc>: Reducing narenas to limit (%d)\n",
1481*1208bc7eSAndroid Build Coastguard Worker 		    narenas_auto);
1482*1208bc7eSAndroid Build Coastguard Worker 	}
1483*1208bc7eSAndroid Build Coastguard Worker 	narenas_total_set(narenas_auto);
1484*1208bc7eSAndroid Build Coastguard Worker 
1485*1208bc7eSAndroid Build Coastguard Worker 	return false;
1486*1208bc7eSAndroid Build Coastguard Worker }
1487*1208bc7eSAndroid Build Coastguard Worker 
1488*1208bc7eSAndroid Build Coastguard Worker static void
1489*1208bc7eSAndroid Build Coastguard Worker malloc_init_percpu(void) {
1490*1208bc7eSAndroid Build Coastguard Worker 	opt_percpu_arena = percpu_arena_as_initialized(opt_percpu_arena);
1491*1208bc7eSAndroid Build Coastguard Worker }
1492*1208bc7eSAndroid Build Coastguard Worker 
1493*1208bc7eSAndroid Build Coastguard Worker static bool
1494*1208bc7eSAndroid Build Coastguard Worker malloc_init_hard_finish(void) {
1495*1208bc7eSAndroid Build Coastguard Worker 	if (malloc_mutex_boot()) {
1496*1208bc7eSAndroid Build Coastguard Worker 		return true;
1497*1208bc7eSAndroid Build Coastguard Worker 	}
1498*1208bc7eSAndroid Build Coastguard Worker 
1499*1208bc7eSAndroid Build Coastguard Worker 	malloc_init_state = malloc_init_initialized;
1500*1208bc7eSAndroid Build Coastguard Worker 	malloc_slow_flag_init();
1501*1208bc7eSAndroid Build Coastguard Worker 
1502*1208bc7eSAndroid Build Coastguard Worker 	return false;
1503*1208bc7eSAndroid Build Coastguard Worker }
1504*1208bc7eSAndroid Build Coastguard Worker 
1505*1208bc7eSAndroid Build Coastguard Worker static void
1506*1208bc7eSAndroid Build Coastguard Worker malloc_init_hard_cleanup(tsdn_t *tsdn, bool reentrancy_set) {
1507*1208bc7eSAndroid Build Coastguard Worker 	malloc_mutex_assert_owner(tsdn, &init_lock);
1508*1208bc7eSAndroid Build Coastguard Worker 	malloc_mutex_unlock(tsdn, &init_lock);
1509*1208bc7eSAndroid Build Coastguard Worker 	if (reentrancy_set) {
1510*1208bc7eSAndroid Build Coastguard Worker 		assert(!tsdn_null(tsdn));
1511*1208bc7eSAndroid Build Coastguard Worker 		tsd_t *tsd = tsdn_tsd(tsdn);
1512*1208bc7eSAndroid Build Coastguard Worker 		assert(tsd_reentrancy_level_get(tsd) > 0);
1513*1208bc7eSAndroid Build Coastguard Worker 		post_reentrancy(tsd);
1514*1208bc7eSAndroid Build Coastguard Worker 	}
1515*1208bc7eSAndroid Build Coastguard Worker }
1516*1208bc7eSAndroid Build Coastguard Worker 
1517*1208bc7eSAndroid Build Coastguard Worker static bool
1518*1208bc7eSAndroid Build Coastguard Worker malloc_init_hard(void) {
1519*1208bc7eSAndroid Build Coastguard Worker 	tsd_t *tsd;
1520*1208bc7eSAndroid Build Coastguard Worker 
1521*1208bc7eSAndroid Build Coastguard Worker #if defined(_WIN32) && _WIN32_WINNT < 0x0600
1522*1208bc7eSAndroid Build Coastguard Worker 	_init_init_lock();
1523*1208bc7eSAndroid Build Coastguard Worker #endif
1524*1208bc7eSAndroid Build Coastguard Worker 	malloc_mutex_lock(TSDN_NULL, &init_lock);
1525*1208bc7eSAndroid Build Coastguard Worker 
1526*1208bc7eSAndroid Build Coastguard Worker #define UNLOCK_RETURN(tsdn, ret, reentrancy)		\
1527*1208bc7eSAndroid Build Coastguard Worker 	malloc_init_hard_cleanup(tsdn, reentrancy);	\
1528*1208bc7eSAndroid Build Coastguard Worker 	return ret;
1529*1208bc7eSAndroid Build Coastguard Worker 
1530*1208bc7eSAndroid Build Coastguard Worker 	if (!malloc_init_hard_needed()) {
1531*1208bc7eSAndroid Build Coastguard Worker 		UNLOCK_RETURN(TSDN_NULL, false, false)
1532*1208bc7eSAndroid Build Coastguard Worker 	}
1533*1208bc7eSAndroid Build Coastguard Worker 
1534*1208bc7eSAndroid Build Coastguard Worker 	if (malloc_init_state != malloc_init_a0_initialized &&
1535*1208bc7eSAndroid Build Coastguard Worker 	    malloc_init_hard_a0_locked()) {
1536*1208bc7eSAndroid Build Coastguard Worker 		UNLOCK_RETURN(TSDN_NULL, true, false)
1537*1208bc7eSAndroid Build Coastguard Worker 	}
1538*1208bc7eSAndroid Build Coastguard Worker 
1539*1208bc7eSAndroid Build Coastguard Worker 	malloc_mutex_unlock(TSDN_NULL, &init_lock);
1540*1208bc7eSAndroid Build Coastguard Worker 	/* Recursive allocation relies on functional tsd. */
1541*1208bc7eSAndroid Build Coastguard Worker 	tsd = malloc_tsd_boot0();
1542*1208bc7eSAndroid Build Coastguard Worker 	if (tsd == NULL) {
1543*1208bc7eSAndroid Build Coastguard Worker 		return true;
1544*1208bc7eSAndroid Build Coastguard Worker 	}
1545*1208bc7eSAndroid Build Coastguard Worker 	if (malloc_init_hard_recursible()) {
1546*1208bc7eSAndroid Build Coastguard Worker 		return true;
1547*1208bc7eSAndroid Build Coastguard Worker 	}
1548*1208bc7eSAndroid Build Coastguard Worker 
1549*1208bc7eSAndroid Build Coastguard Worker 	malloc_mutex_lock(tsd_tsdn(tsd), &init_lock);
1550*1208bc7eSAndroid Build Coastguard Worker 	/* Set reentrancy level to 1 during init. */
1551*1208bc7eSAndroid Build Coastguard Worker 	pre_reentrancy(tsd, NULL);
1552*1208bc7eSAndroid Build Coastguard Worker 	/* Initialize narenas before prof_boot2 (for allocation). */
1553*1208bc7eSAndroid Build Coastguard Worker 	if (malloc_init_narenas() || background_thread_boot1(tsd_tsdn(tsd))) {
1554*1208bc7eSAndroid Build Coastguard Worker 		UNLOCK_RETURN(tsd_tsdn(tsd), true, true)
1555*1208bc7eSAndroid Build Coastguard Worker 	}
1556*1208bc7eSAndroid Build Coastguard Worker 	if (config_prof && prof_boot2(tsd)) {
1557*1208bc7eSAndroid Build Coastguard Worker 		UNLOCK_RETURN(tsd_tsdn(tsd), true, true)
1558*1208bc7eSAndroid Build Coastguard Worker 	}
1559*1208bc7eSAndroid Build Coastguard Worker 
1560*1208bc7eSAndroid Build Coastguard Worker 	malloc_init_percpu();
1561*1208bc7eSAndroid Build Coastguard Worker 
1562*1208bc7eSAndroid Build Coastguard Worker 	if (malloc_init_hard_finish()) {
1563*1208bc7eSAndroid Build Coastguard Worker 		UNLOCK_RETURN(tsd_tsdn(tsd), true, true)
1564*1208bc7eSAndroid Build Coastguard Worker 	}
1565*1208bc7eSAndroid Build Coastguard Worker 	post_reentrancy(tsd);
1566*1208bc7eSAndroid Build Coastguard Worker 	malloc_mutex_unlock(tsd_tsdn(tsd), &init_lock);
1567*1208bc7eSAndroid Build Coastguard Worker 
1568*1208bc7eSAndroid Build Coastguard Worker 	witness_assert_lockless(witness_tsd_tsdn(
1569*1208bc7eSAndroid Build Coastguard Worker 	    tsd_witness_tsdp_get_unsafe(tsd)));
1570*1208bc7eSAndroid Build Coastguard Worker 	malloc_tsd_boot1();
1571*1208bc7eSAndroid Build Coastguard Worker 	/* Update TSD after tsd_boot1. */
1572*1208bc7eSAndroid Build Coastguard Worker 	tsd = tsd_fetch();
1573*1208bc7eSAndroid Build Coastguard Worker 	if (opt_background_thread) {
1574*1208bc7eSAndroid Build Coastguard Worker 		assert(have_background_thread);
1575*1208bc7eSAndroid Build Coastguard Worker 		/*
1576*1208bc7eSAndroid Build Coastguard Worker 		 * Need to finish init & unlock first before creating background
1577*1208bc7eSAndroid Build Coastguard Worker 		 * threads (pthread_create depends on malloc).  ctl_init (which
1578*1208bc7eSAndroid Build Coastguard Worker 		 * sets isthreaded) needs to be called without holding any lock.
1579*1208bc7eSAndroid Build Coastguard Worker 		 */
1580*1208bc7eSAndroid Build Coastguard Worker 		background_thread_ctl_init(tsd_tsdn(tsd));
1581*1208bc7eSAndroid Build Coastguard Worker 
1582*1208bc7eSAndroid Build Coastguard Worker 		malloc_mutex_lock(tsd_tsdn(tsd), &background_thread_lock);
1583*1208bc7eSAndroid Build Coastguard Worker 		bool err = background_thread_create(tsd, 0);
1584*1208bc7eSAndroid Build Coastguard Worker 		malloc_mutex_unlock(tsd_tsdn(tsd), &background_thread_lock);
1585*1208bc7eSAndroid Build Coastguard Worker 		if (err) {
1586*1208bc7eSAndroid Build Coastguard Worker 			return true;
1587*1208bc7eSAndroid Build Coastguard Worker 		}
1588*1208bc7eSAndroid Build Coastguard Worker 	}
1589*1208bc7eSAndroid Build Coastguard Worker #undef UNLOCK_RETURN
1590*1208bc7eSAndroid Build Coastguard Worker 	return false;
1591*1208bc7eSAndroid Build Coastguard Worker }
1592*1208bc7eSAndroid Build Coastguard Worker 
1593*1208bc7eSAndroid Build Coastguard Worker /*
1594*1208bc7eSAndroid Build Coastguard Worker  * End initialization functions.
1595*1208bc7eSAndroid Build Coastguard Worker  */
1596*1208bc7eSAndroid Build Coastguard Worker /******************************************************************************/
1597*1208bc7eSAndroid Build Coastguard Worker /*
1598*1208bc7eSAndroid Build Coastguard Worker  * Begin allocation-path internal functions and data structures.
1599*1208bc7eSAndroid Build Coastguard Worker  */
1600*1208bc7eSAndroid Build Coastguard Worker 
1601*1208bc7eSAndroid Build Coastguard Worker /*
1602*1208bc7eSAndroid Build Coastguard Worker  * Settings determined by the documented behavior of the allocation functions.
1603*1208bc7eSAndroid Build Coastguard Worker  */
1604*1208bc7eSAndroid Build Coastguard Worker typedef struct static_opts_s static_opts_t;
1605*1208bc7eSAndroid Build Coastguard Worker struct static_opts_s {
1606*1208bc7eSAndroid Build Coastguard Worker 	/* Whether or not allocation size may overflow. */
1607*1208bc7eSAndroid Build Coastguard Worker 	bool may_overflow;
1608*1208bc7eSAndroid Build Coastguard Worker 	/* Whether or not allocations of size 0 should be treated as size 1. */
1609*1208bc7eSAndroid Build Coastguard Worker 	bool bump_empty_alloc;
1610*1208bc7eSAndroid Build Coastguard Worker 	/*
1611*1208bc7eSAndroid Build Coastguard Worker 	 * Whether to assert that allocations are not of size 0 (after any
1612*1208bc7eSAndroid Build Coastguard Worker 	 * bumping).
1613*1208bc7eSAndroid Build Coastguard Worker 	 */
1614*1208bc7eSAndroid Build Coastguard Worker 	bool assert_nonempty_alloc;
1615*1208bc7eSAndroid Build Coastguard Worker 
1616*1208bc7eSAndroid Build Coastguard Worker 	/*
1617*1208bc7eSAndroid Build Coastguard Worker 	 * Whether or not to modify the 'result' argument to malloc in case of
1618*1208bc7eSAndroid Build Coastguard Worker 	 * error.
1619*1208bc7eSAndroid Build Coastguard Worker 	 */
1620*1208bc7eSAndroid Build Coastguard Worker 	bool null_out_result_on_error;
1621*1208bc7eSAndroid Build Coastguard Worker 	/* Whether to set errno when we encounter an error condition. */
1622*1208bc7eSAndroid Build Coastguard Worker 	bool set_errno_on_error;
1623*1208bc7eSAndroid Build Coastguard Worker 
1624*1208bc7eSAndroid Build Coastguard Worker 	/*
1625*1208bc7eSAndroid Build Coastguard Worker 	 * The minimum valid alignment for functions requesting aligned storage.
1626*1208bc7eSAndroid Build Coastguard Worker 	 */
1627*1208bc7eSAndroid Build Coastguard Worker 	size_t min_alignment;
1628*1208bc7eSAndroid Build Coastguard Worker 
1629*1208bc7eSAndroid Build Coastguard Worker 	/* The error string to use if we oom. */
1630*1208bc7eSAndroid Build Coastguard Worker 	const char *oom_string;
1631*1208bc7eSAndroid Build Coastguard Worker 	/* The error string to use if the passed-in alignment is invalid. */
1632*1208bc7eSAndroid Build Coastguard Worker 	const char *invalid_alignment_string;
1633*1208bc7eSAndroid Build Coastguard Worker 
1634*1208bc7eSAndroid Build Coastguard Worker 	/*
1635*1208bc7eSAndroid Build Coastguard Worker 	 * False if we're configured to skip some time-consuming operations.
1636*1208bc7eSAndroid Build Coastguard Worker 	 *
1637*1208bc7eSAndroid Build Coastguard Worker 	 * This isn't really a malloc "behavior", but it acts as a useful
1638*1208bc7eSAndroid Build Coastguard Worker 	 * summary of several other static (or at least, static after program
1639*1208bc7eSAndroid Build Coastguard Worker 	 * initialization) options.
1640*1208bc7eSAndroid Build Coastguard Worker 	 */
1641*1208bc7eSAndroid Build Coastguard Worker 	bool slow;
1642*1208bc7eSAndroid Build Coastguard Worker };
1643*1208bc7eSAndroid Build Coastguard Worker 
1644*1208bc7eSAndroid Build Coastguard Worker JEMALLOC_ALWAYS_INLINE void
1645*1208bc7eSAndroid Build Coastguard Worker static_opts_init(static_opts_t *static_opts) {
1646*1208bc7eSAndroid Build Coastguard Worker 	static_opts->may_overflow = false;
1647*1208bc7eSAndroid Build Coastguard Worker 	static_opts->bump_empty_alloc = false;
1648*1208bc7eSAndroid Build Coastguard Worker 	static_opts->assert_nonempty_alloc = false;
1649*1208bc7eSAndroid Build Coastguard Worker 	static_opts->null_out_result_on_error = false;
1650*1208bc7eSAndroid Build Coastguard Worker 	static_opts->set_errno_on_error = false;
1651*1208bc7eSAndroid Build Coastguard Worker 	static_opts->min_alignment = 0;
1652*1208bc7eSAndroid Build Coastguard Worker 	static_opts->oom_string = "";
1653*1208bc7eSAndroid Build Coastguard Worker 	static_opts->invalid_alignment_string = "";
1654*1208bc7eSAndroid Build Coastguard Worker 	static_opts->slow = false;
1655*1208bc7eSAndroid Build Coastguard Worker }
1656*1208bc7eSAndroid Build Coastguard Worker 
1657*1208bc7eSAndroid Build Coastguard Worker /*
1658*1208bc7eSAndroid Build Coastguard Worker  * These correspond to the macros in jemalloc/jemalloc_macros.h.  Broadly, we
1659*1208bc7eSAndroid Build Coastguard Worker  * should have one constant here per magic value there.  Note however that the
1660*1208bc7eSAndroid Build Coastguard Worker  * representations need not be related.
1661*1208bc7eSAndroid Build Coastguard Worker  */
1662*1208bc7eSAndroid Build Coastguard Worker #define TCACHE_IND_NONE ((unsigned)-1)
1663*1208bc7eSAndroid Build Coastguard Worker #define TCACHE_IND_AUTOMATIC ((unsigned)-2)
1664*1208bc7eSAndroid Build Coastguard Worker #define ARENA_IND_AUTOMATIC ((unsigned)-1)
1665*1208bc7eSAndroid Build Coastguard Worker 
1666*1208bc7eSAndroid Build Coastguard Worker typedef struct dynamic_opts_s dynamic_opts_t;
1667*1208bc7eSAndroid Build Coastguard Worker struct dynamic_opts_s {
1668*1208bc7eSAndroid Build Coastguard Worker 	void **result;
1669*1208bc7eSAndroid Build Coastguard Worker 	size_t num_items;
1670*1208bc7eSAndroid Build Coastguard Worker 	size_t item_size;
1671*1208bc7eSAndroid Build Coastguard Worker 	size_t alignment;
1672*1208bc7eSAndroid Build Coastguard Worker 	bool zero;
1673*1208bc7eSAndroid Build Coastguard Worker 	unsigned tcache_ind;
1674*1208bc7eSAndroid Build Coastguard Worker 	unsigned arena_ind;
1675*1208bc7eSAndroid Build Coastguard Worker };
1676*1208bc7eSAndroid Build Coastguard Worker 
1677*1208bc7eSAndroid Build Coastguard Worker JEMALLOC_ALWAYS_INLINE void
1678*1208bc7eSAndroid Build Coastguard Worker dynamic_opts_init(dynamic_opts_t *dynamic_opts) {
1679*1208bc7eSAndroid Build Coastguard Worker 	dynamic_opts->result = NULL;
1680*1208bc7eSAndroid Build Coastguard Worker 	dynamic_opts->num_items = 0;
1681*1208bc7eSAndroid Build Coastguard Worker 	dynamic_opts->item_size = 0;
1682*1208bc7eSAndroid Build Coastguard Worker 	dynamic_opts->alignment = 0;
1683*1208bc7eSAndroid Build Coastguard Worker 	dynamic_opts->zero = false;
1684*1208bc7eSAndroid Build Coastguard Worker 	dynamic_opts->tcache_ind = TCACHE_IND_AUTOMATIC;
1685*1208bc7eSAndroid Build Coastguard Worker 	dynamic_opts->arena_ind = ARENA_IND_AUTOMATIC;
1686*1208bc7eSAndroid Build Coastguard Worker }
1687*1208bc7eSAndroid Build Coastguard Worker 
1688*1208bc7eSAndroid Build Coastguard Worker /* ind is ignored if dopts->alignment > 0. */
1689*1208bc7eSAndroid Build Coastguard Worker JEMALLOC_ALWAYS_INLINE void *
1690*1208bc7eSAndroid Build Coastguard Worker imalloc_no_sample(static_opts_t *sopts, dynamic_opts_t *dopts, tsd_t *tsd,
1691*1208bc7eSAndroid Build Coastguard Worker     size_t size, size_t usize, szind_t ind) {
1692*1208bc7eSAndroid Build Coastguard Worker 	tcache_t *tcache;
1693*1208bc7eSAndroid Build Coastguard Worker 	arena_t *arena;
1694*1208bc7eSAndroid Build Coastguard Worker 
1695*1208bc7eSAndroid Build Coastguard Worker 	/* Fill in the tcache. */
1696*1208bc7eSAndroid Build Coastguard Worker 	if (dopts->tcache_ind == TCACHE_IND_AUTOMATIC) {
1697*1208bc7eSAndroid Build Coastguard Worker 		if (likely(!sopts->slow)) {
1698*1208bc7eSAndroid Build Coastguard Worker 			/* Getting tcache ptr unconditionally. */
1699*1208bc7eSAndroid Build Coastguard Worker 			tcache = tsd_tcachep_get(tsd);
1700*1208bc7eSAndroid Build Coastguard Worker 			assert(tcache == tcache_get(tsd));
1701*1208bc7eSAndroid Build Coastguard Worker 		} else {
1702*1208bc7eSAndroid Build Coastguard Worker 			tcache = tcache_get(tsd);
1703*1208bc7eSAndroid Build Coastguard Worker 		}
1704*1208bc7eSAndroid Build Coastguard Worker 	} else if (dopts->tcache_ind == TCACHE_IND_NONE) {
1705*1208bc7eSAndroid Build Coastguard Worker 		tcache = NULL;
1706*1208bc7eSAndroid Build Coastguard Worker 	} else {
1707*1208bc7eSAndroid Build Coastguard Worker 		tcache = tcaches_get(tsd, dopts->tcache_ind);
1708*1208bc7eSAndroid Build Coastguard Worker 	}
1709*1208bc7eSAndroid Build Coastguard Worker 
1710*1208bc7eSAndroid Build Coastguard Worker 	/* Fill in the arena. */
1711*1208bc7eSAndroid Build Coastguard Worker 	if (dopts->arena_ind == ARENA_IND_AUTOMATIC) {
1712*1208bc7eSAndroid Build Coastguard Worker 		/*
1713*1208bc7eSAndroid Build Coastguard Worker 		 * In case of automatic arena management, we defer arena
1714*1208bc7eSAndroid Build Coastguard Worker 		 * computation until as late as we can, hoping to fill the
1715*1208bc7eSAndroid Build Coastguard Worker 		 * allocation out of the tcache.
1716*1208bc7eSAndroid Build Coastguard Worker 		 */
1717*1208bc7eSAndroid Build Coastguard Worker 		arena = NULL;
1718*1208bc7eSAndroid Build Coastguard Worker 	} else {
1719*1208bc7eSAndroid Build Coastguard Worker 		arena = arena_get(tsd_tsdn(tsd), dopts->arena_ind, true);
1720*1208bc7eSAndroid Build Coastguard Worker 	}
1721*1208bc7eSAndroid Build Coastguard Worker 
1722*1208bc7eSAndroid Build Coastguard Worker 	if (unlikely(dopts->alignment != 0)) {
1723*1208bc7eSAndroid Build Coastguard Worker 		return ipalloct(tsd_tsdn(tsd), usize, dopts->alignment,
1724*1208bc7eSAndroid Build Coastguard Worker 		    dopts->zero, tcache, arena);
1725*1208bc7eSAndroid Build Coastguard Worker 	}
1726*1208bc7eSAndroid Build Coastguard Worker 
1727*1208bc7eSAndroid Build Coastguard Worker 	return iallocztm(tsd_tsdn(tsd), size, ind, dopts->zero, tcache, false,
1728*1208bc7eSAndroid Build Coastguard Worker 	    arena, sopts->slow);
1729*1208bc7eSAndroid Build Coastguard Worker }
1730*1208bc7eSAndroid Build Coastguard Worker 
1731*1208bc7eSAndroid Build Coastguard Worker JEMALLOC_ALWAYS_INLINE void *
1732*1208bc7eSAndroid Build Coastguard Worker imalloc_sample(static_opts_t *sopts, dynamic_opts_t *dopts, tsd_t *tsd,
1733*1208bc7eSAndroid Build Coastguard Worker     size_t usize, szind_t ind) {
1734*1208bc7eSAndroid Build Coastguard Worker 	void *ret;
1735*1208bc7eSAndroid Build Coastguard Worker 
1736*1208bc7eSAndroid Build Coastguard Worker 	/*
1737*1208bc7eSAndroid Build Coastguard Worker 	 * For small allocations, sampling bumps the usize.  If so, we allocate
1738*1208bc7eSAndroid Build Coastguard Worker 	 * from the ind_large bucket.
1739*1208bc7eSAndroid Build Coastguard Worker 	 */
1740*1208bc7eSAndroid Build Coastguard Worker 	szind_t ind_large;
1741*1208bc7eSAndroid Build Coastguard Worker 	size_t bumped_usize = usize;
1742*1208bc7eSAndroid Build Coastguard Worker 
1743*1208bc7eSAndroid Build Coastguard Worker 	if (usize <= SMALL_MAXCLASS) {
1744*1208bc7eSAndroid Build Coastguard Worker 		assert(((dopts->alignment == 0) ? sz_s2u(LARGE_MINCLASS) :
1745*1208bc7eSAndroid Build Coastguard Worker 		    sz_sa2u(LARGE_MINCLASS, dopts->alignment))
1746*1208bc7eSAndroid Build Coastguard Worker 		    == LARGE_MINCLASS);
1747*1208bc7eSAndroid Build Coastguard Worker 		ind_large = sz_size2index(LARGE_MINCLASS);
1748*1208bc7eSAndroid Build Coastguard Worker 		bumped_usize = sz_s2u(LARGE_MINCLASS);
1749*1208bc7eSAndroid Build Coastguard Worker 		ret = imalloc_no_sample(sopts, dopts, tsd, bumped_usize,
1750*1208bc7eSAndroid Build Coastguard Worker 		    bumped_usize, ind_large);
1751*1208bc7eSAndroid Build Coastguard Worker 		if (unlikely(ret == NULL)) {
1752*1208bc7eSAndroid Build Coastguard Worker 			return NULL;
1753*1208bc7eSAndroid Build Coastguard Worker 		}
1754*1208bc7eSAndroid Build Coastguard Worker 		arena_prof_promote(tsd_tsdn(tsd), ret, usize);
1755*1208bc7eSAndroid Build Coastguard Worker 	} else {
1756*1208bc7eSAndroid Build Coastguard Worker 		ret = imalloc_no_sample(sopts, dopts, tsd, usize, usize, ind);
1757*1208bc7eSAndroid Build Coastguard Worker 	}
1758*1208bc7eSAndroid Build Coastguard Worker 
1759*1208bc7eSAndroid Build Coastguard Worker 	return ret;
1760*1208bc7eSAndroid Build Coastguard Worker }
1761*1208bc7eSAndroid Build Coastguard Worker 
1762*1208bc7eSAndroid Build Coastguard Worker /*
1763*1208bc7eSAndroid Build Coastguard Worker  * Returns true if the allocation will overflow, and false otherwise.  Sets
1764*1208bc7eSAndroid Build Coastguard Worker  * *size to the product either way.
1765*1208bc7eSAndroid Build Coastguard Worker  */
1766*1208bc7eSAndroid Build Coastguard Worker JEMALLOC_ALWAYS_INLINE bool
1767*1208bc7eSAndroid Build Coastguard Worker compute_size_with_overflow(bool may_overflow, dynamic_opts_t *dopts,
1768*1208bc7eSAndroid Build Coastguard Worker     size_t *size) {
1769*1208bc7eSAndroid Build Coastguard Worker 	/*
1770*1208bc7eSAndroid Build Coastguard Worker 	 * This function is just num_items * item_size, except that we may have
1771*1208bc7eSAndroid Build Coastguard Worker 	 * to check for overflow.
1772*1208bc7eSAndroid Build Coastguard Worker 	 */
1773*1208bc7eSAndroid Build Coastguard Worker 
1774*1208bc7eSAndroid Build Coastguard Worker 	if (!may_overflow) {
1775*1208bc7eSAndroid Build Coastguard Worker 		assert(dopts->num_items == 1);
1776*1208bc7eSAndroid Build Coastguard Worker 		*size = dopts->item_size;
1777*1208bc7eSAndroid Build Coastguard Worker 		return false;
1778*1208bc7eSAndroid Build Coastguard Worker 	}
1779*1208bc7eSAndroid Build Coastguard Worker 
1780*1208bc7eSAndroid Build Coastguard Worker 	/* A size_t with its high-half bits all set to 1. */
1781*1208bc7eSAndroid Build Coastguard Worker 	static const size_t high_bits = SIZE_T_MAX << (sizeof(size_t) * 8 / 2);
1782*1208bc7eSAndroid Build Coastguard Worker 
1783*1208bc7eSAndroid Build Coastguard Worker 	*size = dopts->item_size * dopts->num_items;
1784*1208bc7eSAndroid Build Coastguard Worker 
1785*1208bc7eSAndroid Build Coastguard Worker 	if (unlikely(*size == 0)) {
1786*1208bc7eSAndroid Build Coastguard Worker 		return (dopts->num_items != 0 && dopts->item_size != 0);
1787*1208bc7eSAndroid Build Coastguard Worker 	}
1788*1208bc7eSAndroid Build Coastguard Worker 
1789*1208bc7eSAndroid Build Coastguard Worker 	/*
1790*1208bc7eSAndroid Build Coastguard Worker 	 * We got a non-zero size, but we don't know if we overflowed to get
1791*1208bc7eSAndroid Build Coastguard Worker 	 * there.  To avoid having to do a divide, we'll be clever and note that
1792*1208bc7eSAndroid Build Coastguard Worker 	 * if both A and B can be represented in N/2 bits, then their product
1793*1208bc7eSAndroid Build Coastguard Worker 	 * can be represented in N bits (without the possibility of overflow).
1794*1208bc7eSAndroid Build Coastguard Worker 	 */
1795*1208bc7eSAndroid Build Coastguard Worker 	if (likely((high_bits & (dopts->num_items | dopts->item_size)) == 0)) {
1796*1208bc7eSAndroid Build Coastguard Worker 		return false;
1797*1208bc7eSAndroid Build Coastguard Worker 	}
1798*1208bc7eSAndroid Build Coastguard Worker 	if (likely(*size / dopts->item_size == dopts->num_items)) {
1799*1208bc7eSAndroid Build Coastguard Worker 		return false;
1800*1208bc7eSAndroid Build Coastguard Worker 	}
1801*1208bc7eSAndroid Build Coastguard Worker 	return true;
1802*1208bc7eSAndroid Build Coastguard Worker }
1803*1208bc7eSAndroid Build Coastguard Worker 
1804*1208bc7eSAndroid Build Coastguard Worker JEMALLOC_ALWAYS_INLINE int
1805*1208bc7eSAndroid Build Coastguard Worker imalloc_body(static_opts_t *sopts, dynamic_opts_t *dopts, tsd_t *tsd) {
1806*1208bc7eSAndroid Build Coastguard Worker 	/* Where the actual allocated memory will live. */
1807*1208bc7eSAndroid Build Coastguard Worker 	void *allocation = NULL;
1808*1208bc7eSAndroid Build Coastguard Worker 	/* Filled in by compute_size_with_overflow below. */
1809*1208bc7eSAndroid Build Coastguard Worker 	size_t size = 0;
1810*1208bc7eSAndroid Build Coastguard Worker 	/*
1811*1208bc7eSAndroid Build Coastguard Worker 	 * For unaligned allocations, we need only ind.  For aligned
1812*1208bc7eSAndroid Build Coastguard Worker 	 * allocations, or in case of stats or profiling we need usize.
1813*1208bc7eSAndroid Build Coastguard Worker 	 *
1814*1208bc7eSAndroid Build Coastguard Worker 	 * These are actually dead stores, in that their values are reset before
1815*1208bc7eSAndroid Build Coastguard Worker 	 * any branch on their value is taken.  Sometimes though, it's
1816*1208bc7eSAndroid Build Coastguard Worker 	 * convenient to pass them as arguments before this point.  To avoid
1817*1208bc7eSAndroid Build Coastguard Worker 	 * undefined behavior then, we initialize them with dummy stores.
1818*1208bc7eSAndroid Build Coastguard Worker 	 */
1819*1208bc7eSAndroid Build Coastguard Worker 	szind_t ind = 0;
1820*1208bc7eSAndroid Build Coastguard Worker 	size_t usize = 0;
1821*1208bc7eSAndroid Build Coastguard Worker 
1822*1208bc7eSAndroid Build Coastguard Worker 	/* Reentrancy is only checked on slow path. */
1823*1208bc7eSAndroid Build Coastguard Worker 	int8_t reentrancy_level;
1824*1208bc7eSAndroid Build Coastguard Worker 
1825*1208bc7eSAndroid Build Coastguard Worker 	/* Compute the amount of memory the user wants. */
1826*1208bc7eSAndroid Build Coastguard Worker 	if (unlikely(compute_size_with_overflow(sopts->may_overflow, dopts,
1827*1208bc7eSAndroid Build Coastguard Worker 	    &size))) {
1828*1208bc7eSAndroid Build Coastguard Worker 		goto label_oom;
1829*1208bc7eSAndroid Build Coastguard Worker 	}
1830*1208bc7eSAndroid Build Coastguard Worker 
1831*1208bc7eSAndroid Build Coastguard Worker 	/* Validate the user input. */
1832*1208bc7eSAndroid Build Coastguard Worker 	if (sopts->bump_empty_alloc) {
1833*1208bc7eSAndroid Build Coastguard Worker 		if (unlikely(size == 0)) {
1834*1208bc7eSAndroid Build Coastguard Worker 			size = 1;
1835*1208bc7eSAndroid Build Coastguard Worker 		}
1836*1208bc7eSAndroid Build Coastguard Worker 	}
1837*1208bc7eSAndroid Build Coastguard Worker 
1838*1208bc7eSAndroid Build Coastguard Worker 	if (sopts->assert_nonempty_alloc) {
1839*1208bc7eSAndroid Build Coastguard Worker 		assert (size != 0);
1840*1208bc7eSAndroid Build Coastguard Worker 	}
1841*1208bc7eSAndroid Build Coastguard Worker 
1842*1208bc7eSAndroid Build Coastguard Worker 	if (unlikely(dopts->alignment < sopts->min_alignment
1843*1208bc7eSAndroid Build Coastguard Worker 	    || (dopts->alignment & (dopts->alignment - 1)) != 0)) {
1844*1208bc7eSAndroid Build Coastguard Worker 		goto label_invalid_alignment;
1845*1208bc7eSAndroid Build Coastguard Worker 	}
1846*1208bc7eSAndroid Build Coastguard Worker 
1847*1208bc7eSAndroid Build Coastguard Worker 	/* This is the beginning of the "core" algorithm. */
1848*1208bc7eSAndroid Build Coastguard Worker 
1849*1208bc7eSAndroid Build Coastguard Worker 	if (dopts->alignment == 0) {
1850*1208bc7eSAndroid Build Coastguard Worker 		ind = sz_size2index(size);
1851*1208bc7eSAndroid Build Coastguard Worker 		if (unlikely(ind >= NSIZES)) {
1852*1208bc7eSAndroid Build Coastguard Worker 			goto label_oom;
1853*1208bc7eSAndroid Build Coastguard Worker 		}
1854*1208bc7eSAndroid Build Coastguard Worker 		if (config_stats || (config_prof && opt_prof)) {
1855*1208bc7eSAndroid Build Coastguard Worker 			usize = sz_index2size(ind);
1856*1208bc7eSAndroid Build Coastguard Worker 			assert(usize > 0 && usize <= LARGE_MAXCLASS);
1857*1208bc7eSAndroid Build Coastguard Worker 		}
1858*1208bc7eSAndroid Build Coastguard Worker 	} else {
1859*1208bc7eSAndroid Build Coastguard Worker 		usize = sz_sa2u(size, dopts->alignment);
1860*1208bc7eSAndroid Build Coastguard Worker 		if (unlikely(usize == 0 || usize > LARGE_MAXCLASS)) {
1861*1208bc7eSAndroid Build Coastguard Worker 			goto label_oom;
1862*1208bc7eSAndroid Build Coastguard Worker 		}
1863*1208bc7eSAndroid Build Coastguard Worker 	}
1864*1208bc7eSAndroid Build Coastguard Worker 
1865*1208bc7eSAndroid Build Coastguard Worker 	check_entry_exit_locking(tsd_tsdn(tsd));
1866*1208bc7eSAndroid Build Coastguard Worker 
1867*1208bc7eSAndroid Build Coastguard Worker 	/*
1868*1208bc7eSAndroid Build Coastguard Worker 	 * If we need to handle reentrancy, we can do it out of a
1869*1208bc7eSAndroid Build Coastguard Worker 	 * known-initialized arena (i.e. arena 0).
1870*1208bc7eSAndroid Build Coastguard Worker 	 */
1871*1208bc7eSAndroid Build Coastguard Worker 	reentrancy_level = tsd_reentrancy_level_get(tsd);
1872*1208bc7eSAndroid Build Coastguard Worker 	if (sopts->slow && unlikely(reentrancy_level > 0)) {
1873*1208bc7eSAndroid Build Coastguard Worker 		/*
1874*1208bc7eSAndroid Build Coastguard Worker 		 * We should never specify particular arenas or tcaches from
1875*1208bc7eSAndroid Build Coastguard Worker 		 * within our internal allocations.
1876*1208bc7eSAndroid Build Coastguard Worker 		 */
1877*1208bc7eSAndroid Build Coastguard Worker 		assert(dopts->tcache_ind == TCACHE_IND_AUTOMATIC ||
1878*1208bc7eSAndroid Build Coastguard Worker 		    dopts->tcache_ind == TCACHE_IND_NONE);
1879*1208bc7eSAndroid Build Coastguard Worker 		assert(dopts->arena_ind == ARENA_IND_AUTOMATIC);
1880*1208bc7eSAndroid Build Coastguard Worker 		dopts->tcache_ind = TCACHE_IND_NONE;
1881*1208bc7eSAndroid Build Coastguard Worker 		/* We know that arena 0 has already been initialized. */
1882*1208bc7eSAndroid Build Coastguard Worker 		dopts->arena_ind = 0;
1883*1208bc7eSAndroid Build Coastguard Worker 	}
1884*1208bc7eSAndroid Build Coastguard Worker 
1885*1208bc7eSAndroid Build Coastguard Worker 	/* If profiling is on, get our profiling context. */
1886*1208bc7eSAndroid Build Coastguard Worker 	if (config_prof && opt_prof) {
1887*1208bc7eSAndroid Build Coastguard Worker 		/*
1888*1208bc7eSAndroid Build Coastguard Worker 		 * Note that if we're going down this path, usize must have been
1889*1208bc7eSAndroid Build Coastguard Worker 		 * initialized in the previous if statement.
1890*1208bc7eSAndroid Build Coastguard Worker 		 */
1891*1208bc7eSAndroid Build Coastguard Worker 		prof_tctx_t *tctx = prof_alloc_prep(
1892*1208bc7eSAndroid Build Coastguard Worker 		    tsd, usize, prof_active_get_unlocked(), true);
1893*1208bc7eSAndroid Build Coastguard Worker 
1894*1208bc7eSAndroid Build Coastguard Worker 		alloc_ctx_t alloc_ctx;
1895*1208bc7eSAndroid Build Coastguard Worker 		if (likely((uintptr_t)tctx == (uintptr_t)1U)) {
1896*1208bc7eSAndroid Build Coastguard Worker 			alloc_ctx.slab = (usize <= SMALL_MAXCLASS);
1897*1208bc7eSAndroid Build Coastguard Worker 			allocation = imalloc_no_sample(
1898*1208bc7eSAndroid Build Coastguard Worker 			    sopts, dopts, tsd, usize, usize, ind);
1899*1208bc7eSAndroid Build Coastguard Worker 		} else if ((uintptr_t)tctx > (uintptr_t)1U) {
1900*1208bc7eSAndroid Build Coastguard Worker 			/*
1901*1208bc7eSAndroid Build Coastguard Worker 			 * Note that ind might still be 0 here.  This is fine;
1902*1208bc7eSAndroid Build Coastguard Worker 			 * imalloc_sample ignores ind if dopts->alignment > 0.
1903*1208bc7eSAndroid Build Coastguard Worker 			 */
1904*1208bc7eSAndroid Build Coastguard Worker 			allocation = imalloc_sample(
1905*1208bc7eSAndroid Build Coastguard Worker 			    sopts, dopts, tsd, usize, ind);
1906*1208bc7eSAndroid Build Coastguard Worker 			alloc_ctx.slab = false;
1907*1208bc7eSAndroid Build Coastguard Worker 		} else {
1908*1208bc7eSAndroid Build Coastguard Worker 			allocation = NULL;
1909*1208bc7eSAndroid Build Coastguard Worker 		}
1910*1208bc7eSAndroid Build Coastguard Worker 
1911*1208bc7eSAndroid Build Coastguard Worker 		if (unlikely(allocation == NULL)) {
1912*1208bc7eSAndroid Build Coastguard Worker 			prof_alloc_rollback(tsd, tctx, true);
1913*1208bc7eSAndroid Build Coastguard Worker 			goto label_oom;
1914*1208bc7eSAndroid Build Coastguard Worker 		}
1915*1208bc7eSAndroid Build Coastguard Worker 		prof_malloc(tsd_tsdn(tsd), allocation, usize, &alloc_ctx, tctx);
1916*1208bc7eSAndroid Build Coastguard Worker 	} else {
1917*1208bc7eSAndroid Build Coastguard Worker 		/*
1918*1208bc7eSAndroid Build Coastguard Worker 		 * If dopts->alignment > 0, then ind is still 0, but usize was
1919*1208bc7eSAndroid Build Coastguard Worker 		 * computed in the previous if statement.  Down the positive
1920*1208bc7eSAndroid Build Coastguard Worker 		 * alignment path, imalloc_no_sample ignores ind and size
1921*1208bc7eSAndroid Build Coastguard Worker 		 * (relying only on usize).
1922*1208bc7eSAndroid Build Coastguard Worker 		 */
1923*1208bc7eSAndroid Build Coastguard Worker 		allocation = imalloc_no_sample(sopts, dopts, tsd, size, usize,
1924*1208bc7eSAndroid Build Coastguard Worker 		    ind);
1925*1208bc7eSAndroid Build Coastguard Worker 		if (unlikely(allocation == NULL)) {
1926*1208bc7eSAndroid Build Coastguard Worker 			goto label_oom;
1927*1208bc7eSAndroid Build Coastguard Worker 		}
1928*1208bc7eSAndroid Build Coastguard Worker 	}
1929*1208bc7eSAndroid Build Coastguard Worker 
1930*1208bc7eSAndroid Build Coastguard Worker 	/*
1931*1208bc7eSAndroid Build Coastguard Worker 	 * Allocation has been done at this point.  We still have some
1932*1208bc7eSAndroid Build Coastguard Worker 	 * post-allocation work to do though.
1933*1208bc7eSAndroid Build Coastguard Worker 	 */
1934*1208bc7eSAndroid Build Coastguard Worker 	assert(dopts->alignment == 0
1935*1208bc7eSAndroid Build Coastguard Worker 	    || ((uintptr_t)allocation & (dopts->alignment - 1)) == ZU(0));
1936*1208bc7eSAndroid Build Coastguard Worker 
1937*1208bc7eSAndroid Build Coastguard Worker 	if (config_stats) {
1938*1208bc7eSAndroid Build Coastguard Worker 		assert(usize == isalloc(tsd_tsdn(tsd), allocation));
1939*1208bc7eSAndroid Build Coastguard Worker 		*tsd_thread_allocatedp_get(tsd) += usize;
1940*1208bc7eSAndroid Build Coastguard Worker 	}
1941*1208bc7eSAndroid Build Coastguard Worker 
1942*1208bc7eSAndroid Build Coastguard Worker 	if (sopts->slow) {
1943*1208bc7eSAndroid Build Coastguard Worker 		UTRACE(0, size, allocation);
1944*1208bc7eSAndroid Build Coastguard Worker 	}
1945*1208bc7eSAndroid Build Coastguard Worker 
1946*1208bc7eSAndroid Build Coastguard Worker 	/* Success! */
1947*1208bc7eSAndroid Build Coastguard Worker 	check_entry_exit_locking(tsd_tsdn(tsd));
1948*1208bc7eSAndroid Build Coastguard Worker 	*dopts->result = allocation;
1949*1208bc7eSAndroid Build Coastguard Worker 	return 0;
1950*1208bc7eSAndroid Build Coastguard Worker 
1951*1208bc7eSAndroid Build Coastguard Worker label_oom:
1952*1208bc7eSAndroid Build Coastguard Worker 	if (unlikely(sopts->slow) && config_xmalloc && unlikely(opt_xmalloc)) {
1953*1208bc7eSAndroid Build Coastguard Worker 		malloc_write(sopts->oom_string);
1954*1208bc7eSAndroid Build Coastguard Worker 		abort();
1955*1208bc7eSAndroid Build Coastguard Worker 	}
1956*1208bc7eSAndroid Build Coastguard Worker 
1957*1208bc7eSAndroid Build Coastguard Worker 	if (sopts->slow) {
1958*1208bc7eSAndroid Build Coastguard Worker 		UTRACE(NULL, size, NULL);
1959*1208bc7eSAndroid Build Coastguard Worker 	}
1960*1208bc7eSAndroid Build Coastguard Worker 
1961*1208bc7eSAndroid Build Coastguard Worker 	check_entry_exit_locking(tsd_tsdn(tsd));
1962*1208bc7eSAndroid Build Coastguard Worker 
1963*1208bc7eSAndroid Build Coastguard Worker 	if (sopts->set_errno_on_error) {
1964*1208bc7eSAndroid Build Coastguard Worker 		set_errno(ENOMEM);
1965*1208bc7eSAndroid Build Coastguard Worker 	}
1966*1208bc7eSAndroid Build Coastguard Worker 
1967*1208bc7eSAndroid Build Coastguard Worker 	if (sopts->null_out_result_on_error) {
1968*1208bc7eSAndroid Build Coastguard Worker 		*dopts->result = NULL;
1969*1208bc7eSAndroid Build Coastguard Worker 	}
1970*1208bc7eSAndroid Build Coastguard Worker 
1971*1208bc7eSAndroid Build Coastguard Worker 	return ENOMEM;
1972*1208bc7eSAndroid Build Coastguard Worker 
1973*1208bc7eSAndroid Build Coastguard Worker 	/*
1974*1208bc7eSAndroid Build Coastguard Worker 	 * This label is only jumped to by one goto; we move it out of line
1975*1208bc7eSAndroid Build Coastguard Worker 	 * anyways to avoid obscuring the non-error paths, and for symmetry with
1976*1208bc7eSAndroid Build Coastguard Worker 	 * the oom case.
1977*1208bc7eSAndroid Build Coastguard Worker 	 */
1978*1208bc7eSAndroid Build Coastguard Worker label_invalid_alignment:
1979*1208bc7eSAndroid Build Coastguard Worker 	if (config_xmalloc && unlikely(opt_xmalloc)) {
1980*1208bc7eSAndroid Build Coastguard Worker 		malloc_write(sopts->invalid_alignment_string);
1981*1208bc7eSAndroid Build Coastguard Worker 		abort();
1982*1208bc7eSAndroid Build Coastguard Worker 	}
1983*1208bc7eSAndroid Build Coastguard Worker 
1984*1208bc7eSAndroid Build Coastguard Worker 	if (sopts->set_errno_on_error) {
1985*1208bc7eSAndroid Build Coastguard Worker 		set_errno(EINVAL);
1986*1208bc7eSAndroid Build Coastguard Worker 	}
1987*1208bc7eSAndroid Build Coastguard Worker 
1988*1208bc7eSAndroid Build Coastguard Worker 	if (sopts->slow) {
1989*1208bc7eSAndroid Build Coastguard Worker 		UTRACE(NULL, size, NULL);
1990*1208bc7eSAndroid Build Coastguard Worker 	}
1991*1208bc7eSAndroid Build Coastguard Worker 
1992*1208bc7eSAndroid Build Coastguard Worker 	check_entry_exit_locking(tsd_tsdn(tsd));
1993*1208bc7eSAndroid Build Coastguard Worker 
1994*1208bc7eSAndroid Build Coastguard Worker 	if (sopts->null_out_result_on_error) {
1995*1208bc7eSAndroid Build Coastguard Worker 		*dopts->result = NULL;
1996*1208bc7eSAndroid Build Coastguard Worker 	}
1997*1208bc7eSAndroid Build Coastguard Worker 
1998*1208bc7eSAndroid Build Coastguard Worker 	return EINVAL;
1999*1208bc7eSAndroid Build Coastguard Worker }
2000*1208bc7eSAndroid Build Coastguard Worker 
2001*1208bc7eSAndroid Build Coastguard Worker /* Returns the errno-style error code of the allocation. */
2002*1208bc7eSAndroid Build Coastguard Worker JEMALLOC_ALWAYS_INLINE int
2003*1208bc7eSAndroid Build Coastguard Worker imalloc(static_opts_t *sopts, dynamic_opts_t *dopts) {
2004*1208bc7eSAndroid Build Coastguard Worker 	if (unlikely(!malloc_initialized()) && unlikely(malloc_init())) {
2005*1208bc7eSAndroid Build Coastguard Worker 		if (config_xmalloc && unlikely(opt_xmalloc)) {
2006*1208bc7eSAndroid Build Coastguard Worker 			malloc_write(sopts->oom_string);
2007*1208bc7eSAndroid Build Coastguard Worker 			abort();
2008*1208bc7eSAndroid Build Coastguard Worker 		}
2009*1208bc7eSAndroid Build Coastguard Worker 		UTRACE(NULL, dopts->num_items * dopts->item_size, NULL);
2010*1208bc7eSAndroid Build Coastguard Worker 		set_errno(ENOMEM);
2011*1208bc7eSAndroid Build Coastguard Worker 		*dopts->result = NULL;
2012*1208bc7eSAndroid Build Coastguard Worker 
2013*1208bc7eSAndroid Build Coastguard Worker 		return ENOMEM;
2014*1208bc7eSAndroid Build Coastguard Worker 	}
2015*1208bc7eSAndroid Build Coastguard Worker 
2016*1208bc7eSAndroid Build Coastguard Worker 	/* We always need the tsd.  Let's grab it right away. */
2017*1208bc7eSAndroid Build Coastguard Worker 	tsd_t *tsd = tsd_fetch();
2018*1208bc7eSAndroid Build Coastguard Worker 	assert(tsd);
2019*1208bc7eSAndroid Build Coastguard Worker 	if (likely(tsd_fast(tsd))) {
2020*1208bc7eSAndroid Build Coastguard Worker 		/* Fast and common path. */
2021*1208bc7eSAndroid Build Coastguard Worker 		tsd_assert_fast(tsd);
2022*1208bc7eSAndroid Build Coastguard Worker 		sopts->slow = false;
2023*1208bc7eSAndroid Build Coastguard Worker 		return imalloc_body(sopts, dopts, tsd);
2024*1208bc7eSAndroid Build Coastguard Worker 	} else {
2025*1208bc7eSAndroid Build Coastguard Worker 		sopts->slow = true;
2026*1208bc7eSAndroid Build Coastguard Worker 		return imalloc_body(sopts, dopts, tsd);
2027*1208bc7eSAndroid Build Coastguard Worker 	}
2028*1208bc7eSAndroid Build Coastguard Worker }
2029*1208bc7eSAndroid Build Coastguard Worker /******************************************************************************/
2030*1208bc7eSAndroid Build Coastguard Worker /*
2031*1208bc7eSAndroid Build Coastguard Worker  * Begin malloc(3)-compatible functions.
2032*1208bc7eSAndroid Build Coastguard Worker  */
2033*1208bc7eSAndroid Build Coastguard Worker 
2034*1208bc7eSAndroid Build Coastguard Worker JEMALLOC_EXPORT JEMALLOC_ALLOCATOR JEMALLOC_RESTRICT_RETURN
2035*1208bc7eSAndroid Build Coastguard Worker void JEMALLOC_NOTHROW *
2036*1208bc7eSAndroid Build Coastguard Worker JEMALLOC_ATTR(malloc) JEMALLOC_ALLOC_SIZE(1)
2037*1208bc7eSAndroid Build Coastguard Worker je_malloc(size_t size) {
2038*1208bc7eSAndroid Build Coastguard Worker 	void *ret;
2039*1208bc7eSAndroid Build Coastguard Worker 	static_opts_t sopts;
2040*1208bc7eSAndroid Build Coastguard Worker 	dynamic_opts_t dopts;
2041*1208bc7eSAndroid Build Coastguard Worker 
2042*1208bc7eSAndroid Build Coastguard Worker 	LOG("core.malloc.entry", "size: %zu", size);
2043*1208bc7eSAndroid Build Coastguard Worker 
2044*1208bc7eSAndroid Build Coastguard Worker 	static_opts_init(&sopts);
2045*1208bc7eSAndroid Build Coastguard Worker 	dynamic_opts_init(&dopts);
2046*1208bc7eSAndroid Build Coastguard Worker 
2047*1208bc7eSAndroid Build Coastguard Worker 	sopts.bump_empty_alloc = true;
2048*1208bc7eSAndroid Build Coastguard Worker 	sopts.null_out_result_on_error = true;
2049*1208bc7eSAndroid Build Coastguard Worker 	sopts.set_errno_on_error = true;
2050*1208bc7eSAndroid Build Coastguard Worker 	sopts.oom_string = "<jemalloc>: Error in malloc(): out of memory\n";
2051*1208bc7eSAndroid Build Coastguard Worker 
2052*1208bc7eSAndroid Build Coastguard Worker 	dopts.result = &ret;
2053*1208bc7eSAndroid Build Coastguard Worker 	dopts.num_items = 1;
2054*1208bc7eSAndroid Build Coastguard Worker 	dopts.item_size = size;
2055*1208bc7eSAndroid Build Coastguard Worker 
2056*1208bc7eSAndroid Build Coastguard Worker 	imalloc(&sopts, &dopts);
2057*1208bc7eSAndroid Build Coastguard Worker 
2058*1208bc7eSAndroid Build Coastguard Worker 	LOG("core.malloc.exit", "result: %p", ret);
2059*1208bc7eSAndroid Build Coastguard Worker 
2060*1208bc7eSAndroid Build Coastguard Worker 	return ret;
2061*1208bc7eSAndroid Build Coastguard Worker }
2062*1208bc7eSAndroid Build Coastguard Worker 
2063*1208bc7eSAndroid Build Coastguard Worker JEMALLOC_EXPORT int JEMALLOC_NOTHROW
2064*1208bc7eSAndroid Build Coastguard Worker JEMALLOC_ATTR(nonnull(1))
2065*1208bc7eSAndroid Build Coastguard Worker je_posix_memalign(void **memptr, size_t alignment, size_t size) {
2066*1208bc7eSAndroid Build Coastguard Worker 	int ret;
2067*1208bc7eSAndroid Build Coastguard Worker 	static_opts_t sopts;
2068*1208bc7eSAndroid Build Coastguard Worker 	dynamic_opts_t dopts;
2069*1208bc7eSAndroid Build Coastguard Worker 
2070*1208bc7eSAndroid Build Coastguard Worker 	LOG("core.posix_memalign.entry", "mem ptr: %p, alignment: %zu, "
2071*1208bc7eSAndroid Build Coastguard Worker 	    "size: %zu", memptr, alignment, size);
2072*1208bc7eSAndroid Build Coastguard Worker 
2073*1208bc7eSAndroid Build Coastguard Worker 	static_opts_init(&sopts);
2074*1208bc7eSAndroid Build Coastguard Worker 	dynamic_opts_init(&dopts);
2075*1208bc7eSAndroid Build Coastguard Worker 
2076*1208bc7eSAndroid Build Coastguard Worker 	sopts.bump_empty_alloc = true;
2077*1208bc7eSAndroid Build Coastguard Worker 	sopts.min_alignment = sizeof(void *);
2078*1208bc7eSAndroid Build Coastguard Worker 	sopts.oom_string =
2079*1208bc7eSAndroid Build Coastguard Worker 	    "<jemalloc>: Error allocating aligned memory: out of memory\n";
2080*1208bc7eSAndroid Build Coastguard Worker 	sopts.invalid_alignment_string =
2081*1208bc7eSAndroid Build Coastguard Worker 	    "<jemalloc>: Error allocating aligned memory: invalid alignment\n";
2082*1208bc7eSAndroid Build Coastguard Worker 
2083*1208bc7eSAndroid Build Coastguard Worker 	dopts.result = memptr;
2084*1208bc7eSAndroid Build Coastguard Worker 	dopts.num_items = 1;
2085*1208bc7eSAndroid Build Coastguard Worker 	dopts.item_size = size;
2086*1208bc7eSAndroid Build Coastguard Worker 	dopts.alignment = alignment;
2087*1208bc7eSAndroid Build Coastguard Worker 
2088*1208bc7eSAndroid Build Coastguard Worker 	ret = imalloc(&sopts, &dopts);
2089*1208bc7eSAndroid Build Coastguard Worker 
2090*1208bc7eSAndroid Build Coastguard Worker 	LOG("core.posix_memalign.exit", "result: %d, alloc ptr: %p", ret,
2091*1208bc7eSAndroid Build Coastguard Worker 	    *memptr);
2092*1208bc7eSAndroid Build Coastguard Worker 
2093*1208bc7eSAndroid Build Coastguard Worker 	return ret;
2094*1208bc7eSAndroid Build Coastguard Worker }
2095*1208bc7eSAndroid Build Coastguard Worker 
2096*1208bc7eSAndroid Build Coastguard Worker JEMALLOC_EXPORT JEMALLOC_ALLOCATOR JEMALLOC_RESTRICT_RETURN
2097*1208bc7eSAndroid Build Coastguard Worker void JEMALLOC_NOTHROW *
2098*1208bc7eSAndroid Build Coastguard Worker JEMALLOC_ATTR(malloc) JEMALLOC_ALLOC_SIZE(2)
2099*1208bc7eSAndroid Build Coastguard Worker je_aligned_alloc(size_t alignment, size_t size) {
2100*1208bc7eSAndroid Build Coastguard Worker 	void *ret;
2101*1208bc7eSAndroid Build Coastguard Worker 
2102*1208bc7eSAndroid Build Coastguard Worker 	static_opts_t sopts;
2103*1208bc7eSAndroid Build Coastguard Worker 	dynamic_opts_t dopts;
2104*1208bc7eSAndroid Build Coastguard Worker 
2105*1208bc7eSAndroid Build Coastguard Worker 	LOG("core.aligned_alloc.entry", "alignment: %zu, size: %zu\n",
2106*1208bc7eSAndroid Build Coastguard Worker 	    alignment, size);
2107*1208bc7eSAndroid Build Coastguard Worker 
2108*1208bc7eSAndroid Build Coastguard Worker 	static_opts_init(&sopts);
2109*1208bc7eSAndroid Build Coastguard Worker 	dynamic_opts_init(&dopts);
2110*1208bc7eSAndroid Build Coastguard Worker 
2111*1208bc7eSAndroid Build Coastguard Worker 	sopts.bump_empty_alloc = true;
2112*1208bc7eSAndroid Build Coastguard Worker 	sopts.null_out_result_on_error = true;
2113*1208bc7eSAndroid Build Coastguard Worker 	sopts.set_errno_on_error = true;
2114*1208bc7eSAndroid Build Coastguard Worker 	sopts.min_alignment = 1;
2115*1208bc7eSAndroid Build Coastguard Worker 	sopts.oom_string =
2116*1208bc7eSAndroid Build Coastguard Worker 	    "<jemalloc>: Error allocating aligned memory: out of memory\n";
2117*1208bc7eSAndroid Build Coastguard Worker 	sopts.invalid_alignment_string =
2118*1208bc7eSAndroid Build Coastguard Worker 	    "<jemalloc>: Error allocating aligned memory: invalid alignment\n";
2119*1208bc7eSAndroid Build Coastguard Worker 
2120*1208bc7eSAndroid Build Coastguard Worker 	dopts.result = &ret;
2121*1208bc7eSAndroid Build Coastguard Worker 	dopts.num_items = 1;
2122*1208bc7eSAndroid Build Coastguard Worker 	dopts.item_size = size;
2123*1208bc7eSAndroid Build Coastguard Worker 	dopts.alignment = alignment;
2124*1208bc7eSAndroid Build Coastguard Worker 
2125*1208bc7eSAndroid Build Coastguard Worker 	imalloc(&sopts, &dopts);
2126*1208bc7eSAndroid Build Coastguard Worker 
2127*1208bc7eSAndroid Build Coastguard Worker 	LOG("core.aligned_alloc.exit", "result: %p", ret);
2128*1208bc7eSAndroid Build Coastguard Worker 
2129*1208bc7eSAndroid Build Coastguard Worker 	return ret;
2130*1208bc7eSAndroid Build Coastguard Worker }
2131*1208bc7eSAndroid Build Coastguard Worker 
2132*1208bc7eSAndroid Build Coastguard Worker JEMALLOC_EXPORT JEMALLOC_ALLOCATOR JEMALLOC_RESTRICT_RETURN
2133*1208bc7eSAndroid Build Coastguard Worker void JEMALLOC_NOTHROW *
2134*1208bc7eSAndroid Build Coastguard Worker JEMALLOC_ATTR(malloc) JEMALLOC_ALLOC_SIZE2(1, 2)
2135*1208bc7eSAndroid Build Coastguard Worker je_calloc(size_t num, size_t size) {
2136*1208bc7eSAndroid Build Coastguard Worker 	void *ret;
2137*1208bc7eSAndroid Build Coastguard Worker 	static_opts_t sopts;
2138*1208bc7eSAndroid Build Coastguard Worker 	dynamic_opts_t dopts;
2139*1208bc7eSAndroid Build Coastguard Worker 
2140*1208bc7eSAndroid Build Coastguard Worker 	LOG("core.calloc.entry", "num: %zu, size: %zu\n", num, size);
2141*1208bc7eSAndroid Build Coastguard Worker 
2142*1208bc7eSAndroid Build Coastguard Worker 	static_opts_init(&sopts);
2143*1208bc7eSAndroid Build Coastguard Worker 	dynamic_opts_init(&dopts);
2144*1208bc7eSAndroid Build Coastguard Worker 
2145*1208bc7eSAndroid Build Coastguard Worker 	sopts.may_overflow = true;
2146*1208bc7eSAndroid Build Coastguard Worker 	sopts.bump_empty_alloc = true;
2147*1208bc7eSAndroid Build Coastguard Worker 	sopts.null_out_result_on_error = true;
2148*1208bc7eSAndroid Build Coastguard Worker 	sopts.set_errno_on_error = true;
2149*1208bc7eSAndroid Build Coastguard Worker 	sopts.oom_string = "<jemalloc>: Error in calloc(): out of memory\n";
2150*1208bc7eSAndroid Build Coastguard Worker 
2151*1208bc7eSAndroid Build Coastguard Worker 	dopts.result = &ret;
2152*1208bc7eSAndroid Build Coastguard Worker 	dopts.num_items = num;
2153*1208bc7eSAndroid Build Coastguard Worker 	dopts.item_size = size;
2154*1208bc7eSAndroid Build Coastguard Worker 	dopts.zero = true;
2155*1208bc7eSAndroid Build Coastguard Worker 
2156*1208bc7eSAndroid Build Coastguard Worker 	imalloc(&sopts, &dopts);
2157*1208bc7eSAndroid Build Coastguard Worker 
2158*1208bc7eSAndroid Build Coastguard Worker 	LOG("core.calloc.exit", "result: %p", ret);
2159*1208bc7eSAndroid Build Coastguard Worker 
2160*1208bc7eSAndroid Build Coastguard Worker 	return ret;
2161*1208bc7eSAndroid Build Coastguard Worker }
2162*1208bc7eSAndroid Build Coastguard Worker 
2163*1208bc7eSAndroid Build Coastguard Worker static void *
2164*1208bc7eSAndroid Build Coastguard Worker irealloc_prof_sample(tsd_t *tsd, void *old_ptr, size_t old_usize, size_t usize,
2165*1208bc7eSAndroid Build Coastguard Worker     prof_tctx_t *tctx) {
2166*1208bc7eSAndroid Build Coastguard Worker 	void *p;
2167*1208bc7eSAndroid Build Coastguard Worker 
2168*1208bc7eSAndroid Build Coastguard Worker 	if (tctx == NULL) {
2169*1208bc7eSAndroid Build Coastguard Worker 		return NULL;
2170*1208bc7eSAndroid Build Coastguard Worker 	}
2171*1208bc7eSAndroid Build Coastguard Worker 	if (usize <= SMALL_MAXCLASS) {
2172*1208bc7eSAndroid Build Coastguard Worker 		p = iralloc(tsd, old_ptr, old_usize, LARGE_MINCLASS, 0, false);
2173*1208bc7eSAndroid Build Coastguard Worker 		if (p == NULL) {
2174*1208bc7eSAndroid Build Coastguard Worker 			return NULL;
2175*1208bc7eSAndroid Build Coastguard Worker 		}
2176*1208bc7eSAndroid Build Coastguard Worker 		arena_prof_promote(tsd_tsdn(tsd), p, usize);
2177*1208bc7eSAndroid Build Coastguard Worker 	} else {
2178*1208bc7eSAndroid Build Coastguard Worker 		p = iralloc(tsd, old_ptr, old_usize, usize, 0, false);
2179*1208bc7eSAndroid Build Coastguard Worker 	}
2180*1208bc7eSAndroid Build Coastguard Worker 
2181*1208bc7eSAndroid Build Coastguard Worker 	return p;
2182*1208bc7eSAndroid Build Coastguard Worker }
2183*1208bc7eSAndroid Build Coastguard Worker 
2184*1208bc7eSAndroid Build Coastguard Worker JEMALLOC_ALWAYS_INLINE void *
2185*1208bc7eSAndroid Build Coastguard Worker irealloc_prof(tsd_t *tsd, void *old_ptr, size_t old_usize, size_t usize,
2186*1208bc7eSAndroid Build Coastguard Worker    alloc_ctx_t *alloc_ctx) {
2187*1208bc7eSAndroid Build Coastguard Worker 	void *p;
2188*1208bc7eSAndroid Build Coastguard Worker 	bool prof_active;
2189*1208bc7eSAndroid Build Coastguard Worker 	prof_tctx_t *old_tctx, *tctx;
2190*1208bc7eSAndroid Build Coastguard Worker 
2191*1208bc7eSAndroid Build Coastguard Worker 	prof_active = prof_active_get_unlocked();
2192*1208bc7eSAndroid Build Coastguard Worker 	old_tctx = prof_tctx_get(tsd_tsdn(tsd), old_ptr, alloc_ctx);
2193*1208bc7eSAndroid Build Coastguard Worker 	tctx = prof_alloc_prep(tsd, usize, prof_active, true);
2194*1208bc7eSAndroid Build Coastguard Worker 	if (unlikely((uintptr_t)tctx != (uintptr_t)1U)) {
2195*1208bc7eSAndroid Build Coastguard Worker 		p = irealloc_prof_sample(tsd, old_ptr, old_usize, usize, tctx);
2196*1208bc7eSAndroid Build Coastguard Worker 	} else {
2197*1208bc7eSAndroid Build Coastguard Worker 		p = iralloc(tsd, old_ptr, old_usize, usize, 0, false);
2198*1208bc7eSAndroid Build Coastguard Worker 	}
2199*1208bc7eSAndroid Build Coastguard Worker 	if (unlikely(p == NULL)) {
2200*1208bc7eSAndroid Build Coastguard Worker 		prof_alloc_rollback(tsd, tctx, true);
2201*1208bc7eSAndroid Build Coastguard Worker 		return NULL;
2202*1208bc7eSAndroid Build Coastguard Worker 	}
2203*1208bc7eSAndroid Build Coastguard Worker 	prof_realloc(tsd, p, usize, tctx, prof_active, true, old_ptr, old_usize,
2204*1208bc7eSAndroid Build Coastguard Worker 	    old_tctx);
2205*1208bc7eSAndroid Build Coastguard Worker 
2206*1208bc7eSAndroid Build Coastguard Worker 	return p;
2207*1208bc7eSAndroid Build Coastguard Worker }
2208*1208bc7eSAndroid Build Coastguard Worker 
2209*1208bc7eSAndroid Build Coastguard Worker JEMALLOC_ALWAYS_INLINE void
2210*1208bc7eSAndroid Build Coastguard Worker ifree(tsd_t *tsd, void *ptr, tcache_t *tcache, bool slow_path) {
2211*1208bc7eSAndroid Build Coastguard Worker 	if (!slow_path) {
2212*1208bc7eSAndroid Build Coastguard Worker 		tsd_assert_fast(tsd);
2213*1208bc7eSAndroid Build Coastguard Worker 	}
2214*1208bc7eSAndroid Build Coastguard Worker 	check_entry_exit_locking(tsd_tsdn(tsd));
2215*1208bc7eSAndroid Build Coastguard Worker 	if (tsd_reentrancy_level_get(tsd) != 0) {
2216*1208bc7eSAndroid Build Coastguard Worker 		assert(slow_path);
2217*1208bc7eSAndroid Build Coastguard Worker 	}
2218*1208bc7eSAndroid Build Coastguard Worker 
2219*1208bc7eSAndroid Build Coastguard Worker 	assert(ptr != NULL);
2220*1208bc7eSAndroid Build Coastguard Worker 	assert(malloc_initialized() || IS_INITIALIZER);
2221*1208bc7eSAndroid Build Coastguard Worker 
2222*1208bc7eSAndroid Build Coastguard Worker 	alloc_ctx_t alloc_ctx;
2223*1208bc7eSAndroid Build Coastguard Worker 	rtree_ctx_t *rtree_ctx = tsd_rtree_ctx(tsd);
2224*1208bc7eSAndroid Build Coastguard Worker 	rtree_szind_slab_read(tsd_tsdn(tsd), &extents_rtree, rtree_ctx,
2225*1208bc7eSAndroid Build Coastguard Worker 	    (uintptr_t)ptr, true, &alloc_ctx.szind, &alloc_ctx.slab);
2226*1208bc7eSAndroid Build Coastguard Worker 	assert(alloc_ctx.szind != NSIZES);
2227*1208bc7eSAndroid Build Coastguard Worker 
2228*1208bc7eSAndroid Build Coastguard Worker 	size_t usize;
2229*1208bc7eSAndroid Build Coastguard Worker 	if (config_prof && opt_prof) {
2230*1208bc7eSAndroid Build Coastguard Worker 		usize = sz_index2size(alloc_ctx.szind);
2231*1208bc7eSAndroid Build Coastguard Worker 		prof_free(tsd, ptr, usize, &alloc_ctx);
2232*1208bc7eSAndroid Build Coastguard Worker 	} else if (config_stats) {
2233*1208bc7eSAndroid Build Coastguard Worker 		usize = sz_index2size(alloc_ctx.szind);
2234*1208bc7eSAndroid Build Coastguard Worker 	}
2235*1208bc7eSAndroid Build Coastguard Worker 	if (config_stats) {
2236*1208bc7eSAndroid Build Coastguard Worker 		*tsd_thread_deallocatedp_get(tsd) += usize;
2237*1208bc7eSAndroid Build Coastguard Worker 	}
2238*1208bc7eSAndroid Build Coastguard Worker 
2239*1208bc7eSAndroid Build Coastguard Worker 	if (likely(!slow_path)) {
2240*1208bc7eSAndroid Build Coastguard Worker 		idalloctm(tsd_tsdn(tsd), ptr, tcache, &alloc_ctx, false,
2241*1208bc7eSAndroid Build Coastguard Worker 		    false);
2242*1208bc7eSAndroid Build Coastguard Worker 	} else {
2243*1208bc7eSAndroid Build Coastguard Worker 		idalloctm(tsd_tsdn(tsd), ptr, tcache, &alloc_ctx, false,
2244*1208bc7eSAndroid Build Coastguard Worker 		    true);
2245*1208bc7eSAndroid Build Coastguard Worker 	}
2246*1208bc7eSAndroid Build Coastguard Worker }
2247*1208bc7eSAndroid Build Coastguard Worker 
2248*1208bc7eSAndroid Build Coastguard Worker JEMALLOC_ALWAYS_INLINE void
2249*1208bc7eSAndroid Build Coastguard Worker isfree(tsd_t *tsd, void *ptr, size_t usize, tcache_t *tcache, bool slow_path) {
2250*1208bc7eSAndroid Build Coastguard Worker 	if (!slow_path) {
2251*1208bc7eSAndroid Build Coastguard Worker 		tsd_assert_fast(tsd);
2252*1208bc7eSAndroid Build Coastguard Worker 	}
2253*1208bc7eSAndroid Build Coastguard Worker 	check_entry_exit_locking(tsd_tsdn(tsd));
2254*1208bc7eSAndroid Build Coastguard Worker 	if (tsd_reentrancy_level_get(tsd) != 0) {
2255*1208bc7eSAndroid Build Coastguard Worker 		assert(slow_path);
2256*1208bc7eSAndroid Build Coastguard Worker 	}
2257*1208bc7eSAndroid Build Coastguard Worker 
2258*1208bc7eSAndroid Build Coastguard Worker 	assert(ptr != NULL);
2259*1208bc7eSAndroid Build Coastguard Worker 	assert(malloc_initialized() || IS_INITIALIZER);
2260*1208bc7eSAndroid Build Coastguard Worker 
2261*1208bc7eSAndroid Build Coastguard Worker 	alloc_ctx_t alloc_ctx, *ctx;
2262*1208bc7eSAndroid Build Coastguard Worker 	if (!config_cache_oblivious && ((uintptr_t)ptr & PAGE_MASK) != 0) {
2263*1208bc7eSAndroid Build Coastguard Worker 		/*
2264*1208bc7eSAndroid Build Coastguard Worker 		 * When cache_oblivious is disabled and ptr is not page aligned,
2265*1208bc7eSAndroid Build Coastguard Worker 		 * the allocation was not sampled -- usize can be used to
2266*1208bc7eSAndroid Build Coastguard Worker 		 * determine szind directly.
2267*1208bc7eSAndroid Build Coastguard Worker 		 */
2268*1208bc7eSAndroid Build Coastguard Worker 		alloc_ctx.szind = sz_size2index(usize);
2269*1208bc7eSAndroid Build Coastguard Worker 		alloc_ctx.slab = true;
2270*1208bc7eSAndroid Build Coastguard Worker 		ctx = &alloc_ctx;
2271*1208bc7eSAndroid Build Coastguard Worker 		if (config_debug) {
2272*1208bc7eSAndroid Build Coastguard Worker 			alloc_ctx_t dbg_ctx;
2273*1208bc7eSAndroid Build Coastguard Worker 			rtree_ctx_t *rtree_ctx = tsd_rtree_ctx(tsd);
2274*1208bc7eSAndroid Build Coastguard Worker 			rtree_szind_slab_read(tsd_tsdn(tsd), &extents_rtree,
2275*1208bc7eSAndroid Build Coastguard Worker 			    rtree_ctx, (uintptr_t)ptr, true, &dbg_ctx.szind,
2276*1208bc7eSAndroid Build Coastguard Worker 			    &dbg_ctx.slab);
2277*1208bc7eSAndroid Build Coastguard Worker 			assert(dbg_ctx.szind == alloc_ctx.szind);
2278*1208bc7eSAndroid Build Coastguard Worker 			assert(dbg_ctx.slab == alloc_ctx.slab);
2279*1208bc7eSAndroid Build Coastguard Worker 		}
2280*1208bc7eSAndroid Build Coastguard Worker 	} else if (config_prof && opt_prof) {
2281*1208bc7eSAndroid Build Coastguard Worker 		rtree_ctx_t *rtree_ctx = tsd_rtree_ctx(tsd);
2282*1208bc7eSAndroid Build Coastguard Worker 		rtree_szind_slab_read(tsd_tsdn(tsd), &extents_rtree, rtree_ctx,
2283*1208bc7eSAndroid Build Coastguard Worker 		    (uintptr_t)ptr, true, &alloc_ctx.szind, &alloc_ctx.slab);
2284*1208bc7eSAndroid Build Coastguard Worker 		assert(alloc_ctx.szind == sz_size2index(usize));
2285*1208bc7eSAndroid Build Coastguard Worker 		ctx = &alloc_ctx;
2286*1208bc7eSAndroid Build Coastguard Worker 	} else {
2287*1208bc7eSAndroid Build Coastguard Worker 		ctx = NULL;
2288*1208bc7eSAndroid Build Coastguard Worker 	}
2289*1208bc7eSAndroid Build Coastguard Worker 
2290*1208bc7eSAndroid Build Coastguard Worker 	if (config_prof && opt_prof) {
2291*1208bc7eSAndroid Build Coastguard Worker 		prof_free(tsd, ptr, usize, ctx);
2292*1208bc7eSAndroid Build Coastguard Worker 	}
2293*1208bc7eSAndroid Build Coastguard Worker 	if (config_stats) {
2294*1208bc7eSAndroid Build Coastguard Worker 		*tsd_thread_deallocatedp_get(tsd) += usize;
2295*1208bc7eSAndroid Build Coastguard Worker 	}
2296*1208bc7eSAndroid Build Coastguard Worker 
2297*1208bc7eSAndroid Build Coastguard Worker 	if (likely(!slow_path)) {
2298*1208bc7eSAndroid Build Coastguard Worker 		isdalloct(tsd_tsdn(tsd), ptr, usize, tcache, ctx, false);
2299*1208bc7eSAndroid Build Coastguard Worker 	} else {
2300*1208bc7eSAndroid Build Coastguard Worker 		isdalloct(tsd_tsdn(tsd), ptr, usize, tcache, ctx, true);
2301*1208bc7eSAndroid Build Coastguard Worker 	}
2302*1208bc7eSAndroid Build Coastguard Worker }
2303*1208bc7eSAndroid Build Coastguard Worker 
2304*1208bc7eSAndroid Build Coastguard Worker JEMALLOC_EXPORT JEMALLOC_ALLOCATOR JEMALLOC_RESTRICT_RETURN
2305*1208bc7eSAndroid Build Coastguard Worker void JEMALLOC_NOTHROW *
2306*1208bc7eSAndroid Build Coastguard Worker JEMALLOC_ALLOC_SIZE(2)
2307*1208bc7eSAndroid Build Coastguard Worker je_realloc(void *ptr, size_t size) {
2308*1208bc7eSAndroid Build Coastguard Worker 	void *ret;
2309*1208bc7eSAndroid Build Coastguard Worker 	tsdn_t *tsdn JEMALLOC_CC_SILENCE_INIT(NULL);
2310*1208bc7eSAndroid Build Coastguard Worker 	size_t usize JEMALLOC_CC_SILENCE_INIT(0);
2311*1208bc7eSAndroid Build Coastguard Worker 	size_t old_usize = 0;
2312*1208bc7eSAndroid Build Coastguard Worker 
2313*1208bc7eSAndroid Build Coastguard Worker 	LOG("core.realloc.entry", "ptr: %p, size: %zu\n", ptr, size);
2314*1208bc7eSAndroid Build Coastguard Worker 
2315*1208bc7eSAndroid Build Coastguard Worker 	if (unlikely(size == 0)) {
2316*1208bc7eSAndroid Build Coastguard Worker 		if (ptr != NULL) {
2317*1208bc7eSAndroid Build Coastguard Worker 			/* realloc(ptr, 0) is equivalent to free(ptr). */
2318*1208bc7eSAndroid Build Coastguard Worker 			UTRACE(ptr, 0, 0);
2319*1208bc7eSAndroid Build Coastguard Worker 			tcache_t *tcache;
2320*1208bc7eSAndroid Build Coastguard Worker 			tsd_t *tsd = tsd_fetch();
2321*1208bc7eSAndroid Build Coastguard Worker 			if (tsd_reentrancy_level_get(tsd) == 0) {
2322*1208bc7eSAndroid Build Coastguard Worker 				tcache = tcache_get(tsd);
2323*1208bc7eSAndroid Build Coastguard Worker 			} else {
2324*1208bc7eSAndroid Build Coastguard Worker 				tcache = NULL;
2325*1208bc7eSAndroid Build Coastguard Worker 			}
2326*1208bc7eSAndroid Build Coastguard Worker 			ifree(tsd, ptr, tcache, true);
2327*1208bc7eSAndroid Build Coastguard Worker 
2328*1208bc7eSAndroid Build Coastguard Worker 			LOG("core.realloc.exit", "result: %p", NULL);
2329*1208bc7eSAndroid Build Coastguard Worker 			return NULL;
2330*1208bc7eSAndroid Build Coastguard Worker 		}
2331*1208bc7eSAndroid Build Coastguard Worker 		size = 1;
2332*1208bc7eSAndroid Build Coastguard Worker 	}
2333*1208bc7eSAndroid Build Coastguard Worker 
2334*1208bc7eSAndroid Build Coastguard Worker 	if (likely(ptr != NULL)) {
2335*1208bc7eSAndroid Build Coastguard Worker 		assert(malloc_initialized() || IS_INITIALIZER);
2336*1208bc7eSAndroid Build Coastguard Worker 		tsd_t *tsd = tsd_fetch();
2337*1208bc7eSAndroid Build Coastguard Worker 
2338*1208bc7eSAndroid Build Coastguard Worker 		check_entry_exit_locking(tsd_tsdn(tsd));
2339*1208bc7eSAndroid Build Coastguard Worker 
2340*1208bc7eSAndroid Build Coastguard Worker 		alloc_ctx_t alloc_ctx;
2341*1208bc7eSAndroid Build Coastguard Worker 		rtree_ctx_t *rtree_ctx = tsd_rtree_ctx(tsd);
2342*1208bc7eSAndroid Build Coastguard Worker 		rtree_szind_slab_read(tsd_tsdn(tsd), &extents_rtree, rtree_ctx,
2343*1208bc7eSAndroid Build Coastguard Worker 		    (uintptr_t)ptr, true, &alloc_ctx.szind, &alloc_ctx.slab);
2344*1208bc7eSAndroid Build Coastguard Worker 		assert(alloc_ctx.szind != NSIZES);
2345*1208bc7eSAndroid Build Coastguard Worker 		old_usize = sz_index2size(alloc_ctx.szind);
2346*1208bc7eSAndroid Build Coastguard Worker 		assert(old_usize == isalloc(tsd_tsdn(tsd), ptr));
2347*1208bc7eSAndroid Build Coastguard Worker 		if (config_prof && opt_prof) {
2348*1208bc7eSAndroid Build Coastguard Worker 			usize = sz_s2u(size);
2349*1208bc7eSAndroid Build Coastguard Worker 			ret = unlikely(usize == 0 || usize > LARGE_MAXCLASS) ?
2350*1208bc7eSAndroid Build Coastguard Worker 			    NULL : irealloc_prof(tsd, ptr, old_usize, usize,
2351*1208bc7eSAndroid Build Coastguard Worker 			    &alloc_ctx);
2352*1208bc7eSAndroid Build Coastguard Worker 		} else {
2353*1208bc7eSAndroid Build Coastguard Worker 			if (config_stats) {
2354*1208bc7eSAndroid Build Coastguard Worker 				usize = sz_s2u(size);
2355*1208bc7eSAndroid Build Coastguard Worker 			}
2356*1208bc7eSAndroid Build Coastguard Worker 			ret = iralloc(tsd, ptr, old_usize, size, 0, false);
2357*1208bc7eSAndroid Build Coastguard Worker 		}
2358*1208bc7eSAndroid Build Coastguard Worker 		tsdn = tsd_tsdn(tsd);
2359*1208bc7eSAndroid Build Coastguard Worker 	} else {
2360*1208bc7eSAndroid Build Coastguard Worker 		/* realloc(NULL, size) is equivalent to malloc(size). */
2361*1208bc7eSAndroid Build Coastguard Worker 		void *ret = je_malloc(size);
2362*1208bc7eSAndroid Build Coastguard Worker 		LOG("core.realloc.exit", "result: %p", ret);
2363*1208bc7eSAndroid Build Coastguard Worker 		return ret;
2364*1208bc7eSAndroid Build Coastguard Worker 	}
2365*1208bc7eSAndroid Build Coastguard Worker 
2366*1208bc7eSAndroid Build Coastguard Worker 	if (unlikely(ret == NULL)) {
2367*1208bc7eSAndroid Build Coastguard Worker 		if (config_xmalloc && unlikely(opt_xmalloc)) {
2368*1208bc7eSAndroid Build Coastguard Worker 			malloc_write("<jemalloc>: Error in realloc(): "
2369*1208bc7eSAndroid Build Coastguard Worker 			    "out of memory\n");
2370*1208bc7eSAndroid Build Coastguard Worker 			abort();
2371*1208bc7eSAndroid Build Coastguard Worker 		}
2372*1208bc7eSAndroid Build Coastguard Worker 		set_errno(ENOMEM);
2373*1208bc7eSAndroid Build Coastguard Worker 	}
2374*1208bc7eSAndroid Build Coastguard Worker 	if (config_stats && likely(ret != NULL)) {
2375*1208bc7eSAndroid Build Coastguard Worker 		tsd_t *tsd;
2376*1208bc7eSAndroid Build Coastguard Worker 
2377*1208bc7eSAndroid Build Coastguard Worker 		assert(usize == isalloc(tsdn, ret));
2378*1208bc7eSAndroid Build Coastguard Worker 		tsd = tsdn_tsd(tsdn);
2379*1208bc7eSAndroid Build Coastguard Worker 		*tsd_thread_allocatedp_get(tsd) += usize;
2380*1208bc7eSAndroid Build Coastguard Worker 		*tsd_thread_deallocatedp_get(tsd) += old_usize;
2381*1208bc7eSAndroid Build Coastguard Worker 	}
2382*1208bc7eSAndroid Build Coastguard Worker 	UTRACE(ptr, size, ret);
2383*1208bc7eSAndroid Build Coastguard Worker 	check_entry_exit_locking(tsdn);
2384*1208bc7eSAndroid Build Coastguard Worker 
2385*1208bc7eSAndroid Build Coastguard Worker 	LOG("core.realloc.exit", "result: %p", ret);
2386*1208bc7eSAndroid Build Coastguard Worker 	return ret;
2387*1208bc7eSAndroid Build Coastguard Worker }
2388*1208bc7eSAndroid Build Coastguard Worker 
2389*1208bc7eSAndroid Build Coastguard Worker JEMALLOC_EXPORT void JEMALLOC_NOTHROW
2390*1208bc7eSAndroid Build Coastguard Worker je_free(void *ptr) {
2391*1208bc7eSAndroid Build Coastguard Worker 	LOG("core.free.entry", "ptr: %p", ptr);
2392*1208bc7eSAndroid Build Coastguard Worker 
2393*1208bc7eSAndroid Build Coastguard Worker 	UTRACE(ptr, 0, 0);
2394*1208bc7eSAndroid Build Coastguard Worker 	if (likely(ptr != NULL)) {
2395*1208bc7eSAndroid Build Coastguard Worker 		/*
2396*1208bc7eSAndroid Build Coastguard Worker 		 * We avoid setting up tsd fully (e.g. tcache, arena binding)
2397*1208bc7eSAndroid Build Coastguard Worker 		 * based on only free() calls -- other activities trigger the
2398*1208bc7eSAndroid Build Coastguard Worker 		 * minimal to full transition.  This is because free() may
2399*1208bc7eSAndroid Build Coastguard Worker 		 * happen during thread shutdown after tls deallocation: if a
2400*1208bc7eSAndroid Build Coastguard Worker 		 * thread never had any malloc activities until then, a
2401*1208bc7eSAndroid Build Coastguard Worker 		 * fully-setup tsd won't be destructed properly.
2402*1208bc7eSAndroid Build Coastguard Worker 		 */
2403*1208bc7eSAndroid Build Coastguard Worker 		tsd_t *tsd = tsd_fetch_min();
2404*1208bc7eSAndroid Build Coastguard Worker 		check_entry_exit_locking(tsd_tsdn(tsd));
2405*1208bc7eSAndroid Build Coastguard Worker 
2406*1208bc7eSAndroid Build Coastguard Worker 		tcache_t *tcache;
2407*1208bc7eSAndroid Build Coastguard Worker 		if (likely(tsd_fast(tsd))) {
2408*1208bc7eSAndroid Build Coastguard Worker 			tsd_assert_fast(tsd);
2409*1208bc7eSAndroid Build Coastguard Worker 			/* Unconditionally get tcache ptr on fast path. */
2410*1208bc7eSAndroid Build Coastguard Worker 			tcache = tsd_tcachep_get(tsd);
2411*1208bc7eSAndroid Build Coastguard Worker 			ifree(tsd, ptr, tcache, false);
2412*1208bc7eSAndroid Build Coastguard Worker 		} else {
2413*1208bc7eSAndroid Build Coastguard Worker 			if (likely(tsd_reentrancy_level_get(tsd) == 0)) {
2414*1208bc7eSAndroid Build Coastguard Worker 				tcache = tcache_get(tsd);
2415*1208bc7eSAndroid Build Coastguard Worker 			} else {
2416*1208bc7eSAndroid Build Coastguard Worker 				tcache = NULL;
2417*1208bc7eSAndroid Build Coastguard Worker 			}
2418*1208bc7eSAndroid Build Coastguard Worker 			ifree(tsd, ptr, tcache, true);
2419*1208bc7eSAndroid Build Coastguard Worker 		}
2420*1208bc7eSAndroid Build Coastguard Worker 		check_entry_exit_locking(tsd_tsdn(tsd));
2421*1208bc7eSAndroid Build Coastguard Worker 	}
2422*1208bc7eSAndroid Build Coastguard Worker 	LOG("core.free.exit", "");
2423*1208bc7eSAndroid Build Coastguard Worker }
2424*1208bc7eSAndroid Build Coastguard Worker 
2425*1208bc7eSAndroid Build Coastguard Worker /*
2426*1208bc7eSAndroid Build Coastguard Worker  * End malloc(3)-compatible functions.
2427*1208bc7eSAndroid Build Coastguard Worker  */
2428*1208bc7eSAndroid Build Coastguard Worker /******************************************************************************/
2429*1208bc7eSAndroid Build Coastguard Worker /*
2430*1208bc7eSAndroid Build Coastguard Worker  * Begin non-standard override functions.
2431*1208bc7eSAndroid Build Coastguard Worker  */
2432*1208bc7eSAndroid Build Coastguard Worker 
2433*1208bc7eSAndroid Build Coastguard Worker #ifdef JEMALLOC_OVERRIDE_MEMALIGN
2434*1208bc7eSAndroid Build Coastguard Worker JEMALLOC_EXPORT JEMALLOC_ALLOCATOR JEMALLOC_RESTRICT_RETURN
2435*1208bc7eSAndroid Build Coastguard Worker void JEMALLOC_NOTHROW *
2436*1208bc7eSAndroid Build Coastguard Worker JEMALLOC_ATTR(malloc)
2437*1208bc7eSAndroid Build Coastguard Worker je_memalign(size_t alignment, size_t size) {
2438*1208bc7eSAndroid Build Coastguard Worker 	void *ret;
2439*1208bc7eSAndroid Build Coastguard Worker 	static_opts_t sopts;
2440*1208bc7eSAndroid Build Coastguard Worker 	dynamic_opts_t dopts;
2441*1208bc7eSAndroid Build Coastguard Worker 
2442*1208bc7eSAndroid Build Coastguard Worker 	LOG("core.memalign.entry", "alignment: %zu, size: %zu\n", alignment,
2443*1208bc7eSAndroid Build Coastguard Worker 	    size);
2444*1208bc7eSAndroid Build Coastguard Worker 
2445*1208bc7eSAndroid Build Coastguard Worker 	static_opts_init(&sopts);
2446*1208bc7eSAndroid Build Coastguard Worker 	dynamic_opts_init(&dopts);
2447*1208bc7eSAndroid Build Coastguard Worker 
2448*1208bc7eSAndroid Build Coastguard Worker 	sopts.bump_empty_alloc = true;
2449*1208bc7eSAndroid Build Coastguard Worker 	sopts.min_alignment = 1;
2450*1208bc7eSAndroid Build Coastguard Worker 	sopts.oom_string =
2451*1208bc7eSAndroid Build Coastguard Worker 	    "<jemalloc>: Error allocating aligned memory: out of memory\n";
2452*1208bc7eSAndroid Build Coastguard Worker 	sopts.invalid_alignment_string =
2453*1208bc7eSAndroid Build Coastguard Worker 	    "<jemalloc>: Error allocating aligned memory: invalid alignment\n";
2454*1208bc7eSAndroid Build Coastguard Worker 	sopts.null_out_result_on_error = true;
2455*1208bc7eSAndroid Build Coastguard Worker 
2456*1208bc7eSAndroid Build Coastguard Worker 	dopts.result = &ret;
2457*1208bc7eSAndroid Build Coastguard Worker 	dopts.num_items = 1;
2458*1208bc7eSAndroid Build Coastguard Worker 	dopts.item_size = size;
2459*1208bc7eSAndroid Build Coastguard Worker 	dopts.alignment = alignment;
2460*1208bc7eSAndroid Build Coastguard Worker 
2461*1208bc7eSAndroid Build Coastguard Worker 	imalloc(&sopts, &dopts);
2462*1208bc7eSAndroid Build Coastguard Worker 
2463*1208bc7eSAndroid Build Coastguard Worker 	LOG("core.memalign.exit", "result: %p", ret);
2464*1208bc7eSAndroid Build Coastguard Worker 	return ret;
2465*1208bc7eSAndroid Build Coastguard Worker }
2466*1208bc7eSAndroid Build Coastguard Worker #endif
2467*1208bc7eSAndroid Build Coastguard Worker 
2468*1208bc7eSAndroid Build Coastguard Worker #ifdef JEMALLOC_OVERRIDE_VALLOC
2469*1208bc7eSAndroid Build Coastguard Worker JEMALLOC_EXPORT JEMALLOC_ALLOCATOR JEMALLOC_RESTRICT_RETURN
2470*1208bc7eSAndroid Build Coastguard Worker void JEMALLOC_NOTHROW *
2471*1208bc7eSAndroid Build Coastguard Worker JEMALLOC_ATTR(malloc)
2472*1208bc7eSAndroid Build Coastguard Worker je_valloc(size_t size) {
2473*1208bc7eSAndroid Build Coastguard Worker 	void *ret;
2474*1208bc7eSAndroid Build Coastguard Worker 
2475*1208bc7eSAndroid Build Coastguard Worker 	static_opts_t sopts;
2476*1208bc7eSAndroid Build Coastguard Worker 	dynamic_opts_t dopts;
2477*1208bc7eSAndroid Build Coastguard Worker 
2478*1208bc7eSAndroid Build Coastguard Worker 	LOG("core.valloc.entry", "size: %zu\n", size);
2479*1208bc7eSAndroid Build Coastguard Worker 
2480*1208bc7eSAndroid Build Coastguard Worker 	static_opts_init(&sopts);
2481*1208bc7eSAndroid Build Coastguard Worker 	dynamic_opts_init(&dopts);
2482*1208bc7eSAndroid Build Coastguard Worker 
2483*1208bc7eSAndroid Build Coastguard Worker 	sopts.bump_empty_alloc = true;
2484*1208bc7eSAndroid Build Coastguard Worker 	sopts.null_out_result_on_error = true;
2485*1208bc7eSAndroid Build Coastguard Worker 	sopts.min_alignment = PAGE;
2486*1208bc7eSAndroid Build Coastguard Worker 	sopts.oom_string =
2487*1208bc7eSAndroid Build Coastguard Worker 	    "<jemalloc>: Error allocating aligned memory: out of memory\n";
2488*1208bc7eSAndroid Build Coastguard Worker 	sopts.invalid_alignment_string =
2489*1208bc7eSAndroid Build Coastguard Worker 	    "<jemalloc>: Error allocating aligned memory: invalid alignment\n";
2490*1208bc7eSAndroid Build Coastguard Worker 
2491*1208bc7eSAndroid Build Coastguard Worker 	dopts.result = &ret;
2492*1208bc7eSAndroid Build Coastguard Worker 	dopts.num_items = 1;
2493*1208bc7eSAndroid Build Coastguard Worker 	dopts.item_size = size;
2494*1208bc7eSAndroid Build Coastguard Worker 	dopts.alignment = PAGE;
2495*1208bc7eSAndroid Build Coastguard Worker 
2496*1208bc7eSAndroid Build Coastguard Worker 	imalloc(&sopts, &dopts);
2497*1208bc7eSAndroid Build Coastguard Worker 
2498*1208bc7eSAndroid Build Coastguard Worker 	LOG("core.valloc.exit", "result: %p\n", ret);
2499*1208bc7eSAndroid Build Coastguard Worker 	return ret;
2500*1208bc7eSAndroid Build Coastguard Worker }
2501*1208bc7eSAndroid Build Coastguard Worker #endif
2502*1208bc7eSAndroid Build Coastguard Worker 
2503*1208bc7eSAndroid Build Coastguard Worker #if defined(JEMALLOC_IS_MALLOC) && defined(JEMALLOC_GLIBC_MALLOC_HOOK)
2504*1208bc7eSAndroid Build Coastguard Worker /*
2505*1208bc7eSAndroid Build Coastguard Worker  * glibc provides the RTLD_DEEPBIND flag for dlopen which can make it possible
2506*1208bc7eSAndroid Build Coastguard Worker  * to inconsistently reference libc's malloc(3)-compatible functions
2507*1208bc7eSAndroid Build Coastguard Worker  * (https://bugzilla.mozilla.org/show_bug.cgi?id=493541).
2508*1208bc7eSAndroid Build Coastguard Worker  *
2509*1208bc7eSAndroid Build Coastguard Worker  * These definitions interpose hooks in glibc.  The functions are actually
2510*1208bc7eSAndroid Build Coastguard Worker  * passed an extra argument for the caller return address, which will be
2511*1208bc7eSAndroid Build Coastguard Worker  * ignored.
2512*1208bc7eSAndroid Build Coastguard Worker  */
2513*1208bc7eSAndroid Build Coastguard Worker JEMALLOC_EXPORT void (*__free_hook)(void *ptr) = je_free;
2514*1208bc7eSAndroid Build Coastguard Worker JEMALLOC_EXPORT void *(*__malloc_hook)(size_t size) = je_malloc;
2515*1208bc7eSAndroid Build Coastguard Worker JEMALLOC_EXPORT void *(*__realloc_hook)(void *ptr, size_t size) = je_realloc;
2516*1208bc7eSAndroid Build Coastguard Worker #  ifdef JEMALLOC_GLIBC_MEMALIGN_HOOK
2517*1208bc7eSAndroid Build Coastguard Worker JEMALLOC_EXPORT void *(*__memalign_hook)(size_t alignment, size_t size) =
2518*1208bc7eSAndroid Build Coastguard Worker     je_memalign;
2519*1208bc7eSAndroid Build Coastguard Worker #  endif
2520*1208bc7eSAndroid Build Coastguard Worker 
2521*1208bc7eSAndroid Build Coastguard Worker #  ifdef CPU_COUNT
2522*1208bc7eSAndroid Build Coastguard Worker /*
2523*1208bc7eSAndroid Build Coastguard Worker  * To enable static linking with glibc, the libc specific malloc interface must
2524*1208bc7eSAndroid Build Coastguard Worker  * be implemented also, so none of glibc's malloc.o functions are added to the
2525*1208bc7eSAndroid Build Coastguard Worker  * link.
2526*1208bc7eSAndroid Build Coastguard Worker  */
2527*1208bc7eSAndroid Build Coastguard Worker #    define ALIAS(je_fn)	__attribute__((alias (#je_fn), used))
2528*1208bc7eSAndroid Build Coastguard Worker /* To force macro expansion of je_ prefix before stringification. */
2529*1208bc7eSAndroid Build Coastguard Worker #    define PREALIAS(je_fn)	ALIAS(je_fn)
2530*1208bc7eSAndroid Build Coastguard Worker #    ifdef JEMALLOC_OVERRIDE___LIBC_CALLOC
2531*1208bc7eSAndroid Build Coastguard Worker void *__libc_calloc(size_t n, size_t size) PREALIAS(je_calloc);
2532*1208bc7eSAndroid Build Coastguard Worker #    endif
2533*1208bc7eSAndroid Build Coastguard Worker #    ifdef JEMALLOC_OVERRIDE___LIBC_FREE
2534*1208bc7eSAndroid Build Coastguard Worker void __libc_free(void* ptr) PREALIAS(je_free);
2535*1208bc7eSAndroid Build Coastguard Worker #    endif
2536*1208bc7eSAndroid Build Coastguard Worker #    ifdef JEMALLOC_OVERRIDE___LIBC_MALLOC
2537*1208bc7eSAndroid Build Coastguard Worker void *__libc_malloc(size_t size) PREALIAS(je_malloc);
2538*1208bc7eSAndroid Build Coastguard Worker #    endif
2539*1208bc7eSAndroid Build Coastguard Worker #    ifdef JEMALLOC_OVERRIDE___LIBC_MEMALIGN
2540*1208bc7eSAndroid Build Coastguard Worker void *__libc_memalign(size_t align, size_t s) PREALIAS(je_memalign);
2541*1208bc7eSAndroid Build Coastguard Worker #    endif
2542*1208bc7eSAndroid Build Coastguard Worker #    ifdef JEMALLOC_OVERRIDE___LIBC_REALLOC
2543*1208bc7eSAndroid Build Coastguard Worker void *__libc_realloc(void* ptr, size_t size) PREALIAS(je_realloc);
2544*1208bc7eSAndroid Build Coastguard Worker #    endif
2545*1208bc7eSAndroid Build Coastguard Worker #    ifdef JEMALLOC_OVERRIDE___LIBC_VALLOC
2546*1208bc7eSAndroid Build Coastguard Worker void *__libc_valloc(size_t size) PREALIAS(je_valloc);
2547*1208bc7eSAndroid Build Coastguard Worker #    endif
2548*1208bc7eSAndroid Build Coastguard Worker #    ifdef JEMALLOC_OVERRIDE___POSIX_MEMALIGN
2549*1208bc7eSAndroid Build Coastguard Worker int __posix_memalign(void** r, size_t a, size_t s) PREALIAS(je_posix_memalign);
2550*1208bc7eSAndroid Build Coastguard Worker #    endif
2551*1208bc7eSAndroid Build Coastguard Worker #    undef PREALIAS
2552*1208bc7eSAndroid Build Coastguard Worker #    undef ALIAS
2553*1208bc7eSAndroid Build Coastguard Worker #  endif
2554*1208bc7eSAndroid Build Coastguard Worker #endif
2555*1208bc7eSAndroid Build Coastguard Worker 
2556*1208bc7eSAndroid Build Coastguard Worker /*
2557*1208bc7eSAndroid Build Coastguard Worker  * End non-standard override functions.
2558*1208bc7eSAndroid Build Coastguard Worker  */
2559*1208bc7eSAndroid Build Coastguard Worker /******************************************************************************/
2560*1208bc7eSAndroid Build Coastguard Worker /*
2561*1208bc7eSAndroid Build Coastguard Worker  * Begin non-standard functions.
2562*1208bc7eSAndroid Build Coastguard Worker  */
2563*1208bc7eSAndroid Build Coastguard Worker 
2564*1208bc7eSAndroid Build Coastguard Worker JEMALLOC_EXPORT JEMALLOC_ALLOCATOR JEMALLOC_RESTRICT_RETURN
2565*1208bc7eSAndroid Build Coastguard Worker void JEMALLOC_NOTHROW *
2566*1208bc7eSAndroid Build Coastguard Worker JEMALLOC_ATTR(malloc) JEMALLOC_ALLOC_SIZE(1)
2567*1208bc7eSAndroid Build Coastguard Worker je_mallocx(size_t size, int flags) {
2568*1208bc7eSAndroid Build Coastguard Worker 	void *ret;
2569*1208bc7eSAndroid Build Coastguard Worker 	static_opts_t sopts;
2570*1208bc7eSAndroid Build Coastguard Worker 	dynamic_opts_t dopts;
2571*1208bc7eSAndroid Build Coastguard Worker 
2572*1208bc7eSAndroid Build Coastguard Worker 	LOG("core.mallocx.entry", "size: %zu, flags: %d", size, flags);
2573*1208bc7eSAndroid Build Coastguard Worker 
2574*1208bc7eSAndroid Build Coastguard Worker 	static_opts_init(&sopts);
2575*1208bc7eSAndroid Build Coastguard Worker 	dynamic_opts_init(&dopts);
2576*1208bc7eSAndroid Build Coastguard Worker 
2577*1208bc7eSAndroid Build Coastguard Worker 	sopts.assert_nonempty_alloc = true;
2578*1208bc7eSAndroid Build Coastguard Worker 	sopts.null_out_result_on_error = true;
2579*1208bc7eSAndroid Build Coastguard Worker 	sopts.oom_string = "<jemalloc>: Error in mallocx(): out of memory\n";
2580*1208bc7eSAndroid Build Coastguard Worker 
2581*1208bc7eSAndroid Build Coastguard Worker 	dopts.result = &ret;
2582*1208bc7eSAndroid Build Coastguard Worker 	dopts.num_items = 1;
2583*1208bc7eSAndroid Build Coastguard Worker 	dopts.item_size = size;
2584*1208bc7eSAndroid Build Coastguard Worker 	if (unlikely(flags != 0)) {
2585*1208bc7eSAndroid Build Coastguard Worker 		if ((flags & MALLOCX_LG_ALIGN_MASK) != 0) {
2586*1208bc7eSAndroid Build Coastguard Worker 			dopts.alignment = MALLOCX_ALIGN_GET_SPECIFIED(flags);
2587*1208bc7eSAndroid Build Coastguard Worker 		}
2588*1208bc7eSAndroid Build Coastguard Worker 
2589*1208bc7eSAndroid Build Coastguard Worker 		dopts.zero = MALLOCX_ZERO_GET(flags);
2590*1208bc7eSAndroid Build Coastguard Worker 
2591*1208bc7eSAndroid Build Coastguard Worker 		if ((flags & MALLOCX_TCACHE_MASK) != 0) {
2592*1208bc7eSAndroid Build Coastguard Worker 			if ((flags & MALLOCX_TCACHE_MASK)
2593*1208bc7eSAndroid Build Coastguard Worker 			    == MALLOCX_TCACHE_NONE) {
2594*1208bc7eSAndroid Build Coastguard Worker 				dopts.tcache_ind = TCACHE_IND_NONE;
2595*1208bc7eSAndroid Build Coastguard Worker 			} else {
2596*1208bc7eSAndroid Build Coastguard Worker 				dopts.tcache_ind = MALLOCX_TCACHE_GET(flags);
2597*1208bc7eSAndroid Build Coastguard Worker 			}
2598*1208bc7eSAndroid Build Coastguard Worker 		} else {
2599*1208bc7eSAndroid Build Coastguard Worker 			dopts.tcache_ind = TCACHE_IND_AUTOMATIC;
2600*1208bc7eSAndroid Build Coastguard Worker 		}
2601*1208bc7eSAndroid Build Coastguard Worker 
2602*1208bc7eSAndroid Build Coastguard Worker 		if ((flags & MALLOCX_ARENA_MASK) != 0)
2603*1208bc7eSAndroid Build Coastguard Worker 			dopts.arena_ind = MALLOCX_ARENA_GET(flags);
2604*1208bc7eSAndroid Build Coastguard Worker 	}
2605*1208bc7eSAndroid Build Coastguard Worker 
2606*1208bc7eSAndroid Build Coastguard Worker 	imalloc(&sopts, &dopts);
2607*1208bc7eSAndroid Build Coastguard Worker 
2608*1208bc7eSAndroid Build Coastguard Worker 	LOG("core.mallocx.exit", "result: %p", ret);
2609*1208bc7eSAndroid Build Coastguard Worker 	return ret;
2610*1208bc7eSAndroid Build Coastguard Worker }
2611*1208bc7eSAndroid Build Coastguard Worker 
2612*1208bc7eSAndroid Build Coastguard Worker static void *
2613*1208bc7eSAndroid Build Coastguard Worker irallocx_prof_sample(tsdn_t *tsdn, void *old_ptr, size_t old_usize,
2614*1208bc7eSAndroid Build Coastguard Worker     size_t usize, size_t alignment, bool zero, tcache_t *tcache, arena_t *arena,
2615*1208bc7eSAndroid Build Coastguard Worker     prof_tctx_t *tctx) {
2616*1208bc7eSAndroid Build Coastguard Worker 	void *p;
2617*1208bc7eSAndroid Build Coastguard Worker 
2618*1208bc7eSAndroid Build Coastguard Worker 	if (tctx == NULL) {
2619*1208bc7eSAndroid Build Coastguard Worker 		return NULL;
2620*1208bc7eSAndroid Build Coastguard Worker 	}
2621*1208bc7eSAndroid Build Coastguard Worker 	if (usize <= SMALL_MAXCLASS) {
2622*1208bc7eSAndroid Build Coastguard Worker 		p = iralloct(tsdn, old_ptr, old_usize, LARGE_MINCLASS,
2623*1208bc7eSAndroid Build Coastguard Worker 		    alignment, zero, tcache, arena);
2624*1208bc7eSAndroid Build Coastguard Worker 		if (p == NULL) {
2625*1208bc7eSAndroid Build Coastguard Worker 			return NULL;
2626*1208bc7eSAndroid Build Coastguard Worker 		}
2627*1208bc7eSAndroid Build Coastguard Worker 		arena_prof_promote(tsdn, p, usize);
2628*1208bc7eSAndroid Build Coastguard Worker 	} else {
2629*1208bc7eSAndroid Build Coastguard Worker 		p = iralloct(tsdn, old_ptr, old_usize, usize, alignment, zero,
2630*1208bc7eSAndroid Build Coastguard Worker 		    tcache, arena);
2631*1208bc7eSAndroid Build Coastguard Worker 	}
2632*1208bc7eSAndroid Build Coastguard Worker 
2633*1208bc7eSAndroid Build Coastguard Worker 	return p;
2634*1208bc7eSAndroid Build Coastguard Worker }
2635*1208bc7eSAndroid Build Coastguard Worker 
2636*1208bc7eSAndroid Build Coastguard Worker JEMALLOC_ALWAYS_INLINE void *
2637*1208bc7eSAndroid Build Coastguard Worker irallocx_prof(tsd_t *tsd, void *old_ptr, size_t old_usize, size_t size,
2638*1208bc7eSAndroid Build Coastguard Worker     size_t alignment, size_t *usize, bool zero, tcache_t *tcache,
2639*1208bc7eSAndroid Build Coastguard Worker     arena_t *arena, alloc_ctx_t *alloc_ctx) {
2640*1208bc7eSAndroid Build Coastguard Worker 	void *p;
2641*1208bc7eSAndroid Build Coastguard Worker 	bool prof_active;
2642*1208bc7eSAndroid Build Coastguard Worker 	prof_tctx_t *old_tctx, *tctx;
2643*1208bc7eSAndroid Build Coastguard Worker 
2644*1208bc7eSAndroid Build Coastguard Worker 	prof_active = prof_active_get_unlocked();
2645*1208bc7eSAndroid Build Coastguard Worker 	old_tctx = prof_tctx_get(tsd_tsdn(tsd), old_ptr, alloc_ctx);
2646*1208bc7eSAndroid Build Coastguard Worker 	tctx = prof_alloc_prep(tsd, *usize, prof_active, false);
2647*1208bc7eSAndroid Build Coastguard Worker 	if (unlikely((uintptr_t)tctx != (uintptr_t)1U)) {
2648*1208bc7eSAndroid Build Coastguard Worker 		p = irallocx_prof_sample(tsd_tsdn(tsd), old_ptr, old_usize,
2649*1208bc7eSAndroid Build Coastguard Worker 		    *usize, alignment, zero, tcache, arena, tctx);
2650*1208bc7eSAndroid Build Coastguard Worker 	} else {
2651*1208bc7eSAndroid Build Coastguard Worker 		p = iralloct(tsd_tsdn(tsd), old_ptr, old_usize, size, alignment,
2652*1208bc7eSAndroid Build Coastguard Worker 		    zero, tcache, arena);
2653*1208bc7eSAndroid Build Coastguard Worker 	}
2654*1208bc7eSAndroid Build Coastguard Worker 	if (unlikely(p == NULL)) {
2655*1208bc7eSAndroid Build Coastguard Worker 		prof_alloc_rollback(tsd, tctx, false);
2656*1208bc7eSAndroid Build Coastguard Worker 		return NULL;
2657*1208bc7eSAndroid Build Coastguard Worker 	}
2658*1208bc7eSAndroid Build Coastguard Worker 
2659*1208bc7eSAndroid Build Coastguard Worker 	if (p == old_ptr && alignment != 0) {
2660*1208bc7eSAndroid Build Coastguard Worker 		/*
2661*1208bc7eSAndroid Build Coastguard Worker 		 * The allocation did not move, so it is possible that the size
2662*1208bc7eSAndroid Build Coastguard Worker 		 * class is smaller than would guarantee the requested
2663*1208bc7eSAndroid Build Coastguard Worker 		 * alignment, and that the alignment constraint was
2664*1208bc7eSAndroid Build Coastguard Worker 		 * serendipitously satisfied.  Additionally, old_usize may not
2665*1208bc7eSAndroid Build Coastguard Worker 		 * be the same as the current usize because of in-place large
2666*1208bc7eSAndroid Build Coastguard Worker 		 * reallocation.  Therefore, query the actual value of usize.
2667*1208bc7eSAndroid Build Coastguard Worker 		 */
2668*1208bc7eSAndroid Build Coastguard Worker 		*usize = isalloc(tsd_tsdn(tsd), p);
2669*1208bc7eSAndroid Build Coastguard Worker 	}
2670*1208bc7eSAndroid Build Coastguard Worker 	prof_realloc(tsd, p, *usize, tctx, prof_active, false, old_ptr,
2671*1208bc7eSAndroid Build Coastguard Worker 	    old_usize, old_tctx);
2672*1208bc7eSAndroid Build Coastguard Worker 
2673*1208bc7eSAndroid Build Coastguard Worker 	return p;
2674*1208bc7eSAndroid Build Coastguard Worker }
2675*1208bc7eSAndroid Build Coastguard Worker 
2676*1208bc7eSAndroid Build Coastguard Worker JEMALLOC_EXPORT JEMALLOC_ALLOCATOR JEMALLOC_RESTRICT_RETURN
2677*1208bc7eSAndroid Build Coastguard Worker void JEMALLOC_NOTHROW *
2678*1208bc7eSAndroid Build Coastguard Worker JEMALLOC_ALLOC_SIZE(2)
2679*1208bc7eSAndroid Build Coastguard Worker je_rallocx(void *ptr, size_t size, int flags) {
2680*1208bc7eSAndroid Build Coastguard Worker 	void *p;
2681*1208bc7eSAndroid Build Coastguard Worker 	tsd_t *tsd;
2682*1208bc7eSAndroid Build Coastguard Worker 	size_t usize;
2683*1208bc7eSAndroid Build Coastguard Worker 	size_t old_usize;
2684*1208bc7eSAndroid Build Coastguard Worker 	size_t alignment = MALLOCX_ALIGN_GET(flags);
2685*1208bc7eSAndroid Build Coastguard Worker 	bool zero = flags & MALLOCX_ZERO;
2686*1208bc7eSAndroid Build Coastguard Worker 	arena_t *arena;
2687*1208bc7eSAndroid Build Coastguard Worker 	tcache_t *tcache;
2688*1208bc7eSAndroid Build Coastguard Worker 
2689*1208bc7eSAndroid Build Coastguard Worker 	LOG("core.rallocx.entry", "ptr: %p, size: %zu, flags: %d", ptr,
2690*1208bc7eSAndroid Build Coastguard Worker 	    size, flags);
2691*1208bc7eSAndroid Build Coastguard Worker 
2692*1208bc7eSAndroid Build Coastguard Worker 
2693*1208bc7eSAndroid Build Coastguard Worker 	assert(ptr != NULL);
2694*1208bc7eSAndroid Build Coastguard Worker 	assert(size != 0);
2695*1208bc7eSAndroid Build Coastguard Worker 	assert(malloc_initialized() || IS_INITIALIZER);
2696*1208bc7eSAndroid Build Coastguard Worker 	tsd = tsd_fetch();
2697*1208bc7eSAndroid Build Coastguard Worker 	check_entry_exit_locking(tsd_tsdn(tsd));
2698*1208bc7eSAndroid Build Coastguard Worker 
2699*1208bc7eSAndroid Build Coastguard Worker 	if (unlikely((flags & MALLOCX_ARENA_MASK) != 0)) {
2700*1208bc7eSAndroid Build Coastguard Worker 		unsigned arena_ind = MALLOCX_ARENA_GET(flags);
2701*1208bc7eSAndroid Build Coastguard Worker 		arena = arena_get(tsd_tsdn(tsd), arena_ind, true);
2702*1208bc7eSAndroid Build Coastguard Worker 		if (unlikely(arena == NULL)) {
2703*1208bc7eSAndroid Build Coastguard Worker 			goto label_oom;
2704*1208bc7eSAndroid Build Coastguard Worker 		}
2705*1208bc7eSAndroid Build Coastguard Worker 	} else {
2706*1208bc7eSAndroid Build Coastguard Worker 		arena = NULL;
2707*1208bc7eSAndroid Build Coastguard Worker 	}
2708*1208bc7eSAndroid Build Coastguard Worker 
2709*1208bc7eSAndroid Build Coastguard Worker 	if (unlikely((flags & MALLOCX_TCACHE_MASK) != 0)) {
2710*1208bc7eSAndroid Build Coastguard Worker 		if ((flags & MALLOCX_TCACHE_MASK) == MALLOCX_TCACHE_NONE) {
2711*1208bc7eSAndroid Build Coastguard Worker 			tcache = NULL;
2712*1208bc7eSAndroid Build Coastguard Worker 		} else {
2713*1208bc7eSAndroid Build Coastguard Worker 			tcache = tcaches_get(tsd, MALLOCX_TCACHE_GET(flags));
2714*1208bc7eSAndroid Build Coastguard Worker 		}
2715*1208bc7eSAndroid Build Coastguard Worker 	} else {
2716*1208bc7eSAndroid Build Coastguard Worker 		tcache = tcache_get(tsd);
2717*1208bc7eSAndroid Build Coastguard Worker 	}
2718*1208bc7eSAndroid Build Coastguard Worker 
2719*1208bc7eSAndroid Build Coastguard Worker 	alloc_ctx_t alloc_ctx;
2720*1208bc7eSAndroid Build Coastguard Worker 	rtree_ctx_t *rtree_ctx = tsd_rtree_ctx(tsd);
2721*1208bc7eSAndroid Build Coastguard Worker 	rtree_szind_slab_read(tsd_tsdn(tsd), &extents_rtree, rtree_ctx,
2722*1208bc7eSAndroid Build Coastguard Worker 	    (uintptr_t)ptr, true, &alloc_ctx.szind, &alloc_ctx.slab);
2723*1208bc7eSAndroid Build Coastguard Worker 	assert(alloc_ctx.szind != NSIZES);
2724*1208bc7eSAndroid Build Coastguard Worker 	old_usize = sz_index2size(alloc_ctx.szind);
2725*1208bc7eSAndroid Build Coastguard Worker 	assert(old_usize == isalloc(tsd_tsdn(tsd), ptr));
2726*1208bc7eSAndroid Build Coastguard Worker 	if (config_prof && opt_prof) {
2727*1208bc7eSAndroid Build Coastguard Worker 		usize = (alignment == 0) ?
2728*1208bc7eSAndroid Build Coastguard Worker 		    sz_s2u(size) : sz_sa2u(size, alignment);
2729*1208bc7eSAndroid Build Coastguard Worker 		if (unlikely(usize == 0 || usize > LARGE_MAXCLASS)) {
2730*1208bc7eSAndroid Build Coastguard Worker 			goto label_oom;
2731*1208bc7eSAndroid Build Coastguard Worker 		}
2732*1208bc7eSAndroid Build Coastguard Worker 		p = irallocx_prof(tsd, ptr, old_usize, size, alignment, &usize,
2733*1208bc7eSAndroid Build Coastguard Worker 		    zero, tcache, arena, &alloc_ctx);
2734*1208bc7eSAndroid Build Coastguard Worker 		if (unlikely(p == NULL)) {
2735*1208bc7eSAndroid Build Coastguard Worker 			goto label_oom;
2736*1208bc7eSAndroid Build Coastguard Worker 		}
2737*1208bc7eSAndroid Build Coastguard Worker 	} else {
2738*1208bc7eSAndroid Build Coastguard Worker 		p = iralloct(tsd_tsdn(tsd), ptr, old_usize, size, alignment,
2739*1208bc7eSAndroid Build Coastguard Worker 		    zero, tcache, arena);
2740*1208bc7eSAndroid Build Coastguard Worker 		if (unlikely(p == NULL)) {
2741*1208bc7eSAndroid Build Coastguard Worker 			goto label_oom;
2742*1208bc7eSAndroid Build Coastguard Worker 		}
2743*1208bc7eSAndroid Build Coastguard Worker 		if (config_stats) {
2744*1208bc7eSAndroid Build Coastguard Worker 			usize = isalloc(tsd_tsdn(tsd), p);
2745*1208bc7eSAndroid Build Coastguard Worker 		}
2746*1208bc7eSAndroid Build Coastguard Worker 	}
2747*1208bc7eSAndroid Build Coastguard Worker 	assert(alignment == 0 || ((uintptr_t)p & (alignment - 1)) == ZU(0));
2748*1208bc7eSAndroid Build Coastguard Worker 
2749*1208bc7eSAndroid Build Coastguard Worker 	if (config_stats) {
2750*1208bc7eSAndroid Build Coastguard Worker 		*tsd_thread_allocatedp_get(tsd) += usize;
2751*1208bc7eSAndroid Build Coastguard Worker 		*tsd_thread_deallocatedp_get(tsd) += old_usize;
2752*1208bc7eSAndroid Build Coastguard Worker 	}
2753*1208bc7eSAndroid Build Coastguard Worker 	UTRACE(ptr, size, p);
2754*1208bc7eSAndroid Build Coastguard Worker 	check_entry_exit_locking(tsd_tsdn(tsd));
2755*1208bc7eSAndroid Build Coastguard Worker 
2756*1208bc7eSAndroid Build Coastguard Worker 	LOG("core.rallocx.exit", "result: %p", p);
2757*1208bc7eSAndroid Build Coastguard Worker 	return p;
2758*1208bc7eSAndroid Build Coastguard Worker label_oom:
2759*1208bc7eSAndroid Build Coastguard Worker 	if (config_xmalloc && unlikely(opt_xmalloc)) {
2760*1208bc7eSAndroid Build Coastguard Worker 		malloc_write("<jemalloc>: Error in rallocx(): out of memory\n");
2761*1208bc7eSAndroid Build Coastguard Worker 		abort();
2762*1208bc7eSAndroid Build Coastguard Worker 	}
2763*1208bc7eSAndroid Build Coastguard Worker 	UTRACE(ptr, size, 0);
2764*1208bc7eSAndroid Build Coastguard Worker 	check_entry_exit_locking(tsd_tsdn(tsd));
2765*1208bc7eSAndroid Build Coastguard Worker 
2766*1208bc7eSAndroid Build Coastguard Worker 	LOG("core.rallocx.exit", "result: %p", NULL);
2767*1208bc7eSAndroid Build Coastguard Worker 	return NULL;
2768*1208bc7eSAndroid Build Coastguard Worker }
2769*1208bc7eSAndroid Build Coastguard Worker 
2770*1208bc7eSAndroid Build Coastguard Worker JEMALLOC_ALWAYS_INLINE size_t
2771*1208bc7eSAndroid Build Coastguard Worker ixallocx_helper(tsdn_t *tsdn, void *ptr, size_t old_usize, size_t size,
2772*1208bc7eSAndroid Build Coastguard Worker     size_t extra, size_t alignment, bool zero) {
2773*1208bc7eSAndroid Build Coastguard Worker 	size_t usize;
2774*1208bc7eSAndroid Build Coastguard Worker 
2775*1208bc7eSAndroid Build Coastguard Worker 	if (ixalloc(tsdn, ptr, old_usize, size, extra, alignment, zero)) {
2776*1208bc7eSAndroid Build Coastguard Worker 		return old_usize;
2777*1208bc7eSAndroid Build Coastguard Worker 	}
2778*1208bc7eSAndroid Build Coastguard Worker 	usize = isalloc(tsdn, ptr);
2779*1208bc7eSAndroid Build Coastguard Worker 
2780*1208bc7eSAndroid Build Coastguard Worker 	return usize;
2781*1208bc7eSAndroid Build Coastguard Worker }
2782*1208bc7eSAndroid Build Coastguard Worker 
2783*1208bc7eSAndroid Build Coastguard Worker static size_t
2784*1208bc7eSAndroid Build Coastguard Worker ixallocx_prof_sample(tsdn_t *tsdn, void *ptr, size_t old_usize, size_t size,
2785*1208bc7eSAndroid Build Coastguard Worker     size_t extra, size_t alignment, bool zero, prof_tctx_t *tctx) {
2786*1208bc7eSAndroid Build Coastguard Worker 	size_t usize;
2787*1208bc7eSAndroid Build Coastguard Worker 
2788*1208bc7eSAndroid Build Coastguard Worker 	if (tctx == NULL) {
2789*1208bc7eSAndroid Build Coastguard Worker 		return old_usize;
2790*1208bc7eSAndroid Build Coastguard Worker 	}
2791*1208bc7eSAndroid Build Coastguard Worker 	usize = ixallocx_helper(tsdn, ptr, old_usize, size, extra, alignment,
2792*1208bc7eSAndroid Build Coastguard Worker 	    zero);
2793*1208bc7eSAndroid Build Coastguard Worker 
2794*1208bc7eSAndroid Build Coastguard Worker 	return usize;
2795*1208bc7eSAndroid Build Coastguard Worker }
2796*1208bc7eSAndroid Build Coastguard Worker 
2797*1208bc7eSAndroid Build Coastguard Worker JEMALLOC_ALWAYS_INLINE size_t
2798*1208bc7eSAndroid Build Coastguard Worker ixallocx_prof(tsd_t *tsd, void *ptr, size_t old_usize, size_t size,
2799*1208bc7eSAndroid Build Coastguard Worker     size_t extra, size_t alignment, bool zero, alloc_ctx_t *alloc_ctx) {
2800*1208bc7eSAndroid Build Coastguard Worker 	size_t usize_max, usize;
2801*1208bc7eSAndroid Build Coastguard Worker 	bool prof_active;
2802*1208bc7eSAndroid Build Coastguard Worker 	prof_tctx_t *old_tctx, *tctx;
2803*1208bc7eSAndroid Build Coastguard Worker 
2804*1208bc7eSAndroid Build Coastguard Worker 	prof_active = prof_active_get_unlocked();
2805*1208bc7eSAndroid Build Coastguard Worker 	old_tctx = prof_tctx_get(tsd_tsdn(tsd), ptr, alloc_ctx);
2806*1208bc7eSAndroid Build Coastguard Worker 	/*
2807*1208bc7eSAndroid Build Coastguard Worker 	 * usize isn't knowable before ixalloc() returns when extra is non-zero.
2808*1208bc7eSAndroid Build Coastguard Worker 	 * Therefore, compute its maximum possible value and use that in
2809*1208bc7eSAndroid Build Coastguard Worker 	 * prof_alloc_prep() to decide whether to capture a backtrace.
2810*1208bc7eSAndroid Build Coastguard Worker 	 * prof_realloc() will use the actual usize to decide whether to sample.
2811*1208bc7eSAndroid Build Coastguard Worker 	 */
2812*1208bc7eSAndroid Build Coastguard Worker 	if (alignment == 0) {
2813*1208bc7eSAndroid Build Coastguard Worker 		usize_max = sz_s2u(size+extra);
2814*1208bc7eSAndroid Build Coastguard Worker 		assert(usize_max > 0 && usize_max <= LARGE_MAXCLASS);
2815*1208bc7eSAndroid Build Coastguard Worker 	} else {
2816*1208bc7eSAndroid Build Coastguard Worker 		usize_max = sz_sa2u(size+extra, alignment);
2817*1208bc7eSAndroid Build Coastguard Worker 		if (unlikely(usize_max == 0 || usize_max > LARGE_MAXCLASS)) {
2818*1208bc7eSAndroid Build Coastguard Worker 			/*
2819*1208bc7eSAndroid Build Coastguard Worker 			 * usize_max is out of range, and chances are that
2820*1208bc7eSAndroid Build Coastguard Worker 			 * allocation will fail, but use the maximum possible
2821*1208bc7eSAndroid Build Coastguard Worker 			 * value and carry on with prof_alloc_prep(), just in
2822*1208bc7eSAndroid Build Coastguard Worker 			 * case allocation succeeds.
2823*1208bc7eSAndroid Build Coastguard Worker 			 */
2824*1208bc7eSAndroid Build Coastguard Worker 			usize_max = LARGE_MAXCLASS;
2825*1208bc7eSAndroid Build Coastguard Worker 		}
2826*1208bc7eSAndroid Build Coastguard Worker 	}
2827*1208bc7eSAndroid Build Coastguard Worker 	tctx = prof_alloc_prep(tsd, usize_max, prof_active, false);
2828*1208bc7eSAndroid Build Coastguard Worker 
2829*1208bc7eSAndroid Build Coastguard Worker 	if (unlikely((uintptr_t)tctx != (uintptr_t)1U)) {
2830*1208bc7eSAndroid Build Coastguard Worker 		usize = ixallocx_prof_sample(tsd_tsdn(tsd), ptr, old_usize,
2831*1208bc7eSAndroid Build Coastguard Worker 		    size, extra, alignment, zero, tctx);
2832*1208bc7eSAndroid Build Coastguard Worker 	} else {
2833*1208bc7eSAndroid Build Coastguard Worker 		usize = ixallocx_helper(tsd_tsdn(tsd), ptr, old_usize, size,
2834*1208bc7eSAndroid Build Coastguard Worker 		    extra, alignment, zero);
2835*1208bc7eSAndroid Build Coastguard Worker 	}
2836*1208bc7eSAndroid Build Coastguard Worker 	if (usize == old_usize) {
2837*1208bc7eSAndroid Build Coastguard Worker 		prof_alloc_rollback(tsd, tctx, false);
2838*1208bc7eSAndroid Build Coastguard Worker 		return usize;
2839*1208bc7eSAndroid Build Coastguard Worker 	}
2840*1208bc7eSAndroid Build Coastguard Worker 	prof_realloc(tsd, ptr, usize, tctx, prof_active, false, ptr, old_usize,
2841*1208bc7eSAndroid Build Coastguard Worker 	    old_tctx);
2842*1208bc7eSAndroid Build Coastguard Worker 
2843*1208bc7eSAndroid Build Coastguard Worker 	return usize;
2844*1208bc7eSAndroid Build Coastguard Worker }
2845*1208bc7eSAndroid Build Coastguard Worker 
2846*1208bc7eSAndroid Build Coastguard Worker JEMALLOC_EXPORT size_t JEMALLOC_NOTHROW
2847*1208bc7eSAndroid Build Coastguard Worker je_xallocx(void *ptr, size_t size, size_t extra, int flags) {
2848*1208bc7eSAndroid Build Coastguard Worker 	tsd_t *tsd;
2849*1208bc7eSAndroid Build Coastguard Worker 	size_t usize, old_usize;
2850*1208bc7eSAndroid Build Coastguard Worker 	size_t alignment = MALLOCX_ALIGN_GET(flags);
2851*1208bc7eSAndroid Build Coastguard Worker 	bool zero = flags & MALLOCX_ZERO;
2852*1208bc7eSAndroid Build Coastguard Worker 
2853*1208bc7eSAndroid Build Coastguard Worker 	LOG("core.xallocx.entry", "ptr: %p, size: %zu, extra: %zu, "
2854*1208bc7eSAndroid Build Coastguard Worker 	    "flags: %d", ptr, size, extra, flags);
2855*1208bc7eSAndroid Build Coastguard Worker 
2856*1208bc7eSAndroid Build Coastguard Worker 	assert(ptr != NULL);
2857*1208bc7eSAndroid Build Coastguard Worker 	assert(size != 0);
2858*1208bc7eSAndroid Build Coastguard Worker 	assert(SIZE_T_MAX - size >= extra);
2859*1208bc7eSAndroid Build Coastguard Worker 	assert(malloc_initialized() || IS_INITIALIZER);
2860*1208bc7eSAndroid Build Coastguard Worker 	tsd = tsd_fetch();
2861*1208bc7eSAndroid Build Coastguard Worker 	check_entry_exit_locking(tsd_tsdn(tsd));
2862*1208bc7eSAndroid Build Coastguard Worker 
2863*1208bc7eSAndroid Build Coastguard Worker 	alloc_ctx_t alloc_ctx;
2864*1208bc7eSAndroid Build Coastguard Worker 	rtree_ctx_t *rtree_ctx = tsd_rtree_ctx(tsd);
2865*1208bc7eSAndroid Build Coastguard Worker 	rtree_szind_slab_read(tsd_tsdn(tsd), &extents_rtree, rtree_ctx,
2866*1208bc7eSAndroid Build Coastguard Worker 	    (uintptr_t)ptr, true, &alloc_ctx.szind, &alloc_ctx.slab);
2867*1208bc7eSAndroid Build Coastguard Worker 	assert(alloc_ctx.szind != NSIZES);
2868*1208bc7eSAndroid Build Coastguard Worker 	old_usize = sz_index2size(alloc_ctx.szind);
2869*1208bc7eSAndroid Build Coastguard Worker 	assert(old_usize == isalloc(tsd_tsdn(tsd), ptr));
2870*1208bc7eSAndroid Build Coastguard Worker 	/*
2871*1208bc7eSAndroid Build Coastguard Worker 	 * The API explicitly absolves itself of protecting against (size +
2872*1208bc7eSAndroid Build Coastguard Worker 	 * extra) numerical overflow, but we may need to clamp extra to avoid
2873*1208bc7eSAndroid Build Coastguard Worker 	 * exceeding LARGE_MAXCLASS.
2874*1208bc7eSAndroid Build Coastguard Worker 	 *
2875*1208bc7eSAndroid Build Coastguard Worker 	 * Ordinarily, size limit checking is handled deeper down, but here we
2876*1208bc7eSAndroid Build Coastguard Worker 	 * have to check as part of (size + extra) clamping, since we need the
2877*1208bc7eSAndroid Build Coastguard Worker 	 * clamped value in the above helper functions.
2878*1208bc7eSAndroid Build Coastguard Worker 	 */
2879*1208bc7eSAndroid Build Coastguard Worker 	if (unlikely(size > LARGE_MAXCLASS)) {
2880*1208bc7eSAndroid Build Coastguard Worker 		usize = old_usize;
2881*1208bc7eSAndroid Build Coastguard Worker 		goto label_not_resized;
2882*1208bc7eSAndroid Build Coastguard Worker 	}
2883*1208bc7eSAndroid Build Coastguard Worker 	if (unlikely(LARGE_MAXCLASS - size < extra)) {
2884*1208bc7eSAndroid Build Coastguard Worker 		extra = LARGE_MAXCLASS - size;
2885*1208bc7eSAndroid Build Coastguard Worker 	}
2886*1208bc7eSAndroid Build Coastguard Worker 
2887*1208bc7eSAndroid Build Coastguard Worker 	if (config_prof && opt_prof) {
2888*1208bc7eSAndroid Build Coastguard Worker 		usize = ixallocx_prof(tsd, ptr, old_usize, size, extra,
2889*1208bc7eSAndroid Build Coastguard Worker 		    alignment, zero, &alloc_ctx);
2890*1208bc7eSAndroid Build Coastguard Worker 	} else {
2891*1208bc7eSAndroid Build Coastguard Worker 		usize = ixallocx_helper(tsd_tsdn(tsd), ptr, old_usize, size,
2892*1208bc7eSAndroid Build Coastguard Worker 		    extra, alignment, zero);
2893*1208bc7eSAndroid Build Coastguard Worker 	}
2894*1208bc7eSAndroid Build Coastguard Worker 	if (unlikely(usize == old_usize)) {
2895*1208bc7eSAndroid Build Coastguard Worker 		goto label_not_resized;
2896*1208bc7eSAndroid Build Coastguard Worker 	}
2897*1208bc7eSAndroid Build Coastguard Worker 
2898*1208bc7eSAndroid Build Coastguard Worker 	if (config_stats) {
2899*1208bc7eSAndroid Build Coastguard Worker 		*tsd_thread_allocatedp_get(tsd) += usize;
2900*1208bc7eSAndroid Build Coastguard Worker 		*tsd_thread_deallocatedp_get(tsd) += old_usize;
2901*1208bc7eSAndroid Build Coastguard Worker 	}
2902*1208bc7eSAndroid Build Coastguard Worker label_not_resized:
2903*1208bc7eSAndroid Build Coastguard Worker 	UTRACE(ptr, size, ptr);
2904*1208bc7eSAndroid Build Coastguard Worker 	check_entry_exit_locking(tsd_tsdn(tsd));
2905*1208bc7eSAndroid Build Coastguard Worker 
2906*1208bc7eSAndroid Build Coastguard Worker 	LOG("core.xallocx.exit", "result: %zu", usize);
2907*1208bc7eSAndroid Build Coastguard Worker 	return usize;
2908*1208bc7eSAndroid Build Coastguard Worker }
2909*1208bc7eSAndroid Build Coastguard Worker 
2910*1208bc7eSAndroid Build Coastguard Worker JEMALLOC_EXPORT size_t JEMALLOC_NOTHROW
2911*1208bc7eSAndroid Build Coastguard Worker JEMALLOC_ATTR(pure)
2912*1208bc7eSAndroid Build Coastguard Worker je_sallocx(const void *ptr, UNUSED int flags) {
2913*1208bc7eSAndroid Build Coastguard Worker 	size_t usize;
2914*1208bc7eSAndroid Build Coastguard Worker 	tsdn_t *tsdn;
2915*1208bc7eSAndroid Build Coastguard Worker 
2916*1208bc7eSAndroid Build Coastguard Worker 	LOG("core.sallocx.entry", "ptr: %p, flags: %d", ptr, flags);
2917*1208bc7eSAndroid Build Coastguard Worker 
2918*1208bc7eSAndroid Build Coastguard Worker 	assert(malloc_initialized() || IS_INITIALIZER);
2919*1208bc7eSAndroid Build Coastguard Worker 	assert(ptr != NULL);
2920*1208bc7eSAndroid Build Coastguard Worker 
2921*1208bc7eSAndroid Build Coastguard Worker 	tsdn = tsdn_fetch();
2922*1208bc7eSAndroid Build Coastguard Worker 	check_entry_exit_locking(tsdn);
2923*1208bc7eSAndroid Build Coastguard Worker 
2924*1208bc7eSAndroid Build Coastguard Worker 	if (config_debug || force_ivsalloc) {
2925*1208bc7eSAndroid Build Coastguard Worker 		usize = ivsalloc(tsdn, ptr);
2926*1208bc7eSAndroid Build Coastguard Worker 		assert(force_ivsalloc || usize != 0);
2927*1208bc7eSAndroid Build Coastguard Worker 	} else {
2928*1208bc7eSAndroid Build Coastguard Worker 		usize = isalloc(tsdn, ptr);
2929*1208bc7eSAndroid Build Coastguard Worker 	}
2930*1208bc7eSAndroid Build Coastguard Worker 
2931*1208bc7eSAndroid Build Coastguard Worker 	check_entry_exit_locking(tsdn);
2932*1208bc7eSAndroid Build Coastguard Worker 
2933*1208bc7eSAndroid Build Coastguard Worker 	LOG("core.sallocx.exit", "result: %zu", usize);
2934*1208bc7eSAndroid Build Coastguard Worker 	return usize;
2935*1208bc7eSAndroid Build Coastguard Worker }
2936*1208bc7eSAndroid Build Coastguard Worker 
2937*1208bc7eSAndroid Build Coastguard Worker JEMALLOC_EXPORT void JEMALLOC_NOTHROW
2938*1208bc7eSAndroid Build Coastguard Worker je_dallocx(void *ptr, int flags) {
2939*1208bc7eSAndroid Build Coastguard Worker 	LOG("core.dallocx.entry", "ptr: %p, flags: %d", ptr, flags);
2940*1208bc7eSAndroid Build Coastguard Worker 
2941*1208bc7eSAndroid Build Coastguard Worker 	assert(ptr != NULL);
2942*1208bc7eSAndroid Build Coastguard Worker 	assert(malloc_initialized() || IS_INITIALIZER);
2943*1208bc7eSAndroid Build Coastguard Worker 
2944*1208bc7eSAndroid Build Coastguard Worker 	tsd_t *tsd = tsd_fetch();
2945*1208bc7eSAndroid Build Coastguard Worker 	bool fast = tsd_fast(tsd);
2946*1208bc7eSAndroid Build Coastguard Worker 	check_entry_exit_locking(tsd_tsdn(tsd));
2947*1208bc7eSAndroid Build Coastguard Worker 
2948*1208bc7eSAndroid Build Coastguard Worker 	tcache_t *tcache;
2949*1208bc7eSAndroid Build Coastguard Worker 	if (unlikely((flags & MALLOCX_TCACHE_MASK) != 0)) {
2950*1208bc7eSAndroid Build Coastguard Worker 		/* Not allowed to be reentrant and specify a custom tcache. */
2951*1208bc7eSAndroid Build Coastguard Worker 		assert(tsd_reentrancy_level_get(tsd) == 0);
2952*1208bc7eSAndroid Build Coastguard Worker 		if ((flags & MALLOCX_TCACHE_MASK) == MALLOCX_TCACHE_NONE) {
2953*1208bc7eSAndroid Build Coastguard Worker 			tcache = NULL;
2954*1208bc7eSAndroid Build Coastguard Worker 		} else {
2955*1208bc7eSAndroid Build Coastguard Worker 			tcache = tcaches_get(tsd, MALLOCX_TCACHE_GET(flags));
2956*1208bc7eSAndroid Build Coastguard Worker 		}
2957*1208bc7eSAndroid Build Coastguard Worker 	} else {
2958*1208bc7eSAndroid Build Coastguard Worker 		if (likely(fast)) {
2959*1208bc7eSAndroid Build Coastguard Worker 			tcache = tsd_tcachep_get(tsd);
2960*1208bc7eSAndroid Build Coastguard Worker 			assert(tcache == tcache_get(tsd));
2961*1208bc7eSAndroid Build Coastguard Worker 		} else {
2962*1208bc7eSAndroid Build Coastguard Worker 			if (likely(tsd_reentrancy_level_get(tsd) == 0)) {
2963*1208bc7eSAndroid Build Coastguard Worker 				tcache = tcache_get(tsd);
2964*1208bc7eSAndroid Build Coastguard Worker 			}  else {
2965*1208bc7eSAndroid Build Coastguard Worker 				tcache = NULL;
2966*1208bc7eSAndroid Build Coastguard Worker 			}
2967*1208bc7eSAndroid Build Coastguard Worker 		}
2968*1208bc7eSAndroid Build Coastguard Worker 	}
2969*1208bc7eSAndroid Build Coastguard Worker 
2970*1208bc7eSAndroid Build Coastguard Worker 	UTRACE(ptr, 0, 0);
2971*1208bc7eSAndroid Build Coastguard Worker 	if (likely(fast)) {
2972*1208bc7eSAndroid Build Coastguard Worker 		tsd_assert_fast(tsd);
2973*1208bc7eSAndroid Build Coastguard Worker 		ifree(tsd, ptr, tcache, false);
2974*1208bc7eSAndroid Build Coastguard Worker 	} else {
2975*1208bc7eSAndroid Build Coastguard Worker 		ifree(tsd, ptr, tcache, true);
2976*1208bc7eSAndroid Build Coastguard Worker 	}
2977*1208bc7eSAndroid Build Coastguard Worker 	check_entry_exit_locking(tsd_tsdn(tsd));
2978*1208bc7eSAndroid Build Coastguard Worker 
2979*1208bc7eSAndroid Build Coastguard Worker 	LOG("core.dallocx.exit", "");
2980*1208bc7eSAndroid Build Coastguard Worker }
2981*1208bc7eSAndroid Build Coastguard Worker 
2982*1208bc7eSAndroid Build Coastguard Worker JEMALLOC_ALWAYS_INLINE size_t
2983*1208bc7eSAndroid Build Coastguard Worker inallocx(tsdn_t *tsdn, size_t size, int flags) {
2984*1208bc7eSAndroid Build Coastguard Worker 	check_entry_exit_locking(tsdn);
2985*1208bc7eSAndroid Build Coastguard Worker 
2986*1208bc7eSAndroid Build Coastguard Worker 	size_t usize;
2987*1208bc7eSAndroid Build Coastguard Worker 	if (likely((flags & MALLOCX_LG_ALIGN_MASK) == 0)) {
2988*1208bc7eSAndroid Build Coastguard Worker 		usize = sz_s2u(size);
2989*1208bc7eSAndroid Build Coastguard Worker 	} else {
2990*1208bc7eSAndroid Build Coastguard Worker 		usize = sz_sa2u(size, MALLOCX_ALIGN_GET_SPECIFIED(flags));
2991*1208bc7eSAndroid Build Coastguard Worker 	}
2992*1208bc7eSAndroid Build Coastguard Worker 	check_entry_exit_locking(tsdn);
2993*1208bc7eSAndroid Build Coastguard Worker 	return usize;
2994*1208bc7eSAndroid Build Coastguard Worker }
2995*1208bc7eSAndroid Build Coastguard Worker 
2996*1208bc7eSAndroid Build Coastguard Worker JEMALLOC_EXPORT void JEMALLOC_NOTHROW
2997*1208bc7eSAndroid Build Coastguard Worker je_sdallocx(void *ptr, size_t size, int flags) {
2998*1208bc7eSAndroid Build Coastguard Worker 	assert(ptr != NULL);
2999*1208bc7eSAndroid Build Coastguard Worker 	assert(malloc_initialized() || IS_INITIALIZER);
3000*1208bc7eSAndroid Build Coastguard Worker 
3001*1208bc7eSAndroid Build Coastguard Worker 	LOG("core.sdallocx.entry", "ptr: %p, size: %zu, flags: %d", ptr,
3002*1208bc7eSAndroid Build Coastguard Worker 	    size, flags);
3003*1208bc7eSAndroid Build Coastguard Worker 
3004*1208bc7eSAndroid Build Coastguard Worker 	tsd_t *tsd = tsd_fetch();
3005*1208bc7eSAndroid Build Coastguard Worker 	bool fast = tsd_fast(tsd);
3006*1208bc7eSAndroid Build Coastguard Worker 	size_t usize = inallocx(tsd_tsdn(tsd), size, flags);
3007*1208bc7eSAndroid Build Coastguard Worker 	assert(usize == isalloc(tsd_tsdn(tsd), ptr));
3008*1208bc7eSAndroid Build Coastguard Worker 	check_entry_exit_locking(tsd_tsdn(tsd));
3009*1208bc7eSAndroid Build Coastguard Worker 
3010*1208bc7eSAndroid Build Coastguard Worker 	tcache_t *tcache;
3011*1208bc7eSAndroid Build Coastguard Worker 	if (unlikely((flags & MALLOCX_TCACHE_MASK) != 0)) {
3012*1208bc7eSAndroid Build Coastguard Worker 		/* Not allowed to be reentrant and specify a custom tcache. */
3013*1208bc7eSAndroid Build Coastguard Worker 		assert(tsd_reentrancy_level_get(tsd) == 0);
3014*1208bc7eSAndroid Build Coastguard Worker 		if ((flags & MALLOCX_TCACHE_MASK) == MALLOCX_TCACHE_NONE) {
3015*1208bc7eSAndroid Build Coastguard Worker 			tcache = NULL;
3016*1208bc7eSAndroid Build Coastguard Worker 		} else {
3017*1208bc7eSAndroid Build Coastguard Worker 			tcache = tcaches_get(tsd, MALLOCX_TCACHE_GET(flags));
3018*1208bc7eSAndroid Build Coastguard Worker 		}
3019*1208bc7eSAndroid Build Coastguard Worker 	} else {
3020*1208bc7eSAndroid Build Coastguard Worker 		if (likely(fast)) {
3021*1208bc7eSAndroid Build Coastguard Worker 			tcache = tsd_tcachep_get(tsd);
3022*1208bc7eSAndroid Build Coastguard Worker 			assert(tcache == tcache_get(tsd));
3023*1208bc7eSAndroid Build Coastguard Worker 		} else {
3024*1208bc7eSAndroid Build Coastguard Worker 			if (likely(tsd_reentrancy_level_get(tsd) == 0)) {
3025*1208bc7eSAndroid Build Coastguard Worker 				tcache = tcache_get(tsd);
3026*1208bc7eSAndroid Build Coastguard Worker 			} else {
3027*1208bc7eSAndroid Build Coastguard Worker 				tcache = NULL;
3028*1208bc7eSAndroid Build Coastguard Worker 			}
3029*1208bc7eSAndroid Build Coastguard Worker 		}
3030*1208bc7eSAndroid Build Coastguard Worker 	}
3031*1208bc7eSAndroid Build Coastguard Worker 
3032*1208bc7eSAndroid Build Coastguard Worker 	UTRACE(ptr, 0, 0);
3033*1208bc7eSAndroid Build Coastguard Worker 	if (likely(fast)) {
3034*1208bc7eSAndroid Build Coastguard Worker 		tsd_assert_fast(tsd);
3035*1208bc7eSAndroid Build Coastguard Worker 		isfree(tsd, ptr, usize, tcache, false);
3036*1208bc7eSAndroid Build Coastguard Worker 	} else {
3037*1208bc7eSAndroid Build Coastguard Worker 		isfree(tsd, ptr, usize, tcache, true);
3038*1208bc7eSAndroid Build Coastguard Worker 	}
3039*1208bc7eSAndroid Build Coastguard Worker 	check_entry_exit_locking(tsd_tsdn(tsd));
3040*1208bc7eSAndroid Build Coastguard Worker 
3041*1208bc7eSAndroid Build Coastguard Worker 	LOG("core.sdallocx.exit", "");
3042*1208bc7eSAndroid Build Coastguard Worker }
3043*1208bc7eSAndroid Build Coastguard Worker 
3044*1208bc7eSAndroid Build Coastguard Worker JEMALLOC_EXPORT size_t JEMALLOC_NOTHROW
3045*1208bc7eSAndroid Build Coastguard Worker JEMALLOC_ATTR(pure)
3046*1208bc7eSAndroid Build Coastguard Worker je_nallocx(size_t size, int flags) {
3047*1208bc7eSAndroid Build Coastguard Worker 	size_t usize;
3048*1208bc7eSAndroid Build Coastguard Worker 	tsdn_t *tsdn;
3049*1208bc7eSAndroid Build Coastguard Worker 
3050*1208bc7eSAndroid Build Coastguard Worker 	assert(size != 0);
3051*1208bc7eSAndroid Build Coastguard Worker 
3052*1208bc7eSAndroid Build Coastguard Worker 	if (unlikely(malloc_init())) {
3053*1208bc7eSAndroid Build Coastguard Worker 		LOG("core.nallocx.exit", "result: %zu", ZU(0));
3054*1208bc7eSAndroid Build Coastguard Worker 		return 0;
3055*1208bc7eSAndroid Build Coastguard Worker 	}
3056*1208bc7eSAndroid Build Coastguard Worker 
3057*1208bc7eSAndroid Build Coastguard Worker 	tsdn = tsdn_fetch();
3058*1208bc7eSAndroid Build Coastguard Worker 	check_entry_exit_locking(tsdn);
3059*1208bc7eSAndroid Build Coastguard Worker 
3060*1208bc7eSAndroid Build Coastguard Worker 	usize = inallocx(tsdn, size, flags);
3061*1208bc7eSAndroid Build Coastguard Worker 	if (unlikely(usize > LARGE_MAXCLASS)) {
3062*1208bc7eSAndroid Build Coastguard Worker 		LOG("core.nallocx.exit", "result: %zu", ZU(0));
3063*1208bc7eSAndroid Build Coastguard Worker 		return 0;
3064*1208bc7eSAndroid Build Coastguard Worker 	}
3065*1208bc7eSAndroid Build Coastguard Worker 
3066*1208bc7eSAndroid Build Coastguard Worker 	check_entry_exit_locking(tsdn);
3067*1208bc7eSAndroid Build Coastguard Worker 	LOG("core.nallocx.exit", "result: %zu", usize);
3068*1208bc7eSAndroid Build Coastguard Worker 	return usize;
3069*1208bc7eSAndroid Build Coastguard Worker }
3070*1208bc7eSAndroid Build Coastguard Worker 
3071*1208bc7eSAndroid Build Coastguard Worker JEMALLOC_EXPORT int JEMALLOC_NOTHROW
3072*1208bc7eSAndroid Build Coastguard Worker je_mallctl(const char *name, void *oldp, size_t *oldlenp, void *newp,
3073*1208bc7eSAndroid Build Coastguard Worker     size_t newlen) {
3074*1208bc7eSAndroid Build Coastguard Worker 	int ret;
3075*1208bc7eSAndroid Build Coastguard Worker 	tsd_t *tsd;
3076*1208bc7eSAndroid Build Coastguard Worker 
3077*1208bc7eSAndroid Build Coastguard Worker 	LOG("core.mallctl.entry", "name: %s", name);
3078*1208bc7eSAndroid Build Coastguard Worker 
3079*1208bc7eSAndroid Build Coastguard Worker 	if (unlikely(malloc_init())) {
3080*1208bc7eSAndroid Build Coastguard Worker 		LOG("core.mallctl.exit", "result: %d", EAGAIN);
3081*1208bc7eSAndroid Build Coastguard Worker 		return EAGAIN;
3082*1208bc7eSAndroid Build Coastguard Worker 	}
3083*1208bc7eSAndroid Build Coastguard Worker 
3084*1208bc7eSAndroid Build Coastguard Worker 	tsd = tsd_fetch();
3085*1208bc7eSAndroid Build Coastguard Worker 	check_entry_exit_locking(tsd_tsdn(tsd));
3086*1208bc7eSAndroid Build Coastguard Worker 	ret = ctl_byname(tsd, name, oldp, oldlenp, newp, newlen);
3087*1208bc7eSAndroid Build Coastguard Worker 	check_entry_exit_locking(tsd_tsdn(tsd));
3088*1208bc7eSAndroid Build Coastguard Worker 
3089*1208bc7eSAndroid Build Coastguard Worker 	LOG("core.mallctl.exit", "result: %d", ret);
3090*1208bc7eSAndroid Build Coastguard Worker 	return ret;
3091*1208bc7eSAndroid Build Coastguard Worker }
3092*1208bc7eSAndroid Build Coastguard Worker 
3093*1208bc7eSAndroid Build Coastguard Worker JEMALLOC_EXPORT int JEMALLOC_NOTHROW
3094*1208bc7eSAndroid Build Coastguard Worker je_mallctlnametomib(const char *name, size_t *mibp, size_t *miblenp) {
3095*1208bc7eSAndroid Build Coastguard Worker 	int ret;
3096*1208bc7eSAndroid Build Coastguard Worker 
3097*1208bc7eSAndroid Build Coastguard Worker 	LOG("core.mallctlnametomib.entry", "name: %s", name);
3098*1208bc7eSAndroid Build Coastguard Worker 
3099*1208bc7eSAndroid Build Coastguard Worker 	if (unlikely(malloc_init())) {
3100*1208bc7eSAndroid Build Coastguard Worker 		LOG("core.mallctlnametomib.exit", "result: %d", EAGAIN);
3101*1208bc7eSAndroid Build Coastguard Worker 		return EAGAIN;
3102*1208bc7eSAndroid Build Coastguard Worker 	}
3103*1208bc7eSAndroid Build Coastguard Worker 
3104*1208bc7eSAndroid Build Coastguard Worker 	tsd_t *tsd = tsd_fetch();
3105*1208bc7eSAndroid Build Coastguard Worker 	check_entry_exit_locking(tsd_tsdn(tsd));
3106*1208bc7eSAndroid Build Coastguard Worker 	ret = ctl_nametomib(tsd, name, mibp, miblenp);
3107*1208bc7eSAndroid Build Coastguard Worker 	check_entry_exit_locking(tsd_tsdn(tsd));
3108*1208bc7eSAndroid Build Coastguard Worker 
3109*1208bc7eSAndroid Build Coastguard Worker 	LOG("core.mallctlnametomib.exit", "result: %d", ret);
3110*1208bc7eSAndroid Build Coastguard Worker 	return ret;
3111*1208bc7eSAndroid Build Coastguard Worker }
3112*1208bc7eSAndroid Build Coastguard Worker 
3113*1208bc7eSAndroid Build Coastguard Worker JEMALLOC_EXPORT int JEMALLOC_NOTHROW
3114*1208bc7eSAndroid Build Coastguard Worker je_mallctlbymib(const size_t *mib, size_t miblen, void *oldp, size_t *oldlenp,
3115*1208bc7eSAndroid Build Coastguard Worker   void *newp, size_t newlen) {
3116*1208bc7eSAndroid Build Coastguard Worker 	int ret;
3117*1208bc7eSAndroid Build Coastguard Worker 	tsd_t *tsd;
3118*1208bc7eSAndroid Build Coastguard Worker 
3119*1208bc7eSAndroid Build Coastguard Worker 	LOG("core.mallctlbymib.entry", "");
3120*1208bc7eSAndroid Build Coastguard Worker 
3121*1208bc7eSAndroid Build Coastguard Worker 	if (unlikely(malloc_init())) {
3122*1208bc7eSAndroid Build Coastguard Worker 		LOG("core.mallctlbymib.exit", "result: %d", EAGAIN);
3123*1208bc7eSAndroid Build Coastguard Worker 		return EAGAIN;
3124*1208bc7eSAndroid Build Coastguard Worker 	}
3125*1208bc7eSAndroid Build Coastguard Worker 
3126*1208bc7eSAndroid Build Coastguard Worker 	tsd = tsd_fetch();
3127*1208bc7eSAndroid Build Coastguard Worker 	check_entry_exit_locking(tsd_tsdn(tsd));
3128*1208bc7eSAndroid Build Coastguard Worker 	ret = ctl_bymib(tsd, mib, miblen, oldp, oldlenp, newp, newlen);
3129*1208bc7eSAndroid Build Coastguard Worker 	check_entry_exit_locking(tsd_tsdn(tsd));
3130*1208bc7eSAndroid Build Coastguard Worker 	LOG("core.mallctlbymib.exit", "result: %d", ret);
3131*1208bc7eSAndroid Build Coastguard Worker 	return ret;
3132*1208bc7eSAndroid Build Coastguard Worker }
3133*1208bc7eSAndroid Build Coastguard Worker 
3134*1208bc7eSAndroid Build Coastguard Worker JEMALLOC_EXPORT void JEMALLOC_NOTHROW
3135*1208bc7eSAndroid Build Coastguard Worker je_malloc_stats_print(void (*write_cb)(void *, const char *), void *cbopaque,
3136*1208bc7eSAndroid Build Coastguard Worker     const char *opts) {
3137*1208bc7eSAndroid Build Coastguard Worker 	tsdn_t *tsdn;
3138*1208bc7eSAndroid Build Coastguard Worker 
3139*1208bc7eSAndroid Build Coastguard Worker 	LOG("core.malloc_stats_print.entry", "");
3140*1208bc7eSAndroid Build Coastguard Worker 
3141*1208bc7eSAndroid Build Coastguard Worker 	tsdn = tsdn_fetch();
3142*1208bc7eSAndroid Build Coastguard Worker 	check_entry_exit_locking(tsdn);
3143*1208bc7eSAndroid Build Coastguard Worker 	stats_print(write_cb, cbopaque, opts);
3144*1208bc7eSAndroid Build Coastguard Worker 	check_entry_exit_locking(tsdn);
3145*1208bc7eSAndroid Build Coastguard Worker 	LOG("core.malloc_stats_print.exit", "");
3146*1208bc7eSAndroid Build Coastguard Worker }
3147*1208bc7eSAndroid Build Coastguard Worker 
3148*1208bc7eSAndroid Build Coastguard Worker JEMALLOC_EXPORT size_t JEMALLOC_NOTHROW
3149*1208bc7eSAndroid Build Coastguard Worker je_malloc_usable_size(JEMALLOC_USABLE_SIZE_CONST void *ptr) {
3150*1208bc7eSAndroid Build Coastguard Worker 	size_t ret;
3151*1208bc7eSAndroid Build Coastguard Worker 	tsdn_t *tsdn;
3152*1208bc7eSAndroid Build Coastguard Worker 
3153*1208bc7eSAndroid Build Coastguard Worker 	LOG("core.malloc_usable_size.entry", "ptr: %p", ptr);
3154*1208bc7eSAndroid Build Coastguard Worker 
3155*1208bc7eSAndroid Build Coastguard Worker 	assert(malloc_initialized() || IS_INITIALIZER);
3156*1208bc7eSAndroid Build Coastguard Worker 
3157*1208bc7eSAndroid Build Coastguard Worker 	tsdn = tsdn_fetch();
3158*1208bc7eSAndroid Build Coastguard Worker 	check_entry_exit_locking(tsdn);
3159*1208bc7eSAndroid Build Coastguard Worker 
3160*1208bc7eSAndroid Build Coastguard Worker 	if (unlikely(ptr == NULL)) {
3161*1208bc7eSAndroid Build Coastguard Worker 		ret = 0;
3162*1208bc7eSAndroid Build Coastguard Worker 	} else {
3163*1208bc7eSAndroid Build Coastguard Worker 		if (config_debug || force_ivsalloc) {
3164*1208bc7eSAndroid Build Coastguard Worker 			ret = ivsalloc(tsdn, ptr);
3165*1208bc7eSAndroid Build Coastguard Worker 			assert(force_ivsalloc || ret != 0);
3166*1208bc7eSAndroid Build Coastguard Worker 		} else {
3167*1208bc7eSAndroid Build Coastguard Worker 			ret = isalloc(tsdn, ptr);
3168*1208bc7eSAndroid Build Coastguard Worker 		}
3169*1208bc7eSAndroid Build Coastguard Worker 	}
3170*1208bc7eSAndroid Build Coastguard Worker 
3171*1208bc7eSAndroid Build Coastguard Worker 	check_entry_exit_locking(tsdn);
3172*1208bc7eSAndroid Build Coastguard Worker 	LOG("core.malloc_usable_size.exit", "result: %zu", ret);
3173*1208bc7eSAndroid Build Coastguard Worker 	return ret;
3174*1208bc7eSAndroid Build Coastguard Worker }
3175*1208bc7eSAndroid Build Coastguard Worker 
3176*1208bc7eSAndroid Build Coastguard Worker /*
3177*1208bc7eSAndroid Build Coastguard Worker  * End non-standard functions.
3178*1208bc7eSAndroid Build Coastguard Worker  */
3179*1208bc7eSAndroid Build Coastguard Worker /******************************************************************************/
3180*1208bc7eSAndroid Build Coastguard Worker /*
3181*1208bc7eSAndroid Build Coastguard Worker  * The following functions are used by threading libraries for protection of
3182*1208bc7eSAndroid Build Coastguard Worker  * malloc during fork().
3183*1208bc7eSAndroid Build Coastguard Worker  */
3184*1208bc7eSAndroid Build Coastguard Worker 
3185*1208bc7eSAndroid Build Coastguard Worker /*
3186*1208bc7eSAndroid Build Coastguard Worker  * If an application creates a thread before doing any allocation in the main
3187*1208bc7eSAndroid Build Coastguard Worker  * thread, then calls fork(2) in the main thread followed by memory allocation
3188*1208bc7eSAndroid Build Coastguard Worker  * in the child process, a race can occur that results in deadlock within the
3189*1208bc7eSAndroid Build Coastguard Worker  * child: the main thread may have forked while the created thread had
3190*1208bc7eSAndroid Build Coastguard Worker  * partially initialized the allocator.  Ordinarily jemalloc prevents
3191*1208bc7eSAndroid Build Coastguard Worker  * fork/malloc races via the following functions it registers during
3192*1208bc7eSAndroid Build Coastguard Worker  * initialization using pthread_atfork(), but of course that does no good if
3193*1208bc7eSAndroid Build Coastguard Worker  * the allocator isn't fully initialized at fork time.  The following library
3194*1208bc7eSAndroid Build Coastguard Worker  * constructor is a partial solution to this problem.  It may still be possible
3195*1208bc7eSAndroid Build Coastguard Worker  * to trigger the deadlock described above, but doing so would involve forking
3196*1208bc7eSAndroid Build Coastguard Worker  * via a library constructor that runs before jemalloc's runs.
3197*1208bc7eSAndroid Build Coastguard Worker  */
3198*1208bc7eSAndroid Build Coastguard Worker #ifndef JEMALLOC_JET
3199*1208bc7eSAndroid Build Coastguard Worker JEMALLOC_ATTR(constructor)
3200*1208bc7eSAndroid Build Coastguard Worker static void
3201*1208bc7eSAndroid Build Coastguard Worker jemalloc_constructor(void) {
3202*1208bc7eSAndroid Build Coastguard Worker 	malloc_init();
3203*1208bc7eSAndroid Build Coastguard Worker }
3204*1208bc7eSAndroid Build Coastguard Worker #endif
3205*1208bc7eSAndroid Build Coastguard Worker 
3206*1208bc7eSAndroid Build Coastguard Worker #ifndef JEMALLOC_MUTEX_INIT_CB
3207*1208bc7eSAndroid Build Coastguard Worker void
3208*1208bc7eSAndroid Build Coastguard Worker jemalloc_prefork(void)
3209*1208bc7eSAndroid Build Coastguard Worker #else
3210*1208bc7eSAndroid Build Coastguard Worker JEMALLOC_EXPORT void
3211*1208bc7eSAndroid Build Coastguard Worker _malloc_prefork(void)
3212*1208bc7eSAndroid Build Coastguard Worker #endif
3213*1208bc7eSAndroid Build Coastguard Worker {
3214*1208bc7eSAndroid Build Coastguard Worker 	tsd_t *tsd;
3215*1208bc7eSAndroid Build Coastguard Worker 	unsigned i, j, narenas;
3216*1208bc7eSAndroid Build Coastguard Worker 	arena_t *arena;
3217*1208bc7eSAndroid Build Coastguard Worker 
3218*1208bc7eSAndroid Build Coastguard Worker #ifdef JEMALLOC_MUTEX_INIT_CB
3219*1208bc7eSAndroid Build Coastguard Worker 	if (!malloc_initialized()) {
3220*1208bc7eSAndroid Build Coastguard Worker 		return;
3221*1208bc7eSAndroid Build Coastguard Worker 	}
3222*1208bc7eSAndroid Build Coastguard Worker #endif
3223*1208bc7eSAndroid Build Coastguard Worker 	assert(malloc_initialized());
3224*1208bc7eSAndroid Build Coastguard Worker 
3225*1208bc7eSAndroid Build Coastguard Worker 	tsd = tsd_fetch();
3226*1208bc7eSAndroid Build Coastguard Worker 
3227*1208bc7eSAndroid Build Coastguard Worker 	narenas = narenas_total_get();
3228*1208bc7eSAndroid Build Coastguard Worker 
3229*1208bc7eSAndroid Build Coastguard Worker 	witness_prefork(tsd_witness_tsdp_get(tsd));
3230*1208bc7eSAndroid Build Coastguard Worker 	/* Acquire all mutexes in a safe order. */
3231*1208bc7eSAndroid Build Coastguard Worker 	ctl_prefork(tsd_tsdn(tsd));
3232*1208bc7eSAndroid Build Coastguard Worker 	tcache_prefork(tsd_tsdn(tsd));
3233*1208bc7eSAndroid Build Coastguard Worker 	malloc_mutex_prefork(tsd_tsdn(tsd), &arenas_lock);
3234*1208bc7eSAndroid Build Coastguard Worker 	if (have_background_thread) {
3235*1208bc7eSAndroid Build Coastguard Worker 		background_thread_prefork0(tsd_tsdn(tsd));
3236*1208bc7eSAndroid Build Coastguard Worker 	}
3237*1208bc7eSAndroid Build Coastguard Worker 	prof_prefork0(tsd_tsdn(tsd));
3238*1208bc7eSAndroid Build Coastguard Worker 	if (have_background_thread) {
3239*1208bc7eSAndroid Build Coastguard Worker 		background_thread_prefork1(tsd_tsdn(tsd));
3240*1208bc7eSAndroid Build Coastguard Worker 	}
3241*1208bc7eSAndroid Build Coastguard Worker 	/* Break arena prefork into stages to preserve lock order. */
3242*1208bc7eSAndroid Build Coastguard Worker 	for (i = 0; i < 8; i++) {
3243*1208bc7eSAndroid Build Coastguard Worker 		for (j = 0; j < narenas; j++) {
3244*1208bc7eSAndroid Build Coastguard Worker 			if ((arena = arena_get(tsd_tsdn(tsd), j, false)) !=
3245*1208bc7eSAndroid Build Coastguard Worker 			    NULL) {
3246*1208bc7eSAndroid Build Coastguard Worker 				switch (i) {
3247*1208bc7eSAndroid Build Coastguard Worker 				case 0:
3248*1208bc7eSAndroid Build Coastguard Worker 					arena_prefork0(tsd_tsdn(tsd), arena);
3249*1208bc7eSAndroid Build Coastguard Worker 					break;
3250*1208bc7eSAndroid Build Coastguard Worker 				case 1:
3251*1208bc7eSAndroid Build Coastguard Worker 					arena_prefork1(tsd_tsdn(tsd), arena);
3252*1208bc7eSAndroid Build Coastguard Worker 					break;
3253*1208bc7eSAndroid Build Coastguard Worker 				case 2:
3254*1208bc7eSAndroid Build Coastguard Worker 					arena_prefork2(tsd_tsdn(tsd), arena);
3255*1208bc7eSAndroid Build Coastguard Worker 					break;
3256*1208bc7eSAndroid Build Coastguard Worker 				case 3:
3257*1208bc7eSAndroid Build Coastguard Worker 					arena_prefork3(tsd_tsdn(tsd), arena);
3258*1208bc7eSAndroid Build Coastguard Worker 					break;
3259*1208bc7eSAndroid Build Coastguard Worker 				case 4:
3260*1208bc7eSAndroid Build Coastguard Worker 					arena_prefork4(tsd_tsdn(tsd), arena);
3261*1208bc7eSAndroid Build Coastguard Worker 					break;
3262*1208bc7eSAndroid Build Coastguard Worker 				case 5:
3263*1208bc7eSAndroid Build Coastguard Worker 					arena_prefork5(tsd_tsdn(tsd), arena);
3264*1208bc7eSAndroid Build Coastguard Worker 					break;
3265*1208bc7eSAndroid Build Coastguard Worker 				case 6:
3266*1208bc7eSAndroid Build Coastguard Worker 					arena_prefork6(tsd_tsdn(tsd), arena);
3267*1208bc7eSAndroid Build Coastguard Worker 					break;
3268*1208bc7eSAndroid Build Coastguard Worker 				case 7:
3269*1208bc7eSAndroid Build Coastguard Worker 					arena_prefork7(tsd_tsdn(tsd), arena);
3270*1208bc7eSAndroid Build Coastguard Worker 					break;
3271*1208bc7eSAndroid Build Coastguard Worker 				default: not_reached();
3272*1208bc7eSAndroid Build Coastguard Worker 				}
3273*1208bc7eSAndroid Build Coastguard Worker 			}
3274*1208bc7eSAndroid Build Coastguard Worker 		}
3275*1208bc7eSAndroid Build Coastguard Worker 	}
3276*1208bc7eSAndroid Build Coastguard Worker 	prof_prefork1(tsd_tsdn(tsd));
3277*1208bc7eSAndroid Build Coastguard Worker }
3278*1208bc7eSAndroid Build Coastguard Worker 
3279*1208bc7eSAndroid Build Coastguard Worker #ifndef JEMALLOC_MUTEX_INIT_CB
3280*1208bc7eSAndroid Build Coastguard Worker void
3281*1208bc7eSAndroid Build Coastguard Worker jemalloc_postfork_parent(void)
3282*1208bc7eSAndroid Build Coastguard Worker #else
3283*1208bc7eSAndroid Build Coastguard Worker JEMALLOC_EXPORT void
3284*1208bc7eSAndroid Build Coastguard Worker _malloc_postfork(void)
3285*1208bc7eSAndroid Build Coastguard Worker #endif
3286*1208bc7eSAndroid Build Coastguard Worker {
3287*1208bc7eSAndroid Build Coastguard Worker 	tsd_t *tsd;
3288*1208bc7eSAndroid Build Coastguard Worker 	unsigned i, narenas;
3289*1208bc7eSAndroid Build Coastguard Worker 
3290*1208bc7eSAndroid Build Coastguard Worker #ifdef JEMALLOC_MUTEX_INIT_CB
3291*1208bc7eSAndroid Build Coastguard Worker 	if (!malloc_initialized()) {
3292*1208bc7eSAndroid Build Coastguard Worker 		return;
3293*1208bc7eSAndroid Build Coastguard Worker 	}
3294*1208bc7eSAndroid Build Coastguard Worker #endif
3295*1208bc7eSAndroid Build Coastguard Worker 	assert(malloc_initialized());
3296*1208bc7eSAndroid Build Coastguard Worker 
3297*1208bc7eSAndroid Build Coastguard Worker 	tsd = tsd_fetch();
3298*1208bc7eSAndroid Build Coastguard Worker 
3299*1208bc7eSAndroid Build Coastguard Worker 	witness_postfork_parent(tsd_witness_tsdp_get(tsd));
3300*1208bc7eSAndroid Build Coastguard Worker 	/* Release all mutexes, now that fork() has completed. */
3301*1208bc7eSAndroid Build Coastguard Worker 	for (i = 0, narenas = narenas_total_get(); i < narenas; i++) {
3302*1208bc7eSAndroid Build Coastguard Worker 		arena_t *arena;
3303*1208bc7eSAndroid Build Coastguard Worker 
3304*1208bc7eSAndroid Build Coastguard Worker 		if ((arena = arena_get(tsd_tsdn(tsd), i, false)) != NULL) {
3305*1208bc7eSAndroid Build Coastguard Worker 			arena_postfork_parent(tsd_tsdn(tsd), arena);
3306*1208bc7eSAndroid Build Coastguard Worker 		}
3307*1208bc7eSAndroid Build Coastguard Worker 	}
3308*1208bc7eSAndroid Build Coastguard Worker 	prof_postfork_parent(tsd_tsdn(tsd));
3309*1208bc7eSAndroid Build Coastguard Worker 	if (have_background_thread) {
3310*1208bc7eSAndroid Build Coastguard Worker 		background_thread_postfork_parent(tsd_tsdn(tsd));
3311*1208bc7eSAndroid Build Coastguard Worker 	}
3312*1208bc7eSAndroid Build Coastguard Worker 	malloc_mutex_postfork_parent(tsd_tsdn(tsd), &arenas_lock);
3313*1208bc7eSAndroid Build Coastguard Worker 	tcache_postfork_parent(tsd_tsdn(tsd));
3314*1208bc7eSAndroid Build Coastguard Worker 	ctl_postfork_parent(tsd_tsdn(tsd));
3315*1208bc7eSAndroid Build Coastguard Worker }
3316*1208bc7eSAndroid Build Coastguard Worker 
3317*1208bc7eSAndroid Build Coastguard Worker void
3318*1208bc7eSAndroid Build Coastguard Worker jemalloc_postfork_child(void) {
3319*1208bc7eSAndroid Build Coastguard Worker 	tsd_t *tsd;
3320*1208bc7eSAndroid Build Coastguard Worker 	unsigned i, narenas;
3321*1208bc7eSAndroid Build Coastguard Worker 
3322*1208bc7eSAndroid Build Coastguard Worker 	assert(malloc_initialized());
3323*1208bc7eSAndroid Build Coastguard Worker 
3324*1208bc7eSAndroid Build Coastguard Worker 	tsd = tsd_fetch();
3325*1208bc7eSAndroid Build Coastguard Worker 
3326*1208bc7eSAndroid Build Coastguard Worker 	witness_postfork_child(tsd_witness_tsdp_get(tsd));
3327*1208bc7eSAndroid Build Coastguard Worker 	extent_postfork_child(tsd_tsdn(tsd));
3328*1208bc7eSAndroid Build Coastguard Worker 	/* Release all mutexes, now that fork() has completed. */
3329*1208bc7eSAndroid Build Coastguard Worker 	for (i = 0, narenas = narenas_total_get(); i < narenas; i++) {
3330*1208bc7eSAndroid Build Coastguard Worker 		arena_t *arena;
3331*1208bc7eSAndroid Build Coastguard Worker 
3332*1208bc7eSAndroid Build Coastguard Worker 		if ((arena = arena_get(tsd_tsdn(tsd), i, false)) != NULL) {
3333*1208bc7eSAndroid Build Coastguard Worker 			arena_postfork_child(tsd_tsdn(tsd), arena);
3334*1208bc7eSAndroid Build Coastguard Worker 		}
3335*1208bc7eSAndroid Build Coastguard Worker 	}
3336*1208bc7eSAndroid Build Coastguard Worker 	prof_postfork_child(tsd_tsdn(tsd));
3337*1208bc7eSAndroid Build Coastguard Worker 	if (have_background_thread) {
3338*1208bc7eSAndroid Build Coastguard Worker 		background_thread_postfork_child(tsd_tsdn(tsd));
3339*1208bc7eSAndroid Build Coastguard Worker 	}
3340*1208bc7eSAndroid Build Coastguard Worker 	malloc_mutex_postfork_child(tsd_tsdn(tsd), &arenas_lock);
3341*1208bc7eSAndroid Build Coastguard Worker 	tcache_postfork_child(tsd_tsdn(tsd));
3342*1208bc7eSAndroid Build Coastguard Worker 	ctl_postfork_child(tsd_tsdn(tsd));
3343*1208bc7eSAndroid Build Coastguard Worker }
3344*1208bc7eSAndroid Build Coastguard Worker 
3345*1208bc7eSAndroid Build Coastguard Worker /******************************************************************************/
3346*1208bc7eSAndroid Build Coastguard Worker 
3347*1208bc7eSAndroid Build Coastguard Worker #if defined(__BIONIC__) && !defined(JEMALLOC_JET)
3348*1208bc7eSAndroid Build Coastguard Worker #include "android_je_iterate.c"
3349*1208bc7eSAndroid Build Coastguard Worker #include "android_je_mallinfo.c"
3350*1208bc7eSAndroid Build Coastguard Worker #include "android_je_stats.c"
3351*1208bc7eSAndroid Build Coastguard Worker #endif
3352