Home | History | Annotate | Download | only in src
      1 #define	JEMALLOC_C_
      2 #include "jemalloc/internal/jemalloc_internal.h"
      3 
      4 /******************************************************************************/
      5 /* Data. */
      6 
      7 /* Runtime configuration options. */
      8 const char	*je_malloc_conf JEMALLOC_ATTR(weak);
      9 bool	opt_abort =
     10 #ifdef JEMALLOC_DEBUG
     11     true
     12 #else
     13     false
     14 #endif
     15     ;
     16 const char	*opt_junk =
     17 #if (defined(JEMALLOC_DEBUG) && defined(JEMALLOC_FILL))
     18     "true"
     19 #else
     20     "false"
     21 #endif
     22     ;
     23 bool	opt_junk_alloc =
     24 #if (defined(JEMALLOC_DEBUG) && defined(JEMALLOC_FILL))
     25     true
     26 #else
     27     false
     28 #endif
     29     ;
     30 bool	opt_junk_free =
     31 #if (defined(JEMALLOC_DEBUG) && defined(JEMALLOC_FILL))
     32     true
     33 #else
     34     false
     35 #endif
     36     ;
     37 
     38 size_t	opt_quarantine = ZU(0);
     39 bool	opt_redzone = false;
     40 bool	opt_utrace = false;
     41 bool	opt_xmalloc = false;
     42 bool	opt_zero = false;
     43 size_t	opt_narenas = 0;
     44 
     45 /* Initialized to true if the process is running inside Valgrind. */
     46 bool	in_valgrind;
     47 
     48 unsigned	ncpus;
     49 
     50 /* Protects arenas initialization (arenas, narenas_total). */
     51 static malloc_mutex_t	arenas_lock;
     52 /*
     53  * Arenas that are used to service external requests.  Not all elements of the
     54  * arenas array are necessarily used; arenas are created lazily as needed.
     55  *
     56  * arenas[0..narenas_auto) are used for automatic multiplexing of threads and
     57  * arenas.  arenas[narenas_auto..narenas_total) are only used if the application
     58  * takes some action to create them and allocate from them.
     59  */
     60 static arena_t		**arenas;
     61 static unsigned		narenas_total;
     62 static arena_t		*a0; /* arenas[0]; read-only after initialization. */
     63 static unsigned		narenas_auto; /* Read-only after initialization. */
     64 
     65 typedef enum {
     66 	malloc_init_uninitialized	= 3,
     67 	malloc_init_a0_initialized	= 2,
     68 	malloc_init_recursible		= 1,
     69 	malloc_init_initialized		= 0 /* Common case --> jnz. */
     70 } malloc_init_t;
     71 static malloc_init_t	malloc_init_state = malloc_init_uninitialized;
     72 
     73 JEMALLOC_ALIGNED(CACHELINE)
     74 const size_t	index2size_tab[NSIZES] = {
     75 #define	SC(index, lg_grp, lg_delta, ndelta, bin, lg_delta_lookup) \
     76 	((ZU(1)<<lg_grp) + (ZU(ndelta)<<lg_delta)),
     77 	SIZE_CLASSES
     78 #undef SC
     79 };
     80 
     81 JEMALLOC_ALIGNED(CACHELINE)
     82 const uint8_t	size2index_tab[] = {
     83 #if LG_TINY_MIN == 0
     84 #warning "Dangerous LG_TINY_MIN"
     85 #define	S2B_0(i)	i,
     86 #elif LG_TINY_MIN == 1
     87 #warning "Dangerous LG_TINY_MIN"
     88 #define	S2B_1(i)	i,
     89 #elif LG_TINY_MIN == 2
     90 #warning "Dangerous LG_TINY_MIN"
     91 #define	S2B_2(i)	i,
     92 #elif LG_TINY_MIN == 3
     93 #define	S2B_3(i)	i,
     94 #elif LG_TINY_MIN == 4
     95 #define	S2B_4(i)	i,
     96 #elif LG_TINY_MIN == 5
     97 #define	S2B_5(i)	i,
     98 #elif LG_TINY_MIN == 6
     99 #define	S2B_6(i)	i,
    100 #elif LG_TINY_MIN == 7
    101 #define	S2B_7(i)	i,
    102 #elif LG_TINY_MIN == 8
    103 #define	S2B_8(i)	i,
    104 #elif LG_TINY_MIN == 9
    105 #define	S2B_9(i)	i,
    106 #elif LG_TINY_MIN == 10
    107 #define	S2B_10(i)	i,
    108 #elif LG_TINY_MIN == 11
    109 #define	S2B_11(i)	i,
    110 #else
    111 #error "Unsupported LG_TINY_MIN"
    112 #endif
    113 #if LG_TINY_MIN < 1
    114 #define	S2B_1(i)	S2B_0(i) S2B_0(i)
    115 #endif
    116 #if LG_TINY_MIN < 2
    117 #define	S2B_2(i)	S2B_1(i) S2B_1(i)
    118 #endif
    119 #if LG_TINY_MIN < 3
    120 #define	S2B_3(i)	S2B_2(i) S2B_2(i)
    121 #endif
    122 #if LG_TINY_MIN < 4
    123 #define	S2B_4(i)	S2B_3(i) S2B_3(i)
    124 #endif
    125 #if LG_TINY_MIN < 5
    126 #define	S2B_5(i)	S2B_4(i) S2B_4(i)
    127 #endif
    128 #if LG_TINY_MIN < 6
    129 #define	S2B_6(i)	S2B_5(i) S2B_5(i)
    130 #endif
    131 #if LG_TINY_MIN < 7
    132 #define	S2B_7(i)	S2B_6(i) S2B_6(i)
    133 #endif
    134 #if LG_TINY_MIN < 8
    135 #define	S2B_8(i)	S2B_7(i) S2B_7(i)
    136 #endif
    137 #if LG_TINY_MIN < 9
    138 #define	S2B_9(i)	S2B_8(i) S2B_8(i)
    139 #endif
    140 #if LG_TINY_MIN < 10
    141 #define	S2B_10(i)	S2B_9(i) S2B_9(i)
    142 #endif
    143 #if LG_TINY_MIN < 11
    144 #define	S2B_11(i)	S2B_10(i) S2B_10(i)
    145 #endif
    146 #define	S2B_no(i)
    147 #define	SC(index, lg_grp, lg_delta, ndelta, bin, lg_delta_lookup) \
    148 	S2B_##lg_delta_lookup(index)
    149 	SIZE_CLASSES
    150 #undef S2B_3
    151 #undef S2B_4
    152 #undef S2B_5
    153 #undef S2B_6
    154 #undef S2B_7
    155 #undef S2B_8
    156 #undef S2B_9
    157 #undef S2B_10
    158 #undef S2B_11
    159 #undef S2B_no
    160 #undef SC
    161 };
    162 
    163 #ifdef JEMALLOC_THREADED_INIT
    164 /* Used to let the initializing thread recursively allocate. */
    165 #  define NO_INITIALIZER	((unsigned long)0)
    166 #  define INITIALIZER		pthread_self()
    167 #  define IS_INITIALIZER	(malloc_initializer == pthread_self())
    168 static pthread_t		malloc_initializer = NO_INITIALIZER;
    169 #else
    170 #  define NO_INITIALIZER	false
    171 #  define INITIALIZER		true
    172 #  define IS_INITIALIZER	malloc_initializer
    173 static bool			malloc_initializer = NO_INITIALIZER;
    174 #endif
    175 
    176 /* Used to avoid initialization races. */
    177 #ifdef _WIN32
    178 static malloc_mutex_t	init_lock;
    179 
    180 JEMALLOC_ATTR(constructor)
    181 static void WINAPI
    182 _init_init_lock(void)
    183 {
    184 
    185 	malloc_mutex_init(&init_lock);
    186 }
    187 
    188 #ifdef _MSC_VER
    189 #  pragma section(".CRT$XCU", read)
    190 JEMALLOC_SECTION(".CRT$XCU") JEMALLOC_ATTR(used)
    191 static const void (WINAPI *init_init_lock)(void) = _init_init_lock;
    192 #endif
    193 
    194 #else
    195 static malloc_mutex_t	init_lock = MALLOC_MUTEX_INITIALIZER;
    196 #endif
    197 
    198 typedef struct {
    199 	void	*p;	/* Input pointer (as in realloc(p, s)). */
    200 	size_t	s;	/* Request size. */
    201 	void	*r;	/* Result pointer. */
    202 } malloc_utrace_t;
    203 
    204 #ifdef JEMALLOC_UTRACE
    205 #  define UTRACE(a, b, c) do {						\
    206 	if (unlikely(opt_utrace)) {					\
    207 		int utrace_serrno = errno;				\
    208 		malloc_utrace_t ut;					\
    209 		ut.p = (a);						\
    210 		ut.s = (b);						\
    211 		ut.r = (c);						\
    212 		utrace(&ut, sizeof(ut));				\
    213 		errno = utrace_serrno;					\
    214 	}								\
    215 } while (0)
    216 #else
    217 #  define UTRACE(a, b, c)
    218 #endif
    219 
    220 /******************************************************************************/
    221 /*
    222  * Function prototypes for static functions that are referenced prior to
    223  * definition.
    224  */
    225 
    226 static bool	malloc_init_hard_a0(void);
    227 static bool	malloc_init_hard(void);
    228 
    229 /******************************************************************************/
    230 /*
    231  * Begin miscellaneous support functions.
    232  */
    233 
    234 JEMALLOC_ALWAYS_INLINE_C bool
    235 malloc_initialized(void)
    236 {
    237 
    238 	return (malloc_init_state == malloc_init_initialized);
    239 }
    240 
    241 JEMALLOC_ALWAYS_INLINE_C void
    242 malloc_thread_init(void)
    243 {
    244 
    245 	/*
    246 	 * TSD initialization can't be safely done as a side effect of
    247 	 * deallocation, because it is possible for a thread to do nothing but
    248 	 * deallocate its TLS data via free(), in which case writing to TLS
    249 	 * would cause write-after-free memory corruption.  The quarantine
    250 	 * facility *only* gets used as a side effect of deallocation, so make
    251 	 * a best effort attempt at initializing its TSD by hooking all
    252 	 * allocation events.
    253 	 */
    254 	if (config_fill && unlikely(opt_quarantine))
    255 		quarantine_alloc_hook();
    256 }
    257 
    258 JEMALLOC_ALWAYS_INLINE_C bool
    259 malloc_init_a0(void)
    260 {
    261 
    262 	if (unlikely(malloc_init_state == malloc_init_uninitialized))
    263 		return (malloc_init_hard_a0());
    264 	return (false);
    265 }
    266 
    267 JEMALLOC_ALWAYS_INLINE_C bool
    268 malloc_init(void)
    269 {
    270 
    271 	if (unlikely(!malloc_initialized()) && malloc_init_hard())
    272 		return (true);
    273 	malloc_thread_init();
    274 
    275 	return (false);
    276 }
    277 
    278 /*
    279  * The a0*() functions are used instead of i[mcd]alloc() in situations that
    280  * cannot tolerate TLS variable access.
    281  */
    282 
    283 arena_t *
    284 a0get(void)
    285 {
    286 
    287 	assert(a0 != NULL);
    288 	return (a0);
    289 }
    290 
    291 static void *
    292 a0ialloc(size_t size, bool zero, bool is_metadata)
    293 {
    294 
    295 	if (unlikely(malloc_init_a0()))
    296 		return (NULL);
    297 
    298 	return (iallocztm(NULL, size, zero, false, is_metadata, a0get()));
    299 }
    300 
    301 static void
    302 a0idalloc(void *ptr, bool is_metadata)
    303 {
    304 
    305 	idalloctm(NULL, ptr, false, is_metadata);
    306 }
    307 
    308 void *
    309 a0malloc(size_t size)
    310 {
    311 
    312 	return (a0ialloc(size, false, true));
    313 }
    314 
    315 void
    316 a0dalloc(void *ptr)
    317 {
    318 
    319 	a0idalloc(ptr, true);
    320 }
    321 
    322 /*
    323  * FreeBSD's libc uses the bootstrap_*() functions in bootstrap-senstive
    324  * situations that cannot tolerate TLS variable access (TLS allocation and very
    325  * early internal data structure initialization).
    326  */
    327 
    328 void *
    329 bootstrap_malloc(size_t size)
    330 {
    331 
    332 	if (unlikely(size == 0))
    333 		size = 1;
    334 
    335 	return (a0ialloc(size, false, false));
    336 }
    337 
    338 void *
    339 bootstrap_calloc(size_t num, size_t size)
    340 {
    341 	size_t num_size;
    342 
    343 	num_size = num * size;
    344 	if (unlikely(num_size == 0)) {
    345 		assert(num == 0 || size == 0);
    346 		num_size = 1;
    347 	}
    348 
    349 	return (a0ialloc(num_size, true, false));
    350 }
    351 
    352 void
    353 bootstrap_free(void *ptr)
    354 {
    355 
    356 	if (unlikely(ptr == NULL))
    357 		return;
    358 
    359 	a0idalloc(ptr, false);
    360 }
    361 
    362 /* Create a new arena and insert it into the arenas array at index ind. */
    363 static arena_t *
    364 arena_init_locked(unsigned ind)
    365 {
    366 	arena_t *arena;
    367 
    368 	/* Expand arenas if necessary. */
    369 	assert(ind <= narenas_total);
    370 	if (ind > MALLOCX_ARENA_MAX)
    371 		return (NULL);
    372 	if (ind == narenas_total) {
    373 		unsigned narenas_new = narenas_total + 1;
    374 		arena_t **arenas_new =
    375 		    (arena_t **)a0malloc(CACHELINE_CEILING(narenas_new *
    376 		    sizeof(arena_t *)));
    377 		if (arenas_new == NULL)
    378 			return (NULL);
    379 		memcpy(arenas_new, arenas, narenas_total * sizeof(arena_t *));
    380 		arenas_new[ind] = NULL;
    381 		/*
    382 		 * Deallocate only if arenas came from a0malloc() (not
    383 		 * base_alloc()).
    384 		 */
    385 		if (narenas_total != narenas_auto)
    386 			a0dalloc(arenas);
    387 		arenas = arenas_new;
    388 		narenas_total = narenas_new;
    389 	}
    390 
    391 	/*
    392 	 * Another thread may have already initialized arenas[ind] if it's an
    393 	 * auto arena.
    394 	 */
    395 	arena = arenas[ind];
    396 	if (arena != NULL) {
    397 		assert(ind < narenas_auto);
    398 		return (arena);
    399 	}
    400 
    401 	/* Actually initialize the arena. */
    402 	arena = arenas[ind] = arena_new(ind);
    403 	return (arena);
    404 }
    405 
    406 arena_t *
    407 arena_init(unsigned ind)
    408 {
    409 	arena_t *arena;
    410 
    411 	malloc_mutex_lock(&arenas_lock);
    412 	arena = arena_init_locked(ind);
    413 	malloc_mutex_unlock(&arenas_lock);
    414 	return (arena);
    415 }
    416 
    417 unsigned
    418 narenas_total_get(void)
    419 {
    420 	unsigned narenas;
    421 
    422 	malloc_mutex_lock(&arenas_lock);
    423 	narenas = narenas_total;
    424 	malloc_mutex_unlock(&arenas_lock);
    425 
    426 	return (narenas);
    427 }
    428 
    429 static void
    430 arena_bind_locked(tsd_t *tsd, unsigned ind)
    431 {
    432 	arena_t *arena;
    433 
    434 	arena = arenas[ind];
    435 	arena->nthreads++;
    436 
    437 	if (tsd_nominal(tsd))
    438 		tsd_arena_set(tsd, arena);
    439 }
    440 
    441 static void
    442 arena_bind(tsd_t *tsd, unsigned ind)
    443 {
    444 
    445 	malloc_mutex_lock(&arenas_lock);
    446 	arena_bind_locked(tsd, ind);
    447 	malloc_mutex_unlock(&arenas_lock);
    448 }
    449 
    450 void
    451 arena_migrate(tsd_t *tsd, unsigned oldind, unsigned newind)
    452 {
    453 	arena_t *oldarena, *newarena;
    454 
    455 	malloc_mutex_lock(&arenas_lock);
    456 	oldarena = arenas[oldind];
    457 	newarena = arenas[newind];
    458 	oldarena->nthreads--;
    459 	newarena->nthreads++;
    460 	malloc_mutex_unlock(&arenas_lock);
    461 	tsd_arena_set(tsd, newarena);
    462 }
    463 
    464 unsigned
    465 arena_nbound(unsigned ind)
    466 {
    467 	unsigned nthreads;
    468 
    469 	malloc_mutex_lock(&arenas_lock);
    470 	nthreads = arenas[ind]->nthreads;
    471 	malloc_mutex_unlock(&arenas_lock);
    472 	return (nthreads);
    473 }
    474 
    475 static void
    476 arena_unbind(tsd_t *tsd, unsigned ind)
    477 {
    478 	arena_t *arena;
    479 
    480 	malloc_mutex_lock(&arenas_lock);
    481 	arena = arenas[ind];
    482 	arena->nthreads--;
    483 	malloc_mutex_unlock(&arenas_lock);
    484 	tsd_arena_set(tsd, NULL);
    485 }
    486 
    487 arena_t *
    488 arena_get_hard(tsd_t *tsd, unsigned ind, bool init_if_missing)
    489 {
    490 	arena_t *arena;
    491 	arena_t **arenas_cache = tsd_arenas_cache_get(tsd);
    492 	unsigned narenas_cache = tsd_narenas_cache_get(tsd);
    493 	unsigned narenas_actual = narenas_total_get();
    494 
    495 	/* Deallocate old cache if it's too small. */
    496 	if (arenas_cache != NULL && narenas_cache < narenas_actual) {
    497 		a0dalloc(arenas_cache);
    498 		arenas_cache = NULL;
    499 		narenas_cache = 0;
    500 		tsd_arenas_cache_set(tsd, arenas_cache);
    501 		tsd_narenas_cache_set(tsd, narenas_cache);
    502 	}
    503 
    504 	/* Allocate cache if it's missing. */
    505 	if (arenas_cache == NULL) {
    506 		bool *arenas_cache_bypassp = tsd_arenas_cache_bypassp_get(tsd);
    507 		assert(ind < narenas_actual || !init_if_missing);
    508 		narenas_cache = (ind < narenas_actual) ? narenas_actual : ind+1;
    509 
    510 		if (!*arenas_cache_bypassp) {
    511 			*arenas_cache_bypassp = true;
    512 			arenas_cache = (arena_t **)a0malloc(sizeof(arena_t *) *
    513 			    narenas_cache);
    514 			*arenas_cache_bypassp = false;
    515 		} else
    516 			arenas_cache = NULL;
    517 		if (arenas_cache == NULL) {
    518 			/*
    519 			 * This function must always tell the truth, even if
    520 			 * it's slow, so don't let OOM or recursive allocation
    521 			 * avoidance (note arenas_cache_bypass check) get in the
    522 			 * way.
    523 			 */
    524 			if (ind >= narenas_actual)
    525 				return (NULL);
    526 			malloc_mutex_lock(&arenas_lock);
    527 			arena = arenas[ind];
    528 			malloc_mutex_unlock(&arenas_lock);
    529 			return (arena);
    530 		}
    531 		tsd_arenas_cache_set(tsd, arenas_cache);
    532 		tsd_narenas_cache_set(tsd, narenas_cache);
    533 	}
    534 
    535 	/*
    536 	 * Copy to cache.  It's possible that the actual number of arenas has
    537 	 * increased since narenas_total_get() was called above, but that causes
    538 	 * no correctness issues unless two threads concurrently execute the
    539 	 * arenas.extend mallctl, which we trust mallctl synchronization to
    540 	 * prevent.
    541 	 */
    542 	malloc_mutex_lock(&arenas_lock);
    543 	memcpy(arenas_cache, arenas, sizeof(arena_t *) * narenas_actual);
    544 	malloc_mutex_unlock(&arenas_lock);
    545 	if (narenas_cache > narenas_actual) {
    546 		memset(&arenas_cache[narenas_actual], 0, sizeof(arena_t *) *
    547 		    (narenas_cache - narenas_actual));
    548 	}
    549 
    550 	/* Read the refreshed cache, and init the arena if necessary. */
    551 	arena = arenas_cache[ind];
    552 	if (init_if_missing && arena == NULL)
    553 		arena = arenas_cache[ind] = arena_init(ind);
    554 	return (arena);
    555 }
    556 
    557 /* Slow path, called only by arena_choose(). */
    558 arena_t *
    559 arena_choose_hard(tsd_t *tsd)
    560 {
    561 	arena_t *ret;
    562 
    563 	if (narenas_auto > 1) {
    564 		unsigned i, choose, first_null;
    565 
    566 		choose = 0;
    567 		first_null = narenas_auto;
    568 		malloc_mutex_lock(&arenas_lock);
    569 		assert(a0get() != NULL);
    570 		for (i = 1; i < narenas_auto; i++) {
    571 			if (arenas[i] != NULL) {
    572 				/*
    573 				 * Choose the first arena that has the lowest
    574 				 * number of threads assigned to it.
    575 				 */
    576 				if (arenas[i]->nthreads <
    577 				    arenas[choose]->nthreads)
    578 					choose = i;
    579 			} else if (first_null == narenas_auto) {
    580 				/*
    581 				 * Record the index of the first uninitialized
    582 				 * arena, in case all extant arenas are in use.
    583 				 *
    584 				 * NB: It is possible for there to be
    585 				 * discontinuities in terms of initialized
    586 				 * versus uninitialized arenas, due to the
    587 				 * "thread.arena" mallctl.
    588 				 */
    589 				first_null = i;
    590 			}
    591 		}
    592 
    593 		if (arenas[choose]->nthreads == 0
    594 		    || first_null == narenas_auto) {
    595 			/*
    596 			 * Use an unloaded arena, or the least loaded arena if
    597 			 * all arenas are already initialized.
    598 			 */
    599 			ret = arenas[choose];
    600 		} else {
    601 			/* Initialize a new arena. */
    602 			choose = first_null;
    603 			ret = arena_init_locked(choose);
    604 			if (ret == NULL) {
    605 				malloc_mutex_unlock(&arenas_lock);
    606 				return (NULL);
    607 			}
    608 		}
    609 		arena_bind_locked(tsd, choose);
    610 		malloc_mutex_unlock(&arenas_lock);
    611 	} else {
    612 		ret = a0get();
    613 		arena_bind(tsd, 0);
    614 	}
    615 
    616 	return (ret);
    617 }
    618 
    619 void
    620 thread_allocated_cleanup(tsd_t *tsd)
    621 {
    622 
    623 	/* Do nothing. */
    624 }
    625 
    626 void
    627 thread_deallocated_cleanup(tsd_t *tsd)
    628 {
    629 
    630 	/* Do nothing. */
    631 }
    632 
    633 void
    634 arena_cleanup(tsd_t *tsd)
    635 {
    636 	arena_t *arena;
    637 
    638 	arena = tsd_arena_get(tsd);
    639 	if (arena != NULL)
    640 		arena_unbind(tsd, arena->ind);
    641 }
    642 
    643 void
    644 arenas_cache_cleanup(tsd_t *tsd)
    645 {
    646 	arena_t **arenas_cache;
    647 
    648 	arenas_cache = tsd_arenas_cache_get(tsd);
    649 	if (arenas_cache != NULL) {
    650 		/* ANDROID change */
    651 		/* Make sure that the arena cache cannot be reused. */
    652 		bool *arenas_cache_bypassp = tsd_arenas_cache_bypassp_get(tsd);
    653 		*arenas_cache_bypassp = true;
    654 		tsd_arenas_cache_set(tsd, NULL);
    655 		/* End ANDROID change */
    656 		a0dalloc(arenas_cache);
    657 	}
    658 }
    659 
    660 void
    661 narenas_cache_cleanup(tsd_t *tsd)
    662 {
    663 
    664 	/* Do nothing. */
    665 }
    666 
    667 void
    668 arenas_cache_bypass_cleanup(tsd_t *tsd)
    669 {
    670 
    671 	/* Do nothing. */
    672 }
    673 
    674 static void
    675 stats_print_atexit(void)
    676 {
    677 
    678 	if (config_tcache && config_stats) {
    679 		unsigned narenas, i;
    680 
    681 		/*
    682 		 * Merge stats from extant threads.  This is racy, since
    683 		 * individual threads do not lock when recording tcache stats
    684 		 * events.  As a consequence, the final stats may be slightly
    685 		 * out of date by the time they are reported, if other threads
    686 		 * continue to allocate.
    687 		 */
    688 		for (i = 0, narenas = narenas_total_get(); i < narenas; i++) {
    689 			arena_t *arena = arenas[i];
    690 			if (arena != NULL) {
    691 				tcache_t *tcache;
    692 
    693 				/*
    694 				 * tcache_stats_merge() locks bins, so if any
    695 				 * code is introduced that acquires both arena
    696 				 * and bin locks in the opposite order,
    697 				 * deadlocks may result.
    698 				 */
    699 				malloc_mutex_lock(&arena->lock);
    700 				ql_foreach(tcache, &arena->tcache_ql, link) {
    701 					tcache_stats_merge(tcache, arena);
    702 				}
    703 				malloc_mutex_unlock(&arena->lock);
    704 			}
    705 		}
    706 	}
    707 	je_malloc_stats_print(NULL, NULL, NULL);
    708 }
    709 
    710 /*
    711  * End miscellaneous support functions.
    712  */
    713 /******************************************************************************/
    714 /*
    715  * Begin initialization functions.
    716  */
    717 
    718 #ifndef JEMALLOC_HAVE_SECURE_GETENV
    719 static char *
    720 secure_getenv(const char *name)
    721 {
    722 
    723 #  ifdef JEMALLOC_HAVE_ISSETUGID
    724 	if (issetugid() != 0)
    725 		return (NULL);
    726 #  endif
    727 	return (getenv(name));
    728 }
    729 #endif
    730 
    731 static unsigned
    732 malloc_ncpus(void)
    733 {
    734 	long result;
    735 
    736 #ifdef _WIN32
    737 	SYSTEM_INFO si;
    738 	GetSystemInfo(&si);
    739 	result = si.dwNumberOfProcessors;
    740 #else
    741 	result = sysconf(_SC_NPROCESSORS_ONLN);
    742 #endif
    743 	return ((result == -1) ? 1 : (unsigned)result);
    744 }
    745 
    746 static bool
    747 malloc_conf_next(char const **opts_p, char const **k_p, size_t *klen_p,
    748     char const **v_p, size_t *vlen_p)
    749 {
    750 	bool accept;
    751 	const char *opts = *opts_p;
    752 
    753 	*k_p = opts;
    754 
    755 	for (accept = false; !accept;) {
    756 		switch (*opts) {
    757 		case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
    758 		case 'G': case 'H': case 'I': case 'J': case 'K': case 'L':
    759 		case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R':
    760 		case 'S': case 'T': case 'U': case 'V': case 'W': case 'X':
    761 		case 'Y': case 'Z':
    762 		case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
    763 		case 'g': case 'h': case 'i': case 'j': case 'k': case 'l':
    764 		case 'm': case 'n': case 'o': case 'p': case 'q': case 'r':
    765 		case 's': case 't': case 'u': case 'v': case 'w': case 'x':
    766 		case 'y': case 'z':
    767 		case '0': case '1': case '2': case '3': case '4': case '5':
    768 		case '6': case '7': case '8': case '9':
    769 		case '_':
    770 			opts++;
    771 			break;
    772 		case ':':
    773 			opts++;
    774 			*klen_p = (uintptr_t)opts - 1 - (uintptr_t)*k_p;
    775 			*v_p = opts;
    776 			accept = true;
    777 			break;
    778 		case '\0':
    779 			if (opts != *opts_p) {
    780 				malloc_write("<jemalloc>: Conf string ends "
    781 				    "with key\n");
    782 			}
    783 			return (true);
    784 		default:
    785 			malloc_write("<jemalloc>: Malformed conf string\n");
    786 			return (true);
    787 		}
    788 	}
    789 
    790 	for (accept = false; !accept;) {
    791 		switch (*opts) {
    792 		case ',':
    793 			opts++;
    794 			/*
    795 			 * Look ahead one character here, because the next time
    796 			 * this function is called, it will assume that end of
    797 			 * input has been cleanly reached if no input remains,
    798 			 * but we have optimistically already consumed the
    799 			 * comma if one exists.
    800 			 */
    801 			if (*opts == '\0') {
    802 				malloc_write("<jemalloc>: Conf string ends "
    803 				    "with comma\n");
    804 			}
    805 			*vlen_p = (uintptr_t)opts - 1 - (uintptr_t)*v_p;
    806 			accept = true;
    807 			break;
    808 		case '\0':
    809 			*vlen_p = (uintptr_t)opts - (uintptr_t)*v_p;
    810 			accept = true;
    811 			break;
    812 		default:
    813 			opts++;
    814 			break;
    815 		}
    816 	}
    817 
    818 	*opts_p = opts;
    819 	return (false);
    820 }
    821 
    822 static void
    823 malloc_conf_error(const char *msg, const char *k, size_t klen, const char *v,
    824     size_t vlen)
    825 {
    826 
    827 	malloc_printf("<jemalloc>: %s: %.*s:%.*s\n", msg, (int)klen, k,
    828 	    (int)vlen, v);
    829 }
    830 
    831 static void
    832 malloc_conf_init(void)
    833 {
    834 	unsigned i;
    835 	char buf[PATH_MAX + 1];
    836 	const char *opts, *k, *v;
    837 	size_t klen, vlen;
    838 
    839 	/*
    840 	 * Automatically configure valgrind before processing options.  The
    841 	 * valgrind option remains in jemalloc 3.x for compatibility reasons.
    842 	 */
    843 	if (config_valgrind) {
    844 		in_valgrind = (RUNNING_ON_VALGRIND != 0) ? true : false;
    845 		if (config_fill && unlikely(in_valgrind)) {
    846 			opt_junk = "false";
    847 			opt_junk_alloc = false;
    848 			opt_junk_free = false;
    849 			assert(!opt_zero);
    850 			opt_quarantine = JEMALLOC_VALGRIND_QUARANTINE_DEFAULT;
    851 			opt_redzone = true;
    852 		}
    853 		if (config_tcache && unlikely(in_valgrind))
    854 			opt_tcache = false;
    855 	}
    856 
    857 #if defined(__ANDROID__)
    858 	/* Android only supports compiled options. */
    859 	for (i = 0; i < 1; i++) {
    860 #else
    861 	for (i = 0; i < 3; i++) {
    862 #endif
    863 		/* Get runtime configuration. */
    864 		switch (i) {
    865 		case 0:
    866 			if (je_malloc_conf != NULL) {
    867 				/*
    868 				 * Use options that were compiled into the
    869 				 * program.
    870 				 */
    871 				opts = je_malloc_conf;
    872 			} else {
    873 				/* No configuration specified. */
    874 				buf[0] = '\0';
    875 				opts = buf;
    876 			}
    877 			break;
    878 		case 1: {
    879 			int linklen = 0;
    880 #ifndef _WIN32
    881 			int saved_errno = errno;
    882 			const char *linkname =
    883 #  ifdef JEMALLOC_PREFIX
    884 			    "/etc/"JEMALLOC_PREFIX"malloc.conf"
    885 #  else
    886 			    "/etc/malloc.conf"
    887 #  endif
    888 			    ;
    889 
    890 			/*
    891 			 * Try to use the contents of the "/etc/malloc.conf"
    892 			 * symbolic link's name.
    893 			 */
    894 			linklen = readlink(linkname, buf, sizeof(buf) - 1);
    895 			if (linklen == -1) {
    896 				/* No configuration specified. */
    897 				linklen = 0;
    898 				/* Restore errno. */
    899 				set_errno(saved_errno);
    900 			}
    901 #endif
    902 			buf[linklen] = '\0';
    903 			opts = buf;
    904 			break;
    905 		} case 2: {
    906 			const char *envname =
    907 #ifdef JEMALLOC_PREFIX
    908 			    JEMALLOC_CPREFIX"MALLOC_CONF"
    909 #else
    910 			    "MALLOC_CONF"
    911 #endif
    912 			    ;
    913 
    914 			if ((opts = secure_getenv(envname)) != NULL) {
    915 				/*
    916 				 * Do nothing; opts is already initialized to
    917 				 * the value of the MALLOC_CONF environment
    918 				 * variable.
    919 				 */
    920 			} else {
    921 				/* No configuration specified. */
    922 				buf[0] = '\0';
    923 				opts = buf;
    924 			}
    925 			break;
    926 		} default:
    927 			not_reached();
    928 			buf[0] = '\0';
    929 			opts = buf;
    930 		}
    931 
    932 		while (*opts != '\0' && !malloc_conf_next(&opts, &k, &klen, &v,
    933 		    &vlen)) {
    934 #define	CONF_MATCH(n)							\
    935 	(sizeof(n)-1 == klen && strncmp(n, k, klen) == 0)
    936 #define	CONF_MATCH_VALUE(n)						\
    937 	(sizeof(n)-1 == vlen && strncmp(n, v, vlen) == 0)
    938 #define	CONF_HANDLE_BOOL(o, n, cont)					\
    939 			if (CONF_MATCH(n)) {				\
    940 				if (CONF_MATCH_VALUE("true"))		\
    941 					o = true;			\
    942 				else if (CONF_MATCH_VALUE("false"))	\
    943 					o = false;			\
    944 				else {					\
    945 					malloc_conf_error(		\
    946 					    "Invalid conf value",	\
    947 					    k, klen, v, vlen);		\
    948 				}					\
    949 				if (cont)				\
    950 					continue;			\
    951 			}
    952 #define	CONF_HANDLE_SIZE_T(o, n, min, max, clip)			\
    953 			if (CONF_MATCH(n)) {				\
    954 				uintmax_t um;				\
    955 				char *end;				\
    956 									\
    957 				set_errno(0);				\
    958 				um = malloc_strtoumax(v, &end, 0);	\
    959 				if (get_errno() != 0 || (uintptr_t)end -\
    960 				    (uintptr_t)v != vlen) {		\
    961 					malloc_conf_error(		\
    962 					    "Invalid conf value",	\
    963 					    k, klen, v, vlen);		\
    964 				} else if (clip) {			\
    965 					if ((min) != 0 && um < (min))	\
    966 						o = (min);		\
    967 					else if (um > (max))		\
    968 						o = (max);		\
    969 					else				\
    970 						o = um;			\
    971 				} else {				\
    972 					if (((min) != 0 && um < (min))	\
    973 					    || um > (max)) {		\
    974 						malloc_conf_error(	\
    975 						    "Out-of-range "	\
    976 						    "conf value",	\
    977 						    k, klen, v, vlen);	\
    978 					} else				\
    979 						o = um;			\
    980 				}					\
    981 				continue;				\
    982 			}
    983 #define	CONF_HANDLE_SSIZE_T(o, n, min, max)				\
    984 			if (CONF_MATCH(n)) {				\
    985 				long l;					\
    986 				char *end;				\
    987 									\
    988 				set_errno(0);				\
    989 				l = strtol(v, &end, 0);			\
    990 				if (get_errno() != 0 || (uintptr_t)end -\
    991 				    (uintptr_t)v != vlen) {		\
    992 					malloc_conf_error(		\
    993 					    "Invalid conf value",	\
    994 					    k, klen, v, vlen);		\
    995 				} else if (l < (ssize_t)(min) || l >	\
    996 				    (ssize_t)(max)) {			\
    997 					malloc_conf_error(		\
    998 					    "Out-of-range conf value",	\
    999 					    k, klen, v, vlen);		\
   1000 				} else					\
   1001 					o = l;				\
   1002 				continue;				\
   1003 			}
   1004 #define	CONF_HANDLE_CHAR_P(o, n, d)					\
   1005 			if (CONF_MATCH(n)) {				\
   1006 				size_t cpylen = (vlen <=		\
   1007 				    sizeof(o)-1) ? vlen :		\
   1008 				    sizeof(o)-1;			\
   1009 				strncpy(o, v, cpylen);			\
   1010 				o[cpylen] = '\0';			\
   1011 				continue;				\
   1012 			}
   1013 
   1014 			CONF_HANDLE_BOOL(opt_abort, "abort", true)
   1015 			/*
   1016 			 * Chunks always require at least one header page,
   1017 			 * as many as 2^(LG_SIZE_CLASS_GROUP+1) data pages, and
   1018 			 * possibly an additional page in the presence of
   1019 			 * redzones.  In order to simplify options processing,
   1020 			 * use a conservative bound that accommodates all these
   1021 			 * constraints.
   1022 			 */
   1023 			CONF_HANDLE_SIZE_T(opt_lg_chunk, "lg_chunk", LG_PAGE +
   1024 			    LG_SIZE_CLASS_GROUP + (config_fill ? 2 : 1),
   1025 			    (sizeof(size_t) << 3) - 1, true)
   1026 			if (strncmp("dss", k, klen) == 0) {
   1027 				int i;
   1028 				bool match = false;
   1029 				for (i = 0; i < dss_prec_limit; i++) {
   1030 					if (strncmp(dss_prec_names[i], v, vlen)
   1031 					    == 0) {
   1032 						if (chunk_dss_prec_set(i)) {
   1033 							malloc_conf_error(
   1034 							    "Error setting dss",
   1035 							    k, klen, v, vlen);
   1036 						} else {
   1037 							opt_dss =
   1038 							    dss_prec_names[i];
   1039 							match = true;
   1040 							break;
   1041 						}
   1042 					}
   1043 				}
   1044 				if (!match) {
   1045 					malloc_conf_error("Invalid conf value",
   1046 					    k, klen, v, vlen);
   1047 				}
   1048 				continue;
   1049 			}
   1050 			CONF_HANDLE_SIZE_T(opt_narenas, "narenas", 1,
   1051 			    SIZE_T_MAX, false)
   1052 			CONF_HANDLE_SSIZE_T(opt_lg_dirty_mult, "lg_dirty_mult",
   1053 			    -1, (sizeof(size_t) << 3) - 1)
   1054 			CONF_HANDLE_BOOL(opt_stats_print, "stats_print", true)
   1055 			if (config_fill) {
   1056 				if (CONF_MATCH("junk")) {
   1057 					if (CONF_MATCH_VALUE("true")) {
   1058 						opt_junk = "true";
   1059 						opt_junk_alloc = opt_junk_free =
   1060 						    true;
   1061 					} else if (CONF_MATCH_VALUE("false")) {
   1062 						opt_junk = "false";
   1063 						opt_junk_alloc = opt_junk_free =
   1064 						    false;
   1065 					} else if (CONF_MATCH_VALUE("alloc")) {
   1066 						opt_junk = "alloc";
   1067 						opt_junk_alloc = true;
   1068 						opt_junk_free = false;
   1069 					} else if (CONF_MATCH_VALUE("free")) {
   1070 						opt_junk = "free";
   1071 						opt_junk_alloc = false;
   1072 						opt_junk_free = true;
   1073 					} else {
   1074 						malloc_conf_error(
   1075 						    "Invalid conf value", k,
   1076 						    klen, v, vlen);
   1077 					}
   1078 					continue;
   1079 				}
   1080 				CONF_HANDLE_SIZE_T(opt_quarantine, "quarantine",
   1081 				    0, SIZE_T_MAX, false)
   1082 				CONF_HANDLE_BOOL(opt_redzone, "redzone", true)
   1083 				CONF_HANDLE_BOOL(opt_zero, "zero", true)
   1084 			}
   1085 			if (config_utrace) {
   1086 				CONF_HANDLE_BOOL(opt_utrace, "utrace", true)
   1087 			}
   1088 			if (config_xmalloc) {
   1089 				CONF_HANDLE_BOOL(opt_xmalloc, "xmalloc", true)
   1090 			}
   1091 			if (config_tcache) {
   1092 				CONF_HANDLE_BOOL(opt_tcache, "tcache",
   1093 				    !config_valgrind || !in_valgrind)
   1094 				if (CONF_MATCH("tcache")) {
   1095 					assert(config_valgrind && in_valgrind);
   1096 					if (opt_tcache) {
   1097 						opt_tcache = false;
   1098 						malloc_conf_error(
   1099 						"tcache cannot be enabled "
   1100 						"while running inside Valgrind",
   1101 						k, klen, v, vlen);
   1102 					}
   1103 					continue;
   1104 				}
   1105 				CONF_HANDLE_SSIZE_T(opt_lg_tcache_max,
   1106 				    "lg_tcache_max", -1,
   1107 				    (sizeof(size_t) << 3) - 1)
   1108 			}
   1109 			if (config_prof) {
   1110 				CONF_HANDLE_BOOL(opt_prof, "prof", true)
   1111 				CONF_HANDLE_CHAR_P(opt_prof_prefix,
   1112 				    "prof_prefix", "jeprof")
   1113 				CONF_HANDLE_BOOL(opt_prof_active, "prof_active",
   1114 				    true)
   1115 				CONF_HANDLE_BOOL(opt_prof_thread_active_init,
   1116 				    "prof_thread_active_init", true)
   1117 				CONF_HANDLE_SIZE_T(opt_lg_prof_sample,
   1118 				    "lg_prof_sample", 0,
   1119 				    (sizeof(uint64_t) << 3) - 1, true)
   1120 				CONF_HANDLE_BOOL(opt_prof_accum, "prof_accum",
   1121 				    true)
   1122 				CONF_HANDLE_SSIZE_T(opt_lg_prof_interval,
   1123 				    "lg_prof_interval", -1,
   1124 				    (sizeof(uint64_t) << 3) - 1)
   1125 				CONF_HANDLE_BOOL(opt_prof_gdump, "prof_gdump",
   1126 				    true)
   1127 				CONF_HANDLE_BOOL(opt_prof_final, "prof_final",
   1128 				    true)
   1129 				CONF_HANDLE_BOOL(opt_prof_leak, "prof_leak",
   1130 				    true)
   1131 			}
   1132 			malloc_conf_error("Invalid conf pair", k, klen, v,
   1133 			    vlen);
   1134 #undef CONF_MATCH
   1135 #undef CONF_HANDLE_BOOL
   1136 #undef CONF_HANDLE_SIZE_T
   1137 #undef CONF_HANDLE_SSIZE_T
   1138 #undef CONF_HANDLE_CHAR_P
   1139 		}
   1140 	}
   1141 }
   1142 
   1143 /* init_lock must be held. */
   1144 static bool
   1145 malloc_init_hard_needed(void)
   1146 {
   1147 
   1148 	if (malloc_initialized() || (IS_INITIALIZER && malloc_init_state ==
   1149 	    malloc_init_recursible)) {
   1150 		/*
   1151 		 * Another thread initialized the allocator before this one
   1152 		 * acquired init_lock, or this thread is the initializing
   1153 		 * thread, and it is recursively allocating.
   1154 		 */
   1155 		return (false);
   1156 	}
   1157 #ifdef JEMALLOC_THREADED_INIT
   1158 	if (malloc_initializer != NO_INITIALIZER && !IS_INITIALIZER) {
   1159 		/* Busy-wait until the initializing thread completes. */
   1160 		do {
   1161 			malloc_mutex_unlock(&init_lock);
   1162 			CPU_SPINWAIT;
   1163 			malloc_mutex_lock(&init_lock);
   1164 		} while (!malloc_initialized());
   1165 		return (false);
   1166 	}
   1167 #endif
   1168 	return (true);
   1169 }
   1170 
   1171 /* init_lock must be held. */
   1172 static bool
   1173 malloc_init_hard_a0_locked(void)
   1174 {
   1175 
   1176 	malloc_initializer = INITIALIZER;
   1177 
   1178 	if (config_prof)
   1179 		prof_boot0();
   1180 	malloc_conf_init();
   1181 	if (opt_stats_print) {
   1182 		/* Print statistics at exit. */
   1183 		if (atexit(stats_print_atexit) != 0) {
   1184 			malloc_write("<jemalloc>: Error in atexit()\n");
   1185 			if (opt_abort)
   1186 				abort();
   1187 		}
   1188 	}
   1189 	if (base_boot())
   1190 		return (true);
   1191 	if (chunk_boot())
   1192 		return (true);
   1193 	if (ctl_boot())
   1194 		return (true);
   1195 	if (config_prof)
   1196 		prof_boot1();
   1197 	if (arena_boot())
   1198 		return (true);
   1199 	if (config_tcache && tcache_boot())
   1200 		return (true);
   1201 	if (malloc_mutex_init(&arenas_lock))
   1202 		return (true);
   1203 	/*
   1204 	 * Create enough scaffolding to allow recursive allocation in
   1205 	 * malloc_ncpus().
   1206 	 */
   1207 	narenas_total = narenas_auto = 1;
   1208 	arenas = &a0;
   1209 	memset(arenas, 0, sizeof(arena_t *) * narenas_auto);
   1210 	/*
   1211 	 * Initialize one arena here.  The rest are lazily created in
   1212 	 * arena_choose_hard().
   1213 	 */
   1214 	if (arena_init(0) == NULL)
   1215 		return (true);
   1216 	malloc_init_state = malloc_init_a0_initialized;
   1217 	return (false);
   1218 }
   1219 
   1220 static bool
   1221 malloc_init_hard_a0(void)
   1222 {
   1223 	bool ret;
   1224 
   1225 	malloc_mutex_lock(&init_lock);
   1226 	ret = malloc_init_hard_a0_locked();
   1227 	malloc_mutex_unlock(&init_lock);
   1228 	return (ret);
   1229 }
   1230 
   1231 /*
   1232  * Initialize data structures which may trigger recursive allocation.
   1233  *
   1234  * init_lock must be held.
   1235  */
   1236 static void
   1237 malloc_init_hard_recursible(void)
   1238 {
   1239 
   1240 	malloc_init_state = malloc_init_recursible;
   1241 	malloc_mutex_unlock(&init_lock);
   1242 
   1243 	ncpus = malloc_ncpus();
   1244 
   1245 #if (!defined(JEMALLOC_MUTEX_INIT_CB) && !defined(JEMALLOC_ZONE) \
   1246     && !defined(_WIN32) && !defined(__native_client__))
   1247 	/* LinuxThreads's pthread_atfork() allocates. */
   1248 	if (pthread_atfork(jemalloc_prefork, jemalloc_postfork_parent,
   1249 	    jemalloc_postfork_child) != 0) {
   1250 		malloc_write("<jemalloc>: Error in pthread_atfork()\n");
   1251 		if (opt_abort)
   1252 			abort();
   1253 	}
   1254 #endif
   1255 	malloc_mutex_lock(&init_lock);
   1256 }
   1257 
   1258 /* init_lock must be held. */
   1259 static bool
   1260 malloc_init_hard_finish(void)
   1261 {
   1262 
   1263 	if (mutex_boot())
   1264 		return (true);
   1265 
   1266 	if (opt_narenas == 0) {
   1267 		/*
   1268 		 * For SMP systems, create more than one arena per CPU by
   1269 		 * default.
   1270 		 */
   1271 		if (ncpus > 1)
   1272 			opt_narenas = ncpus << 2;
   1273 		else
   1274 			opt_narenas = 1;
   1275 	}
   1276 #if defined(ANDROID_MAX_ARENAS)
   1277 	/* Never create more than MAX_ARENAS arenas regardless of num_cpus.
   1278 	 * Extra arenas use more PSS and are not very useful unless
   1279 	 * lots of threads are allocing/freeing at the same time.
   1280 	 */
   1281 	if (opt_narenas > ANDROID_MAX_ARENAS)
   1282 		opt_narenas = ANDROID_MAX_ARENAS;
   1283 #endif
   1284 	narenas_auto = opt_narenas;
   1285 	/*
   1286 	 * Make sure that the arenas array can be allocated.  In practice, this
   1287 	 * limit is enough to allow the allocator to function, but the ctl
   1288 	 * machinery will fail to allocate memory at far lower limits.
   1289 	 */
   1290 	if (narenas_auto > chunksize / sizeof(arena_t *)) {
   1291 		narenas_auto = chunksize / sizeof(arena_t *);
   1292 		malloc_printf("<jemalloc>: Reducing narenas to limit (%d)\n",
   1293 		    narenas_auto);
   1294 	}
   1295 	narenas_total = narenas_auto;
   1296 
   1297 	/* Allocate and initialize arenas. */
   1298 	arenas = (arena_t **)base_alloc(sizeof(arena_t *) * narenas_total);
   1299 	if (arenas == NULL)
   1300 		return (true);
   1301 	/*
   1302 	 * Zero the array.  In practice, this should always be pre-zeroed,
   1303 	 * since it was just mmap()ed, but let's be sure.
   1304 	 */
   1305 	memset(arenas, 0, sizeof(arena_t *) * narenas_total);
   1306 	/* Copy the pointer to the one arena that was already initialized. */
   1307 	arenas[0] = a0;
   1308 
   1309 	malloc_init_state = malloc_init_initialized;
   1310 	return (false);
   1311 }
   1312 
   1313 static bool
   1314 malloc_init_hard(void)
   1315 {
   1316 
   1317 	malloc_mutex_lock(&init_lock);
   1318 	if (!malloc_init_hard_needed()) {
   1319 		malloc_mutex_unlock(&init_lock);
   1320 		return (false);
   1321 	}
   1322 
   1323 	if (malloc_init_state != malloc_init_a0_initialized &&
   1324 	    malloc_init_hard_a0_locked()) {
   1325 		malloc_mutex_unlock(&init_lock);
   1326 		return (true);
   1327 	}
   1328 	if (malloc_tsd_boot0()) {
   1329 		malloc_mutex_unlock(&init_lock);
   1330 		return (true);
   1331 	}
   1332 	if (config_prof && prof_boot2()) {
   1333 		malloc_mutex_unlock(&init_lock);
   1334 		return (true);
   1335 	}
   1336 
   1337 	malloc_init_hard_recursible();
   1338 
   1339 	if (malloc_init_hard_finish()) {
   1340 		malloc_mutex_unlock(&init_lock);
   1341 		return (true);
   1342 	}
   1343 
   1344 	malloc_mutex_unlock(&init_lock);
   1345 	malloc_tsd_boot1();
   1346 	return (false);
   1347 }
   1348 
   1349 /*
   1350  * End initialization functions.
   1351  */
   1352 /******************************************************************************/
   1353 /*
   1354  * Begin malloc(3)-compatible functions.
   1355  */
   1356 
   1357 static void *
   1358 imalloc_prof_sample(tsd_t *tsd, size_t usize, prof_tctx_t *tctx)
   1359 {
   1360 	void *p;
   1361 
   1362 	if (tctx == NULL)
   1363 		return (NULL);
   1364 	if (usize <= SMALL_MAXCLASS) {
   1365 		p = imalloc(tsd, LARGE_MINCLASS);
   1366 		if (p == NULL)
   1367 			return (NULL);
   1368 		arena_prof_promoted(p, usize);
   1369 	} else
   1370 		p = imalloc(tsd, usize);
   1371 
   1372 	return (p);
   1373 }
   1374 
   1375 JEMALLOC_ALWAYS_INLINE_C void *
   1376 imalloc_prof(tsd_t *tsd, size_t usize)
   1377 {
   1378 	void *p;
   1379 	prof_tctx_t *tctx;
   1380 
   1381 	tctx = prof_alloc_prep(tsd, usize, true);
   1382 	if (unlikely((uintptr_t)tctx != (uintptr_t)1U))
   1383 		p = imalloc_prof_sample(tsd, usize, tctx);
   1384 	else
   1385 		p = imalloc(tsd, usize);
   1386 	if (unlikely(p == NULL)) {
   1387 		prof_alloc_rollback(tsd, tctx, true);
   1388 		return (NULL);
   1389 	}
   1390 	prof_malloc(p, usize, tctx);
   1391 
   1392 	return (p);
   1393 }
   1394 
   1395 JEMALLOC_ALWAYS_INLINE_C void *
   1396 imalloc_body(size_t size, tsd_t **tsd, size_t *usize)
   1397 {
   1398 
   1399 	if (unlikely(malloc_init()))
   1400 		return (NULL);
   1401 	*tsd = tsd_fetch();
   1402 
   1403 	if (config_prof && opt_prof) {
   1404 		*usize = s2u(size);
   1405 		return (imalloc_prof(*tsd, *usize));
   1406 	}
   1407 
   1408 	if (config_stats || (config_valgrind && unlikely(in_valgrind)))
   1409 		*usize = s2u(size);
   1410 	return (imalloc(*tsd, size));
   1411 }
   1412 
   1413 void *
   1414 je_malloc(size_t size)
   1415 {
   1416 	void *ret;
   1417 	tsd_t *tsd;
   1418 	size_t usize JEMALLOC_CC_SILENCE_INIT(0);
   1419 
   1420 	if (size == 0)
   1421 		size = 1;
   1422 
   1423 	ret = imalloc_body(size, &tsd, &usize);
   1424 	if (unlikely(ret == NULL)) {
   1425 		if (config_xmalloc && unlikely(opt_xmalloc)) {
   1426 			malloc_write("<jemalloc>: Error in malloc(): "
   1427 			    "out of memory\n");
   1428 			abort();
   1429 		}
   1430 		set_errno(ENOMEM);
   1431 	}
   1432 	if (config_stats && likely(ret != NULL)) {
   1433 		assert(usize == isalloc(ret, config_prof));
   1434 		*tsd_thread_allocatedp_get(tsd) += usize;
   1435 	}
   1436 	UTRACE(0, size, ret);
   1437 	JEMALLOC_VALGRIND_MALLOC(ret != NULL, ret, usize, false);
   1438 	return (ret);
   1439 }
   1440 
   1441 static void *
   1442 imemalign_prof_sample(tsd_t *tsd, size_t alignment, size_t usize,
   1443     prof_tctx_t *tctx)
   1444 {
   1445 	void *p;
   1446 
   1447 	if (tctx == NULL)
   1448 		return (NULL);
   1449 	if (usize <= SMALL_MAXCLASS) {
   1450 		assert(sa2u(LARGE_MINCLASS, alignment) == LARGE_MINCLASS);
   1451 		p = imalloc(tsd, LARGE_MINCLASS);
   1452 		if (p == NULL)
   1453 			return (NULL);
   1454 		arena_prof_promoted(p, usize);
   1455 	} else
   1456 		p = ipalloc(tsd, usize, alignment, false);
   1457 
   1458 	return (p);
   1459 }
   1460 
   1461 JEMALLOC_ALWAYS_INLINE_C void *
   1462 imemalign_prof(tsd_t *tsd, size_t alignment, size_t usize)
   1463 {
   1464 	void *p;
   1465 	prof_tctx_t *tctx;
   1466 
   1467 	tctx = prof_alloc_prep(tsd, usize, true);
   1468 	if (unlikely((uintptr_t)tctx != (uintptr_t)1U))
   1469 		p = imemalign_prof_sample(tsd, alignment, usize, tctx);
   1470 	else
   1471 		p = ipalloc(tsd, usize, alignment, false);
   1472 	if (unlikely(p == NULL)) {
   1473 		prof_alloc_rollback(tsd, tctx, true);
   1474 		return (NULL);
   1475 	}
   1476 	prof_malloc(p, usize, tctx);
   1477 
   1478 	return (p);
   1479 }
   1480 
   1481 JEMALLOC_ATTR(nonnull(1))
   1482 static int
   1483 imemalign(void **memptr, size_t alignment, size_t size, size_t min_alignment)
   1484 {
   1485 	int ret;
   1486 	tsd_t *tsd;
   1487 	size_t usize;
   1488 	void *result;
   1489 
   1490 	assert(min_alignment != 0);
   1491 
   1492 	if (unlikely(malloc_init())) {
   1493 		result = NULL;
   1494 		goto label_oom;
   1495 	} else {
   1496 		tsd = tsd_fetch();
   1497 		if (size == 0)
   1498 			size = 1;
   1499 
   1500 		/* Make sure that alignment is a large enough power of 2. */
   1501 		if (unlikely(((alignment - 1) & alignment) != 0
   1502 		    || (alignment < min_alignment))) {
   1503 			if (config_xmalloc && unlikely(opt_xmalloc)) {
   1504 				malloc_write("<jemalloc>: Error allocating "
   1505 				    "aligned memory: invalid alignment\n");
   1506 				abort();
   1507 			}
   1508 			result = NULL;
   1509 			ret = EINVAL;
   1510 			goto label_return;
   1511 		}
   1512 
   1513 		usize = sa2u(size, alignment);
   1514 		if (unlikely(usize == 0)) {
   1515 			result = NULL;
   1516 			goto label_oom;
   1517 		}
   1518 
   1519 		if (config_prof && opt_prof)
   1520 			result = imemalign_prof(tsd, alignment, usize);
   1521 		else
   1522 			result = ipalloc(tsd, usize, alignment, false);
   1523 		if (unlikely(result == NULL))
   1524 			goto label_oom;
   1525 	}
   1526 
   1527 	*memptr = result;
   1528 	ret = 0;
   1529 label_return:
   1530 	if (config_stats && likely(result != NULL)) {
   1531 		assert(usize == isalloc(result, config_prof));
   1532 		*tsd_thread_allocatedp_get(tsd) += usize;
   1533 	}
   1534 	UTRACE(0, size, result);
   1535 	return (ret);
   1536 label_oom:
   1537 	assert(result == NULL);
   1538 	if (config_xmalloc && unlikely(opt_xmalloc)) {
   1539 		malloc_write("<jemalloc>: Error allocating aligned memory: "
   1540 		    "out of memory\n");
   1541 		abort();
   1542 	}
   1543 	ret = ENOMEM;
   1544 	goto label_return;
   1545 }
   1546 
   1547 int
   1548 je_posix_memalign(void **memptr, size_t alignment, size_t size)
   1549 {
   1550 	int ret = imemalign(memptr, alignment, size, sizeof(void *));
   1551 	JEMALLOC_VALGRIND_MALLOC(ret == 0, *memptr, isalloc(*memptr,
   1552 	    config_prof), false);
   1553 	return (ret);
   1554 }
   1555 
   1556 void *
   1557 je_aligned_alloc(size_t alignment, size_t size)
   1558 {
   1559 	void *ret;
   1560 	int err;
   1561 
   1562 	if (unlikely((err = imemalign(&ret, alignment, size, 1)) != 0)) {
   1563 		ret = NULL;
   1564 		set_errno(err);
   1565 	}
   1566 	JEMALLOC_VALGRIND_MALLOC(err == 0, ret, isalloc(ret, config_prof),
   1567 	    false);
   1568 	return (ret);
   1569 }
   1570 
   1571 static void *
   1572 icalloc_prof_sample(tsd_t *tsd, size_t usize, prof_tctx_t *tctx)
   1573 {
   1574 	void *p;
   1575 
   1576 	if (tctx == NULL)
   1577 		return (NULL);
   1578 	if (usize <= SMALL_MAXCLASS) {
   1579 		p = icalloc(tsd, LARGE_MINCLASS);
   1580 		if (p == NULL)
   1581 			return (NULL);
   1582 		arena_prof_promoted(p, usize);
   1583 	} else
   1584 		p = icalloc(tsd, usize);
   1585 
   1586 	return (p);
   1587 }
   1588 
   1589 JEMALLOC_ALWAYS_INLINE_C void *
   1590 icalloc_prof(tsd_t *tsd, size_t usize)
   1591 {
   1592 	void *p;
   1593 	prof_tctx_t *tctx;
   1594 
   1595 	tctx = prof_alloc_prep(tsd, usize, true);
   1596 	if (unlikely((uintptr_t)tctx != (uintptr_t)1U))
   1597 		p = icalloc_prof_sample(tsd, usize, tctx);
   1598 	else
   1599 		p = icalloc(tsd, usize);
   1600 	if (unlikely(p == NULL)) {
   1601 		prof_alloc_rollback(tsd, tctx, true);
   1602 		return (NULL);
   1603 	}
   1604 	prof_malloc(p, usize, tctx);
   1605 
   1606 	return (p);
   1607 }
   1608 
   1609 void *
   1610 je_calloc(size_t num, size_t size)
   1611 {
   1612 	void *ret;
   1613 	tsd_t *tsd;
   1614 	size_t num_size;
   1615 	size_t usize JEMALLOC_CC_SILENCE_INIT(0);
   1616 
   1617 	if (unlikely(malloc_init())) {
   1618 		num_size = 0;
   1619 		ret = NULL;
   1620 		goto label_return;
   1621 	}
   1622 	tsd = tsd_fetch();
   1623 
   1624 	num_size = num * size;
   1625 	if (unlikely(num_size == 0)) {
   1626 		if (num == 0 || size == 0)
   1627 			num_size = 1;
   1628 		else {
   1629 			ret = NULL;
   1630 			goto label_return;
   1631 		}
   1632 	/*
   1633 	 * Try to avoid division here.  We know that it isn't possible to
   1634 	 * overflow during multiplication if neither operand uses any of the
   1635 	 * most significant half of the bits in a size_t.
   1636 	 */
   1637 	} else if (unlikely(((num | size) & (SIZE_T_MAX << (sizeof(size_t) <<
   1638 	    2))) && (num_size / size != num))) {
   1639 		/* size_t overflow. */
   1640 		ret = NULL;
   1641 		goto label_return;
   1642 	}
   1643 
   1644 	if (config_prof && opt_prof) {
   1645 		usize = s2u(num_size);
   1646 		ret = icalloc_prof(tsd, usize);
   1647 	} else {
   1648 		if (config_stats || (config_valgrind && unlikely(in_valgrind)))
   1649 			usize = s2u(num_size);
   1650 		ret = icalloc(tsd, num_size);
   1651 	}
   1652 
   1653 label_return:
   1654 	if (unlikely(ret == NULL)) {
   1655 		if (config_xmalloc && unlikely(opt_xmalloc)) {
   1656 			malloc_write("<jemalloc>: Error in calloc(): out of "
   1657 			    "memory\n");
   1658 			abort();
   1659 		}
   1660 		set_errno(ENOMEM);
   1661 	}
   1662 	if (config_stats && likely(ret != NULL)) {
   1663 		assert(usize == isalloc(ret, config_prof));
   1664 		*tsd_thread_allocatedp_get(tsd) += usize;
   1665 	}
   1666 	UTRACE(0, num_size, ret);
   1667 	JEMALLOC_VALGRIND_MALLOC(ret != NULL, ret, usize, true);
   1668 	return (ret);
   1669 }
   1670 
   1671 static void *
   1672 irealloc_prof_sample(tsd_t *tsd, void *oldptr, size_t old_usize, size_t usize,
   1673     prof_tctx_t *tctx)
   1674 {
   1675 	void *p;
   1676 
   1677 	if (tctx == NULL)
   1678 		return (NULL);
   1679 	if (usize <= SMALL_MAXCLASS) {
   1680 		p = iralloc(tsd, oldptr, old_usize, LARGE_MINCLASS, 0, false);
   1681 		if (p == NULL)
   1682 			return (NULL);
   1683 		arena_prof_promoted(p, usize);
   1684 	} else
   1685 		p = iralloc(tsd, oldptr, old_usize, usize, 0, false);
   1686 
   1687 	return (p);
   1688 }
   1689 
   1690 JEMALLOC_ALWAYS_INLINE_C void *
   1691 irealloc_prof(tsd_t *tsd, void *oldptr, size_t old_usize, size_t usize)
   1692 {
   1693 	void *p;
   1694 	prof_tctx_t *old_tctx, *tctx;
   1695 
   1696 	old_tctx = prof_tctx_get(oldptr);
   1697 	tctx = prof_alloc_prep(tsd, usize, true);
   1698 	if (unlikely((uintptr_t)tctx != (uintptr_t)1U))
   1699 		p = irealloc_prof_sample(tsd, oldptr, old_usize, usize, tctx);
   1700 	else
   1701 		p = iralloc(tsd, oldptr, old_usize, usize, 0, false);
   1702 	if (p == NULL)
   1703 		return (NULL);
   1704 	prof_realloc(tsd, p, usize, tctx, true, old_usize, old_tctx);
   1705 
   1706 	return (p);
   1707 }
   1708 
   1709 JEMALLOC_INLINE_C void
   1710 ifree(tsd_t *tsd, void *ptr, tcache_t *tcache)
   1711 {
   1712 	size_t usize;
   1713 	UNUSED size_t rzsize JEMALLOC_CC_SILENCE_INIT(0);
   1714 
   1715 	assert(ptr != NULL);
   1716 	assert(malloc_initialized() || IS_INITIALIZER);
   1717 
   1718 	if (config_prof && opt_prof) {
   1719 		usize = isalloc(ptr, config_prof);
   1720 		prof_free(tsd, ptr, usize);
   1721 	} else if (config_stats || config_valgrind)
   1722 		usize = isalloc(ptr, config_prof);
   1723 	if (config_stats)
   1724 		*tsd_thread_deallocatedp_get(tsd) += usize;
   1725 	if (config_valgrind && unlikely(in_valgrind))
   1726 		rzsize = p2rz(ptr);
   1727 	iqalloc(tsd, ptr, tcache);
   1728 	JEMALLOC_VALGRIND_FREE(ptr, rzsize);
   1729 }
   1730 
   1731 JEMALLOC_INLINE_C void
   1732 isfree(tsd_t *tsd, void *ptr, size_t usize, tcache_t *tcache)
   1733 {
   1734 	UNUSED size_t rzsize JEMALLOC_CC_SILENCE_INIT(0);
   1735 
   1736 	assert(ptr != NULL);
   1737 	assert(malloc_initialized() || IS_INITIALIZER);
   1738 
   1739 	if (config_prof && opt_prof)
   1740 		prof_free(tsd, ptr, usize);
   1741 	if (config_stats)
   1742 		*tsd_thread_deallocatedp_get(tsd) += usize;
   1743 	if (config_valgrind && unlikely(in_valgrind))
   1744 		rzsize = p2rz(ptr);
   1745 	isqalloc(tsd, ptr, usize, tcache);
   1746 	JEMALLOC_VALGRIND_FREE(ptr, rzsize);
   1747 }
   1748 
   1749 void *
   1750 je_realloc(void *ptr, size_t size)
   1751 {
   1752 	void *ret;
   1753 	tsd_t *tsd JEMALLOC_CC_SILENCE_INIT(NULL);
   1754 	size_t usize JEMALLOC_CC_SILENCE_INIT(0);
   1755 	size_t old_usize = 0;
   1756 	UNUSED size_t old_rzsize JEMALLOC_CC_SILENCE_INIT(0);
   1757 
   1758 	if (unlikely(size == 0)) {
   1759 		if (ptr != NULL) {
   1760 			/* realloc(ptr, 0) is equivalent to free(ptr). */
   1761 			UTRACE(ptr, 0, 0);
   1762 			tsd = tsd_fetch();
   1763 			ifree(tsd, ptr, tcache_get(tsd, false));
   1764 			return (NULL);
   1765 		}
   1766 		size = 1;
   1767 	}
   1768 
   1769 	if (likely(ptr != NULL)) {
   1770 		assert(malloc_initialized() || IS_INITIALIZER);
   1771 		malloc_thread_init();
   1772 		tsd = tsd_fetch();
   1773 
   1774 		old_usize = isalloc(ptr, config_prof);
   1775 		if (config_valgrind && unlikely(in_valgrind))
   1776 			old_rzsize = config_prof ? p2rz(ptr) : u2rz(old_usize);
   1777 
   1778 		if (config_prof && opt_prof) {
   1779 			usize = s2u(size);
   1780 			ret = irealloc_prof(tsd, ptr, old_usize, usize);
   1781 		} else {
   1782 			if (config_stats || (config_valgrind &&
   1783 			    unlikely(in_valgrind)))
   1784 				usize = s2u(size);
   1785 			ret = iralloc(tsd, ptr, old_usize, size, 0, false);
   1786 		}
   1787 	} else {
   1788 		/* realloc(NULL, size) is equivalent to malloc(size). */
   1789 		ret = imalloc_body(size, &tsd, &usize);
   1790 	}
   1791 
   1792 	if (unlikely(ret == NULL)) {
   1793 		if (config_xmalloc && unlikely(opt_xmalloc)) {
   1794 			malloc_write("<jemalloc>: Error in realloc(): "
   1795 			    "out of memory\n");
   1796 			abort();
   1797 		}
   1798 		set_errno(ENOMEM);
   1799 	}
   1800 	if (config_stats && likely(ret != NULL)) {
   1801 		assert(usize == isalloc(ret, config_prof));
   1802 		*tsd_thread_allocatedp_get(tsd) += usize;
   1803 		*tsd_thread_deallocatedp_get(tsd) += old_usize;
   1804 	}
   1805 	UTRACE(ptr, size, ret);
   1806 	JEMALLOC_VALGRIND_REALLOC(true, ret, usize, true, ptr, old_usize,
   1807 	    old_rzsize, true, false);
   1808 	return (ret);
   1809 }
   1810 
   1811 void
   1812 je_free(void *ptr)
   1813 {
   1814 
   1815 	UTRACE(ptr, 0, 0);
   1816 	if (likely(ptr != NULL)) {
   1817 		tsd_t *tsd = tsd_fetch();
   1818 		ifree(tsd, ptr, tcache_get(tsd, false));
   1819 	}
   1820 }
   1821 
   1822 /*
   1823  * End malloc(3)-compatible functions.
   1824  */
   1825 /******************************************************************************/
   1826 /*
   1827  * Begin non-standard override functions.
   1828  */
   1829 
   1830 #ifdef JEMALLOC_OVERRIDE_MEMALIGN
   1831 void *
   1832 je_memalign(size_t alignment, size_t size)
   1833 {
   1834 	void *ret JEMALLOC_CC_SILENCE_INIT(NULL);
   1835 	if (unlikely(imemalign(&ret, alignment, size, 1) != 0))
   1836 		ret = NULL;
   1837 	JEMALLOC_VALGRIND_MALLOC(ret != NULL, ret, size, false);
   1838 	return (ret);
   1839 }
   1840 #endif
   1841 
   1842 #ifdef JEMALLOC_OVERRIDE_VALLOC
   1843 void *
   1844 je_valloc(size_t size)
   1845 {
   1846 	void *ret JEMALLOC_CC_SILENCE_INIT(NULL);
   1847 	if (unlikely(imemalign(&ret, PAGE, size, 1) != 0))
   1848 		ret = NULL;
   1849 	JEMALLOC_VALGRIND_MALLOC(ret != NULL, ret, size, false);
   1850 	return (ret);
   1851 }
   1852 #endif
   1853 
   1854 /*
   1855  * is_malloc(je_malloc) is some macro magic to detect if jemalloc_defs.h has
   1856  * #define je_malloc malloc
   1857  */
   1858 #define	malloc_is_malloc 1
   1859 #define	is_malloc_(a) malloc_is_ ## a
   1860 #define	is_malloc(a) is_malloc_(a)
   1861 
   1862 #if ((is_malloc(je_malloc) == 1) && defined(JEMALLOC_GLIBC_MALLOC_HOOK))
   1863 /*
   1864  * glibc provides the RTLD_DEEPBIND flag for dlopen which can make it possible
   1865  * to inconsistently reference libc's malloc(3)-compatible functions
   1866  * (https://bugzilla.mozilla.org/show_bug.cgi?id=493541).
   1867  *
   1868  * These definitions interpose hooks in glibc.  The functions are actually
   1869  * passed an extra argument for the caller return address, which will be
   1870  * ignored.
   1871  */
   1872 JEMALLOC_EXPORT void (*__free_hook)(void *ptr) = je_free;
   1873 JEMALLOC_EXPORT void *(*__malloc_hook)(size_t size) = je_malloc;
   1874 JEMALLOC_EXPORT void *(*__realloc_hook)(void *ptr, size_t size) = je_realloc;
   1875 # ifdef JEMALLOC_GLIBC_MEMALIGN_HOOK
   1876 JEMALLOC_EXPORT void *(*__memalign_hook)(size_t alignment, size_t size) =
   1877     je_memalign;
   1878 # endif
   1879 #endif
   1880 
   1881 /*
   1882  * End non-standard override functions.
   1883  */
   1884 /******************************************************************************/
   1885 /*
   1886  * Begin non-standard functions.
   1887  */
   1888 
   1889 JEMALLOC_ALWAYS_INLINE_C bool
   1890 imallocx_flags_decode_hard(tsd_t *tsd, size_t size, int flags, size_t *usize,
   1891     size_t *alignment, bool *zero, tcache_t **tcache, arena_t **arena)
   1892 {
   1893 
   1894 	if ((flags & MALLOCX_LG_ALIGN_MASK) == 0) {
   1895 		*alignment = 0;
   1896 		*usize = s2u(size);
   1897 	} else {
   1898 		*alignment = MALLOCX_ALIGN_GET_SPECIFIED(flags);
   1899 		*usize = sa2u(size, *alignment);
   1900 	}
   1901 	*zero = MALLOCX_ZERO_GET(flags);
   1902 	if ((flags & MALLOCX_TCACHE_MASK) != 0) {
   1903 		if ((flags & MALLOCX_TCACHE_MASK) == MALLOCX_TCACHE_NONE)
   1904 			*tcache = NULL;
   1905 		else
   1906 			*tcache = tcaches_get(tsd, MALLOCX_TCACHE_GET(flags));
   1907 	} else
   1908 		*tcache = tcache_get(tsd, true);
   1909 	if ((flags & MALLOCX_ARENA_MASK) != 0) {
   1910 		unsigned arena_ind = MALLOCX_ARENA_GET(flags);
   1911 		*arena = arena_get(tsd, arena_ind, true, true);
   1912 		if (unlikely(*arena == NULL))
   1913 			return (true);
   1914 	} else
   1915 		*arena = NULL;
   1916 	return (false);
   1917 }
   1918 
   1919 JEMALLOC_ALWAYS_INLINE_C bool
   1920 imallocx_flags_decode(tsd_t *tsd, size_t size, int flags, size_t *usize,
   1921     size_t *alignment, bool *zero, tcache_t **tcache, arena_t **arena)
   1922 {
   1923 
   1924 	if (likely(flags == 0)) {
   1925 		*usize = s2u(size);
   1926 		assert(usize != 0);
   1927 		*alignment = 0;
   1928 		*zero = false;
   1929 		*tcache = tcache_get(tsd, true);
   1930 		*arena = NULL;
   1931 		return (false);
   1932 	} else {
   1933 		return (imallocx_flags_decode_hard(tsd, size, flags, usize,
   1934 		    alignment, zero, tcache, arena));
   1935 	}
   1936 }
   1937 
   1938 JEMALLOC_ALWAYS_INLINE_C void *
   1939 imallocx_flags(tsd_t *tsd, size_t usize, size_t alignment, bool zero,
   1940     tcache_t *tcache, arena_t *arena)
   1941 {
   1942 
   1943 	if (alignment != 0)
   1944 		return (ipalloct(tsd, usize, alignment, zero, tcache, arena));
   1945 	if (zero)
   1946 		return (icalloct(tsd, usize, tcache, arena));
   1947 	return (imalloct(tsd, usize, tcache, arena));
   1948 }
   1949 
   1950 JEMALLOC_ALWAYS_INLINE_C void *
   1951 imallocx_maybe_flags(tsd_t *tsd, size_t size, int flags, size_t usize,
   1952     size_t alignment, bool zero, tcache_t *tcache, arena_t *arena)
   1953 {
   1954 
   1955 	if (likely(flags == 0))
   1956 		return (imalloc(tsd, size));
   1957 	return (imallocx_flags(tsd, usize, alignment, zero, tcache, arena));
   1958 }
   1959 
   1960 static void *
   1961 imallocx_prof_sample(tsd_t *tsd, size_t size, int flags, size_t usize,
   1962     size_t alignment, bool zero, tcache_t *tcache, arena_t *arena)
   1963 {
   1964 	void *p;
   1965 
   1966 	if (usize <= SMALL_MAXCLASS) {
   1967 		assert(((alignment == 0) ? s2u(LARGE_MINCLASS) :
   1968 		    sa2u(LARGE_MINCLASS, alignment)) == LARGE_MINCLASS);
   1969 		p = imalloct(tsd, LARGE_MINCLASS, tcache, arena);
   1970 		if (p == NULL)
   1971 			return (NULL);
   1972 		arena_prof_promoted(p, usize);
   1973 	} else {
   1974 		p = imallocx_maybe_flags(tsd, size, flags, usize, alignment,
   1975 		    zero, tcache, arena);
   1976 	}
   1977 
   1978 	return (p);
   1979 }
   1980 
   1981 JEMALLOC_ALWAYS_INLINE_C void *
   1982 imallocx_prof(tsd_t *tsd, size_t size, int flags, size_t *usize)
   1983 {
   1984 	void *p;
   1985 	size_t alignment;
   1986 	bool zero;
   1987 	tcache_t *tcache;
   1988 	arena_t *arena;
   1989 	prof_tctx_t *tctx;
   1990 
   1991 	if (unlikely(imallocx_flags_decode(tsd, size, flags, usize, &alignment,
   1992 	    &zero, &tcache, &arena)))
   1993 		return (NULL);
   1994 	tctx = prof_alloc_prep(tsd, *usize, true);
   1995 	if (likely((uintptr_t)tctx == (uintptr_t)1U)) {
   1996 		p = imallocx_maybe_flags(tsd, size, flags, *usize, alignment,
   1997 		    zero, tcache, arena);
   1998 	} else if ((uintptr_t)tctx > (uintptr_t)1U) {
   1999 		p = imallocx_prof_sample(tsd, size, flags, *usize, alignment,
   2000 		    zero, tcache, arena);
   2001 	} else
   2002 		p = NULL;
   2003 	if (unlikely(p == NULL)) {
   2004 		prof_alloc_rollback(tsd, tctx, true);
   2005 		return (NULL);
   2006 	}
   2007 	prof_malloc(p, *usize, tctx);
   2008 
   2009 	return (p);
   2010 }
   2011 
   2012 JEMALLOC_ALWAYS_INLINE_C void *
   2013 imallocx_no_prof(tsd_t *tsd, size_t size, int flags, size_t *usize)
   2014 {
   2015 	size_t alignment;
   2016 	bool zero;
   2017 	tcache_t *tcache;
   2018 	arena_t *arena;
   2019 
   2020 	if (likely(flags == 0)) {
   2021 		if (config_stats || (config_valgrind && unlikely(in_valgrind)))
   2022 			*usize = s2u(size);
   2023 		return (imalloc(tsd, size));
   2024 	}
   2025 
   2026 	if (unlikely(imallocx_flags_decode_hard(tsd, size, flags, usize,
   2027 	    &alignment, &zero, &tcache, &arena)))
   2028 		return (NULL);
   2029 	return (imallocx_flags(tsd, *usize, alignment, zero, tcache, arena));
   2030 }
   2031 
   2032 void *
   2033 je_mallocx(size_t size, int flags)
   2034 {
   2035 	tsd_t *tsd;
   2036 	void *p;
   2037 	size_t usize;
   2038 
   2039 	assert(size != 0);
   2040 
   2041 	if (unlikely(malloc_init()))
   2042 		goto label_oom;
   2043 	tsd = tsd_fetch();
   2044 
   2045 	if (config_prof && opt_prof)
   2046 		p = imallocx_prof(tsd, size, flags, &usize);
   2047 	else
   2048 		p = imallocx_no_prof(tsd, size, flags, &usize);
   2049 	if (unlikely(p == NULL))
   2050 		goto label_oom;
   2051 
   2052 	if (config_stats) {
   2053 		assert(usize == isalloc(p, config_prof));
   2054 		*tsd_thread_allocatedp_get(tsd) += usize;
   2055 	}
   2056 	UTRACE(0, size, p);
   2057 	JEMALLOC_VALGRIND_MALLOC(true, p, usize, MALLOCX_ZERO_GET(flags));
   2058 	return (p);
   2059 label_oom:
   2060 	if (config_xmalloc && unlikely(opt_xmalloc)) {
   2061 		malloc_write("<jemalloc>: Error in mallocx(): out of memory\n");
   2062 		abort();
   2063 	}
   2064 	UTRACE(0, size, 0);
   2065 	return (NULL);
   2066 }
   2067 
   2068 static void *
   2069 irallocx_prof_sample(tsd_t *tsd, void *oldptr, size_t old_usize, size_t size,
   2070     size_t alignment, size_t usize, bool zero, tcache_t *tcache, arena_t *arena,
   2071     prof_tctx_t *tctx)
   2072 {
   2073 	void *p;
   2074 
   2075 	if (tctx == NULL)
   2076 		return (NULL);
   2077 	if (usize <= SMALL_MAXCLASS) {
   2078 		p = iralloct(tsd, oldptr, old_usize, LARGE_MINCLASS, alignment,
   2079 		    zero, tcache, arena);
   2080 		if (p == NULL)
   2081 			return (NULL);
   2082 		arena_prof_promoted(p, usize);
   2083 	} else {
   2084 		p = iralloct(tsd, oldptr, old_usize, size, alignment, zero,
   2085 		    tcache, arena);
   2086 	}
   2087 
   2088 	return (p);
   2089 }
   2090 
   2091 JEMALLOC_ALWAYS_INLINE_C void *
   2092 irallocx_prof(tsd_t *tsd, void *oldptr, size_t old_usize, size_t size,
   2093     size_t alignment, size_t *usize, bool zero, tcache_t *tcache,
   2094     arena_t *arena)
   2095 {
   2096 	void *p;
   2097 	prof_tctx_t *old_tctx, *tctx;
   2098 
   2099 	old_tctx = prof_tctx_get(oldptr);
   2100 	tctx = prof_alloc_prep(tsd, *usize, false);
   2101 	if (unlikely((uintptr_t)tctx != (uintptr_t)1U)) {
   2102 		p = irallocx_prof_sample(tsd, oldptr, old_usize, size,
   2103 		    alignment, *usize, zero, tcache, arena, tctx);
   2104 	} else {
   2105 		p = iralloct(tsd, oldptr, old_usize, size, alignment, zero,
   2106 		    tcache, arena);
   2107 	}
   2108 	if (unlikely(p == NULL)) {
   2109 		prof_alloc_rollback(tsd, tctx, false);
   2110 		return (NULL);
   2111 	}
   2112 
   2113 	if (p == oldptr && alignment != 0) {
   2114 		/*
   2115 		 * The allocation did not move, so it is possible that the size
   2116 		 * class is smaller than would guarantee the requested
   2117 		 * alignment, and that the alignment constraint was
   2118 		 * serendipitously satisfied.  Additionally, old_usize may not
   2119 		 * be the same as the current usize because of in-place large
   2120 		 * reallocation.  Therefore, query the actual value of usize.
   2121 		 */
   2122 		*usize = isalloc(p, config_prof);
   2123 	}
   2124 	prof_realloc(tsd, p, *usize, tctx, false, old_usize, old_tctx);
   2125 
   2126 	return (p);
   2127 }
   2128 
   2129 void *
   2130 je_rallocx(void *ptr, size_t size, int flags)
   2131 {
   2132 	void *p;
   2133 	tsd_t *tsd;
   2134 	size_t usize;
   2135 	size_t old_usize;
   2136 	UNUSED size_t old_rzsize JEMALLOC_CC_SILENCE_INIT(0);
   2137 	size_t alignment = MALLOCX_ALIGN_GET(flags);
   2138 	bool zero = flags & MALLOCX_ZERO;
   2139 	arena_t *arena;
   2140 	tcache_t *tcache;
   2141 
   2142 	assert(ptr != NULL);
   2143 	assert(size != 0);
   2144 	assert(malloc_initialized() || IS_INITIALIZER);
   2145 	malloc_thread_init();
   2146 	tsd = tsd_fetch();
   2147 
   2148 	if (unlikely((flags & MALLOCX_ARENA_MASK) != 0)) {
   2149 		unsigned arena_ind = MALLOCX_ARENA_GET(flags);
   2150 		arena = arena_get(tsd, arena_ind, true, true);
   2151 		if (unlikely(arena == NULL))
   2152 			goto label_oom;
   2153 	} else
   2154 		arena = NULL;
   2155 
   2156 	if (unlikely((flags & MALLOCX_TCACHE_MASK) != 0)) {
   2157 		if ((flags & MALLOCX_TCACHE_MASK) == MALLOCX_TCACHE_NONE)
   2158 			tcache = NULL;
   2159 		else
   2160 			tcache = tcaches_get(tsd, MALLOCX_TCACHE_GET(flags));
   2161 	} else
   2162 		tcache = tcache_get(tsd, true);
   2163 
   2164 	old_usize = isalloc(ptr, config_prof);
   2165 	if (config_valgrind && unlikely(in_valgrind))
   2166 		old_rzsize = u2rz(old_usize);
   2167 
   2168 	if (config_prof && opt_prof) {
   2169 		usize = (alignment == 0) ? s2u(size) : sa2u(size, alignment);
   2170 		assert(usize != 0);
   2171 		p = irallocx_prof(tsd, ptr, old_usize, size, alignment, &usize,
   2172 		    zero, tcache, arena);
   2173 		if (unlikely(p == NULL))
   2174 			goto label_oom;
   2175 	} else {
   2176 		p = iralloct(tsd, ptr, old_usize, size, alignment, zero,
   2177 		     tcache, arena);
   2178 		if (unlikely(p == NULL))
   2179 			goto label_oom;
   2180 		if (config_stats || (config_valgrind && unlikely(in_valgrind)))
   2181 			usize = isalloc(p, config_prof);
   2182 	}
   2183 
   2184 	if (config_stats) {
   2185 		*tsd_thread_allocatedp_get(tsd) += usize;
   2186 		*tsd_thread_deallocatedp_get(tsd) += old_usize;
   2187 	}
   2188 	UTRACE(ptr, size, p);
   2189 	JEMALLOC_VALGRIND_REALLOC(true, p, usize, false, ptr, old_usize,
   2190 	    old_rzsize, false, zero);
   2191 	return (p);
   2192 label_oom:
   2193 	if (config_xmalloc && unlikely(opt_xmalloc)) {
   2194 		malloc_write("<jemalloc>: Error in rallocx(): out of memory\n");
   2195 		abort();
   2196 	}
   2197 	UTRACE(ptr, size, 0);
   2198 	return (NULL);
   2199 }
   2200 
   2201 JEMALLOC_ALWAYS_INLINE_C size_t
   2202 ixallocx_helper(void *ptr, size_t old_usize, size_t size, size_t extra,
   2203     size_t alignment, bool zero)
   2204 {
   2205 	size_t usize;
   2206 
   2207 	if (ixalloc(ptr, old_usize, size, extra, alignment, zero))
   2208 		return (old_usize);
   2209 	usize = isalloc(ptr, config_prof);
   2210 
   2211 	return (usize);
   2212 }
   2213 
   2214 static size_t
   2215 ixallocx_prof_sample(void *ptr, size_t old_usize, size_t size, size_t extra,
   2216     size_t alignment, size_t max_usize, bool zero, prof_tctx_t *tctx)
   2217 {
   2218 	size_t usize;
   2219 
   2220 	if (tctx == NULL)
   2221 		return (old_usize);
   2222 	/* Use minimum usize to determine whether promotion may happen. */
   2223 	if (((alignment == 0) ? s2u(size) : sa2u(size, alignment)) <=
   2224 	    SMALL_MAXCLASS) {
   2225 		if (ixalloc(ptr, old_usize, SMALL_MAXCLASS+1,
   2226 		    (SMALL_MAXCLASS+1 >= size+extra) ? 0 : size+extra -
   2227 		    (SMALL_MAXCLASS+1), alignment, zero))
   2228 			return (old_usize);
   2229 		usize = isalloc(ptr, config_prof);
   2230 		if (max_usize < LARGE_MINCLASS)
   2231 			arena_prof_promoted(ptr, usize);
   2232 	} else {
   2233 		usize = ixallocx_helper(ptr, old_usize, size, extra, alignment,
   2234 		    zero);
   2235 	}
   2236 
   2237 	return (usize);
   2238 }
   2239 
   2240 JEMALLOC_ALWAYS_INLINE_C size_t
   2241 ixallocx_prof(tsd_t *tsd, void *ptr, size_t old_usize, size_t size,
   2242     size_t extra, size_t alignment, bool zero)
   2243 {
   2244 	size_t max_usize, usize;
   2245 	prof_tctx_t *old_tctx, *tctx;
   2246 
   2247 	old_tctx = prof_tctx_get(ptr);
   2248 	/*
   2249 	 * usize isn't knowable before ixalloc() returns when extra is non-zero.
   2250 	 * Therefore, compute its maximum possible value and use that in
   2251 	 * prof_alloc_prep() to decide whether to capture a backtrace.
   2252 	 * prof_realloc() will use the actual usize to decide whether to sample.
   2253 	 */
   2254 	max_usize = (alignment == 0) ? s2u(size+extra) : sa2u(size+extra,
   2255 	    alignment);
   2256 	tctx = prof_alloc_prep(tsd, max_usize, false);
   2257 	if (unlikely((uintptr_t)tctx != (uintptr_t)1U)) {
   2258 		usize = ixallocx_prof_sample(ptr, old_usize, size, extra,
   2259 		    alignment, zero, max_usize, tctx);
   2260 	} else {
   2261 		usize = ixallocx_helper(ptr, old_usize, size, extra, alignment,
   2262 		    zero);
   2263 	}
   2264 	if (unlikely(usize == old_usize)) {
   2265 		prof_alloc_rollback(tsd, tctx, false);
   2266 		return (usize);
   2267 	}
   2268 	prof_realloc(tsd, ptr, usize, tctx, false, old_usize, old_tctx);
   2269 
   2270 	return (usize);
   2271 }
   2272 
   2273 size_t
   2274 je_xallocx(void *ptr, size_t size, size_t extra, int flags)
   2275 {
   2276 	tsd_t *tsd;
   2277 	size_t usize, old_usize;
   2278 	UNUSED size_t old_rzsize JEMALLOC_CC_SILENCE_INIT(0);
   2279 	size_t alignment = MALLOCX_ALIGN_GET(flags);
   2280 	bool zero = flags & MALLOCX_ZERO;
   2281 
   2282 	assert(ptr != NULL);
   2283 	assert(size != 0);
   2284 	assert(SIZE_T_MAX - size >= extra);
   2285 	assert(malloc_initialized() || IS_INITIALIZER);
   2286 	malloc_thread_init();
   2287 	tsd = tsd_fetch();
   2288 
   2289 	old_usize = isalloc(ptr, config_prof);
   2290 	if (config_valgrind && unlikely(in_valgrind))
   2291 		old_rzsize = u2rz(old_usize);
   2292 
   2293 	if (config_prof && opt_prof) {
   2294 		usize = ixallocx_prof(tsd, ptr, old_usize, size, extra,
   2295 		    alignment, zero);
   2296 	} else {
   2297 		usize = ixallocx_helper(ptr, old_usize, size, extra, alignment,
   2298 		    zero);
   2299 	}
   2300 	if (unlikely(usize == old_usize))
   2301 		goto label_not_resized;
   2302 
   2303 	if (config_stats) {
   2304 		*tsd_thread_allocatedp_get(tsd) += usize;
   2305 		*tsd_thread_deallocatedp_get(tsd) += old_usize;
   2306 	}
   2307 	JEMALLOC_VALGRIND_REALLOC(false, ptr, usize, false, ptr, old_usize,
   2308 	    old_rzsize, false, zero);
   2309 label_not_resized:
   2310 	UTRACE(ptr, size, ptr);
   2311 	return (usize);
   2312 }
   2313 
   2314 size_t
   2315 je_sallocx(const void *ptr, int flags)
   2316 {
   2317 	size_t usize;
   2318 
   2319 	assert(malloc_initialized() || IS_INITIALIZER);
   2320 	malloc_thread_init();
   2321 
   2322 	if (config_ivsalloc)
   2323 		usize = ivsalloc(ptr, config_prof);
   2324 	else
   2325 		usize = isalloc(ptr, config_prof);
   2326 
   2327 	return (usize);
   2328 }
   2329 
   2330 void
   2331 je_dallocx(void *ptr, int flags)
   2332 {
   2333 	tsd_t *tsd;
   2334 	tcache_t *tcache;
   2335 
   2336 	assert(ptr != NULL);
   2337 	assert(malloc_initialized() || IS_INITIALIZER);
   2338 
   2339 	tsd = tsd_fetch();
   2340 	if (unlikely((flags & MALLOCX_TCACHE_MASK) != 0)) {
   2341 		if ((flags & MALLOCX_TCACHE_MASK) == MALLOCX_TCACHE_NONE)
   2342 			tcache = NULL;
   2343 		else
   2344 			tcache = tcaches_get(tsd, MALLOCX_TCACHE_GET(flags));
   2345 	} else
   2346 		tcache = tcache_get(tsd, false);
   2347 
   2348 	UTRACE(ptr, 0, 0);
   2349 	ifree(tsd_fetch(), ptr, tcache);
   2350 }
   2351 
   2352 JEMALLOC_ALWAYS_INLINE_C size_t
   2353 inallocx(size_t size, int flags)
   2354 {
   2355 	size_t usize;
   2356 
   2357 	if (likely((flags & MALLOCX_LG_ALIGN_MASK) == 0))
   2358 		usize = s2u(size);
   2359 	else
   2360 		usize = sa2u(size, MALLOCX_ALIGN_GET_SPECIFIED(flags));
   2361 	assert(usize != 0);
   2362 	return (usize);
   2363 }
   2364 
   2365 void
   2366 je_sdallocx(void *ptr, size_t size, int flags)
   2367 {
   2368 	tsd_t *tsd;
   2369 	tcache_t *tcache;
   2370 	size_t usize;
   2371 
   2372 	assert(ptr != NULL);
   2373 	assert(malloc_initialized() || IS_INITIALIZER);
   2374 	usize = inallocx(size, flags);
   2375 	assert(usize == isalloc(ptr, config_prof));
   2376 
   2377 	tsd = tsd_fetch();
   2378 	if (unlikely((flags & MALLOCX_TCACHE_MASK) != 0)) {
   2379 		if ((flags & MALLOCX_TCACHE_MASK) == MALLOCX_TCACHE_NONE)
   2380 			tcache = NULL;
   2381 		else
   2382 			tcache = tcaches_get(tsd, MALLOCX_TCACHE_GET(flags));
   2383 	} else
   2384 		tcache = tcache_get(tsd, false);
   2385 
   2386 	UTRACE(ptr, 0, 0);
   2387 	isfree(tsd, ptr, usize, tcache);
   2388 }
   2389 
   2390 size_t
   2391 je_nallocx(size_t size, int flags)
   2392 {
   2393 
   2394 	assert(size != 0);
   2395 
   2396 	if (unlikely(malloc_init()))
   2397 		return (0);
   2398 
   2399 	return (inallocx(size, flags));
   2400 }
   2401 
   2402 int
   2403 je_mallctl(const char *name, void *oldp, size_t *oldlenp, void *newp,
   2404     size_t newlen)
   2405 {
   2406 
   2407 	if (unlikely(malloc_init()))
   2408 		return (EAGAIN);
   2409 
   2410 	return (ctl_byname(name, oldp, oldlenp, newp, newlen));
   2411 }
   2412 
   2413 int
   2414 je_mallctlnametomib(const char *name, size_t *mibp, size_t *miblenp)
   2415 {
   2416 
   2417 	if (unlikely(malloc_init()))
   2418 		return (EAGAIN);
   2419 
   2420 	return (ctl_nametomib(name, mibp, miblenp));
   2421 }
   2422 
   2423 int
   2424 je_mallctlbymib(const size_t *mib, size_t miblen, void *oldp, size_t *oldlenp,
   2425   void *newp, size_t newlen)
   2426 {
   2427 
   2428 	if (unlikely(malloc_init()))
   2429 		return (EAGAIN);
   2430 
   2431 	return (ctl_bymib(mib, miblen, oldp, oldlenp, newp, newlen));
   2432 }
   2433 
   2434 void
   2435 je_malloc_stats_print(void (*write_cb)(void *, const char *), void *cbopaque,
   2436     const char *opts)
   2437 {
   2438 
   2439 	stats_print(write_cb, cbopaque, opts);
   2440 }
   2441 
   2442 size_t
   2443 je_malloc_usable_size(JEMALLOC_USABLE_SIZE_CONST void *ptr)
   2444 {
   2445 	size_t ret;
   2446 
   2447 	assert(malloc_initialized() || IS_INITIALIZER);
   2448 	malloc_thread_init();
   2449 
   2450 	if (config_ivsalloc)
   2451 		ret = ivsalloc(ptr, config_prof);
   2452 	else
   2453 		ret = (ptr == NULL) ? 0 : isalloc(ptr, config_prof);
   2454 
   2455 	return (ret);
   2456 }
   2457 
   2458 /*
   2459  * End non-standard functions.
   2460  */
   2461 /******************************************************************************/
   2462 /*
   2463  * The following functions are used by threading libraries for protection of
   2464  * malloc during fork().
   2465  */
   2466 
   2467 /*
   2468  * If an application creates a thread before doing any allocation in the main
   2469  * thread, then calls fork(2) in the main thread followed by memory allocation
   2470  * in the child process, a race can occur that results in deadlock within the
   2471  * child: the main thread may have forked while the created thread had
   2472  * partially initialized the allocator.  Ordinarily jemalloc prevents
   2473  * fork/malloc races via the following functions it registers during
   2474  * initialization using pthread_atfork(), but of course that does no good if
   2475  * the allocator isn't fully initialized at fork time.  The following library
   2476  * constructor is a partial solution to this problem.  It may still be possible
   2477  * to trigger the deadlock described above, but doing so would involve forking
   2478  * via a library constructor that runs before jemalloc's runs.
   2479  */
   2480 JEMALLOC_ATTR(constructor)
   2481 static void
   2482 jemalloc_constructor(void)
   2483 {
   2484 
   2485 	malloc_init();
   2486 }
   2487 
   2488 #ifndef JEMALLOC_MUTEX_INIT_CB
   2489 void
   2490 jemalloc_prefork(void)
   2491 #else
   2492 JEMALLOC_EXPORT void
   2493 _malloc_prefork(void)
   2494 #endif
   2495 {
   2496 	unsigned i;
   2497 
   2498 #ifdef JEMALLOC_MUTEX_INIT_CB
   2499 	if (!malloc_initialized())
   2500 		return;
   2501 #endif
   2502 	assert(malloc_initialized());
   2503 
   2504 	/* Acquire all mutexes in a safe order. */
   2505 	ctl_prefork();
   2506 	prof_prefork();
   2507 	malloc_mutex_prefork(&arenas_lock);
   2508 	for (i = 0; i < narenas_total; i++) {
   2509 		if (arenas[i] != NULL)
   2510 			arena_prefork(arenas[i]);
   2511 	}
   2512 	chunk_prefork();
   2513 	base_prefork();
   2514 }
   2515 
   2516 #ifndef JEMALLOC_MUTEX_INIT_CB
   2517 void
   2518 jemalloc_postfork_parent(void)
   2519 #else
   2520 JEMALLOC_EXPORT void
   2521 _malloc_postfork(void)
   2522 #endif
   2523 {
   2524 	unsigned i;
   2525 
   2526 #ifdef JEMALLOC_MUTEX_INIT_CB
   2527 	if (!malloc_initialized())
   2528 		return;
   2529 #endif
   2530 	assert(malloc_initialized());
   2531 
   2532 	/* Release all mutexes, now that fork() has completed. */
   2533 	base_postfork_parent();
   2534 	chunk_postfork_parent();
   2535 	for (i = 0; i < narenas_total; i++) {
   2536 		if (arenas[i] != NULL)
   2537 			arena_postfork_parent(arenas[i]);
   2538 	}
   2539 	malloc_mutex_postfork_parent(&arenas_lock);
   2540 	prof_postfork_parent();
   2541 	ctl_postfork_parent();
   2542 }
   2543 
   2544 void
   2545 jemalloc_postfork_child(void)
   2546 {
   2547 	unsigned i;
   2548 
   2549 	assert(malloc_initialized());
   2550 
   2551 	/* Release all mutexes, now that fork() has completed. */
   2552 	base_postfork_child();
   2553 	chunk_postfork_child();
   2554 	for (i = 0; i < narenas_total; i++) {
   2555 		if (arenas[i] != NULL)
   2556 			arena_postfork_child(arenas[i]);
   2557 	}
   2558 	malloc_mutex_postfork_child(&arenas_lock);
   2559 	prof_postfork_child();
   2560 	ctl_postfork_child();
   2561 }
   2562 
   2563 /******************************************************************************/
   2564 
   2565 /* ANDROID change */
   2566 /* This is an implementation that uses the same arena access pattern found
   2567  * in the arena_stats_merge function from src/arena.c.
   2568  */
   2569 struct mallinfo je_mallinfo() {
   2570   struct mallinfo mi;
   2571   memset(&mi, 0, sizeof(mi));
   2572 
   2573   malloc_mutex_lock(&arenas_lock);
   2574   for (unsigned i = 0; i < narenas_auto; i++) {
   2575     if (arenas[i] != NULL) {
   2576       malloc_mutex_lock(&arenas[i]->lock);
   2577       mi.hblkhd += arenas[i]->stats.mapped;
   2578       mi.uordblks += arenas[i]->stats.allocated_large;
   2579       mi.uordblks += arenas[i]->stats.allocated_huge;
   2580       malloc_mutex_unlock(&arenas[i]->lock);
   2581 
   2582       for (unsigned j = 0; j < NBINS; j++) {
   2583         arena_bin_t* bin = &arenas[i]->bins[j];
   2584 
   2585         malloc_mutex_lock(&bin->lock);
   2586         mi.uordblks += arena_bin_info[j].reg_size * bin->stats.curregs;
   2587         malloc_mutex_unlock(&bin->lock);
   2588       }
   2589     }
   2590   }
   2591   malloc_mutex_unlock(&arenas_lock);
   2592   mi.fordblks = mi.hblkhd - mi.uordblks;
   2593   mi.usmblks = mi.hblkhd;
   2594   return mi;
   2595 }
   2596 
   2597 size_t __mallinfo_narenas() {
   2598   return narenas_auto;
   2599 }
   2600 
   2601 size_t __mallinfo_nbins() {
   2602   return NBINS;
   2603 }
   2604 
   2605 struct mallinfo __mallinfo_arena_info(size_t aidx) {
   2606   struct mallinfo mi;
   2607   memset(&mi, 0, sizeof(mi));
   2608 
   2609   malloc_mutex_lock(&arenas_lock);
   2610   if (aidx < narenas_auto) {
   2611     if (arenas[aidx] != NULL) {
   2612       malloc_mutex_lock(&arenas[aidx]->lock);
   2613       mi.hblkhd = arenas[aidx]->stats.mapped;
   2614       mi.ordblks = arenas[aidx]->stats.allocated_large;
   2615       mi.uordblks = arenas[aidx]->stats.allocated_huge;
   2616       malloc_mutex_unlock(&arenas[aidx]->lock);
   2617 
   2618       for (unsigned j = 0; j < NBINS; j++) {
   2619         arena_bin_t* bin = &arenas[aidx]->bins[j];
   2620 
   2621         malloc_mutex_lock(&bin->lock);
   2622         mi.fsmblks += arena_bin_info[j].reg_size * bin->stats.curregs;
   2623         malloc_mutex_unlock(&bin->lock);
   2624       }
   2625     }
   2626   }
   2627   malloc_mutex_unlock(&arenas_lock);
   2628   return mi;
   2629 }
   2630 
   2631 struct mallinfo __mallinfo_bin_info(size_t aidx, size_t bidx) {
   2632   struct mallinfo mi;
   2633   memset(&mi, 0, sizeof(mi));
   2634 
   2635   malloc_mutex_lock(&arenas_lock);
   2636   if (aidx < narenas_auto && bidx < NBINS) {
   2637     if (arenas[aidx] != NULL) {
   2638       arena_bin_t* bin = &arenas[aidx]->bins[bidx];
   2639 
   2640       malloc_mutex_lock(&bin->lock);
   2641       mi.ordblks = arena_bin_info[bidx].reg_size * bin->stats.curregs;
   2642       mi.uordblks = bin->stats.nmalloc;
   2643       mi.fordblks = bin->stats.ndalloc;
   2644       malloc_mutex_unlock(&bin->lock);
   2645     }
   2646   }
   2647   malloc_mutex_unlock(&arenas_lock);
   2648   return mi;
   2649 }
   2650 /* End ANDROID change */
   2651