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