xref: /netbsd-src/lib/libc/stdlib/jemalloc.c (revision 6b3ee451d673206ed73793bef5f2afc789a14c6b)
1*6b3ee451Smrg /*	$NetBSD: jemalloc.c,v 1.64 2023/12/13 23:53:50 mrg Exp $	*/
2e7a9e46bSad 
38a475bcbSad /*-
48a475bcbSad  * Copyright (C) 2006,2007 Jason Evans <jasone@FreeBSD.org>.
5562025fdSad  * Copyright (C) 2023 Andrew Doran <ad@NetBSD.org>.
68a475bcbSad  * All rights reserved.
78a475bcbSad  *
88a475bcbSad  * Redistribution and use in source and binary forms, with or without
98a475bcbSad  * modification, are permitted provided that the following conditions
108a475bcbSad  * are met:
118a475bcbSad  * 1. Redistributions of source code must retain the above copyright
128a475bcbSad  *    notice(s), this list of conditions and the following disclaimer as
138a475bcbSad  *    the first lines of this file unmodified other than the possible
148a475bcbSad  *    addition of one or more copyright notices.
158a475bcbSad  * 2. Redistributions in binary form must reproduce the above copyright
168a475bcbSad  *    notice(s), this list of conditions and the following disclaimer in
178a475bcbSad  *    the documentation and/or other materials provided with the
188a475bcbSad  *    distribution.
198a475bcbSad  *
208a475bcbSad  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY
218a475bcbSad  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
228a475bcbSad  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
238a475bcbSad  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) BE
248a475bcbSad  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
258a475bcbSad  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
268a475bcbSad  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
278a475bcbSad  * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
288a475bcbSad  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
298a475bcbSad  * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
308a475bcbSad  * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
318a475bcbSad  *
328a475bcbSad  *******************************************************************************
338a475bcbSad  *
348a475bcbSad  * This allocator implementation is designed to provide scalable performance
358a475bcbSad  * for multi-threaded programs on multi-processor systems.  The following
368a475bcbSad  * features are included for this purpose:
378a475bcbSad  *
388a475bcbSad  *   + Multiple arenas are used if there are multiple CPUs, which reduces lock
398a475bcbSad  *     contention and cache sloshing.
408a475bcbSad  *
418a475bcbSad  *   + Cache line sharing between arenas is avoided for internal data
428a475bcbSad  *     structures.
438a475bcbSad  *
448a475bcbSad  *   + Memory is managed in chunks and runs (chunks can be split into runs),
458a475bcbSad  *     rather than as individual pages.  This provides a constant-time
468a475bcbSad  *     mechanism for associating allocations with particular arenas.
478a475bcbSad  *
488a475bcbSad  * Allocation requests are rounded up to the nearest size class, and no record
498a475bcbSad  * of the original request size is maintained.  Allocations are broken into
508a475bcbSad  * categories according to size class.  Assuming runtime defaults, 4 kB pages
518a475bcbSad  * and a 16 byte quantum, the size classes in each category are as follows:
528a475bcbSad  *
538a475bcbSad  *   |=====================================|
548a475bcbSad  *   | Category | Subcategory    |    Size |
558a475bcbSad  *   |=====================================|
568a475bcbSad  *   | Small    | Tiny           |       2 |
578a475bcbSad  *   |          |                |       4 |
588a475bcbSad  *   |          |                |       8 |
598a475bcbSad  *   |          |----------------+---------|
608a475bcbSad  *   |          | Quantum-spaced |      16 |
618a475bcbSad  *   |          |                |      32 |
628a475bcbSad  *   |          |                |      48 |
638a475bcbSad  *   |          |                |     ... |
648a475bcbSad  *   |          |                |     480 |
658a475bcbSad  *   |          |                |     496 |
668a475bcbSad  *   |          |                |     512 |
678a475bcbSad  *   |          |----------------+---------|
688a475bcbSad  *   |          | Sub-page       |    1 kB |
698a475bcbSad  *   |          |                |    2 kB |
708a475bcbSad  *   |=====================================|
718a475bcbSad  *   | Large                     |    4 kB |
728a475bcbSad  *   |                           |    8 kB |
738a475bcbSad  *   |                           |   12 kB |
748a475bcbSad  *   |                           |     ... |
758a475bcbSad  *   |                           | 1012 kB |
768a475bcbSad  *   |                           | 1016 kB |
778a475bcbSad  *   |                           | 1020 kB |
788a475bcbSad  *   |=====================================|
798a475bcbSad  *   | Huge                      |    1 MB |
808a475bcbSad  *   |                           |    2 MB |
818a475bcbSad  *   |                           |    3 MB |
828a475bcbSad  *   |                           |     ... |
838a475bcbSad  *   |=====================================|
848a475bcbSad  *
858a475bcbSad  * A different mechanism is used for each category:
868a475bcbSad  *
878a475bcbSad  *   Small : Each size class is segregated into its own set of runs.  Each run
888a475bcbSad  *           maintains a bitmap of which regions are free/allocated.
898a475bcbSad  *
908a475bcbSad  *   Large : Each allocation is backed by a dedicated run.  Metadata are stored
918a475bcbSad  *           in the associated arena chunk header maps.
928a475bcbSad  *
938a475bcbSad  *   Huge : Each allocation is backed by a dedicated contiguous set of chunks.
948a475bcbSad  *          Metadata are stored in a separate red-black tree.
958a475bcbSad  *
968a475bcbSad  *******************************************************************************
978a475bcbSad  */
988a475bcbSad 
99e7a9e46bSad /* LINTLIBRARY */
100e7a9e46bSad 
1018a475bcbSad /*
1028a475bcbSad  * MALLOC_PRODUCTION disables assertions and statistics gathering.  It also
1038a475bcbSad  * defaults the A and J runtime options to off.  These settings are appropriate
1048a475bcbSad  * for production systems.
1058a475bcbSad  */
106e7a9e46bSad #define MALLOC_PRODUCTION
1078a475bcbSad 
1088a475bcbSad #ifndef MALLOC_PRODUCTION
1098a475bcbSad #  define MALLOC_DEBUG
1108a475bcbSad #endif
1118a475bcbSad 
1128a475bcbSad #include <sys/cdefs.h>
113e7a9e46bSad /* __FBSDID("$FreeBSD: src/lib/libc/stdlib/malloc.c,v 1.147 2007/06/15 22:00:16 jasone Exp $"); */
114*6b3ee451Smrg __RCSID("$NetBSD: jemalloc.c,v 1.64 2023/12/13 23:53:50 mrg Exp $");
1158a475bcbSad 
1168a475bcbSad #include "namespace.h"
1178a475bcbSad #include <sys/mman.h>
1188a475bcbSad #include <sys/param.h>
1198a475bcbSad #include <sys/time.h>
1208a475bcbSad #include <sys/types.h>
1218a475bcbSad #include <sys/sysctl.h>
122562025fdSad #include <sys/rbtree.h>
1238a475bcbSad #include <sys/uio.h>
1248a475bcbSad #include <sys/ktrace.h> /* Must come after several other sys/ includes. */
1258a475bcbSad 
1268a475bcbSad #include <errno.h>
1278a475bcbSad #include <limits.h>
1288a475bcbSad #include <pthread.h>
1298a475bcbSad #include <sched.h>
1308a475bcbSad #include <stdarg.h>
1318a475bcbSad #include <stdbool.h>
1328a475bcbSad #include <stdio.h>
1338a475bcbSad #include <stdint.h>
1348a475bcbSad #include <stdlib.h>
1358a475bcbSad #include <string.h>
1368a475bcbSad #include <strings.h>
1378a475bcbSad #include <unistd.h>
138*6b3ee451Smrg #include <malloc.h>
1398a475bcbSad 
140e7a9e46bSad #include <reentrant.h>
14186ef91b8Schristos #include "extern.h"
14286ef91b8Schristos 
1430a20cdb1Schristos #define STRERROR_R(a, b, c)	strerror_r_ss(a, b, c);
1448a475bcbSad 
1458a475bcbSad /* MALLOC_STATS enables statistics calculation. */
1468a475bcbSad #ifndef MALLOC_PRODUCTION
1478a475bcbSad #  define MALLOC_STATS
1488a475bcbSad #endif
1498a475bcbSad 
1508a475bcbSad #ifdef MALLOC_DEBUG
1518a475bcbSad #  ifdef NDEBUG
1528a475bcbSad #    undef NDEBUG
1538a475bcbSad #  endif
1548a475bcbSad #else
1558a475bcbSad #  ifndef NDEBUG
1568a475bcbSad #    define NDEBUG
1578a475bcbSad #  endif
1588a475bcbSad #endif
1598a475bcbSad #include <assert.h>
1608a475bcbSad 
1618a475bcbSad #ifdef MALLOC_DEBUG
1628a475bcbSad    /* Disable inlining to make debugging easier. */
1638a475bcbSad #  define inline
1648a475bcbSad #endif
1658a475bcbSad 
166562025fdSad /*
167562025fdSad  * Compare two pointers of 64/32 bit width and produce a ternary 32-bit
168562025fdSad  * indicator without using conditionals that maintains the expected
169562025fdSad  * ordering: [negative, equal, positive].
170562025fdSad  *
171562025fdSad  * XXX it depends on twos complement arithemetic.
172562025fdSad  * XXX maybe should be a built-in for rbtree?
173562025fdSad  */
174562025fdSad static inline int
ptrcmp(const void * pa,const void * pb)175562025fdSad ptrcmp(const void *pa, const void *pb)
176562025fdSad {
177562025fdSad #ifdef _LP64
178a52713e5Sad 	const uintptr_t a = (uintptr_t)pa, b = (uintptr_t)pb;
179a52713e5Sad 	const uintptr_t diff = a - b;
180562025fdSad 	assert(((a | b) & 1) == 0);
181a52713e5Sad 	return (int)(diff >> 32) | ((unsigned)diff >> 1);
182562025fdSad #else
183744309c5Smrg 	return (intptr_t)pa - (intptr_t)pb;
184562025fdSad #endif
185562025fdSad }
186562025fdSad 
1878a475bcbSad /* Size of stack-allocated buffer passed to strerror_r(). */
1888a475bcbSad #define	STRERROR_BUF		64
1898a475bcbSad 
1908a475bcbSad /* Minimum alignment of allocations is 2^QUANTUM_2POW_MIN bytes. */
191ce92aca1Smartin 
192ce92aca1Smartin /*
193ce92aca1Smartin  * If you touch the TINY_MIN_2POW definition for any architecture, please
194ce92aca1Smartin  * make sure to adjust the corresponding definition for JEMALLOC_TINY_MIN_2POW
195ce92aca1Smartin  * in the gcc 4.8 tree in dist/gcc/tree-ssa-ccp.c and verify that a native
196ce92aca1Smartin  * gcc is still buildable!
197ce92aca1Smartin  */
198ce92aca1Smartin 
1998a475bcbSad #ifdef __i386__
2008a475bcbSad #  define QUANTUM_2POW_MIN	4
2018a475bcbSad #  define SIZEOF_PTR_2POW	2
2028a475bcbSad #  define USE_BRK
2038a475bcbSad #endif
2048a475bcbSad #ifdef __ia64__
2058a475bcbSad #  define QUANTUM_2POW_MIN	4
2068a475bcbSad #  define SIZEOF_PTR_2POW	3
2078a475bcbSad #endif
208547b3a3bSmatt #ifdef __aarch64__
209547b3a3bSmatt #  define QUANTUM_2POW_MIN	4
210547b3a3bSmatt #  define SIZEOF_PTR_2POW	3
2112de10fd6Sjoerg #  define TINY_MIN_2POW		3
212547b3a3bSmatt #endif
2138a475bcbSad #ifdef __alpha__
2148a475bcbSad #  define QUANTUM_2POW_MIN	4
2158a475bcbSad #  define SIZEOF_PTR_2POW	3
21603dbd387Sskrll #  define TINY_MIN_2POW		3
2178a475bcbSad #endif
2188a475bcbSad #ifdef __sparc64__
2198a475bcbSad #  define QUANTUM_2POW_MIN	4
2208a475bcbSad #  define SIZEOF_PTR_2POW	3
221ce92aca1Smartin #  define TINY_MIN_2POW		3
2228a475bcbSad #endif
2238a475bcbSad #ifdef __amd64__
2248a475bcbSad #  define QUANTUM_2POW_MIN	4
2258a475bcbSad #  define SIZEOF_PTR_2POW	3
226ce92aca1Smartin #  define TINY_MIN_2POW		3
2278a475bcbSad #endif
2288a475bcbSad #ifdef __arm__
2298a475bcbSad #  define QUANTUM_2POW_MIN	3
2308a475bcbSad #  define SIZEOF_PTR_2POW	2
2318a475bcbSad #  define USE_BRK
23203dbd387Sskrll #  ifdef __ARM_EABI__
23303dbd387Sskrll #    define TINY_MIN_2POW	3
23403dbd387Sskrll #  endif
2358a475bcbSad #endif
2368a475bcbSad #ifdef __powerpc__
2378a475bcbSad #  define QUANTUM_2POW_MIN	4
2388a475bcbSad #  define SIZEOF_PTR_2POW	2
2398a475bcbSad #  define USE_BRK
240b67fdf35Smartin #  define TINY_MIN_2POW		3
2418a475bcbSad #endif
2427ed9cc8eShe #if defined(__sparc__) && !defined(__sparc64__)
243e7a9e46bSad #  define QUANTUM_2POW_MIN	4
244e7a9e46bSad #  define SIZEOF_PTR_2POW	2
245e7a9e46bSad #  define USE_BRK
246e7a9e46bSad #endif
247623c8b30Smatt #ifdef __or1k__
248623c8b30Smatt #  define QUANTUM_2POW_MIN	4
249623c8b30Smatt #  define SIZEOF_PTR_2POW	2
250623c8b30Smatt #  define USE_BRK
251623c8b30Smatt #endif
252e7a9e46bSad #ifdef __vax__
253e7a9e46bSad #  define QUANTUM_2POW_MIN	4
254e7a9e46bSad #  define SIZEOF_PTR_2POW	2
255e7a9e46bSad #  define USE_BRK
256e7a9e46bSad #endif
257e7a9e46bSad #ifdef __sh__
258e7a9e46bSad #  define QUANTUM_2POW_MIN	4
259e7a9e46bSad #  define SIZEOF_PTR_2POW	2
260e7a9e46bSad #  define USE_BRK
261e7a9e46bSad #endif
262e7a9e46bSad #ifdef __m68k__
263e7a9e46bSad #  define QUANTUM_2POW_MIN	4
264e7a9e46bSad #  define SIZEOF_PTR_2POW	2
265e7a9e46bSad #  define USE_BRK
266e7a9e46bSad #endif
26775b842b8Sskrll #if defined(__mips__)
2680a0fe53eSmatt #  ifdef _LP64
2690a0fe53eSmatt #    define SIZEOF_PTR_2POW	3
2700a0fe53eSmatt #    define TINY_MIN_2POW	3
2710a0fe53eSmatt #  else
272e7a9e46bSad #    define SIZEOF_PTR_2POW	2
2730a0fe53eSmatt #  endif
2740a0fe53eSmatt #  define QUANTUM_2POW_MIN	4
275e7a9e46bSad #  define USE_BRK
276e7a9e46bSad #endif
27775b842b8Sskrll #if defined(__riscv__)
27875b842b8Sskrll #  ifdef _LP64
27975b842b8Sskrll #    define SIZEOF_PTR_2POW	3
28075b842b8Sskrll #    define TINY_MIN_2POW	3
28175b842b8Sskrll #  else
28275b842b8Sskrll #    define SIZEOF_PTR_2POW	2
28375b842b8Sskrll #  endif
28475b842b8Sskrll #  define QUANTUM_2POW_MIN	4
28575b842b8Sskrll #  define USE_BRK
28675b842b8Sskrll #endif
2873465d8dbSad #ifdef __hppa__
2883465d8dbSad #  define QUANTUM_2POW_MIN	4
289f9ef5aa2Sskrll #  define TINY_MIN_2POW		4
2903465d8dbSad #  define SIZEOF_PTR_2POW	2
2913465d8dbSad #  define USE_BRK
2923465d8dbSad #endif
2938a475bcbSad 
2948a475bcbSad #define	SIZEOF_PTR		(1 << SIZEOF_PTR_2POW)
2958a475bcbSad 
2968a475bcbSad /* sizeof(int) == (1 << SIZEOF_INT_2POW). */
2978a475bcbSad #ifndef SIZEOF_INT_2POW
2988a475bcbSad #  define SIZEOF_INT_2POW	2
2998a475bcbSad #endif
3008a475bcbSad 
3018a475bcbSad /*
3028a475bcbSad  * Size and alignment of memory chunks that are allocated by the OS's virtual
3038a475bcbSad  * memory system.
3048a475bcbSad  */
3058a475bcbSad #define	CHUNK_2POW_DEFAULT	20
3068a475bcbSad 
3078a475bcbSad /*
3088a475bcbSad  * Maximum size of L1 cache line.  This is used to avoid cache line aliasing,
3098a475bcbSad  * so over-estimates are okay (up to a point), but under-estimates will
3108a475bcbSad  * negatively affect performance.
3118a475bcbSad  */
3128a475bcbSad #define	CACHELINE_2POW		6
3138a475bcbSad #define	CACHELINE		((size_t)(1 << CACHELINE_2POW))
3148a475bcbSad 
3158a475bcbSad /* Smallest size class to support. */
31603dbd387Sskrll #ifndef TINY_MIN_2POW
31703dbd387Sskrll #define	TINY_MIN_2POW		2
31803dbd387Sskrll #endif
3198a475bcbSad 
3208a475bcbSad /*
3218a475bcbSad  * Maximum size class that is a multiple of the quantum, but not (necessarily)
3228a475bcbSad  * a power of 2.  Above this size, allocations are rounded up to the nearest
3238a475bcbSad  * power of 2.
3248a475bcbSad  */
3258a475bcbSad #define	SMALL_MAX_2POW_DEFAULT	9
3268a475bcbSad #define	SMALL_MAX_DEFAULT	(1 << SMALL_MAX_2POW_DEFAULT)
3278a475bcbSad 
3288a475bcbSad /*
32951cca89dSnjoly  * RUN_MAX_OVRHD indicates maximum desired run header overhead.  Runs are sized
33051cca89dSnjoly  * as small as possible such that this setting is still honored, without
33151cca89dSnjoly  * violating other constraints.  The goal is to make runs as small as possible
33251cca89dSnjoly  * without exceeding a per run external fragmentation threshold.
3338a475bcbSad  *
33451cca89dSnjoly  * We use binary fixed point math for overhead computations, where the binary
33551cca89dSnjoly  * point is implicitly RUN_BFP bits to the left.
3368a475bcbSad  *
33751cca89dSnjoly  * Note that it is possible to set RUN_MAX_OVRHD low enough that it cannot be
33851cca89dSnjoly  * honored for some/all object sizes, since there is one bit of header overhead
33951cca89dSnjoly  * per object (plus a constant).  This constraint is relaxed (ignored) for runs
34051cca89dSnjoly  * that are so small that the per-region overhead is greater than:
34151cca89dSnjoly  *
34251cca89dSnjoly  *   (RUN_MAX_OVRHD / (reg_size << (3+RUN_BFP))
3438a475bcbSad  */
34451cca89dSnjoly #define RUN_BFP			12
34551cca89dSnjoly /*                              \/   Implicit binary fixed point. */
34651cca89dSnjoly #define RUN_MAX_OVRHD		0x0000003dU
34751cca89dSnjoly #define RUN_MAX_OVRHD_RELAX	0x00001800U
3488a475bcbSad 
3498a475bcbSad /* Put a cap on small object run size.  This overrides RUN_MAX_OVRHD. */
3508a475bcbSad #define RUN_MAX_SMALL_2POW	15
3518a475bcbSad #define RUN_MAX_SMALL		(1 << RUN_MAX_SMALL_2POW)
3528a475bcbSad 
3538a475bcbSad /******************************************************************************/
3548a475bcbSad 
355e7a9e46bSad #define	malloc_mutex_t	mutex_t
356e7a9e46bSad 
357e7a9e46bSad /* Set to true once the allocator has been initialized. */
358e7a9e46bSad static bool malloc_initialized = false;
359e7a9e46bSad 
36026ba8048Schristos #ifdef _REENTRANT
361e7a9e46bSad /* Used to avoid initialization races. */
362e7a9e46bSad static mutex_t init_lock = MUTEX_INITIALIZER;
363e7a9e46bSad #endif
3648a475bcbSad 
3658a475bcbSad /******************************************************************************/
3668a475bcbSad /*
3678a475bcbSad  * Statistics data structures.
3688a475bcbSad  */
3698a475bcbSad 
3708a475bcbSad #ifdef MALLOC_STATS
3718a475bcbSad 
3728a475bcbSad typedef struct malloc_bin_stats_s malloc_bin_stats_t;
3738a475bcbSad struct malloc_bin_stats_s {
3748a475bcbSad 	/*
3758a475bcbSad 	 * Number of allocation requests that corresponded to the size of this
3768a475bcbSad 	 * bin.
3778a475bcbSad 	 */
3788a475bcbSad 	uint64_t	nrequests;
3798a475bcbSad 
3808a475bcbSad 	/* Total number of runs created for this bin's size class. */
3818a475bcbSad 	uint64_t	nruns;
3828a475bcbSad 
3838a475bcbSad 	/*
3848a475bcbSad 	 * Total number of runs reused by extracting them from the runs tree for
3858a475bcbSad 	 * this bin's size class.
3868a475bcbSad 	 */
3878a475bcbSad 	uint64_t	reruns;
3888a475bcbSad 
3898a475bcbSad 	/* High-water mark for this bin. */
3908a475bcbSad 	unsigned long	highruns;
3918a475bcbSad 
3928a475bcbSad 	/* Current number of runs in this bin. */
3938a475bcbSad 	unsigned long	curruns;
3948a475bcbSad };
3958a475bcbSad 
3968a475bcbSad typedef struct arena_stats_s arena_stats_t;
3978a475bcbSad struct arena_stats_s {
3988a475bcbSad 	/* Number of bytes currently mapped. */
3998a475bcbSad 	size_t		mapped;
4008a475bcbSad 
4018a475bcbSad 	/* Per-size-category statistics. */
4028a475bcbSad 	size_t		allocated_small;
4038a475bcbSad 	uint64_t	nmalloc_small;
4048a475bcbSad 	uint64_t	ndalloc_small;
4058a475bcbSad 
4068a475bcbSad 	size_t		allocated_large;
4078a475bcbSad 	uint64_t	nmalloc_large;
4088a475bcbSad 	uint64_t	ndalloc_large;
4098a475bcbSad };
4108a475bcbSad 
4118a475bcbSad typedef struct chunk_stats_s chunk_stats_t;
4128a475bcbSad struct chunk_stats_s {
4138a475bcbSad 	/* Number of chunks that were allocated. */
4148a475bcbSad 	uint64_t	nchunks;
4158a475bcbSad 
4168a475bcbSad 	/* High-water mark for number of chunks allocated. */
4178a475bcbSad 	unsigned long	highchunks;
4188a475bcbSad 
4198a475bcbSad 	/*
4208a475bcbSad 	 * Current number of chunks allocated.  This value isn't maintained for
4218a475bcbSad 	 * any other purpose, so keep track of it in order to be able to set
4228a475bcbSad 	 * highchunks.
4238a475bcbSad 	 */
4248a475bcbSad 	unsigned long	curchunks;
4258a475bcbSad };
4268a475bcbSad 
4278a475bcbSad #endif /* #ifdef MALLOC_STATS */
4288a475bcbSad 
4298a475bcbSad /******************************************************************************/
4308a475bcbSad /*
4318a475bcbSad  * Chunk data structures.
4328a475bcbSad  */
4338a475bcbSad 
4348a475bcbSad /* Tree of chunks. */
4358a475bcbSad typedef struct chunk_node_s chunk_node_t;
4368a475bcbSad struct chunk_node_s {
4378a475bcbSad 	/* Linkage for the chunk tree. */
438562025fdSad 	rb_node_t link;
4398a475bcbSad 
4408a475bcbSad 	/*
4418a475bcbSad 	 * Pointer to the chunk that this tree node is responsible for.  In some
4428a475bcbSad 	 * (but certainly not all) cases, this data structure is placed at the
4438a475bcbSad 	 * beginning of the corresponding chunk, so this field may point to this
4448a475bcbSad 	 * node.
4458a475bcbSad 	 */
4468a475bcbSad 	void	*chunk;
4478a475bcbSad 
4488a475bcbSad 	/* Total chunk size. */
4498a475bcbSad 	size_t	size;
4508a475bcbSad };
4518a475bcbSad typedef struct chunk_tree_s chunk_tree_t;
452562025fdSad 
453562025fdSad static int chunk_comp(void *, const void *, const void *);
454562025fdSad 
455562025fdSad static const rb_tree_ops_t chunk_tree_ops = {
456562025fdSad 	.rbto_compare_nodes = chunk_comp,
457562025fdSad 	.rbto_compare_key = chunk_comp,
458562025fdSad 	.rbto_node_offset = offsetof(struct chunk_node_s, link),
459562025fdSad };
4608a475bcbSad 
4618a475bcbSad /******************************************************************************/
4628a475bcbSad /*
4638a475bcbSad  * Arena data structures.
4648a475bcbSad  */
4658a475bcbSad 
4668a475bcbSad typedef struct arena_s arena_t;
4678a475bcbSad typedef struct arena_bin_s arena_bin_t;
4688a475bcbSad 
4698a475bcbSad typedef struct arena_chunk_map_s arena_chunk_map_t;
4708a475bcbSad struct arena_chunk_map_s {
4718a475bcbSad 	/* Number of pages in run. */
4728a475bcbSad 	uint32_t	npages;
4738a475bcbSad 	/*
4748a475bcbSad 	 * Position within run.  For a free run, this is POS_FREE for the first
4758a475bcbSad 	 * and last pages.  The POS_FREE special value makes it possible to
4768a475bcbSad 	 * quickly coalesce free runs.
4778a475bcbSad 	 *
4788a475bcbSad 	 * This is the limiting factor for chunksize; there can be at most 2^31
4798a475bcbSad 	 * pages in a run.
4808a475bcbSad 	 */
4818a475bcbSad #define POS_FREE ((uint32_t)0xffffffffU)
4828a475bcbSad 	uint32_t	pos;
4838a475bcbSad };
4848a475bcbSad 
4858a475bcbSad /* Arena chunk header. */
4868a475bcbSad typedef struct arena_chunk_s arena_chunk_t;
4878a475bcbSad struct arena_chunk_s {
488562025fdSad 	/* Linkage for the arena's chunk tree. */
489562025fdSad 	rb_node_t link;
490562025fdSad 
4918a475bcbSad 	/* Arena that owns the chunk. */
4928a475bcbSad 	arena_t *arena;
4938a475bcbSad 
4948a475bcbSad 	/*
4958a475bcbSad 	 * Number of pages in use.  This is maintained in order to make
4968a475bcbSad 	 * detection of empty chunks fast.
4978a475bcbSad 	 */
4988a475bcbSad 	uint32_t pages_used;
4998a475bcbSad 
5008a475bcbSad 	/*
5018a475bcbSad 	 * Every time a free run larger than this value is created/coalesced,
5028a475bcbSad 	 * this value is increased.  The only way that the value decreases is if
5038a475bcbSad 	 * arena_run_alloc() fails to find a free run as large as advertised by
5048a475bcbSad 	 * this value.
5058a475bcbSad 	 */
5068a475bcbSad 	uint32_t max_frun_npages;
5078a475bcbSad 
5088a475bcbSad 	/*
5098a475bcbSad 	 * Every time a free run that starts at an earlier page than this value
5108a475bcbSad 	 * is created/coalesced, this value is decreased.  It is reset in a
5118a475bcbSad 	 * similar fashion to max_frun_npages.
5128a475bcbSad 	 */
5138a475bcbSad 	uint32_t min_frun_ind;
5148a475bcbSad 
5158a475bcbSad 	/*
5168a475bcbSad 	 * Map of pages within chunk that keeps track of free/large/small.  For
5178a475bcbSad 	 * free runs, only the map entries for the first and last pages are
5188a475bcbSad 	 * kept up to date, so that free runs can be quickly coalesced.
5198a475bcbSad 	 */
5208a475bcbSad 	arena_chunk_map_t map[1]; /* Dynamically sized. */
5218a475bcbSad };
5228a475bcbSad typedef struct arena_chunk_tree_s arena_chunk_tree_t;
523562025fdSad 
524562025fdSad static int arena_chunk_comp(void *, const void *, const void *);
525562025fdSad 
526562025fdSad static const rb_tree_ops_t arena_chunk_tree_ops = {
527562025fdSad 	.rbto_compare_nodes = arena_chunk_comp,
528562025fdSad 	.rbto_compare_key = arena_chunk_comp,
529562025fdSad 	.rbto_node_offset = offsetof(struct arena_chunk_s, link),
530562025fdSad };
5318a475bcbSad 
5328a475bcbSad typedef struct arena_run_s arena_run_t;
5338a475bcbSad struct arena_run_s {
5348a475bcbSad 	/* Linkage for run trees. */
535562025fdSad 	rb_node_t	link;
5368a475bcbSad 
5378a475bcbSad #ifdef MALLOC_DEBUG
5388a475bcbSad 	uint32_t	magic;
5398a475bcbSad #  define ARENA_RUN_MAGIC 0x384adf93
5408a475bcbSad #endif
5418a475bcbSad 
5428a475bcbSad 	/* Bin this run is associated with. */
5438a475bcbSad 	arena_bin_t	*bin;
5448a475bcbSad 
5458a475bcbSad 	/* Index of first element that might have a free region. */
5468a475bcbSad 	unsigned	regs_minelm;
5478a475bcbSad 
5488a475bcbSad 	/* Number of free regions in run. */
5498a475bcbSad 	unsigned	nfree;
5508a475bcbSad 
5518a475bcbSad 	/* Bitmask of in-use regions (0: in use, 1: free). */
5528a475bcbSad 	unsigned	regs_mask[1]; /* Dynamically sized. */
5538a475bcbSad };
5548a475bcbSad typedef struct arena_run_tree_s arena_run_tree_t;
555562025fdSad 
556562025fdSad static int arena_run_comp(void *, const void *, const void *);
557562025fdSad 
558562025fdSad static const rb_tree_ops_t arena_run_tree_ops = {
559562025fdSad 	.rbto_compare_nodes = arena_run_comp,
560562025fdSad 	.rbto_compare_key = arena_run_comp,
561562025fdSad 	.rbto_node_offset = offsetof(struct arena_run_s, link),
562562025fdSad };
5638a475bcbSad 
5648a475bcbSad struct arena_bin_s {
5658a475bcbSad 	/*
5668a475bcbSad 	 * Current run being used to service allocations of this bin's size
5678a475bcbSad 	 * class.
5688a475bcbSad 	 */
5698a475bcbSad 	arena_run_t	*runcur;
5708a475bcbSad 
5718a475bcbSad 	/*
5728a475bcbSad 	 * Tree of non-full runs.  This tree is used when looking for an
5738a475bcbSad 	 * existing run when runcur is no longer usable.  We choose the
5748a475bcbSad 	 * non-full run that is lowest in memory; this policy tends to keep
5758a475bcbSad 	 * objects packed well, and it can also help reduce the number of
5768a475bcbSad 	 * almost-empty chunks.
5778a475bcbSad 	 */
578562025fdSad 	rb_tree_t	runs;
5798a475bcbSad 
5808a475bcbSad 	/* Size of regions in a run for this bin's size class. */
5818a475bcbSad 	size_t		reg_size;
5828a475bcbSad 
5838a475bcbSad 	/* Total size of a run for this bin's size class. */
5848a475bcbSad 	size_t		run_size;
5858a475bcbSad 
5868a475bcbSad 	/* Total number of regions in a run for this bin's size class. */
5878a475bcbSad 	uint32_t	nregs;
5888a475bcbSad 
5898a475bcbSad 	/* Number of elements in a run's regs_mask for this bin's size class. */
5908a475bcbSad 	uint32_t	regs_mask_nelms;
5918a475bcbSad 
5928a475bcbSad 	/* Offset of first region in a run for this bin's size class. */
5938a475bcbSad 	uint32_t	reg0_offset;
5948a475bcbSad 
5958a475bcbSad #ifdef MALLOC_STATS
5968a475bcbSad 	/* Bin statistics. */
5978a475bcbSad 	malloc_bin_stats_t stats;
5988a475bcbSad #endif
5998a475bcbSad };
6008a475bcbSad 
6018a475bcbSad struct arena_s {
6028a475bcbSad #ifdef MALLOC_DEBUG
6038a475bcbSad 	uint32_t		magic;
6048a475bcbSad #  define ARENA_MAGIC 0x947d3d24
6058a475bcbSad #endif
6068a475bcbSad 
6078a475bcbSad 	/* All operations on this arena require that mtx be locked. */
6088a475bcbSad 	malloc_mutex_t		mtx;
6098a475bcbSad 
6108a475bcbSad #ifdef MALLOC_STATS
6118a475bcbSad 	arena_stats_t		stats;
6128a475bcbSad #endif
6138a475bcbSad 
6148a475bcbSad 	/*
6158a475bcbSad 	 * Tree of chunks this arena manages.
6168a475bcbSad 	 */
617562025fdSad 	rb_tree_t	chunks;
6188a475bcbSad 
6198a475bcbSad 	/*
6208a475bcbSad 	 * In order to avoid rapid chunk allocation/deallocation when an arena
6218a475bcbSad 	 * oscillates right on the cusp of needing a new chunk, cache the most
6228a475bcbSad 	 * recently freed chunk.  This caching is disabled by opt_hint.
6238a475bcbSad 	 *
6248a475bcbSad 	 * There is one spare chunk per arena, rather than one spare total, in
6258a475bcbSad 	 * order to avoid interactions between multiple threads that could make
6268a475bcbSad 	 * a single spare inadequate.
6278a475bcbSad 	 */
6288a475bcbSad 	arena_chunk_t *spare;
6298a475bcbSad 
6308a475bcbSad 	/*
6318a475bcbSad 	 * bins is used to store rings of free regions of the following sizes,
6328a475bcbSad 	 * assuming a 16-byte quantum, 4kB pagesize, and default MALLOC_OPTIONS.
6338a475bcbSad 	 *
6348a475bcbSad 	 *   bins[i] | size |
6358a475bcbSad 	 *   --------+------+
6368a475bcbSad 	 *        0  |    2 |
6378a475bcbSad 	 *        1  |    4 |
6388a475bcbSad 	 *        2  |    8 |
6398a475bcbSad 	 *   --------+------+
6408a475bcbSad 	 *        3  |   16 |
6418a475bcbSad 	 *        4  |   32 |
6428a475bcbSad 	 *        5  |   48 |
6438a475bcbSad 	 *        6  |   64 |
6448a475bcbSad 	 *           :      :
6458a475bcbSad 	 *           :      :
6468a475bcbSad 	 *       33  |  496 |
6478a475bcbSad 	 *       34  |  512 |
6488a475bcbSad 	 *   --------+------+
6498a475bcbSad 	 *       35  | 1024 |
6508a475bcbSad 	 *       36  | 2048 |
6518a475bcbSad 	 *   --------+------+
6528a475bcbSad 	 */
6538a475bcbSad 	arena_bin_t		bins[1]; /* Dynamically sized. */
6548a475bcbSad };
6558a475bcbSad 
6568a475bcbSad /******************************************************************************/
6578a475bcbSad /*
6588a475bcbSad  * Data.
6598a475bcbSad  */
6608a475bcbSad 
6618a475bcbSad /* Number of CPUs. */
6628a475bcbSad static unsigned		ncpus;
6638a475bcbSad 
6648a475bcbSad /* VM page size. */
6658a475bcbSad static size_t		pagesize;
6668a475bcbSad static size_t		pagesize_mask;
6678de47c09Schristos static int		pagesize_2pow;
6688a475bcbSad 
6698a475bcbSad /* Various bin-related settings. */
6708a475bcbSad static size_t		bin_maxclass; /* Max size class for bins. */
6718a475bcbSad static unsigned		ntbins; /* Number of (2^n)-spaced tiny bins. */
6728a475bcbSad static unsigned		nqbins; /* Number of quantum-spaced bins. */
6738a475bcbSad static unsigned		nsbins; /* Number of (2^n)-spaced sub-page bins. */
6748a475bcbSad static size_t		small_min;
6758a475bcbSad static size_t		small_max;
6768a475bcbSad 
6778a475bcbSad /* Various quantum-related settings. */
6788a475bcbSad static size_t		quantum;
6798a475bcbSad static size_t		quantum_mask; /* (quantum - 1). */
6808a475bcbSad 
6818a475bcbSad /* Various chunk-related settings. */
6828a475bcbSad static size_t		chunksize;
6838a475bcbSad static size_t		chunksize_mask; /* (chunksize - 1). */
68414bfffc9Syamt static int		chunksize_2pow;
6858a475bcbSad static unsigned		chunk_npages;
6868a475bcbSad static unsigned		arena_chunk_header_npages;
6878a475bcbSad static size_t		arena_maxclass; /* Max size class for arenas. */
6888a475bcbSad 
6898a475bcbSad /********/
6908a475bcbSad /*
6918a475bcbSad  * Chunks.
6928a475bcbSad  */
6938a475bcbSad 
69426ba8048Schristos #ifdef _REENTRANT
6958a475bcbSad /* Protects chunk-related data structures. */
6968a475bcbSad static malloc_mutex_t	chunks_mtx;
69726ba8048Schristos #endif
6988a475bcbSad 
6998a475bcbSad /* Tree of chunks that are stand-alone huge allocations. */
700562025fdSad static rb_tree_t	huge;
7018a475bcbSad 
7028a475bcbSad #ifdef USE_BRK
7038a475bcbSad /*
7048a475bcbSad  * Try to use brk for chunk-size allocations, due to address space constraints.
7058a475bcbSad  */
7068a475bcbSad /*
7078a475bcbSad  * Protects sbrk() calls.  This must be separate from chunks_mtx, since
7088a475bcbSad  * base_pages_alloc() also uses sbrk(), but cannot lock chunks_mtx (doing so
7098a475bcbSad  * could cause recursive lock acquisition).
7108a475bcbSad  */
71115c525fbSchristos #ifdef _REENTRANT
7128a475bcbSad static malloc_mutex_t	brk_mtx;
71315c525fbSchristos #endif
7148a475bcbSad /* Result of first sbrk(0) call. */
7158a475bcbSad static void		*brk_base;
7168a475bcbSad /* Current end of brk, or ((void *)-1) if brk is exhausted. */
7178a475bcbSad static void		*brk_prev;
7188a475bcbSad /* Current upper limit on brk addresses. */
7198a475bcbSad static void		*brk_max;
7208a475bcbSad #endif
7218a475bcbSad 
7228a475bcbSad #ifdef MALLOC_STATS
7238a475bcbSad /* Huge allocation statistics. */
7248a475bcbSad static uint64_t		huge_nmalloc;
7258a475bcbSad static uint64_t		huge_ndalloc;
726b79fded2Syamt static uint64_t		huge_nralloc;
7278a475bcbSad static size_t		huge_allocated;
7288a475bcbSad #endif
7298a475bcbSad 
7308a475bcbSad /*
7318a475bcbSad  * Tree of chunks that were previously allocated.  This is used when allocating
7328a475bcbSad  * chunks, in an attempt to re-use address space.
7338a475bcbSad  */
734562025fdSad static rb_tree_t	old_chunks;
7358a475bcbSad 
7368a475bcbSad /****************************/
7378a475bcbSad /*
7388a475bcbSad  * base (internal allocation).
7398a475bcbSad  */
7408a475bcbSad 
7418a475bcbSad /*
7428a475bcbSad  * Current pages that are being used for internal memory allocations.  These
7438a475bcbSad  * pages are carved up in cacheline-size quanta, so that there is no chance of
7448a475bcbSad  * false cache line sharing.
7458a475bcbSad  */
7468a475bcbSad static void		*base_pages;
7478a475bcbSad static void		*base_next_addr;
7488a475bcbSad static void		*base_past_addr; /* Addr immediately past base_pages. */
7498a475bcbSad static chunk_node_t	*base_chunk_nodes; /* LIFO cache of chunk nodes. */
75026ba8048Schristos #ifdef _REENTRANT
7518a475bcbSad static malloc_mutex_t	base_mtx;
75226ba8048Schristos #endif
7538a475bcbSad #ifdef MALLOC_STATS
7548a475bcbSad static size_t		base_mapped;
7558a475bcbSad #endif
7568a475bcbSad 
7578a475bcbSad /********/
7588a475bcbSad /*
7598a475bcbSad  * Arenas.
7608a475bcbSad  */
7618a475bcbSad 
7628a475bcbSad /*
7638a475bcbSad  * Arenas that are used to service external requests.  Not all elements of the
7648a475bcbSad  * arenas array are necessarily used; arenas are created lazily as needed.
7658a475bcbSad  */
7668a475bcbSad static arena_t		**arenas;
76726ba8048Schristos #ifdef _REENTRANT
7688a475bcbSad static malloc_mutex_t	arenas_mtx; /* Protects arenas initialization. */
76926ba8048Schristos #endif
7708a475bcbSad 
7718a475bcbSad #ifdef MALLOC_STATS
7728a475bcbSad /* Chunk statistics. */
7738a475bcbSad static chunk_stats_t	stats_chunks;
7748a475bcbSad #endif
7758a475bcbSad 
7768a475bcbSad /*******************************/
7778a475bcbSad /*
7788a475bcbSad  * Runtime configuration options.
7798a475bcbSad  */
7808a475bcbSad const char	*_malloc_options;
7818a475bcbSad 
7828a475bcbSad #ifndef MALLOC_PRODUCTION
7838a475bcbSad static bool	opt_abort = true;
7848a475bcbSad static bool	opt_junk = true;
7858a475bcbSad #else
7868a475bcbSad static bool	opt_abort = false;
7878a475bcbSad static bool	opt_junk = false;
7888a475bcbSad #endif
7898a475bcbSad static bool	opt_hint = false;
7908a475bcbSad static bool	opt_print_stats = false;
7918de47c09Schristos static int	opt_quantum_2pow = QUANTUM_2POW_MIN;
7928de47c09Schristos static int	opt_small_max_2pow = SMALL_MAX_2POW_DEFAULT;
7938de47c09Schristos static int	opt_chunk_2pow = CHUNK_2POW_DEFAULT;
7948a475bcbSad static bool	opt_utrace = false;
7958a475bcbSad static bool	opt_sysv = false;
7968a475bcbSad static bool	opt_xmalloc = false;
7978a475bcbSad static bool	opt_zero = false;
7988a475bcbSad 
7998a475bcbSad typedef struct {
8008a475bcbSad 	void	*p;
8018a475bcbSad 	size_t	s;
8028a475bcbSad 	void	*r;
8038a475bcbSad } malloc_utrace_t;
8048a475bcbSad 
805bf5f78d5Sad /* Sprinkle branch hints for the compiler and CPU. */
806bf5f78d5Sad #define	OPT(a)		__predict_false(opt_##a)
807bf5f78d5Sad #define	NOT_OPT(a)	__predict_true(!opt_##a)
808bf5f78d5Sad 
809bf5f78d5Sad /* Trace malloc/free for ktrace/kdump. */
8108a475bcbSad #define	UTRACE(a, b, c)							\
811bf5f78d5Sad 	if (OPT(utrace)) {						\
812e7a9e46bSad 		malloc_utrace_t ut;					\
813e7a9e46bSad 		ut.p = a;						\
814e7a9e46bSad 		ut.s = b;						\
815e7a9e46bSad 		ut.r = c;						\
816bf5f78d5Sad 		utrace("malloc", &ut, sizeof(ut));			\
8178a475bcbSad 	}
8188a475bcbSad 
8198a475bcbSad /******************************************************************************/
8208a475bcbSad /*
8218a475bcbSad  * Begin function prototypes for non-inline static functions.
8228a475bcbSad  */
8238a475bcbSad 
8248a475bcbSad static void	wrtmessage(const char *p1, const char *p2, const char *p3,
8258a475bcbSad 		const char *p4);
8268a475bcbSad #ifdef MALLOC_STATS
8278a475bcbSad static void	malloc_printf(const char *format, ...);
8288a475bcbSad #endif
829d703a148Schristos static char	*size_t2s(size_t x, char *s);
8308a475bcbSad static bool	base_pages_alloc(size_t minsize);
8318a475bcbSad static void	*base_alloc(size_t size);
8328a475bcbSad static chunk_node_t *base_chunk_node_alloc(void);
8338a475bcbSad static void	base_chunk_node_dealloc(chunk_node_t *node);
8348a475bcbSad #ifdef MALLOC_STATS
8358a475bcbSad static void	stats_print(arena_t *arena);
8368a475bcbSad #endif
8378a475bcbSad static void	*pages_map(void *addr, size_t size);
83814bfffc9Syamt static void	*pages_map_align(void *addr, size_t size, int align);
8398a475bcbSad static void	pages_unmap(void *addr, size_t size);
8408a475bcbSad static void	*chunk_alloc(size_t size);
8418a475bcbSad static void	chunk_dealloc(void *chunk, size_t size);
8428a475bcbSad static void	arena_run_split(arena_t *arena, arena_run_t *run, size_t size);
8438a475bcbSad static arena_chunk_t *arena_chunk_alloc(arena_t *arena);
8448a475bcbSad static void	arena_chunk_dealloc(arena_t *arena, arena_chunk_t *chunk);
8458a475bcbSad static arena_run_t *arena_run_alloc(arena_t *arena, size_t size);
8468a475bcbSad static void	arena_run_dalloc(arena_t *arena, arena_run_t *run, size_t size);
8478a475bcbSad static arena_run_t *arena_bin_nonfull_run_get(arena_t *arena, arena_bin_t *bin);
8488a475bcbSad static void *arena_bin_malloc_hard(arena_t *arena, arena_bin_t *bin);
8498a475bcbSad static size_t arena_bin_run_size_calc(arena_bin_t *bin, size_t min_run_size);
8508a475bcbSad static void	*arena_malloc(arena_t *arena, size_t size);
8518a475bcbSad static void	*arena_palloc(arena_t *arena, size_t alignment, size_t size,
8528a475bcbSad     size_t alloc_size);
8538a475bcbSad static size_t	arena_salloc(const void *ptr);
8548a475bcbSad static void	*arena_ralloc(void *ptr, size_t size, size_t oldsize);
8558a475bcbSad static void	arena_dalloc(arena_t *arena, arena_chunk_t *chunk, void *ptr);
856bf5f78d5Sad static void	arena_new(arena_t *arena);
857bf5f78d5Sad static arena_t	*arenas_extend(void);
8588a475bcbSad static void	*huge_malloc(size_t size);
8598a475bcbSad static void	*huge_palloc(size_t alignment, size_t size);
8608a475bcbSad static void	*huge_ralloc(void *ptr, size_t size, size_t oldsize);
8618a475bcbSad static void	huge_dalloc(void *ptr);
8628a475bcbSad static void	*imalloc(size_t size);
8638a475bcbSad static void	*ipalloc(size_t alignment, size_t size);
8648a475bcbSad static void	*icalloc(size_t size);
8658a475bcbSad static size_t	isalloc(const void *ptr);
8668a475bcbSad static void	*iralloc(void *ptr, size_t size);
8678a475bcbSad static void	idalloc(void *ptr);
8688a475bcbSad static void	malloc_print_stats(void);
8698a475bcbSad static bool	malloc_init_hard(void);
8708a475bcbSad 
8718a475bcbSad /*
8728a475bcbSad  * End function prototypes.
8738a475bcbSad  */
8748a475bcbSad /******************************************************************************/
8758a475bcbSad /*
8768a475bcbSad  * Begin mutex.
8778a475bcbSad  */
8788a475bcbSad 
879e7a9e46bSad #define	malloc_mutex_init(m)	mutex_init(m, NULL)
880e7a9e46bSad #define	malloc_mutex_lock(m)	mutex_lock(m)
881e7a9e46bSad #define	malloc_mutex_unlock(m)	mutex_unlock(m)
8828a475bcbSad 
8838a475bcbSad /*
8848a475bcbSad  * End mutex.
8858a475bcbSad  */
8868a475bcbSad /******************************************************************************/
8878a475bcbSad /*
8888a475bcbSad  * Begin Utility functions/macros.
8898a475bcbSad  */
8908a475bcbSad 
8918a475bcbSad /* Return the chunk address for allocation address a. */
8928a475bcbSad #define	CHUNK_ADDR2BASE(a)						\
8938a475bcbSad 	((void *)((uintptr_t)(a) & ~chunksize_mask))
8948a475bcbSad 
8958a475bcbSad /* Return the chunk offset of address a. */
8968a475bcbSad #define	CHUNK_ADDR2OFFSET(a)						\
8978a475bcbSad 	((size_t)((uintptr_t)(a) & chunksize_mask))
8988a475bcbSad 
8998a475bcbSad /* Return the smallest chunk multiple that is >= s. */
9008a475bcbSad #define	CHUNK_CEILING(s)						\
9018a475bcbSad 	(((s) + chunksize_mask) & ~chunksize_mask)
9028a475bcbSad 
9038a475bcbSad /* Return the smallest cacheline multiple that is >= s. */
9048a475bcbSad #define	CACHELINE_CEILING(s)						\
9058a475bcbSad 	(((s) + (CACHELINE - 1)) & ~(CACHELINE - 1))
9068a475bcbSad 
9078a475bcbSad /* Return the smallest quantum multiple that is >= a. */
9088a475bcbSad #define	QUANTUM_CEILING(a)						\
9098a475bcbSad 	(((a) + quantum_mask) & ~quantum_mask)
9108a475bcbSad 
9118a475bcbSad /* Return the smallest pagesize multiple that is >= s. */
9128a475bcbSad #define	PAGE_CEILING(s)							\
9138a475bcbSad 	(((s) + pagesize_mask) & ~pagesize_mask)
9148a475bcbSad 
9158a475bcbSad /* Compute the smallest power of 2 that is >= x. */
9168a475bcbSad static inline size_t
pow2_ceil(size_t x)9178a475bcbSad pow2_ceil(size_t x)
9188a475bcbSad {
9198a475bcbSad 
9208a475bcbSad 	x--;
9218a475bcbSad 	x |= x >> 1;
9228a475bcbSad 	x |= x >> 2;
9238a475bcbSad 	x |= x >> 4;
9248a475bcbSad 	x |= x >> 8;
9258a475bcbSad 	x |= x >> 16;
9268a475bcbSad #if (SIZEOF_PTR == 8)
9278a475bcbSad 	x |= x >> 32;
9288a475bcbSad #endif
9298a475bcbSad 	x++;
9308a475bcbSad 	return (x);
9318a475bcbSad }
9328a475bcbSad 
9338a475bcbSad static void
wrtmessage(const char * p1,const char * p2,const char * p3,const char * p4)9348a475bcbSad wrtmessage(const char *p1, const char *p2, const char *p3, const char *p4)
9358a475bcbSad {
9368a475bcbSad 
93786ef91b8Schristos 	write(STDERR_FILENO, p1, strlen(p1));
93886ef91b8Schristos 	write(STDERR_FILENO, p2, strlen(p2));
93986ef91b8Schristos 	write(STDERR_FILENO, p3, strlen(p3));
94086ef91b8Schristos 	write(STDERR_FILENO, p4, strlen(p4));
9418a475bcbSad }
9428a475bcbSad 
9438a475bcbSad void	(*_malloc_message)(const char *p1, const char *p2, const char *p3,
9448a475bcbSad 	    const char *p4) = wrtmessage;
9458a475bcbSad 
9468a475bcbSad #ifdef MALLOC_STATS
9478a475bcbSad /*
9488a475bcbSad  * Print to stderr in such a way as to (hopefully) avoid memory allocation.
9498a475bcbSad  */
9508a475bcbSad static void
malloc_printf(const char * format,...)9518a475bcbSad malloc_printf(const char *format, ...)
9528a475bcbSad {
9538a475bcbSad 	char buf[4096];
9548a475bcbSad 	va_list ap;
9558a475bcbSad 
9568a475bcbSad 	va_start(ap, format);
9578a475bcbSad 	vsnprintf(buf, sizeof(buf), format, ap);
9588a475bcbSad 	va_end(ap);
9598a475bcbSad 	_malloc_message(buf, "", "", "");
9608a475bcbSad }
9618a475bcbSad #endif
9628a475bcbSad 
9638a475bcbSad /*
9648a475bcbSad  * We don't want to depend on vsnprintf() for production builds, since that can
965d703a148Schristos  * cause unnecessary bloat for static binaries.  size_t2s() provides minimal
9668a475bcbSad  * integer printing functionality, so that malloc_printf() use can be limited to
9678a475bcbSad  * MALLOC_STATS code.
9688a475bcbSad  */
9698a475bcbSad #define UMAX2S_BUFSIZE	21
9708a475bcbSad static char *
size_t2s(size_t x,char * s)971d703a148Schristos size_t2s(size_t x, char *s)
9728a475bcbSad {
9738a475bcbSad 	unsigned i;
9748a475bcbSad 
9758a475bcbSad 	/* Make sure UMAX2S_BUFSIZE is large enough. */
976687cd24eSyamt 	/* LINTED */
977c59812a8Schristos 	assert(sizeof(size_t) <= 8);
9788a475bcbSad 
9798a475bcbSad 	i = UMAX2S_BUFSIZE - 1;
9808a475bcbSad 	s[i] = '\0';
9818a475bcbSad 	do {
9828a475bcbSad 		i--;
983e7a9e46bSad 		s[i] = "0123456789"[(int)x % 10];
984e7a9e46bSad 		x /= (uintmax_t)10LL;
9858a475bcbSad 	} while (x > 0);
9868a475bcbSad 
9878a475bcbSad 	return (&s[i]);
9888a475bcbSad }
9898a475bcbSad 
9908a475bcbSad /******************************************************************************/
9918a475bcbSad 
9928a475bcbSad static bool
base_pages_alloc(size_t minsize)9938a475bcbSad base_pages_alloc(size_t minsize)
9948a475bcbSad {
995e7a9e46bSad 	size_t csize = 0;
9968a475bcbSad 
9978a475bcbSad #ifdef USE_BRK
9988a475bcbSad 	/*
9998a475bcbSad 	 * Do special brk allocation here, since base allocations don't need to
10008a475bcbSad 	 * be chunk-aligned.
10018a475bcbSad 	 */
10028a475bcbSad 	if (brk_prev != (void *)-1) {
10038a475bcbSad 		void *brk_cur;
10048a475bcbSad 		intptr_t incr;
10058a475bcbSad 
10068a475bcbSad 		if (minsize != 0)
10078a475bcbSad 			csize = CHUNK_CEILING(minsize);
10088a475bcbSad 
10098a475bcbSad 		malloc_mutex_lock(&brk_mtx);
10108a475bcbSad 		do {
10118a475bcbSad 			/* Get the current end of brk. */
10128a475bcbSad 			brk_cur = sbrk(0);
10138a475bcbSad 
10148a475bcbSad 			/*
10158a475bcbSad 			 * Calculate how much padding is necessary to
10168a475bcbSad 			 * chunk-align the end of brk.  Don't worry about
10178a475bcbSad 			 * brk_cur not being chunk-aligned though.
10188a475bcbSad 			 */
10198a475bcbSad 			incr = (intptr_t)chunksize
10208a475bcbSad 			    - (intptr_t)CHUNK_ADDR2OFFSET(brk_cur);
10212360d084Slukem 			assert(incr >= 0);
10222360d084Slukem 			if ((size_t)incr < minsize)
10238a475bcbSad 				incr += csize;
10248a475bcbSad 
10258a475bcbSad 			brk_prev = sbrk(incr);
10268a475bcbSad 			if (brk_prev == brk_cur) {
10278a475bcbSad 				/* Success. */
10288a475bcbSad 				malloc_mutex_unlock(&brk_mtx);
10298a475bcbSad 				base_pages = brk_cur;
10308a475bcbSad 				base_next_addr = base_pages;
10318a475bcbSad 				base_past_addr = (void *)((uintptr_t)base_pages
10328a475bcbSad 				    + incr);
10338a475bcbSad #ifdef MALLOC_STATS
10348a475bcbSad 				base_mapped += incr;
10358a475bcbSad #endif
10368a475bcbSad 				return (false);
10378a475bcbSad 			}
10388a475bcbSad 		} while (brk_prev != (void *)-1);
10398a475bcbSad 		malloc_mutex_unlock(&brk_mtx);
10408a475bcbSad 	}
10418a475bcbSad 	if (minsize == 0) {
10428a475bcbSad 		/*
10438a475bcbSad 		 * Failure during initialization doesn't matter, so avoid
10448a475bcbSad 		 * falling through to the mmap-based page mapping code.
10458a475bcbSad 		 */
10468a475bcbSad 		return (true);
10478a475bcbSad 	}
10488a475bcbSad #endif
10498a475bcbSad 	assert(minsize != 0);
10508a475bcbSad 	csize = PAGE_CEILING(minsize);
10518a475bcbSad 	base_pages = pages_map(NULL, csize);
10528a475bcbSad 	if (base_pages == NULL)
10538a475bcbSad 		return (true);
10548a475bcbSad 	base_next_addr = base_pages;
10558a475bcbSad 	base_past_addr = (void *)((uintptr_t)base_pages + csize);
10568a475bcbSad #ifdef MALLOC_STATS
10578a475bcbSad 	base_mapped += csize;
10588a475bcbSad #endif
10598a475bcbSad 	return (false);
10608a475bcbSad }
10618a475bcbSad 
10628a475bcbSad static void *
base_alloc(size_t size)10638a475bcbSad base_alloc(size_t size)
10648a475bcbSad {
10658a475bcbSad 	void *ret;
10668a475bcbSad 	size_t csize;
10678a475bcbSad 
10688a475bcbSad 	/* Round size up to nearest multiple of the cacheline size. */
10698a475bcbSad 	csize = CACHELINE_CEILING(size);
10708a475bcbSad 
10718a475bcbSad 	malloc_mutex_lock(&base_mtx);
10728a475bcbSad 
10738a475bcbSad 	/* Make sure there's enough space for the allocation. */
10748a475bcbSad 	if ((uintptr_t)base_next_addr + csize > (uintptr_t)base_past_addr) {
10758a475bcbSad 		if (base_pages_alloc(csize)) {
10768a475bcbSad 			ret = NULL;
10778a475bcbSad 			goto RETURN;
10788a475bcbSad 		}
10798a475bcbSad 	}
10808a475bcbSad 
10818a475bcbSad 	/* Allocate. */
10828a475bcbSad 	ret = base_next_addr;
10838a475bcbSad 	base_next_addr = (void *)((uintptr_t)base_next_addr + csize);
10848a475bcbSad 
10858a475bcbSad RETURN:
10868a475bcbSad 	malloc_mutex_unlock(&base_mtx);
10878a475bcbSad 	return (ret);
10888a475bcbSad }
10898a475bcbSad 
10908a475bcbSad static chunk_node_t *
base_chunk_node_alloc(void)10918a475bcbSad base_chunk_node_alloc(void)
10928a475bcbSad {
10938a475bcbSad 	chunk_node_t *ret;
10948a475bcbSad 
10958a475bcbSad 	malloc_mutex_lock(&base_mtx);
10968a475bcbSad 	if (base_chunk_nodes != NULL) {
10978a475bcbSad 		ret = base_chunk_nodes;
1098e7a9e46bSad 		/* LINTED */
10998a475bcbSad 		base_chunk_nodes = *(chunk_node_t **)ret;
11008a475bcbSad 		malloc_mutex_unlock(&base_mtx);
11018a475bcbSad 	} else {
11028a475bcbSad 		malloc_mutex_unlock(&base_mtx);
11038a475bcbSad 		ret = (chunk_node_t *)base_alloc(sizeof(chunk_node_t));
11048a475bcbSad 	}
11058a475bcbSad 
11068a475bcbSad 	return (ret);
11078a475bcbSad }
11088a475bcbSad 
11098a475bcbSad static void
base_chunk_node_dealloc(chunk_node_t * node)11108a475bcbSad base_chunk_node_dealloc(chunk_node_t *node)
11118a475bcbSad {
11128a475bcbSad 
11138a475bcbSad 	malloc_mutex_lock(&base_mtx);
1114e7a9e46bSad 	/* LINTED */
11158a475bcbSad 	*(chunk_node_t **)node = base_chunk_nodes;
11168a475bcbSad 	base_chunk_nodes = node;
11178a475bcbSad 	malloc_mutex_unlock(&base_mtx);
11188a475bcbSad }
11198a475bcbSad 
11208a475bcbSad /******************************************************************************/
11218a475bcbSad 
11228a475bcbSad #ifdef MALLOC_STATS
11238a475bcbSad static void
stats_print(arena_t * arena)11248a475bcbSad stats_print(arena_t *arena)
11258a475bcbSad {
1126bf5f78d5Sad 	const unsigned minusone = (unsigned)-1;
1127bf5f78d5Sad 	unsigned i, gap_start;
11288a475bcbSad 
11298a475bcbSad 	malloc_printf(
11308a475bcbSad 	    "          allocated/mapped            nmalloc      ndalloc\n");
1131e7a9e46bSad 
1132e7a9e46bSad 	malloc_printf("small: %12zu %-12s %12llu %12llu\n",
11338a475bcbSad 	    arena->stats.allocated_small, "", arena->stats.nmalloc_small,
11348a475bcbSad 	    arena->stats.ndalloc_small);
1135e7a9e46bSad 	malloc_printf("large: %12zu %-12s %12llu %12llu\n",
11368a475bcbSad 	    arena->stats.allocated_large, "", arena->stats.nmalloc_large,
11378a475bcbSad 	    arena->stats.ndalloc_large);
1138e7a9e46bSad 	malloc_printf("total: %12zu/%-12zu %12llu %12llu\n",
11398a475bcbSad 	    arena->stats.allocated_small + arena->stats.allocated_large,
11408a475bcbSad 	    arena->stats.mapped,
11418a475bcbSad 	    arena->stats.nmalloc_small + arena->stats.nmalloc_large,
11428a475bcbSad 	    arena->stats.ndalloc_small + arena->stats.ndalloc_large);
11438a475bcbSad 
11448a475bcbSad 	malloc_printf("bins:     bin   size regs pgs  requests   newruns"
11458a475bcbSad 	    "    reruns maxruns curruns\n");
1146bf5f78d5Sad 	for (i = 0, gap_start = minusone; i < ntbins + nqbins + nsbins; i++) {
11478a475bcbSad 		if (arena->bins[i].stats.nrequests == 0) {
1148bf5f78d5Sad 			if (gap_start == minusone)
11498a475bcbSad 				gap_start = i;
11508a475bcbSad 		} else {
1151bf5f78d5Sad 			if (gap_start != minusone) {
11528a475bcbSad 				if (i > gap_start + 1) {
11538a475bcbSad 					/* Gap of more than one size class. */
11548a475bcbSad 					malloc_printf("[%u..%u]\n",
11558a475bcbSad 					    gap_start, i - 1);
11568a475bcbSad 				} else {
11578a475bcbSad 					/* Gap of one size class. */
11588a475bcbSad 					malloc_printf("[%u]\n", gap_start);
11598a475bcbSad 				}
1160bf5f78d5Sad 				gap_start = minusone;
11618a475bcbSad 			}
11628a475bcbSad 			malloc_printf(
11638a475bcbSad 			    "%13u %1s %4u %4u %3u %9llu %9llu"
11648a475bcbSad 			    " %9llu %7lu %7lu\n",
11658a475bcbSad 			    i,
11668a475bcbSad 			    i < ntbins ? "T" : i < ntbins + nqbins ? "Q" : "S",
11678a475bcbSad 			    arena->bins[i].reg_size,
11688a475bcbSad 			    arena->bins[i].nregs,
11698a475bcbSad 			    arena->bins[i].run_size >> pagesize_2pow,
11708a475bcbSad 			    arena->bins[i].stats.nrequests,
11718a475bcbSad 			    arena->bins[i].stats.nruns,
11728a475bcbSad 			    arena->bins[i].stats.reruns,
11738a475bcbSad 			    arena->bins[i].stats.highruns,
11748a475bcbSad 			    arena->bins[i].stats.curruns);
11758a475bcbSad 		}
11768a475bcbSad 	}
1177bf5f78d5Sad 	if (gap_start != minusone) {
11788a475bcbSad 		if (i > gap_start + 1) {
11798a475bcbSad 			/* Gap of more than one size class. */
11808a475bcbSad 			malloc_printf("[%u..%u]\n", gap_start, i - 1);
11818a475bcbSad 		} else {
11828a475bcbSad 			/* Gap of one size class. */
11838a475bcbSad 			malloc_printf("[%u]\n", gap_start);
11848a475bcbSad 		}
11858a475bcbSad 	}
11868a475bcbSad }
11878a475bcbSad #endif
11888a475bcbSad 
11898a475bcbSad /*
11908a475bcbSad  * End Utility functions/macros.
11918a475bcbSad  */
11928a475bcbSad /******************************************************************************/
11938a475bcbSad /*
11948a475bcbSad  * Begin chunk management functions.
11958a475bcbSad  */
11968a475bcbSad 
1197562025fdSad static int
chunk_comp(void * context,const void * va,const void * vb)1198562025fdSad chunk_comp(void *context, const void *va, const void *vb)
11998a475bcbSad {
1200562025fdSad 	const chunk_node_t *a = va, *b = vb;
12018a475bcbSad 
12028a475bcbSad 	assert(a != NULL);
12038a475bcbSad 	assert(b != NULL);
12048a475bcbSad 
1205562025fdSad 	return ptrcmp(a->chunk, b->chunk);
12068a475bcbSad }
12078a475bcbSad 
12088a475bcbSad static void *
pages_map_align(void * addr,size_t size,int align)120914bfffc9Syamt pages_map_align(void *addr, size_t size, int align)
12108a475bcbSad {
12118a475bcbSad 	void *ret;
12128a475bcbSad 
12138a475bcbSad 	/*
12148a475bcbSad 	 * We don't use MAP_FIXED here, because it can cause the *replacement*
12158a475bcbSad 	 * of existing mappings, and we only want to create new mappings.
12168a475bcbSad 	 */
121714bfffc9Syamt 	ret = mmap(addr, size, PROT_READ | PROT_WRITE,
121814bfffc9Syamt 	    MAP_PRIVATE | MAP_ANON | MAP_ALIGNED(align), -1, 0);
12198a475bcbSad 	assert(ret != NULL);
12208a475bcbSad 
12218a475bcbSad 	if (ret == MAP_FAILED)
12228a475bcbSad 		ret = NULL;
12238a475bcbSad 	else if (addr != NULL && ret != addr) {
12248a475bcbSad 		/*
12258a475bcbSad 		 * We succeeded in mapping memory, but not in the right place.
12268a475bcbSad 		 */
12278a475bcbSad 		if (munmap(ret, size) == -1) {
12288a475bcbSad 			char buf[STRERROR_BUF];
12298a475bcbSad 
123086ef91b8Schristos 			STRERROR_R(errno, buf, sizeof(buf));
123186ef91b8Schristos 			_malloc_message(getprogname(),
12328a475bcbSad 			    ": (malloc) Error in munmap(): ", buf, "\n");
1233bf5f78d5Sad 			if (OPT(abort))
12348a475bcbSad 				abort();
12358a475bcbSad 		}
12368a475bcbSad 		ret = NULL;
12378a475bcbSad 	}
12388a475bcbSad 
12398a475bcbSad 	assert(ret == NULL || (addr == NULL && ret != addr)
12408a475bcbSad 	    || (addr != NULL && ret == addr));
12418a475bcbSad 	return (ret);
12428a475bcbSad }
12438a475bcbSad 
124414bfffc9Syamt static void *
pages_map(void * addr,size_t size)124514bfffc9Syamt pages_map(void *addr, size_t size)
124614bfffc9Syamt {
124714bfffc9Syamt 
124814bfffc9Syamt 	return pages_map_align(addr, size, 0);
124914bfffc9Syamt }
125014bfffc9Syamt 
12518a475bcbSad static void
pages_unmap(void * addr,size_t size)12528a475bcbSad pages_unmap(void *addr, size_t size)
12538a475bcbSad {
12548a475bcbSad 
12558a475bcbSad 	if (munmap(addr, size) == -1) {
12568a475bcbSad 		char buf[STRERROR_BUF];
12578a475bcbSad 
125886ef91b8Schristos 		STRERROR_R(errno, buf, sizeof(buf));
125986ef91b8Schristos 		_malloc_message(getprogname(),
12608a475bcbSad 		    ": (malloc) Error in munmap(): ", buf, "\n");
1261bf5f78d5Sad 		if (OPT(abort))
12628a475bcbSad 			abort();
12638a475bcbSad 	}
12648a475bcbSad }
12658a475bcbSad 
12668a475bcbSad static void *
chunk_alloc(size_t size)12678a475bcbSad chunk_alloc(size_t size)
12688a475bcbSad {
12698a475bcbSad 	void *ret, *chunk;
12708a475bcbSad 	chunk_node_t *tchunk, *delchunk;
12718a475bcbSad 
12728a475bcbSad 	assert(size != 0);
12738a475bcbSad 	assert((size & chunksize_mask) == 0);
12748a475bcbSad 
12758a475bcbSad 	malloc_mutex_lock(&chunks_mtx);
12768a475bcbSad 
12778a475bcbSad 	if (size == chunksize) {
12788a475bcbSad 		/*
12798a475bcbSad 		 * Check for address ranges that were previously chunks and try
12808a475bcbSad 		 * to use them.
12818a475bcbSad 		 */
12828a475bcbSad 
1283562025fdSad 		tchunk = RB_TREE_MIN(&old_chunks);
12848a475bcbSad 		while (tchunk != NULL) {
12858a475bcbSad 			/* Found an address range.  Try to recycle it. */
12868a475bcbSad 
12878a475bcbSad 			chunk = tchunk->chunk;
12888a475bcbSad 			delchunk = tchunk;
1289562025fdSad 			tchunk = RB_TREE_NEXT(&old_chunks, delchunk);
12908a475bcbSad 
12918a475bcbSad 			/* Remove delchunk from the tree. */
1292562025fdSad 			rb_tree_remove_node(&old_chunks, delchunk);
12938a475bcbSad 			base_chunk_node_dealloc(delchunk);
12948a475bcbSad 
12958a475bcbSad #ifdef USE_BRK
12968a475bcbSad 			if ((uintptr_t)chunk >= (uintptr_t)brk_base
12978a475bcbSad 			    && (uintptr_t)chunk < (uintptr_t)brk_max) {
12988a475bcbSad 				/* Re-use a previously freed brk chunk. */
12998a475bcbSad 				ret = chunk;
13008a475bcbSad 				goto RETURN;
13018a475bcbSad 			}
13028a475bcbSad #endif
13038a475bcbSad 			if ((ret = pages_map(chunk, size)) != NULL) {
13048a475bcbSad 				/* Success. */
13058a475bcbSad 				goto RETURN;
13068a475bcbSad 			}
13078a475bcbSad 		}
13088a475bcbSad 	}
13098a475bcbSad 
13108a475bcbSad 	/*
13118a475bcbSad 	 * Try to over-allocate, but allow the OS to place the allocation
13128a475bcbSad 	 * anywhere.  Beware of size_t wrap-around.
13138a475bcbSad 	 */
13148a475bcbSad 	if (size + chunksize > size) {
131514bfffc9Syamt 		if ((ret = pages_map_align(NULL, size, chunksize_2pow))
131614bfffc9Syamt 		    != NULL) {
13178a475bcbSad 			goto RETURN;
13188a475bcbSad 		}
13198a475bcbSad 	}
13208a475bcbSad 
13218a475bcbSad #ifdef USE_BRK
13228a475bcbSad 	/*
13238a475bcbSad 	 * Try to create allocations in brk, in order to make full use of
13248a475bcbSad 	 * limited address space.
13258a475bcbSad 	 */
13268a475bcbSad 	if (brk_prev != (void *)-1) {
13278a475bcbSad 		void *brk_cur;
13288a475bcbSad 		intptr_t incr;
13298a475bcbSad 
13308a475bcbSad 		/*
13318a475bcbSad 		 * The loop is necessary to recover from races with other
13328a475bcbSad 		 * threads that are using brk for something other than malloc.
13338a475bcbSad 		 */
13348a475bcbSad 		malloc_mutex_lock(&brk_mtx);
13358a475bcbSad 		do {
13368a475bcbSad 			/* Get the current end of brk. */
13378a475bcbSad 			brk_cur = sbrk(0);
13388a475bcbSad 
13398a475bcbSad 			/*
13408a475bcbSad 			 * Calculate how much padding is necessary to
13418a475bcbSad 			 * chunk-align the end of brk.
13428a475bcbSad 			 */
13438a475bcbSad 			incr = (intptr_t)size
13448a475bcbSad 			    - (intptr_t)CHUNK_ADDR2OFFSET(brk_cur);
13452360d084Slukem 			if (incr == (intptr_t)size) {
13468a475bcbSad 				ret = brk_cur;
13478a475bcbSad 			} else {
13488a475bcbSad 				ret = (void *)((intptr_t)brk_cur + incr);
13498a475bcbSad 				incr += size;
13508a475bcbSad 			}
13518a475bcbSad 
13528a475bcbSad 			brk_prev = sbrk(incr);
13538a475bcbSad 			if (brk_prev == brk_cur) {
13548a475bcbSad 				/* Success. */
13558a475bcbSad 				malloc_mutex_unlock(&brk_mtx);
13568a475bcbSad 				brk_max = (void *)((intptr_t)ret + size);
13578a475bcbSad 				goto RETURN;
13588a475bcbSad 			}
13598a475bcbSad 		} while (brk_prev != (void *)-1);
13608a475bcbSad 		malloc_mutex_unlock(&brk_mtx);
13618a475bcbSad 	}
13628a475bcbSad #endif
13638a475bcbSad 
13648a475bcbSad 	/* All strategies for allocation failed. */
13658a475bcbSad 	ret = NULL;
13668a475bcbSad RETURN:
13678a475bcbSad 	if (ret != NULL) {
13688a475bcbSad 		chunk_node_t key;
13698a475bcbSad 		/*
13708a475bcbSad 		 * Clean out any entries in old_chunks that overlap with the
13718a475bcbSad 		 * memory we just allocated.
13728a475bcbSad 		 */
13738a475bcbSad 		key.chunk = ret;
1374562025fdSad 		tchunk = rb_tree_find_node_geq(&old_chunks, &key);
13758a475bcbSad 		while (tchunk != NULL
13768a475bcbSad 		    && (uintptr_t)tchunk->chunk >= (uintptr_t)ret
13778a475bcbSad 		    && (uintptr_t)tchunk->chunk < (uintptr_t)ret + size) {
13788a475bcbSad 			delchunk = tchunk;
1379562025fdSad 			tchunk = RB_TREE_NEXT(&old_chunks, delchunk);
1380562025fdSad 			rb_tree_remove_node(&old_chunks, delchunk);
13818a475bcbSad 			base_chunk_node_dealloc(delchunk);
13828a475bcbSad 		}
13838a475bcbSad 
13848a475bcbSad 	}
13858a475bcbSad #ifdef MALLOC_STATS
13868a475bcbSad 	if (ret != NULL) {
13878a475bcbSad 		stats_chunks.nchunks += (size / chunksize);
13888a475bcbSad 		stats_chunks.curchunks += (size / chunksize);
13898a475bcbSad 	}
13908a475bcbSad 	if (stats_chunks.curchunks > stats_chunks.highchunks)
13918a475bcbSad 		stats_chunks.highchunks = stats_chunks.curchunks;
13928a475bcbSad #endif
13938a475bcbSad 	malloc_mutex_unlock(&chunks_mtx);
13948a475bcbSad 
13958a475bcbSad 	assert(CHUNK_ADDR2BASE(ret) == ret);
13968a475bcbSad 	return (ret);
13978a475bcbSad }
13988a475bcbSad 
13998a475bcbSad static void
chunk_dealloc(void * chunk,size_t size)14008a475bcbSad chunk_dealloc(void *chunk, size_t size)
14018a475bcbSad {
14028a475bcbSad 	chunk_node_t *node;
14038a475bcbSad 
14048a475bcbSad 	assert(chunk != NULL);
14058a475bcbSad 	assert(CHUNK_ADDR2BASE(chunk) == chunk);
14068a475bcbSad 	assert(size != 0);
14078a475bcbSad 	assert((size & chunksize_mask) == 0);
14088a475bcbSad 
14098a475bcbSad 	malloc_mutex_lock(&chunks_mtx);
14108a475bcbSad 
14118a475bcbSad #ifdef USE_BRK
14128a475bcbSad 	if ((uintptr_t)chunk >= (uintptr_t)brk_base
14138a475bcbSad 	    && (uintptr_t)chunk < (uintptr_t)brk_max) {
14148a475bcbSad 		void *brk_cur;
14158a475bcbSad 
14168a475bcbSad 		malloc_mutex_lock(&brk_mtx);
14178a475bcbSad 		/* Get the current end of brk. */
14188a475bcbSad 		brk_cur = sbrk(0);
14198a475bcbSad 
14208a475bcbSad 		/*
14218a475bcbSad 		 * Try to shrink the data segment if this chunk is at the end
14228a475bcbSad 		 * of the data segment.  The sbrk() call here is subject to a
14238a475bcbSad 		 * race condition with threads that use brk(2) or sbrk(2)
14248a475bcbSad 		 * directly, but the alternative would be to leak memory for
14258a475bcbSad 		 * the sake of poorly designed multi-threaded programs.
14268a475bcbSad 		 */
14278a475bcbSad 		if (brk_cur == brk_max
14288a475bcbSad 		    && (void *)((uintptr_t)chunk + size) == brk_max
14298a475bcbSad 		    && sbrk(-(intptr_t)size) == brk_max) {
14308a475bcbSad 			malloc_mutex_unlock(&brk_mtx);
14318a475bcbSad 			if (brk_prev == brk_max) {
14328a475bcbSad 				/* Success. */
14338a475bcbSad 				brk_prev = (void *)((intptr_t)brk_max
14348a475bcbSad 				    - (intptr_t)size);
14358a475bcbSad 				brk_max = brk_prev;
14368a475bcbSad 			}
14378a475bcbSad 		} else {
14388a475bcbSad 			size_t offset;
14398a475bcbSad 
14408a475bcbSad 			malloc_mutex_unlock(&brk_mtx);
14418a475bcbSad 			madvise(chunk, size, MADV_FREE);
14428a475bcbSad 
14438a475bcbSad 			/*
14448a475bcbSad 			 * Iteratively create records of each chunk-sized
14458a475bcbSad 			 * memory region that 'chunk' is comprised of, so that
14468a475bcbSad 			 * the address range can be recycled if memory usage
14478a475bcbSad 			 * increases later on.
14488a475bcbSad 			 */
14498a475bcbSad 			for (offset = 0; offset < size; offset += chunksize) {
14508a475bcbSad 				node = base_chunk_node_alloc();
14518a475bcbSad 				if (node == NULL)
14528a475bcbSad 					break;
14538a475bcbSad 
14548a475bcbSad 				node->chunk = (void *)((uintptr_t)chunk
14558a475bcbSad 				    + (uintptr_t)offset);
14568a475bcbSad 				node->size = chunksize;
1457562025fdSad 				rb_tree_insert_node(&old_chunks, node);
14588a475bcbSad 			}
14598a475bcbSad 		}
14608a475bcbSad 	} else {
14618a475bcbSad #endif
14628a475bcbSad 		pages_unmap(chunk, size);
14638a475bcbSad 
14648a475bcbSad 		/*
14658a475bcbSad 		 * Make a record of the chunk's address, so that the address
14668a475bcbSad 		 * range can be recycled if memory usage increases later on.
14678a475bcbSad 		 * Don't bother to create entries if (size > chunksize), since
14688a475bcbSad 		 * doing so could cause scalability issues for truly gargantuan
14698a475bcbSad 		 * objects (many gigabytes or larger).
14708a475bcbSad 		 */
14718a475bcbSad 		if (size == chunksize) {
14728a475bcbSad 			node = base_chunk_node_alloc();
14738a475bcbSad 			if (node != NULL) {
14748a475bcbSad 				node->chunk = (void *)(uintptr_t)chunk;
14758a475bcbSad 				node->size = chunksize;
1476562025fdSad 				rb_tree_insert_node(&old_chunks, node);
14778a475bcbSad 			}
14788a475bcbSad 		}
14798a475bcbSad #ifdef USE_BRK
14808a475bcbSad 	}
14818a475bcbSad #endif
14828a475bcbSad 
14838a475bcbSad #ifdef MALLOC_STATS
14848a475bcbSad 	stats_chunks.curchunks -= (size / chunksize);
14858a475bcbSad #endif
14868a475bcbSad 	malloc_mutex_unlock(&chunks_mtx);
14878a475bcbSad }
14888a475bcbSad 
14898a475bcbSad /*
14908a475bcbSad  * End chunk management functions.
14918a475bcbSad  */
14928a475bcbSad /******************************************************************************/
14938a475bcbSad /*
14948a475bcbSad  * Begin arena.
14958a475bcbSad  */
14968a475bcbSad 
14978a475bcbSad /*
1498bf5f78d5Sad  * Choose a per-CPU arena.
14998a475bcbSad  */
1500380c3da0Sad static __noinline arena_t *
choose_arena_hard(void)1501380c3da0Sad choose_arena_hard(void)
15028a475bcbSad {
15038a475bcbSad 
1504bf5f78d5Sad 	assert(arenas[0] != NULL);
1505bf5f78d5Sad 
15068a475bcbSad 	malloc_mutex_lock(&arenas_mtx);
1507bf5f78d5Sad 	for (unsigned i = 1; i < ncpus; i++)
1508bf5f78d5Sad 		if (arenas[i] == NULL)
1509bf5f78d5Sad 			arenas[i] = arenas_extend();
15108a475bcbSad 	malloc_mutex_unlock(&arenas_mtx);
15118a475bcbSad 
1512bf5f78d5Sad 	return arenas[thr_curcpu()];
15138a475bcbSad }
15148a475bcbSad 
1515380c3da0Sad static inline arena_t *
choose_arena(void)1516380c3da0Sad choose_arena(void)
1517380c3da0Sad {
1518bf5f78d5Sad 	arena_t *arena;
1519380c3da0Sad 
1520bf5f78d5Sad 	/* NB: when libpthread is absent, thr_curcpu() always returns zero. */
1521bf5f78d5Sad 	arena = arenas[thr_curcpu()];
1522bf5f78d5Sad 	if (__predict_true(arena != NULL))
1523bf5f78d5Sad 		return arena;
1524380c3da0Sad 
1525380c3da0Sad 	return choose_arena_hard();
1526380c3da0Sad }
1527380c3da0Sad 
1528562025fdSad static int
arena_chunk_comp(void * context,const void * va,const void * vb)1529562025fdSad arena_chunk_comp(void *context, const void *va, const void *vb)
1530562025fdSad {
1531562025fdSad 	const arena_chunk_t *a = va, *b = vb;
1532562025fdSad 	int diff;
1533562025fdSad 
1534562025fdSad 	assert(a != NULL);
1535562025fdSad 	assert(b != NULL);
1536562025fdSad 
1537562025fdSad 	if ((diff = a->max_frun_npages - b->max_frun_npages) != 0)
1538562025fdSad 		return diff;
1539562025fdSad 	return ptrcmp(a, b);
1540562025fdSad }
1541562025fdSad 
1542562025fdSad static int
arena_run_comp(void * context,const void * a,const void * b)1543562025fdSad arena_run_comp(void *context, const void *a, const void *b)
15448a475bcbSad {
15458a475bcbSad 
15468a475bcbSad 	assert(a != NULL);
15478a475bcbSad 	assert(b != NULL);
15488a475bcbSad 
1549562025fdSad 	return ptrcmp(a, b);
15508a475bcbSad }
15518a475bcbSad 
15528a475bcbSad static inline void *
arena_run_reg_alloc(arena_run_t * run,arena_bin_t * bin)15538a475bcbSad arena_run_reg_alloc(arena_run_t *run, arena_bin_t *bin)
15548a475bcbSad {
15558a475bcbSad 	void *ret;
15568a475bcbSad 	unsigned i, mask, bit, regind;
15578a475bcbSad 
15588a475bcbSad 	assert(run->magic == ARENA_RUN_MAGIC);
15598a475bcbSad 	assert(run->regs_minelm < bin->regs_mask_nelms);
15608a475bcbSad 
15618a475bcbSad 	/*
15628a475bcbSad 	 * Move the first check outside the loop, so that run->regs_minelm can
15638a475bcbSad 	 * be updated unconditionally, without the possibility of updating it
15648a475bcbSad 	 * multiple times.
15658a475bcbSad 	 */
15668a475bcbSad 	i = run->regs_minelm;
15678a475bcbSad 	mask = run->regs_mask[i];
15688a475bcbSad 	if (mask != 0) {
15698a475bcbSad 		/* Usable allocation found. */
15708a475bcbSad 		bit = ffs((int)mask) - 1;
15718a475bcbSad 
15728a475bcbSad 		regind = ((i << (SIZEOF_INT_2POW + 3)) + bit);
15738a475bcbSad 		ret = (void *)(((uintptr_t)run) + bin->reg0_offset
15748a475bcbSad 		    + (bin->reg_size * regind));
15758a475bcbSad 
15768a475bcbSad 		/* Clear bit. */
1577f34d1bddSkamil 		mask ^= (1U << bit);
15788a475bcbSad 		run->regs_mask[i] = mask;
15798a475bcbSad 
15808a475bcbSad 		return (ret);
15818a475bcbSad 	}
15828a475bcbSad 
15838a475bcbSad 	for (i++; i < bin->regs_mask_nelms; i++) {
15848a475bcbSad 		mask = run->regs_mask[i];
15858a475bcbSad 		if (mask != 0) {
15868a475bcbSad 			/* Usable allocation found. */
15878a475bcbSad 			bit = ffs((int)mask) - 1;
15888a475bcbSad 
15898a475bcbSad 			regind = ((i << (SIZEOF_INT_2POW + 3)) + bit);
15908a475bcbSad 			ret = (void *)(((uintptr_t)run) + bin->reg0_offset
15918a475bcbSad 			    + (bin->reg_size * regind));
15928a475bcbSad 
15938a475bcbSad 			/* Clear bit. */
1594f34d1bddSkamil 			mask ^= (1U << bit);
15958a475bcbSad 			run->regs_mask[i] = mask;
15968a475bcbSad 
15978a475bcbSad 			/*
15988a475bcbSad 			 * Make a note that nothing before this element
15998a475bcbSad 			 * contains a free region.
16008a475bcbSad 			 */
16018a475bcbSad 			run->regs_minelm = i; /* Low payoff: + (mask == 0); */
16028a475bcbSad 
16038a475bcbSad 			return (ret);
16048a475bcbSad 		}
16058a475bcbSad 	}
16068a475bcbSad 	/* Not reached. */
1607687cd24eSyamt 	/* LINTED */
16088a475bcbSad 	assert(0);
16098a475bcbSad 	return (NULL);
16108a475bcbSad }
16118a475bcbSad 
16128a475bcbSad static inline void
arena_run_reg_dalloc(arena_run_t * run,arena_bin_t * bin,void * ptr,size_t size)16138a475bcbSad arena_run_reg_dalloc(arena_run_t *run, arena_bin_t *bin, void *ptr, size_t size)
16148a475bcbSad {
16158a475bcbSad 	/*
16168a475bcbSad 	 * To divide by a number D that is not a power of two we multiply
16178a475bcbSad 	 * by (2^21 / D) and then right shift by 21 positions.
16188a475bcbSad 	 *
16198a475bcbSad 	 *   X / D
16208a475bcbSad 	 *
16218a475bcbSad 	 * becomes
16228a475bcbSad 	 *
16238a475bcbSad 	 *   (X * size_invs[(D >> QUANTUM_2POW_MIN) - 3]) >> SIZE_INV_SHIFT
16248a475bcbSad 	 */
16258a475bcbSad #define SIZE_INV_SHIFT 21
16268a475bcbSad #define SIZE_INV(s) (((1 << SIZE_INV_SHIFT) / (s << QUANTUM_2POW_MIN)) + 1)
16278a475bcbSad 	static const unsigned size_invs[] = {
16288a475bcbSad 	    SIZE_INV(3),
16298a475bcbSad 	    SIZE_INV(4), SIZE_INV(5), SIZE_INV(6), SIZE_INV(7),
16308a475bcbSad 	    SIZE_INV(8), SIZE_INV(9), SIZE_INV(10), SIZE_INV(11),
16318a475bcbSad 	    SIZE_INV(12),SIZE_INV(13), SIZE_INV(14), SIZE_INV(15),
16328a475bcbSad 	    SIZE_INV(16),SIZE_INV(17), SIZE_INV(18), SIZE_INV(19),
16338a475bcbSad 	    SIZE_INV(20),SIZE_INV(21), SIZE_INV(22), SIZE_INV(23),
16348a475bcbSad 	    SIZE_INV(24),SIZE_INV(25), SIZE_INV(26), SIZE_INV(27),
16358a475bcbSad 	    SIZE_INV(28),SIZE_INV(29), SIZE_INV(30), SIZE_INV(31)
16368a475bcbSad #if (QUANTUM_2POW_MIN < 4)
16378a475bcbSad 	    ,
16388a475bcbSad 	    SIZE_INV(32), SIZE_INV(33), SIZE_INV(34), SIZE_INV(35),
16398a475bcbSad 	    SIZE_INV(36), SIZE_INV(37), SIZE_INV(38), SIZE_INV(39),
16408a475bcbSad 	    SIZE_INV(40), SIZE_INV(41), SIZE_INV(42), SIZE_INV(43),
16418a475bcbSad 	    SIZE_INV(44), SIZE_INV(45), SIZE_INV(46), SIZE_INV(47),
16428a475bcbSad 	    SIZE_INV(48), SIZE_INV(49), SIZE_INV(50), SIZE_INV(51),
16438a475bcbSad 	    SIZE_INV(52), SIZE_INV(53), SIZE_INV(54), SIZE_INV(55),
16448a475bcbSad 	    SIZE_INV(56), SIZE_INV(57), SIZE_INV(58), SIZE_INV(59),
16458a475bcbSad 	    SIZE_INV(60), SIZE_INV(61), SIZE_INV(62), SIZE_INV(63)
16468a475bcbSad #endif
16478a475bcbSad 	};
16488a475bcbSad 	unsigned diff, regind, elm, bit;
16498a475bcbSad 
1650687cd24eSyamt 	/* LINTED */
16518a475bcbSad 	assert(run->magic == ARENA_RUN_MAGIC);
16528a475bcbSad 	assert(((sizeof(size_invs)) / sizeof(unsigned)) + 3
16538a475bcbSad 	    >= (SMALL_MAX_DEFAULT >> QUANTUM_2POW_MIN));
16548a475bcbSad 
16558a475bcbSad 	/*
16568a475bcbSad 	 * Avoid doing division with a variable divisor if possible.  Using
16578a475bcbSad 	 * actual division here can reduce allocator throughput by over 20%!
16588a475bcbSad 	 */
16598a475bcbSad 	diff = (unsigned)((uintptr_t)ptr - (uintptr_t)run - bin->reg0_offset);
16608a475bcbSad 	if ((size & (size - 1)) == 0) {
16618a475bcbSad 		/*
16628a475bcbSad 		 * log2_table allows fast division of a power of two in the
16638a475bcbSad 		 * [1..128] range.
16648a475bcbSad 		 *
16658a475bcbSad 		 * (x / divisor) becomes (x >> log2_table[divisor - 1]).
16668a475bcbSad 		 */
16678a475bcbSad 		static const unsigned char log2_table[] = {
16688a475bcbSad 		    0, 1, 0, 2, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 4,
16698a475bcbSad 		    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5,
16708a475bcbSad 		    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
16718a475bcbSad 		    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6,
16728a475bcbSad 		    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
16738a475bcbSad 		    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
16748a475bcbSad 		    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
16758a475bcbSad 		    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7
16768a475bcbSad 		};
16778a475bcbSad 
16788a475bcbSad 		if (size <= 128)
16798a475bcbSad 			regind = (diff >> log2_table[size - 1]);
16808a475bcbSad 		else if (size <= 32768)
16818a475bcbSad 			regind = diff >> (8 + log2_table[(size >> 8) - 1]);
16828a475bcbSad 		else {
16838a475bcbSad 			/*
16848a475bcbSad 			 * The page size is too large for us to use the lookup
16858a475bcbSad 			 * table.  Use real division.
16868a475bcbSad 			 */
16878de47c09Schristos 			regind = (unsigned)(diff / size);
16888a475bcbSad 		}
168913122b28Sad 	} else if (size <= (((sizeof(size_invs) / sizeof(unsigned)) + 2)
169013122b28Sad 	    << QUANTUM_2POW_MIN)) {
16918a475bcbSad 		regind = size_invs[(size >> QUANTUM_2POW_MIN) - 3] * diff;
16928a475bcbSad 		regind >>= SIZE_INV_SHIFT;
16938a475bcbSad 	} else {
16948a475bcbSad 		/*
16958a475bcbSad 		 * size_invs isn't large enough to handle this size class, so
16968a475bcbSad 		 * calculate regind using actual division.  This only happens
16978a475bcbSad 		 * if the user increases small_max via the 'S' runtime
16988a475bcbSad 		 * configuration option.
16998a475bcbSad 		 */
17008de47c09Schristos 		regind = (unsigned)(diff / size);
17018a475bcbSad 	};
17028a475bcbSad 	assert(diff == regind * size);
17038a475bcbSad 	assert(regind < bin->nregs);
17048a475bcbSad 
17058a475bcbSad 	elm = regind >> (SIZEOF_INT_2POW + 3);
17068a475bcbSad 	if (elm < run->regs_minelm)
17078a475bcbSad 		run->regs_minelm = elm;
17088a475bcbSad 	bit = regind - (elm << (SIZEOF_INT_2POW + 3));
1709f34d1bddSkamil 	assert((run->regs_mask[elm] & (1U << bit)) == 0);
1710f34d1bddSkamil 	run->regs_mask[elm] |= (1U << bit);
17118a475bcbSad #undef SIZE_INV
17128a475bcbSad #undef SIZE_INV_SHIFT
17138a475bcbSad }
17148a475bcbSad 
17158a475bcbSad static void
arena_run_split(arena_t * arena,arena_run_t * run,size_t size)17168a475bcbSad arena_run_split(arena_t *arena, arena_run_t *run, size_t size)
17178a475bcbSad {
17188a475bcbSad 	arena_chunk_t *chunk;
17198a475bcbSad 	unsigned run_ind, map_offset, total_pages, need_pages, rem_pages;
17208a475bcbSad 	unsigned i;
17218a475bcbSad 
17228a475bcbSad 	chunk = (arena_chunk_t *)CHUNK_ADDR2BASE(run);
17238a475bcbSad 	run_ind = (unsigned)(((uintptr_t)run - (uintptr_t)chunk)
17248a475bcbSad 	    >> pagesize_2pow);
17258a475bcbSad 	total_pages = chunk->map[run_ind].npages;
17268de47c09Schristos 	need_pages = (unsigned)(size >> pagesize_2pow);
17278a475bcbSad 	assert(need_pages <= total_pages);
17288a475bcbSad 	rem_pages = total_pages - need_pages;
17298a475bcbSad 
17308a475bcbSad 	/* Split enough pages from the front of run to fit allocation size. */
17318a475bcbSad 	map_offset = run_ind;
17328a475bcbSad 	for (i = 0; i < need_pages; i++) {
17338a475bcbSad 		chunk->map[map_offset + i].npages = need_pages;
17348a475bcbSad 		chunk->map[map_offset + i].pos = i;
17358a475bcbSad 	}
17368a475bcbSad 
17378a475bcbSad 	/* Keep track of trailing unused pages for later use. */
17388a475bcbSad 	if (rem_pages > 0) {
17398a475bcbSad 		/* Update map for trailing pages. */
17408a475bcbSad 		map_offset += need_pages;
17418a475bcbSad 		chunk->map[map_offset].npages = rem_pages;
17428a475bcbSad 		chunk->map[map_offset].pos = POS_FREE;
17438a475bcbSad 		chunk->map[map_offset + rem_pages - 1].npages = rem_pages;
17448a475bcbSad 		chunk->map[map_offset + rem_pages - 1].pos = POS_FREE;
17458a475bcbSad 	}
17468a475bcbSad 
17478a475bcbSad 	chunk->pages_used += need_pages;
17488a475bcbSad }
17498a475bcbSad 
17508a475bcbSad static arena_chunk_t *
arena_chunk_alloc(arena_t * arena)17518a475bcbSad arena_chunk_alloc(arena_t *arena)
17528a475bcbSad {
17538a475bcbSad 	arena_chunk_t *chunk;
17548a475bcbSad 
17558a475bcbSad 	if (arena->spare != NULL) {
17568a475bcbSad 		chunk = arena->spare;
17578a475bcbSad 		arena->spare = NULL;
17588a475bcbSad 
1759562025fdSad 		rb_tree_insert_node(&arena->chunks, chunk);
17608a475bcbSad 	} else {
17618a475bcbSad 		chunk = (arena_chunk_t *)chunk_alloc(chunksize);
17628a475bcbSad 		if (chunk == NULL)
17638a475bcbSad 			return (NULL);
17648a475bcbSad #ifdef MALLOC_STATS
17658a475bcbSad 		arena->stats.mapped += chunksize;
17668a475bcbSad #endif
17678a475bcbSad 
17688a475bcbSad 		chunk->arena = arena;
17698a475bcbSad 
17708a475bcbSad 		/*
17718a475bcbSad 		 * Claim that no pages are in use, since the header is merely
17728a475bcbSad 		 * overhead.
17738a475bcbSad 		 */
17748a475bcbSad 		chunk->pages_used = 0;
17758a475bcbSad 
17768a475bcbSad 		chunk->max_frun_npages = chunk_npages -
17778a475bcbSad 		    arena_chunk_header_npages;
17788a475bcbSad 		chunk->min_frun_ind = arena_chunk_header_npages;
17798a475bcbSad 
17808a475bcbSad 		/*
17818a475bcbSad 		 * Initialize enough of the map to support one maximal free run.
17828a475bcbSad 		 */
17838a475bcbSad 		chunk->map[arena_chunk_header_npages].npages = chunk_npages -
17848a475bcbSad 		    arena_chunk_header_npages;
17858a475bcbSad 		chunk->map[arena_chunk_header_npages].pos = POS_FREE;
17868a475bcbSad 		chunk->map[chunk_npages - 1].npages = chunk_npages -
17878a475bcbSad 		    arena_chunk_header_npages;
17888a475bcbSad 		chunk->map[chunk_npages - 1].pos = POS_FREE;
1789c75fe7b8Sjoerg 
1790562025fdSad 		rb_tree_insert_node(&arena->chunks, chunk);
17918a475bcbSad 	}
17928a475bcbSad 
17938a475bcbSad 	return (chunk);
17948a475bcbSad }
17958a475bcbSad 
17968a475bcbSad static void
arena_chunk_dealloc(arena_t * arena,arena_chunk_t * chunk)17978a475bcbSad arena_chunk_dealloc(arena_t *arena, arena_chunk_t *chunk)
17988a475bcbSad {
17998a475bcbSad 
18008a475bcbSad 	/*
18018a475bcbSad 	 * Remove chunk from the chunk tree, regardless of whether this chunk
18028a475bcbSad 	 * will be cached, so that the arena does not use it.
18038a475bcbSad 	 */
1804562025fdSad 	rb_tree_remove_node(&chunk->arena->chunks, chunk);
18058a475bcbSad 
1806bf5f78d5Sad 	if (NOT_OPT(hint)) {
18078a475bcbSad 		if (arena->spare != NULL) {
18088a475bcbSad 			chunk_dealloc((void *)arena->spare, chunksize);
18098a475bcbSad #ifdef MALLOC_STATS
18108a475bcbSad 			arena->stats.mapped -= chunksize;
18118a475bcbSad #endif
18128a475bcbSad 		}
18138a475bcbSad 		arena->spare = chunk;
18148a475bcbSad 	} else {
18158a475bcbSad 		assert(arena->spare == NULL);
18168a475bcbSad 		chunk_dealloc((void *)chunk, chunksize);
18178a475bcbSad #ifdef MALLOC_STATS
18188a475bcbSad 		arena->stats.mapped -= chunksize;
18198a475bcbSad #endif
18208a475bcbSad 	}
18218a475bcbSad }
18228a475bcbSad 
18238a475bcbSad static arena_run_t *
arena_run_alloc(arena_t * arena,size_t size)18248a475bcbSad arena_run_alloc(arena_t *arena, size_t size)
18258a475bcbSad {
1826562025fdSad 	arena_chunk_t *chunk;
18278a475bcbSad 	arena_run_t *run;
1828c75fe7b8Sjoerg 	unsigned need_npages;
18298a475bcbSad 
18308a475bcbSad 	assert(size <= (chunksize - (arena_chunk_header_npages <<
18318a475bcbSad 	    pagesize_2pow)));
18328a475bcbSad 	assert((size & pagesize_mask) == 0);
18338a475bcbSad 
18348a475bcbSad 	/*
1835c75fe7b8Sjoerg 	 * Search through the arena chunk tree for a large enough free run.
1836c75fe7b8Sjoerg 	 * Tree order ensures that any exact fit is picked immediately or
1837c75fe7b8Sjoerg 	 * otherwise the lowest address of the next size.
18388a475bcbSad 	 */
18398de47c09Schristos 	need_npages = (unsigned)(size >> pagesize_2pow);
1840e7a9e46bSad 	/* LINTED */
1841c75fe7b8Sjoerg 	for (;;) {
1842562025fdSad 		rb_node_t *node = arena->chunks.rbt_root;
1843c75fe7b8Sjoerg 		chunk = NULL;
1844562025fdSad 		while (!RB_SENTINEL_P(node)) {
1845562025fdSad 			assert(offsetof(struct arena_chunk_s, link) == 0);
1846562025fdSad 			arena_chunk_t *chunk_tmp = (arena_chunk_t *)node;
1847c75fe7b8Sjoerg 			if (chunk_tmp->max_frun_npages == need_npages) {
1848c75fe7b8Sjoerg 				chunk = chunk_tmp;
1849c75fe7b8Sjoerg 				break;
1850c75fe7b8Sjoerg 			}
1851c75fe7b8Sjoerg 			if (chunk_tmp->max_frun_npages < need_npages) {
1852562025fdSad 				node = node->rb_nodes[1];
1853c75fe7b8Sjoerg 				continue;
1854c75fe7b8Sjoerg 			}
1855c75fe7b8Sjoerg 			chunk = chunk_tmp;
1856562025fdSad 			node = node->rb_nodes[0];
1857c75fe7b8Sjoerg 		}
1858c75fe7b8Sjoerg 		if (chunk == NULL)
1859c75fe7b8Sjoerg 			break;
18608a475bcbSad 		/*
1861c75fe7b8Sjoerg 		 * At this point, the chunk must have a cached run size large
1862c75fe7b8Sjoerg 		 * enough to fit the allocation.
18638a475bcbSad 		 */
1864c75fe7b8Sjoerg 		assert(need_npages <= chunk->max_frun_npages);
1865c75fe7b8Sjoerg 		{
18668a475bcbSad 			arena_chunk_map_t *mapelm;
18678a475bcbSad 			unsigned i;
18688a475bcbSad 			unsigned max_frun_npages = 0;
18698a475bcbSad 			unsigned min_frun_ind = chunk_npages;
18708a475bcbSad 
18718a475bcbSad 			assert(chunk->min_frun_ind >=
18728a475bcbSad 			    arena_chunk_header_npages);
18738a475bcbSad 			for (i = chunk->min_frun_ind; i < chunk_npages;) {
18748a475bcbSad 				mapelm = &chunk->map[i];
18758a475bcbSad 				if (mapelm->pos == POS_FREE) {
18768a475bcbSad 					if (mapelm->npages >= need_npages) {
18778a475bcbSad 						run = (arena_run_t *)
18788a475bcbSad 						    ((uintptr_t)chunk + (i <<
18798a475bcbSad 						    pagesize_2pow));
18808a475bcbSad 						/* Update page map. */
18818a475bcbSad 						arena_run_split(arena, run,
18828a475bcbSad 						    size);
18838a475bcbSad 						return (run);
18848a475bcbSad 					}
18858a475bcbSad 					if (mapelm->npages >
18868a475bcbSad 					    max_frun_npages) {
18878a475bcbSad 						max_frun_npages =
18888a475bcbSad 						    mapelm->npages;
18898a475bcbSad 					}
18908a475bcbSad 					if (i < min_frun_ind) {
18918a475bcbSad 						min_frun_ind = i;
18928a475bcbSad 						if (i < chunk->min_frun_ind)
18938a475bcbSad 							chunk->min_frun_ind = i;
18948a475bcbSad 					}
18958a475bcbSad 				}
18968a475bcbSad 				i += mapelm->npages;
18978a475bcbSad 			}
18988a475bcbSad 			/*
18998a475bcbSad 			 * Search failure.  Reset cached chunk->max_frun_npages.
19008a475bcbSad 			 * chunk->min_frun_ind was already reset above (if
19018a475bcbSad 			 * necessary).
19028a475bcbSad 			 */
1903562025fdSad 			rb_tree_remove_node(&arena->chunks, chunk);
19048a475bcbSad 			chunk->max_frun_npages = max_frun_npages;
1905562025fdSad 			rb_tree_insert_node(&arena->chunks, chunk);
19068a475bcbSad 		}
19078a475bcbSad 	}
19088a475bcbSad 
19098a475bcbSad 	/*
19108a475bcbSad 	 * No usable runs.  Create a new chunk from which to allocate the run.
19118a475bcbSad 	 */
19128a475bcbSad 	chunk = arena_chunk_alloc(arena);
19138a475bcbSad 	if (chunk == NULL)
19148a475bcbSad 		return (NULL);
19158a475bcbSad 	run = (arena_run_t *)((uintptr_t)chunk + (arena_chunk_header_npages <<
19168a475bcbSad 	    pagesize_2pow));
19178a475bcbSad 	/* Update page map. */
19188a475bcbSad 	arena_run_split(arena, run, size);
19198a475bcbSad 	return (run);
19208a475bcbSad }
19218a475bcbSad 
19228a475bcbSad static void
arena_run_dalloc(arena_t * arena,arena_run_t * run,size_t size)19238a475bcbSad arena_run_dalloc(arena_t *arena, arena_run_t *run, size_t size)
19248a475bcbSad {
19258a475bcbSad 	arena_chunk_t *chunk;
19268a475bcbSad 	unsigned run_ind, run_pages;
19278a475bcbSad 
19288a475bcbSad 	chunk = (arena_chunk_t *)CHUNK_ADDR2BASE(run);
19298a475bcbSad 
19308a475bcbSad 	run_ind = (unsigned)(((uintptr_t)run - (uintptr_t)chunk)
19318a475bcbSad 	    >> pagesize_2pow);
19328a475bcbSad 	assert(run_ind >= arena_chunk_header_npages);
19338a475bcbSad 	assert(run_ind < (chunksize >> pagesize_2pow));
19348de47c09Schristos 	run_pages = (unsigned)(size >> pagesize_2pow);
19358a475bcbSad 	assert(run_pages == chunk->map[run_ind].npages);
19368a475bcbSad 
19378a475bcbSad 	/* Subtract pages from count of pages used in chunk. */
19388a475bcbSad 	chunk->pages_used -= run_pages;
19398a475bcbSad 
19408a475bcbSad 	/* Mark run as deallocated. */
19418a475bcbSad 	assert(chunk->map[run_ind].npages == run_pages);
19428a475bcbSad 	chunk->map[run_ind].pos = POS_FREE;
19438a475bcbSad 	assert(chunk->map[run_ind + run_pages - 1].npages == run_pages);
19448a475bcbSad 	chunk->map[run_ind + run_pages - 1].pos = POS_FREE;
19458a475bcbSad 
19468a475bcbSad 	/*
19478a475bcbSad 	 * Tell the kernel that we don't need the data in this run, but only if
19488a475bcbSad 	 * requested via runtime configuration.
19498a475bcbSad 	 */
1950bf5f78d5Sad 	if (OPT(hint))
19518a475bcbSad 		madvise(run, size, MADV_FREE);
19528a475bcbSad 
19538a475bcbSad 	/* Try to coalesce with neighboring runs. */
19548a475bcbSad 	if (run_ind > arena_chunk_header_npages &&
19558a475bcbSad 	    chunk->map[run_ind - 1].pos == POS_FREE) {
19568a475bcbSad 		unsigned prev_npages;
19578a475bcbSad 
19588a475bcbSad 		/* Coalesce with previous run. */
19598a475bcbSad 		prev_npages = chunk->map[run_ind - 1].npages;
19608a475bcbSad 		run_ind -= prev_npages;
19618a475bcbSad 		assert(chunk->map[run_ind].npages == prev_npages);
19628a475bcbSad 		assert(chunk->map[run_ind].pos == POS_FREE);
19638a475bcbSad 		run_pages += prev_npages;
19648a475bcbSad 
19658a475bcbSad 		chunk->map[run_ind].npages = run_pages;
19668a475bcbSad 		assert(chunk->map[run_ind].pos == POS_FREE);
19678a475bcbSad 		chunk->map[run_ind + run_pages - 1].npages = run_pages;
19688a475bcbSad 		assert(chunk->map[run_ind + run_pages - 1].pos == POS_FREE);
19698a475bcbSad 	}
19708a475bcbSad 
19718a475bcbSad 	if (run_ind + run_pages < chunk_npages &&
19728a475bcbSad 	    chunk->map[run_ind + run_pages].pos == POS_FREE) {
19738a475bcbSad 		unsigned next_npages;
19748a475bcbSad 
19758a475bcbSad 		/* Coalesce with next run. */
19768a475bcbSad 		next_npages = chunk->map[run_ind + run_pages].npages;
19778a475bcbSad 		run_pages += next_npages;
19788a475bcbSad 		assert(chunk->map[run_ind + run_pages - 1].npages ==
19798a475bcbSad 		    next_npages);
19808a475bcbSad 		assert(chunk->map[run_ind + run_pages - 1].pos == POS_FREE);
19818a475bcbSad 
19828a475bcbSad 		chunk->map[run_ind].npages = run_pages;
19838a475bcbSad 		chunk->map[run_ind].pos = POS_FREE;
19848a475bcbSad 		chunk->map[run_ind + run_pages - 1].npages = run_pages;
19858a475bcbSad 		assert(chunk->map[run_ind + run_pages - 1].pos == POS_FREE);
19868a475bcbSad 	}
19878a475bcbSad 
1988c75fe7b8Sjoerg 	if (chunk->map[run_ind].npages > chunk->max_frun_npages) {
1989562025fdSad 		rb_tree_remove_node(&arena->chunks, chunk);
19908a475bcbSad 		chunk->max_frun_npages = chunk->map[run_ind].npages;
1991562025fdSad 		rb_tree_insert_node(&arena->chunks, chunk);
1992c75fe7b8Sjoerg 	}
19938a475bcbSad 	if (run_ind < chunk->min_frun_ind)
19948a475bcbSad 		chunk->min_frun_ind = run_ind;
19958a475bcbSad 
19968a475bcbSad 	/* Deallocate chunk if it is now completely unused. */
19978a475bcbSad 	if (chunk->pages_used == 0)
19988a475bcbSad 		arena_chunk_dealloc(arena, chunk);
19998a475bcbSad }
20008a475bcbSad 
20018a475bcbSad static arena_run_t *
arena_bin_nonfull_run_get(arena_t * arena,arena_bin_t * bin)20028a475bcbSad arena_bin_nonfull_run_get(arena_t *arena, arena_bin_t *bin)
20038a475bcbSad {
20048a475bcbSad 	arena_run_t *run;
20058a475bcbSad 	unsigned i, remainder;
20068a475bcbSad 
20078a475bcbSad 	/* Look for a usable run. */
2008562025fdSad 	if ((run = RB_TREE_MIN(&bin->runs)) != NULL) {
20098a475bcbSad 		/* run is guaranteed to have available space. */
2010562025fdSad 		rb_tree_remove_node(&bin->runs, run);
20118a475bcbSad #ifdef MALLOC_STATS
20128a475bcbSad 		bin->stats.reruns++;
20138a475bcbSad #endif
20148a475bcbSad 		return (run);
20158a475bcbSad 	}
20168a475bcbSad 	/* No existing runs have any space available. */
20178a475bcbSad 
20188a475bcbSad 	/* Allocate a new run. */
20198a475bcbSad 	run = arena_run_alloc(arena, bin->run_size);
20208a475bcbSad 	if (run == NULL)
20218a475bcbSad 		return (NULL);
20228a475bcbSad 
20238a475bcbSad 	/* Initialize run internals. */
20248a475bcbSad 	run->bin = bin;
20258a475bcbSad 
20268a475bcbSad 	for (i = 0; i < bin->regs_mask_nelms; i++)
20278a475bcbSad 		run->regs_mask[i] = UINT_MAX;
20288a475bcbSad 	remainder = bin->nregs & ((1 << (SIZEOF_INT_2POW + 3)) - 1);
20298a475bcbSad 	if (remainder != 0) {
20308a475bcbSad 		/* The last element has spare bits that need to be unset. */
20318a475bcbSad 		run->regs_mask[i] = (UINT_MAX >> ((1 << (SIZEOF_INT_2POW + 3))
20328a475bcbSad 		    - remainder));
20338a475bcbSad 	}
20348a475bcbSad 
20358a475bcbSad 	run->regs_minelm = 0;
20368a475bcbSad 
20378a475bcbSad 	run->nfree = bin->nregs;
20388a475bcbSad #ifdef MALLOC_DEBUG
20398a475bcbSad 	run->magic = ARENA_RUN_MAGIC;
20408a475bcbSad #endif
20418a475bcbSad 
20428a475bcbSad #ifdef MALLOC_STATS
20438a475bcbSad 	bin->stats.nruns++;
20448a475bcbSad 	bin->stats.curruns++;
20458a475bcbSad 	if (bin->stats.curruns > bin->stats.highruns)
20468a475bcbSad 		bin->stats.highruns = bin->stats.curruns;
20478a475bcbSad #endif
20488a475bcbSad 	return (run);
20498a475bcbSad }
20508a475bcbSad 
20518a475bcbSad /* bin->runcur must have space available before this function is called. */
20528a475bcbSad static inline void *
arena_bin_malloc_easy(arena_t * arena,arena_bin_t * bin,arena_run_t * run)20538a475bcbSad arena_bin_malloc_easy(arena_t *arena, arena_bin_t *bin, arena_run_t *run)
20548a475bcbSad {
20558a475bcbSad 	void *ret;
20568a475bcbSad 
20578a475bcbSad 	assert(run->magic == ARENA_RUN_MAGIC);
20588a475bcbSad 	assert(run->nfree > 0);
20598a475bcbSad 
20608a475bcbSad 	ret = arena_run_reg_alloc(run, bin);
20618a475bcbSad 	assert(ret != NULL);
20628a475bcbSad 	run->nfree--;
20638a475bcbSad 
20648a475bcbSad 	return (ret);
20658a475bcbSad }
20668a475bcbSad 
20678a475bcbSad /* Re-fill bin->runcur, then call arena_bin_malloc_easy(). */
20688a475bcbSad static void *
arena_bin_malloc_hard(arena_t * arena,arena_bin_t * bin)20698a475bcbSad arena_bin_malloc_hard(arena_t *arena, arena_bin_t *bin)
20708a475bcbSad {
20718a475bcbSad 
20728a475bcbSad 	bin->runcur = arena_bin_nonfull_run_get(arena, bin);
20738a475bcbSad 	if (bin->runcur == NULL)
20748a475bcbSad 		return (NULL);
20758a475bcbSad 	assert(bin->runcur->magic == ARENA_RUN_MAGIC);
20768a475bcbSad 	assert(bin->runcur->nfree > 0);
20778a475bcbSad 
20788a475bcbSad 	return (arena_bin_malloc_easy(arena, bin, bin->runcur));
20798a475bcbSad }
20808a475bcbSad 
20818a475bcbSad /*
20828a475bcbSad  * Calculate bin->run_size such that it meets the following constraints:
20838a475bcbSad  *
20848a475bcbSad  *   *) bin->run_size >= min_run_size
20858a475bcbSad  *   *) bin->run_size <= arena_maxclass
20868a475bcbSad  *   *) bin->run_size <= RUN_MAX_SMALL
20878a475bcbSad  *   *) run header overhead <= RUN_MAX_OVRHD (or header overhead relaxed).
20888a475bcbSad  *
20898a475bcbSad  * bin->nregs, bin->regs_mask_nelms, and bin->reg0_offset are
20908a475bcbSad  * also calculated here, since these settings are all interdependent.
20918a475bcbSad  */
20928a475bcbSad static size_t
arena_bin_run_size_calc(arena_bin_t * bin,size_t min_run_size)20938a475bcbSad arena_bin_run_size_calc(arena_bin_t *bin, size_t min_run_size)
20948a475bcbSad {
20958a475bcbSad 	size_t try_run_size, good_run_size;
20968a475bcbSad 	unsigned good_nregs, good_mask_nelms, good_reg0_offset;
20978a475bcbSad 	unsigned try_nregs, try_mask_nelms, try_reg0_offset;
20988a475bcbSad 
20998a475bcbSad 	assert(min_run_size >= pagesize);
21008a475bcbSad 	assert(min_run_size <= arena_maxclass);
21018a475bcbSad 	assert(min_run_size <= RUN_MAX_SMALL);
21028a475bcbSad 
21038a475bcbSad 	/*
21048a475bcbSad 	 * Calculate known-valid settings before entering the run_size
21058a475bcbSad 	 * expansion loop, so that the first part of the loop always copies
21068a475bcbSad 	 * valid settings.
21078a475bcbSad 	 *
21088a475bcbSad 	 * The do..while loop iteratively reduces the number of regions until
21098a475bcbSad 	 * the run header and the regions no longer overlap.  A closed formula
21108a475bcbSad 	 * would be quite messy, since there is an interdependency between the
21118a475bcbSad 	 * header's mask length and the number of regions.
21128a475bcbSad 	 */
21138a475bcbSad 	try_run_size = min_run_size;
21148de47c09Schristos 	try_nregs = (unsigned)(((try_run_size - sizeof(arena_run_t)) /
211551cca89dSnjoly 	    bin->reg_size) + 1); /* Counter-act try_nregs-- in loop. */
21168a475bcbSad 	do {
21178a475bcbSad 		try_nregs--;
21188a475bcbSad 		try_mask_nelms = (try_nregs >> (SIZEOF_INT_2POW + 3)) +
21198a475bcbSad 		    ((try_nregs & ((1 << (SIZEOF_INT_2POW + 3)) - 1)) ? 1 : 0);
21208de47c09Schristos 		try_reg0_offset = (unsigned)(try_run_size -
21218de47c09Schristos 		    (try_nregs * bin->reg_size));
21228a475bcbSad 	} while (sizeof(arena_run_t) + (sizeof(unsigned) * (try_mask_nelms - 1))
21238a475bcbSad 	    > try_reg0_offset);
21248a475bcbSad 
21258a475bcbSad 	/* run_size expansion loop. */
21268a475bcbSad 	do {
21278a475bcbSad 		/*
21288a475bcbSad 		 * Copy valid settings before trying more aggressive settings.
21298a475bcbSad 		 */
21308a475bcbSad 		good_run_size = try_run_size;
21318a475bcbSad 		good_nregs = try_nregs;
21328a475bcbSad 		good_mask_nelms = try_mask_nelms;
21338a475bcbSad 		good_reg0_offset = try_reg0_offset;
21348a475bcbSad 
21358a475bcbSad 		/* Try more aggressive settings. */
21368a475bcbSad 		try_run_size += pagesize;
21378de47c09Schristos 		try_nregs = (unsigned)(((try_run_size - sizeof(arena_run_t)) /
21388de47c09Schristos 		    bin->reg_size) + 1); /* Counter-act try_nregs-- in loop. */
21398a475bcbSad 		do {
21408a475bcbSad 			try_nregs--;
21418a475bcbSad 			try_mask_nelms = (try_nregs >> (SIZEOF_INT_2POW + 3)) +
21428a475bcbSad 			    ((try_nregs & ((1 << (SIZEOF_INT_2POW + 3)) - 1)) ?
21438a475bcbSad 			    1 : 0);
21448de47c09Schristos 			try_reg0_offset = (unsigned)(try_run_size - (try_nregs *
21458de47c09Schristos 			    bin->reg_size));
21468a475bcbSad 		} while (sizeof(arena_run_t) + (sizeof(unsigned) *
21478a475bcbSad 		    (try_mask_nelms - 1)) > try_reg0_offset);
21488a475bcbSad 	} while (try_run_size <= arena_maxclass && try_run_size <= RUN_MAX_SMALL
214951cca89dSnjoly 	    && RUN_MAX_OVRHD * (bin->reg_size << 3) > RUN_MAX_OVRHD_RELAX
215051cca89dSnjoly 	    && (try_reg0_offset << RUN_BFP) > RUN_MAX_OVRHD * try_run_size);
21518a475bcbSad 
21528a475bcbSad 	assert(sizeof(arena_run_t) + (sizeof(unsigned) * (good_mask_nelms - 1))
21538a475bcbSad 	    <= good_reg0_offset);
21548a475bcbSad 	assert((good_mask_nelms << (SIZEOF_INT_2POW + 3)) >= good_nregs);
21558a475bcbSad 
21568a475bcbSad 	/* Copy final settings. */
21578a475bcbSad 	bin->run_size = good_run_size;
21588a475bcbSad 	bin->nregs = good_nregs;
21598a475bcbSad 	bin->regs_mask_nelms = good_mask_nelms;
21608a475bcbSad 	bin->reg0_offset = good_reg0_offset;
21618a475bcbSad 
21628a475bcbSad 	return (good_run_size);
21638a475bcbSad }
21648a475bcbSad 
21658a475bcbSad static void *
arena_malloc(arena_t * arena,size_t size)21668a475bcbSad arena_malloc(arena_t *arena, size_t size)
21678a475bcbSad {
21688a475bcbSad 	void *ret;
21698a475bcbSad 
21708a475bcbSad 	assert(arena != NULL);
21718a475bcbSad 	assert(arena->magic == ARENA_MAGIC);
21728a475bcbSad 	assert(size != 0);
21738a475bcbSad 	assert(QUANTUM_CEILING(size) <= arena_maxclass);
21748a475bcbSad 
21758a475bcbSad 	if (size <= bin_maxclass) {
21768a475bcbSad 		arena_bin_t *bin;
21778a475bcbSad 		arena_run_t *run;
21788a475bcbSad 
21798a475bcbSad 		/* Small allocation. */
21808a475bcbSad 
21818a475bcbSad 		if (size < small_min) {
21828a475bcbSad 			/* Tiny. */
21838a475bcbSad 			size = pow2_ceil(size);
21848a475bcbSad 			bin = &arena->bins[ffs((int)(size >> (TINY_MIN_2POW +
21858a475bcbSad 			    1)))];
21868a475bcbSad #if (!defined(NDEBUG) || defined(MALLOC_STATS))
21878a475bcbSad 			/*
21888a475bcbSad 			 * Bin calculation is always correct, but we may need
21898a475bcbSad 			 * to fix size for the purposes of assertions and/or
21908a475bcbSad 			 * stats accuracy.
21918a475bcbSad 			 */
21928a475bcbSad 			if (size < (1 << TINY_MIN_2POW))
21938a475bcbSad 				size = (1 << TINY_MIN_2POW);
21948a475bcbSad #endif
21958a475bcbSad 		} else if (size <= small_max) {
21968a475bcbSad 			/* Quantum-spaced. */
21978a475bcbSad 			size = QUANTUM_CEILING(size);
21988a475bcbSad 			bin = &arena->bins[ntbins + (size >> opt_quantum_2pow)
21998a475bcbSad 			    - 1];
22008a475bcbSad 		} else {
22018a475bcbSad 			/* Sub-page. */
22028a475bcbSad 			size = pow2_ceil(size);
22038a475bcbSad 			bin = &arena->bins[ntbins + nqbins
22048a475bcbSad 			    + (ffs((int)(size >> opt_small_max_2pow)) - 2)];
22058a475bcbSad 		}
22068a475bcbSad 		assert(size == bin->reg_size);
22078a475bcbSad 
22088a475bcbSad 		malloc_mutex_lock(&arena->mtx);
22098a475bcbSad 		if ((run = bin->runcur) != NULL && run->nfree > 0)
22108a475bcbSad 			ret = arena_bin_malloc_easy(arena, bin, run);
22118a475bcbSad 		else
22128a475bcbSad 			ret = arena_bin_malloc_hard(arena, bin);
22138a475bcbSad 
22148a475bcbSad 		if (ret == NULL) {
22158a475bcbSad 			malloc_mutex_unlock(&arena->mtx);
22168a475bcbSad 			return (NULL);
22178a475bcbSad 		}
22188a475bcbSad 
22198a475bcbSad #ifdef MALLOC_STATS
22208a475bcbSad 		bin->stats.nrequests++;
22218a475bcbSad 		arena->stats.nmalloc_small++;
22228a475bcbSad 		arena->stats.allocated_small += size;
22238a475bcbSad #endif
22248a475bcbSad 	} else {
22258a475bcbSad 		/* Large allocation. */
22268a475bcbSad 		size = PAGE_CEILING(size);
22278a475bcbSad 		malloc_mutex_lock(&arena->mtx);
22288a475bcbSad 		ret = (void *)arena_run_alloc(arena, size);
22298a475bcbSad 		if (ret == NULL) {
22308a475bcbSad 			malloc_mutex_unlock(&arena->mtx);
22318a475bcbSad 			return (NULL);
22328a475bcbSad 		}
22338a475bcbSad #ifdef MALLOC_STATS
22348a475bcbSad 		arena->stats.nmalloc_large++;
22358a475bcbSad 		arena->stats.allocated_large += size;
22368a475bcbSad #endif
22378a475bcbSad 	}
22388a475bcbSad 
22398a475bcbSad 	malloc_mutex_unlock(&arena->mtx);
22408a475bcbSad 
2241bf5f78d5Sad 	if (OPT(junk))
22428a475bcbSad 		memset(ret, 0xa5, size);
2243bf5f78d5Sad 	else if (OPT(zero))
22448a475bcbSad 		memset(ret, 0, size);
22458a475bcbSad 	return (ret);
22468a475bcbSad }
22478a475bcbSad 
22488a475bcbSad static inline void
arena_palloc_trim(arena_t * arena,arena_chunk_t * chunk,unsigned pageind,unsigned npages)22498a475bcbSad arena_palloc_trim(arena_t *arena, arena_chunk_t *chunk, unsigned pageind,
22508a475bcbSad     unsigned npages)
22518a475bcbSad {
22528a475bcbSad 	unsigned i;
22538a475bcbSad 
22548a475bcbSad 	assert(npages > 0);
22558a475bcbSad 
22568a475bcbSad 	/*
22578a475bcbSad 	 * Modifiy the map such that arena_run_dalloc() sees the run as
22588a475bcbSad 	 * separately allocated.
22598a475bcbSad 	 */
22608a475bcbSad 	for (i = 0; i < npages; i++) {
22618a475bcbSad 		chunk->map[pageind + i].npages = npages;
22628a475bcbSad 		chunk->map[pageind + i].pos = i;
22638a475bcbSad 	}
22648a475bcbSad 	arena_run_dalloc(arena, (arena_run_t *)((uintptr_t)chunk + (pageind <<
22658a475bcbSad 	    pagesize_2pow)), npages << pagesize_2pow);
22668a475bcbSad }
22678a475bcbSad 
22688a475bcbSad /* Only handles large allocations that require more than page alignment. */
22698a475bcbSad static void *
arena_palloc(arena_t * arena,size_t alignment,size_t size,size_t alloc_size)22708a475bcbSad arena_palloc(arena_t *arena, size_t alignment, size_t size, size_t alloc_size)
22718a475bcbSad {
22728a475bcbSad 	void *ret;
22738a475bcbSad 	size_t offset;
22748a475bcbSad 	arena_chunk_t *chunk;
22758a475bcbSad 	unsigned pageind, i, npages;
22768a475bcbSad 
22778a475bcbSad 	assert((size & pagesize_mask) == 0);
22788a475bcbSad 	assert((alignment & pagesize_mask) == 0);
22798a475bcbSad 
22808de47c09Schristos 	npages = (unsigned)(size >> pagesize_2pow);
22818a475bcbSad 
22828a475bcbSad 	malloc_mutex_lock(&arena->mtx);
22838a475bcbSad 	ret = (void *)arena_run_alloc(arena, alloc_size);
22848a475bcbSad 	if (ret == NULL) {
22858a475bcbSad 		malloc_mutex_unlock(&arena->mtx);
22868a475bcbSad 		return (NULL);
22878a475bcbSad 	}
22888a475bcbSad 
22898a475bcbSad 	chunk = (arena_chunk_t *)CHUNK_ADDR2BASE(ret);
22908a475bcbSad 
22918a475bcbSad 	offset = (uintptr_t)ret & (alignment - 1);
22928a475bcbSad 	assert((offset & pagesize_mask) == 0);
22938a475bcbSad 	assert(offset < alloc_size);
22948a475bcbSad 	if (offset == 0) {
22958de47c09Schristos 		pageind = (unsigned)(((uintptr_t)ret - (uintptr_t)chunk) >>
22968a475bcbSad 		    pagesize_2pow);
22978a475bcbSad 
22988a475bcbSad 		/* Update the map for the run to be kept. */
22998a475bcbSad 		for (i = 0; i < npages; i++) {
23008a475bcbSad 			chunk->map[pageind + i].npages = npages;
23018a475bcbSad 			assert(chunk->map[pageind + i].pos == i);
23028a475bcbSad 		}
23038a475bcbSad 
23048a475bcbSad 		/* Trim trailing space. */
23058a475bcbSad 		arena_palloc_trim(arena, chunk, pageind + npages,
23068de47c09Schristos 		    (unsigned)((alloc_size - size) >> pagesize_2pow));
23078a475bcbSad 	} else {
23088a475bcbSad 		size_t leadsize, trailsize;
23098a475bcbSad 
23108a475bcbSad 		leadsize = alignment - offset;
23118a475bcbSad 		ret = (void *)((uintptr_t)ret + leadsize);
23128de47c09Schristos 		pageind = (unsigned)(((uintptr_t)ret - (uintptr_t)chunk) >>
23138a475bcbSad 		    pagesize_2pow);
23148a475bcbSad 
23158a475bcbSad 		/* Update the map for the run to be kept. */
23168a475bcbSad 		for (i = 0; i < npages; i++) {
23178a475bcbSad 			chunk->map[pageind + i].npages = npages;
23188a475bcbSad 			chunk->map[pageind + i].pos = i;
23198a475bcbSad 		}
23208a475bcbSad 
23218a475bcbSad 		/* Trim leading space. */
23228de47c09Schristos 		arena_palloc_trim(arena, chunk,
23238de47c09Schristos 		    (unsigned)(pageind - (leadsize >> pagesize_2pow)),
23248de47c09Schristos 		    (unsigned)(leadsize >> pagesize_2pow));
23258a475bcbSad 
23268a475bcbSad 		trailsize = alloc_size - leadsize - size;
23278a475bcbSad 		if (trailsize != 0) {
23288a475bcbSad 			/* Trim trailing space. */
23298a475bcbSad 			assert(trailsize < alloc_size);
23308a475bcbSad 			arena_palloc_trim(arena, chunk, pageind + npages,
23318de47c09Schristos 			    (unsigned)(trailsize >> pagesize_2pow));
23328a475bcbSad 		}
23338a475bcbSad 	}
23348a475bcbSad 
23358a475bcbSad #ifdef MALLOC_STATS
23368a475bcbSad 	arena->stats.nmalloc_large++;
23378a475bcbSad 	arena->stats.allocated_large += size;
23388a475bcbSad #endif
23398a475bcbSad 	malloc_mutex_unlock(&arena->mtx);
23408a475bcbSad 
2341bf5f78d5Sad 	if (OPT(junk))
23428a475bcbSad 		memset(ret, 0xa5, size);
2343bf5f78d5Sad 	else if (OPT(zero))
23448a475bcbSad 		memset(ret, 0, size);
23458a475bcbSad 	return (ret);
23468a475bcbSad }
23478a475bcbSad 
23488a475bcbSad /* Return the size of the allocation pointed to by ptr. */
23498a475bcbSad static size_t
arena_salloc(const void * ptr)23508a475bcbSad arena_salloc(const void *ptr)
23518a475bcbSad {
23528a475bcbSad 	size_t ret;
23538a475bcbSad 	arena_chunk_t *chunk;
23548a475bcbSad 	arena_chunk_map_t *mapelm;
23558a475bcbSad 	unsigned pageind;
23568a475bcbSad 
23578a475bcbSad 	assert(ptr != NULL);
23588a475bcbSad 	assert(CHUNK_ADDR2BASE(ptr) != ptr);
23598a475bcbSad 
23608a475bcbSad 	/*
23618a475bcbSad 	 * No arena data structures that we query here can change in a way that
23628a475bcbSad 	 * affects this function, so we don't need to lock.
23638a475bcbSad 	 */
23648a475bcbSad 	chunk = (arena_chunk_t *)CHUNK_ADDR2BASE(ptr);
23658de47c09Schristos 	pageind = (unsigned)(((uintptr_t)ptr - (uintptr_t)chunk) >>
23668de47c09Schristos 	    pagesize_2pow);
23678a475bcbSad 	mapelm = &chunk->map[pageind];
236846de0853Ssimonb 	if (mapelm->pos != 0 || ptr != (char *)((uintptr_t)chunk) + (pageind <<
236946de0853Ssimonb 	    pagesize_2pow)) {
237046de0853Ssimonb 		arena_run_t *run;
23718a475bcbSad 
23728a475bcbSad 		pageind -= mapelm->pos;
23738a475bcbSad 
237446de0853Ssimonb 		run = (arena_run_t *)((uintptr_t)chunk + (pageind <<
237546de0853Ssimonb 		    pagesize_2pow));
23768a475bcbSad 		assert(run->magic == ARENA_RUN_MAGIC);
23778a475bcbSad 		ret = run->bin->reg_size;
23788a475bcbSad 	} else
23798a475bcbSad 		ret = mapelm->npages << pagesize_2pow;
23808a475bcbSad 
23818a475bcbSad 	return (ret);
23828a475bcbSad }
23838a475bcbSad 
23848a475bcbSad static void *
arena_ralloc(void * ptr,size_t size,size_t oldsize)23858a475bcbSad arena_ralloc(void *ptr, size_t size, size_t oldsize)
23868a475bcbSad {
23878a475bcbSad 	void *ret;
23888a475bcbSad 
23898a475bcbSad 	/* Avoid moving the allocation if the size class would not change. */
23908a475bcbSad 	if (size < small_min) {
23918a475bcbSad 		if (oldsize < small_min &&
23928a475bcbSad 		    ffs((int)(pow2_ceil(size) >> (TINY_MIN_2POW + 1)))
23938a475bcbSad 		    == ffs((int)(pow2_ceil(oldsize) >> (TINY_MIN_2POW + 1))))
23948a475bcbSad 			goto IN_PLACE;
23958a475bcbSad 	} else if (size <= small_max) {
23968a475bcbSad 		if (oldsize >= small_min && oldsize <= small_max &&
23978a475bcbSad 		    (QUANTUM_CEILING(size) >> opt_quantum_2pow)
23988a475bcbSad 		    == (QUANTUM_CEILING(oldsize) >> opt_quantum_2pow))
23998a475bcbSad 			goto IN_PLACE;
24008a475bcbSad 	} else {
24018a475bcbSad 		/*
24028a475bcbSad 		 * We make no attempt to resize runs here, though it would be
24038a475bcbSad 		 * possible to do so.
24048a475bcbSad 		 */
24058a475bcbSad 		if (oldsize > small_max && PAGE_CEILING(size) == oldsize)
24068a475bcbSad 			goto IN_PLACE;
24078a475bcbSad 	}
24088a475bcbSad 
24098a475bcbSad 	/*
24108a475bcbSad 	 * If we get here, then size and oldsize are different enough that we
24118a475bcbSad 	 * need to use a different size class.  In that case, fall back to
24128a475bcbSad 	 * allocating new space and copying.
24138a475bcbSad 	 */
24148a475bcbSad 	ret = arena_malloc(choose_arena(), size);
24158a475bcbSad 	if (ret == NULL)
24168a475bcbSad 		return (NULL);
24178a475bcbSad 
24188a475bcbSad 	/* Junk/zero-filling were already done by arena_malloc(). */
24198a475bcbSad 	if (size < oldsize)
24208a475bcbSad 		memcpy(ret, ptr, size);
24218a475bcbSad 	else
24228a475bcbSad 		memcpy(ret, ptr, oldsize);
24238a475bcbSad 	idalloc(ptr);
24248a475bcbSad 	return (ret);
24258a475bcbSad IN_PLACE:
2426bf5f78d5Sad 	if (OPT(junk) && size < oldsize)
24278a475bcbSad 		memset((void *)((uintptr_t)ptr + size), 0x5a, oldsize - size);
2428bf5f78d5Sad 	else if (OPT(zero) && size > oldsize)
24298a475bcbSad 		memset((void *)((uintptr_t)ptr + oldsize), 0, size - oldsize);
24308a475bcbSad 	return (ptr);
24318a475bcbSad }
24328a475bcbSad 
24338a475bcbSad static void
arena_dalloc(arena_t * arena,arena_chunk_t * chunk,void * ptr)24348a475bcbSad arena_dalloc(arena_t *arena, arena_chunk_t *chunk, void *ptr)
24358a475bcbSad {
24368a475bcbSad 	unsigned pageind;
24378a475bcbSad 	arena_chunk_map_t *mapelm;
24388a475bcbSad 	size_t size;
24398a475bcbSad 
24408a475bcbSad 	assert(arena != NULL);
24418a475bcbSad 	assert(arena->magic == ARENA_MAGIC);
24428a475bcbSad 	assert(chunk->arena == arena);
24438a475bcbSad 	assert(ptr != NULL);
24448a475bcbSad 	assert(CHUNK_ADDR2BASE(ptr) != ptr);
24458a475bcbSad 
24468de47c09Schristos 	pageind = (unsigned)(((uintptr_t)ptr - (uintptr_t)chunk) >>
24478de47c09Schristos 	    pagesize_2pow);
24488a475bcbSad 	mapelm = &chunk->map[pageind];
244946de0853Ssimonb 	if (mapelm->pos != 0 || ptr != (char *)((uintptr_t)chunk) + (pageind <<
245046de0853Ssimonb 	    pagesize_2pow)) {
245146de0853Ssimonb 		arena_run_t *run;
24528a475bcbSad 		arena_bin_t *bin;
24538a475bcbSad 
24548a475bcbSad 		/* Small allocation. */
24558a475bcbSad 
24568a475bcbSad 		pageind -= mapelm->pos;
24578a475bcbSad 
245846de0853Ssimonb 		run = (arena_run_t *)((uintptr_t)chunk + (pageind <<
245946de0853Ssimonb 		    pagesize_2pow));
24608a475bcbSad 		assert(run->magic == ARENA_RUN_MAGIC);
24618a475bcbSad 		bin = run->bin;
24628a475bcbSad 		size = bin->reg_size;
24638a475bcbSad 
2464bf5f78d5Sad 		if (OPT(junk))
24658a475bcbSad 			memset(ptr, 0x5a, size);
24668a475bcbSad 
24678a475bcbSad 		malloc_mutex_lock(&arena->mtx);
24688a475bcbSad 		arena_run_reg_dalloc(run, bin, ptr, size);
24698a475bcbSad 		run->nfree++;
24708a475bcbSad 
24718a475bcbSad 		if (run->nfree == bin->nregs) {
24728a475bcbSad 			/* Deallocate run. */
24738a475bcbSad 			if (run == bin->runcur)
24748a475bcbSad 				bin->runcur = NULL;
24758a475bcbSad 			else if (bin->nregs != 1) {
24768a475bcbSad 				/*
24778a475bcbSad 				 * This block's conditional is necessary because
24788a475bcbSad 				 * if the run only contains one region, then it
24798a475bcbSad 				 * never gets inserted into the non-full runs
24808a475bcbSad 				 * tree.
24818a475bcbSad 				 */
2482562025fdSad 				rb_tree_remove_node(&bin->runs, run);
24838a475bcbSad 			}
24848a475bcbSad #ifdef MALLOC_DEBUG
24858a475bcbSad 			run->magic = 0;
24868a475bcbSad #endif
24878a475bcbSad 			arena_run_dalloc(arena, run, bin->run_size);
24888a475bcbSad #ifdef MALLOC_STATS
24898a475bcbSad 			bin->stats.curruns--;
24908a475bcbSad #endif
24918a475bcbSad 		} else if (run->nfree == 1 && run != bin->runcur) {
24928a475bcbSad 			/*
24938a475bcbSad 			 * Make sure that bin->runcur always refers to the
24948a475bcbSad 			 * lowest non-full run, if one exists.
24958a475bcbSad 			 */
24968a475bcbSad 			if (bin->runcur == NULL)
24978a475bcbSad 				bin->runcur = run;
24988a475bcbSad 			else if ((uintptr_t)run < (uintptr_t)bin->runcur) {
24998a475bcbSad 				/* Switch runcur. */
25008a475bcbSad 				if (bin->runcur->nfree > 0) {
25018a475bcbSad 					/* Insert runcur. */
2502562025fdSad 					rb_tree_insert_node(&bin->runs, bin->runcur);
25038a475bcbSad 				}
25048a475bcbSad 				bin->runcur = run;
2505e7a9e46bSad 			} else {
2506562025fdSad 				rb_tree_insert_node(&bin->runs, run);
25078a475bcbSad 			}
2508e7a9e46bSad 		}
25098a475bcbSad #ifdef MALLOC_STATS
25108a475bcbSad 		arena->stats.allocated_small -= size;
25118a475bcbSad 		arena->stats.ndalloc_small++;
25128a475bcbSad #endif
25138a475bcbSad 	} else {
25148a475bcbSad 		/* Large allocation. */
25158a475bcbSad 
25168a475bcbSad 		size = mapelm->npages << pagesize_2pow;
25178a475bcbSad 		assert((((uintptr_t)ptr) & pagesize_mask) == 0);
25188a475bcbSad 
2519bf5f78d5Sad 		if (OPT(junk))
25208a475bcbSad 			memset(ptr, 0x5a, size);
25218a475bcbSad 
25228a475bcbSad 		malloc_mutex_lock(&arena->mtx);
25238a475bcbSad 		arena_run_dalloc(arena, (arena_run_t *)ptr, size);
25248a475bcbSad #ifdef MALLOC_STATS
25258a475bcbSad 		arena->stats.allocated_large -= size;
25268a475bcbSad 		arena->stats.ndalloc_large++;
25278a475bcbSad #endif
25288a475bcbSad 	}
25298a475bcbSad 
25308a475bcbSad 	malloc_mutex_unlock(&arena->mtx);
25318a475bcbSad }
25328a475bcbSad 
2533bf5f78d5Sad static void
arena_new(arena_t * arena)25348a475bcbSad arena_new(arena_t *arena)
25358a475bcbSad {
25368a475bcbSad 	unsigned i;
25378a475bcbSad 	arena_bin_t *bin;
2538e7a9e46bSad 	size_t prev_run_size;
25398a475bcbSad 
25408a475bcbSad 	malloc_mutex_init(&arena->mtx);
25418a475bcbSad 
25428a475bcbSad #ifdef MALLOC_STATS
25438a475bcbSad 	memset(&arena->stats, 0, sizeof(arena_stats_t));
25448a475bcbSad #endif
25458a475bcbSad 
25468a475bcbSad 	/* Initialize chunks. */
2547562025fdSad 	rb_tree_init(&arena->chunks, &arena_chunk_tree_ops);
25488a475bcbSad 	arena->spare = NULL;
25498a475bcbSad 
25508a475bcbSad 	/* Initialize bins. */
25518a475bcbSad 	prev_run_size = pagesize;
25528a475bcbSad 
25538a475bcbSad 	/* (2^n)-spaced tiny bins. */
25548a475bcbSad 	for (i = 0; i < ntbins; i++) {
25558a475bcbSad 		bin = &arena->bins[i];
25568a475bcbSad 		bin->runcur = NULL;
2557562025fdSad 		rb_tree_init(&bin->runs, &arena_run_tree_ops);
25588a475bcbSad 
25598a475bcbSad 		bin->reg_size = (1 << (TINY_MIN_2POW + i));
25608a475bcbSad 		prev_run_size = arena_bin_run_size_calc(bin, prev_run_size);
25618a475bcbSad 
25628a475bcbSad #ifdef MALLOC_STATS
25638a475bcbSad 		memset(&bin->stats, 0, sizeof(malloc_bin_stats_t));
25648a475bcbSad #endif
25658a475bcbSad 	}
25668a475bcbSad 
25678a475bcbSad 	/* Quantum-spaced bins. */
25688a475bcbSad 	for (; i < ntbins + nqbins; i++) {
25698a475bcbSad 		bin = &arena->bins[i];
25708a475bcbSad 		bin->runcur = NULL;
2571562025fdSad 		rb_tree_init(&bin->runs, &arena_run_tree_ops);
25728a475bcbSad 
25738a475bcbSad 		bin->reg_size = quantum * (i - ntbins + 1);
2574e7a9e46bSad /*
25758a475bcbSad 		pow2_size = pow2_ceil(quantum * (i - ntbins + 1));
2576e7a9e46bSad */
25778a475bcbSad 		prev_run_size = arena_bin_run_size_calc(bin, prev_run_size);
25788a475bcbSad 
25798a475bcbSad #ifdef MALLOC_STATS
25808a475bcbSad 		memset(&bin->stats, 0, sizeof(malloc_bin_stats_t));
25818a475bcbSad #endif
25828a475bcbSad 	}
25838a475bcbSad 
25848a475bcbSad 	/* (2^n)-spaced sub-page bins. */
25858a475bcbSad 	for (; i < ntbins + nqbins + nsbins; i++) {
25868a475bcbSad 		bin = &arena->bins[i];
25878a475bcbSad 		bin->runcur = NULL;
2588562025fdSad 		rb_tree_init(&bin->runs, &arena_run_tree_ops);
25898a475bcbSad 
25908a475bcbSad 		bin->reg_size = (small_max << (i - (ntbins + nqbins) + 1));
25918a475bcbSad 
25928a475bcbSad 		prev_run_size = arena_bin_run_size_calc(bin, prev_run_size);
25938a475bcbSad 
25948a475bcbSad #ifdef MALLOC_STATS
25958a475bcbSad 		memset(&bin->stats, 0, sizeof(malloc_bin_stats_t));
25968a475bcbSad #endif
25978a475bcbSad 	}
25988a475bcbSad 
25998a475bcbSad #ifdef MALLOC_DEBUG
26008a475bcbSad 	arena->magic = ARENA_MAGIC;
26018a475bcbSad #endif
26028a475bcbSad }
26038a475bcbSad 
26048a475bcbSad /* Create a new arena and insert it into the arenas array at index ind. */
26058a475bcbSad static arena_t *
arenas_extend(void)2606bf5f78d5Sad arenas_extend(void)
26078a475bcbSad {
26088a475bcbSad 	arena_t *ret;
26098a475bcbSad 
26108a475bcbSad 	/* Allocate enough space for trailing bins. */
26118a475bcbSad 	ret = (arena_t *)base_alloc(sizeof(arena_t)
26128a475bcbSad 	    + (sizeof(arena_bin_t) * (ntbins + nqbins + nsbins - 1)));
2613bf5f78d5Sad 	if (ret != NULL) {
2614bf5f78d5Sad 		arena_new(ret);
26158a475bcbSad 		return (ret);
26168a475bcbSad 	}
26178a475bcbSad 	/* Only reached if there is an OOM error. */
26188a475bcbSad 
26198a475bcbSad 	/*
26208a475bcbSad 	 * OOM here is quite inconvenient to propagate, since dealing with it
26218a475bcbSad 	 * would require a check for failure in the fast path.  Instead, punt
26228a475bcbSad 	 * by using arenas[0].  In practice, this is an extremely unlikely
26238a475bcbSad 	 * failure.
26248a475bcbSad 	 */
262586ef91b8Schristos 	_malloc_message(getprogname(),
26268a475bcbSad 	    ": (malloc) Error initializing arena\n", "", "");
2627bf5f78d5Sad 	if (OPT(abort))
26288a475bcbSad 		abort();
26298a475bcbSad 
26308a475bcbSad 	return (arenas[0]);
26318a475bcbSad }
26328a475bcbSad 
26338a475bcbSad /*
26348a475bcbSad  * End arena.
26358a475bcbSad  */
26368a475bcbSad /******************************************************************************/
26378a475bcbSad /*
26388a475bcbSad  * Begin general internal functions.
26398a475bcbSad  */
26408a475bcbSad 
26418a475bcbSad static void *
huge_malloc(size_t size)26428a475bcbSad huge_malloc(size_t size)
26438a475bcbSad {
26448a475bcbSad 	void *ret;
26458a475bcbSad 	size_t csize;
26468a475bcbSad 	chunk_node_t *node;
26478a475bcbSad 
26488a475bcbSad 	/* Allocate one or more contiguous chunks for this request. */
26498a475bcbSad 
26508a475bcbSad 	csize = CHUNK_CEILING(size);
26518a475bcbSad 	if (csize == 0) {
26528a475bcbSad 		/* size is large enough to cause size_t wrap-around. */
26538a475bcbSad 		return (NULL);
26548a475bcbSad 	}
26558a475bcbSad 
26568a475bcbSad 	/* Allocate a chunk node with which to track the chunk. */
26578a475bcbSad 	node = base_chunk_node_alloc();
26588a475bcbSad 	if (node == NULL)
26598a475bcbSad 		return (NULL);
26608a475bcbSad 
26618a475bcbSad 	ret = chunk_alloc(csize);
26628a475bcbSad 	if (ret == NULL) {
26638a475bcbSad 		base_chunk_node_dealloc(node);
26648a475bcbSad 		return (NULL);
26658a475bcbSad 	}
26668a475bcbSad 
26678a475bcbSad 	/* Insert node into huge. */
26688a475bcbSad 	node->chunk = ret;
26698a475bcbSad 	node->size = csize;
26708a475bcbSad 
26718a475bcbSad 	malloc_mutex_lock(&chunks_mtx);
2672562025fdSad 	rb_tree_insert_node(&huge, node);
26738a475bcbSad #ifdef MALLOC_STATS
26748a475bcbSad 	huge_nmalloc++;
26758a475bcbSad 	huge_allocated += csize;
26768a475bcbSad #endif
26778a475bcbSad 	malloc_mutex_unlock(&chunks_mtx);
26788a475bcbSad 
2679bf5f78d5Sad 	if (OPT(junk))
26808a475bcbSad 		memset(ret, 0xa5, csize);
2681bf5f78d5Sad 	else if (OPT(zero))
26828a475bcbSad 		memset(ret, 0, csize);
26838a475bcbSad 
26848a475bcbSad 	return (ret);
26858a475bcbSad }
26868a475bcbSad 
26878a475bcbSad /* Only handles large allocations that require more than chunk alignment. */
26888a475bcbSad static void *
huge_palloc(size_t alignment,size_t size)26898a475bcbSad huge_palloc(size_t alignment, size_t size)
26908a475bcbSad {
26918a475bcbSad 	void *ret;
26928a475bcbSad 	size_t alloc_size, chunk_size, offset;
26938a475bcbSad 	chunk_node_t *node;
26948a475bcbSad 
26958a475bcbSad 	/*
26968a475bcbSad 	 * This allocation requires alignment that is even larger than chunk
26978a475bcbSad 	 * alignment.  This means that huge_malloc() isn't good enough.
26988a475bcbSad 	 *
26998a475bcbSad 	 * Allocate almost twice as many chunks as are demanded by the size or
27008a475bcbSad 	 * alignment, in order to assure the alignment can be achieved, then
27018a475bcbSad 	 * unmap leading and trailing chunks.
27028a475bcbSad 	 */
27038a475bcbSad 	assert(alignment >= chunksize);
27048a475bcbSad 
27058a475bcbSad 	chunk_size = CHUNK_CEILING(size);
27068a475bcbSad 
27078a475bcbSad 	if (size >= alignment)
27088a475bcbSad 		alloc_size = chunk_size + alignment - chunksize;
27098a475bcbSad 	else
27108a475bcbSad 		alloc_size = (alignment << 1) - chunksize;
27118a475bcbSad 
27128a475bcbSad 	/* Allocate a chunk node with which to track the chunk. */
27138a475bcbSad 	node = base_chunk_node_alloc();
27148a475bcbSad 	if (node == NULL)
27158a475bcbSad 		return (NULL);
27168a475bcbSad 
27178a475bcbSad 	ret = chunk_alloc(alloc_size);
27188a475bcbSad 	if (ret == NULL) {
27198a475bcbSad 		base_chunk_node_dealloc(node);
27208a475bcbSad 		return (NULL);
27218a475bcbSad 	}
27228a475bcbSad 
27238a475bcbSad 	offset = (uintptr_t)ret & (alignment - 1);
27248a475bcbSad 	assert((offset & chunksize_mask) == 0);
27258a475bcbSad 	assert(offset < alloc_size);
27268a475bcbSad 	if (offset == 0) {
27278a475bcbSad 		/* Trim trailing space. */
27288a475bcbSad 		chunk_dealloc((void *)((uintptr_t)ret + chunk_size), alloc_size
27298a475bcbSad 		    - chunk_size);
27308a475bcbSad 	} else {
27318a475bcbSad 		size_t trailsize;
27328a475bcbSad 
27338a475bcbSad 		/* Trim leading space. */
27348a475bcbSad 		chunk_dealloc(ret, alignment - offset);
27358a475bcbSad 
27368a475bcbSad 		ret = (void *)((uintptr_t)ret + (alignment - offset));
27378a475bcbSad 
27388a475bcbSad 		trailsize = alloc_size - (alignment - offset) - chunk_size;
27398a475bcbSad 		if (trailsize != 0) {
27408a475bcbSad 		    /* Trim trailing space. */
27418a475bcbSad 		    assert(trailsize < alloc_size);
27428a475bcbSad 		    chunk_dealloc((void *)((uintptr_t)ret + chunk_size),
27438a475bcbSad 			trailsize);
27448a475bcbSad 		}
27458a475bcbSad 	}
27468a475bcbSad 
27478a475bcbSad 	/* Insert node into huge. */
27488a475bcbSad 	node->chunk = ret;
27498a475bcbSad 	node->size = chunk_size;
27508a475bcbSad 
27518a475bcbSad 	malloc_mutex_lock(&chunks_mtx);
2752562025fdSad 	rb_tree_insert_node(&huge, node);
27538a475bcbSad #ifdef MALLOC_STATS
27548a475bcbSad 	huge_nmalloc++;
27558a475bcbSad 	huge_allocated += chunk_size;
27568a475bcbSad #endif
27578a475bcbSad 	malloc_mutex_unlock(&chunks_mtx);
27588a475bcbSad 
2759bf5f78d5Sad 	if (OPT(junk))
27608a475bcbSad 		memset(ret, 0xa5, chunk_size);
2761bf5f78d5Sad 	else if (OPT(zero))
27628a475bcbSad 		memset(ret, 0, chunk_size);
27638a475bcbSad 
27648a475bcbSad 	return (ret);
27658a475bcbSad }
27668a475bcbSad 
27678a475bcbSad static void *
huge_ralloc(void * ptr,size_t size,size_t oldsize)27688a475bcbSad huge_ralloc(void *ptr, size_t size, size_t oldsize)
27698a475bcbSad {
27708a475bcbSad 	void *ret;
27718a475bcbSad 
27728a475bcbSad 	/* Avoid moving the allocation if the size class would not change. */
27738a475bcbSad 	if (oldsize > arena_maxclass &&
27748a475bcbSad 	    CHUNK_CEILING(size) == CHUNK_CEILING(oldsize)) {
2775bf5f78d5Sad 		if (OPT(junk) && size < oldsize) {
27768a475bcbSad 			memset((void *)((uintptr_t)ptr + size), 0x5a, oldsize
27778a475bcbSad 			    - size);
2778bf5f78d5Sad 		} else if (OPT(zero) && size > oldsize) {
27798a475bcbSad 			memset((void *)((uintptr_t)ptr + oldsize), 0, size
27808a475bcbSad 			    - oldsize);
27818a475bcbSad 		}
27828a475bcbSad 		return (ptr);
27838a475bcbSad 	}
27848a475bcbSad 
2785b79fded2Syamt 	if (CHUNK_ADDR2BASE(ptr) == ptr
2786b79fded2Syamt #ifdef USE_BRK
2787b79fded2Syamt 	    && ((uintptr_t)ptr < (uintptr_t)brk_base
2788b79fded2Syamt 	    || (uintptr_t)ptr >= (uintptr_t)brk_max)
2789b79fded2Syamt #endif
2790b79fded2Syamt 	    ) {
2791b79fded2Syamt 		chunk_node_t *node, key;
2792b79fded2Syamt 		void *newptr;
2793b79fded2Syamt 		size_t oldcsize;
2794b79fded2Syamt 		size_t newcsize;
2795b79fded2Syamt 
2796b79fded2Syamt 		newcsize = CHUNK_CEILING(size);
2797b79fded2Syamt 		oldcsize = CHUNK_CEILING(oldsize);
2798b79fded2Syamt 		assert(oldcsize != newcsize);
2799b79fded2Syamt 		if (newcsize == 0) {
2800b79fded2Syamt 			/* size_t wrap-around */
2801b79fded2Syamt 			return (NULL);
2802b79fded2Syamt 		}
2803b79fded2Syamt 
28043df6d336Senami 		/*
28053df6d336Senami 		 * Remove the old region from the tree now.  If mremap()
28063df6d336Senami 		 * returns the region to the system, other thread may
28073df6d336Senami 		 * map it for same huge allocation and insert it to the
28083df6d336Senami 		 * tree before we acquire the mutex lock again.
28093df6d336Senami 		 */
2810b79fded2Syamt 		malloc_mutex_lock(&chunks_mtx);
2811bf5f78d5Sad 		key.chunk = __UNCONST(ptr);
2812562025fdSad 		node = rb_tree_find_node(&huge, &key);
2813b79fded2Syamt 		assert(node != NULL);
2814b79fded2Syamt 		assert(node->chunk == ptr);
2815b79fded2Syamt 		assert(node->size == oldcsize);
2816562025fdSad 		rb_tree_remove_node(&huge, node);
28173df6d336Senami 		malloc_mutex_unlock(&chunks_mtx);
28183df6d336Senami 
28193df6d336Senami 		newptr = mremap(ptr, oldcsize, NULL, newcsize,
28203df6d336Senami 		    MAP_ALIGNED(chunksize_2pow));
28213df6d336Senami 		if (newptr == MAP_FAILED) {
28223df6d336Senami 			/* We still own the old region. */
28233df6d336Senami 			malloc_mutex_lock(&chunks_mtx);
2824562025fdSad 			rb_tree_insert_node(&huge, node);
28253df6d336Senami 			malloc_mutex_unlock(&chunks_mtx);
28263df6d336Senami 		} else {
28273df6d336Senami 			assert(CHUNK_ADDR2BASE(newptr) == newptr);
28283df6d336Senami 
28293df6d336Senami 			/* Insert new or resized old region. */
28303df6d336Senami 			malloc_mutex_lock(&chunks_mtx);
28313df6d336Senami 			node->size = newcsize;
2832b79fded2Syamt 			node->chunk = newptr;
2833562025fdSad 			rb_tree_insert_node(&huge, node);
2834b79fded2Syamt #ifdef MALLOC_STATS
2835b79fded2Syamt 			huge_nralloc++;
2836b79fded2Syamt 			huge_allocated += newcsize - oldcsize;
2837b79fded2Syamt 			if (newcsize > oldcsize) {
2838b79fded2Syamt 				stats_chunks.curchunks +=
2839b79fded2Syamt 				    (newcsize - oldcsize) / chunksize;
2840b79fded2Syamt 				if (stats_chunks.curchunks >
2841b79fded2Syamt 				    stats_chunks.highchunks)
2842b79fded2Syamt 					stats_chunks.highchunks =
2843b79fded2Syamt 					    stats_chunks.curchunks;
2844b79fded2Syamt 			} else {
2845b79fded2Syamt 				stats_chunks.curchunks -=
2846b79fded2Syamt 				    (oldcsize - newcsize) / chunksize;
2847b79fded2Syamt 			}
2848b79fded2Syamt #endif
2849b79fded2Syamt 			malloc_mutex_unlock(&chunks_mtx);
2850b79fded2Syamt 
2851bf5f78d5Sad 			if (OPT(junk) && size < oldsize) {
2852b79fded2Syamt 				memset((void *)((uintptr_t)newptr + size), 0x5a,
2853b79fded2Syamt 				    newcsize - size);
2854bf5f78d5Sad 			} else if (OPT(zero) && size > oldsize) {
2855b79fded2Syamt 				memset((void *)((uintptr_t)newptr + oldsize), 0,
2856b79fded2Syamt 				    size - oldsize);
2857b79fded2Syamt 			}
2858b79fded2Syamt 			return (newptr);
2859b79fded2Syamt 		}
2860b79fded2Syamt 	}
2861b79fded2Syamt 
28628a475bcbSad 	/*
28638a475bcbSad 	 * If we get here, then size and oldsize are different enough that we
28648a475bcbSad 	 * need to use a different size class.  In that case, fall back to
28658a475bcbSad 	 * allocating new space and copying.
28668a475bcbSad 	 */
28678a475bcbSad 	ret = huge_malloc(size);
28688a475bcbSad 	if (ret == NULL)
28698a475bcbSad 		return (NULL);
28708a475bcbSad 
28718a475bcbSad 	if (CHUNK_ADDR2BASE(ptr) == ptr) {
28728a475bcbSad 		/* The old allocation is a chunk. */
28738a475bcbSad 		if (size < oldsize)
28748a475bcbSad 			memcpy(ret, ptr, size);
28758a475bcbSad 		else
28768a475bcbSad 			memcpy(ret, ptr, oldsize);
28778a475bcbSad 	} else {
28788a475bcbSad 		/* The old allocation is a region. */
28798a475bcbSad 		assert(oldsize < size);
28808a475bcbSad 		memcpy(ret, ptr, oldsize);
28818a475bcbSad 	}
28828a475bcbSad 	idalloc(ptr);
28838a475bcbSad 	return (ret);
28848a475bcbSad }
28858a475bcbSad 
28868a475bcbSad static void
huge_dalloc(void * ptr)28878a475bcbSad huge_dalloc(void *ptr)
28888a475bcbSad {
28898a475bcbSad 	chunk_node_t key;
28908a475bcbSad 	chunk_node_t *node;
28918a475bcbSad 
28928a475bcbSad 	malloc_mutex_lock(&chunks_mtx);
28938a475bcbSad 
28948a475bcbSad 	/* Extract from tree of huge allocations. */
28958a475bcbSad 	key.chunk = ptr;
2896562025fdSad 	node = rb_tree_find_node(&huge, &key);
28978a475bcbSad 	assert(node != NULL);
28988a475bcbSad 	assert(node->chunk == ptr);
2899562025fdSad 	rb_tree_remove_node(&huge, node);
29008a475bcbSad 
29018a475bcbSad #ifdef MALLOC_STATS
29028a475bcbSad 	huge_ndalloc++;
29038a475bcbSad 	huge_allocated -= node->size;
29048a475bcbSad #endif
29058a475bcbSad 
29068a475bcbSad 	malloc_mutex_unlock(&chunks_mtx);
29078a475bcbSad 
29088a475bcbSad 	/* Unmap chunk. */
29098a475bcbSad #ifdef USE_BRK
2910bf5f78d5Sad 	if (OPT(junk))
29118a475bcbSad 		memset(node->chunk, 0x5a, node->size);
29128a475bcbSad #endif
29138a475bcbSad 	chunk_dealloc(node->chunk, node->size);
29148a475bcbSad 
29158a475bcbSad 	base_chunk_node_dealloc(node);
29168a475bcbSad }
29178a475bcbSad 
29188a475bcbSad static void *
imalloc(size_t size)29198a475bcbSad imalloc(size_t size)
29208a475bcbSad {
29218a475bcbSad 	void *ret;
29228a475bcbSad 
29238a475bcbSad 	assert(size != 0);
29248a475bcbSad 
29258a475bcbSad 	if (size <= arena_maxclass)
29268a475bcbSad 		ret = arena_malloc(choose_arena(), size);
29278a475bcbSad 	else
29288a475bcbSad 		ret = huge_malloc(size);
29298a475bcbSad 
29308a475bcbSad 	return (ret);
29318a475bcbSad }
29328a475bcbSad 
29338a475bcbSad static void *
ipalloc(size_t alignment,size_t size)29348a475bcbSad ipalloc(size_t alignment, size_t size)
29358a475bcbSad {
29368a475bcbSad 	void *ret;
29378a475bcbSad 	size_t ceil_size;
29388a475bcbSad 
29398a475bcbSad 	/*
29408a475bcbSad 	 * Round size up to the nearest multiple of alignment.
29418a475bcbSad 	 *
29428a475bcbSad 	 * This done, we can take advantage of the fact that for each small
29438a475bcbSad 	 * size class, every object is aligned at the smallest power of two
29448a475bcbSad 	 * that is non-zero in the base two representation of the size.  For
29458a475bcbSad 	 * example:
29468a475bcbSad 	 *
29478a475bcbSad 	 *   Size |   Base 2 | Minimum alignment
29488a475bcbSad 	 *   -----+----------+------------------
29498a475bcbSad 	 *     96 |  1100000 |  32
29508a475bcbSad 	 *    144 | 10100000 |  32
29518a475bcbSad 	 *    192 | 11000000 |  64
29528a475bcbSad 	 *
29538a475bcbSad 	 * Depending on runtime settings, it is possible that arena_malloc()
29548a475bcbSad 	 * will further round up to a power of two, but that never causes
29558a475bcbSad 	 * correctness issues.
29568a475bcbSad 	 */
29578a475bcbSad 	ceil_size = (size + (alignment - 1)) & (-alignment);
29588a475bcbSad 	/*
29598a475bcbSad 	 * (ceil_size < size) protects against the combination of maximal
29608a475bcbSad 	 * alignment and size greater than maximal alignment.
29618a475bcbSad 	 */
29628a475bcbSad 	if (ceil_size < size) {
29638a475bcbSad 		/* size_t overflow. */
29648a475bcbSad 		return (NULL);
29658a475bcbSad 	}
29668a475bcbSad 
29678a475bcbSad 	if (ceil_size <= pagesize || (alignment <= pagesize
29688a475bcbSad 	    && ceil_size <= arena_maxclass))
29698a475bcbSad 		ret = arena_malloc(choose_arena(), ceil_size);
29708a475bcbSad 	else {
29718a475bcbSad 		size_t run_size;
29728a475bcbSad 
29738a475bcbSad 		/*
29748a475bcbSad 		 * We can't achieve sub-page alignment, so round up alignment
29758a475bcbSad 		 * permanently; it makes later calculations simpler.
29768a475bcbSad 		 */
29778a475bcbSad 		alignment = PAGE_CEILING(alignment);
29788a475bcbSad 		ceil_size = PAGE_CEILING(size);
29798a475bcbSad 		/*
29808a475bcbSad 		 * (ceil_size < size) protects against very large sizes within
29818a475bcbSad 		 * pagesize of SIZE_T_MAX.
29828a475bcbSad 		 *
29838a475bcbSad 		 * (ceil_size + alignment < ceil_size) protects against the
29848a475bcbSad 		 * combination of maximal alignment and ceil_size large enough
29858a475bcbSad 		 * to cause overflow.  This is similar to the first overflow
29868a475bcbSad 		 * check above, but it needs to be repeated due to the new
29878a475bcbSad 		 * ceil_size value, which may now be *equal* to maximal
29888a475bcbSad 		 * alignment, whereas before we only detected overflow if the
29898a475bcbSad 		 * original size was *greater* than maximal alignment.
29908a475bcbSad 		 */
29918a475bcbSad 		if (ceil_size < size || ceil_size + alignment < ceil_size) {
29928a475bcbSad 			/* size_t overflow. */
29938a475bcbSad 			return (NULL);
29948a475bcbSad 		}
29958a475bcbSad 
29968a475bcbSad 		/*
29978a475bcbSad 		 * Calculate the size of the over-size run that arena_palloc()
29988a475bcbSad 		 * would need to allocate in order to guarantee the alignment.
29998a475bcbSad 		 */
30008a475bcbSad 		if (ceil_size >= alignment)
30018a475bcbSad 			run_size = ceil_size + alignment - pagesize;
30028a475bcbSad 		else {
30038a475bcbSad 			/*
30048a475bcbSad 			 * It is possible that (alignment << 1) will cause
30058a475bcbSad 			 * overflow, but it doesn't matter because we also
30068a475bcbSad 			 * subtract pagesize, which in the case of overflow
30078a475bcbSad 			 * leaves us with a very large run_size.  That causes
30088a475bcbSad 			 * the first conditional below to fail, which means
30098a475bcbSad 			 * that the bogus run_size value never gets used for
30108a475bcbSad 			 * anything important.
30118a475bcbSad 			 */
30128a475bcbSad 			run_size = (alignment << 1) - pagesize;
30138a475bcbSad 		}
30148a475bcbSad 
30158a475bcbSad 		if (run_size <= arena_maxclass) {
30168a475bcbSad 			ret = arena_palloc(choose_arena(), alignment, ceil_size,
30178a475bcbSad 			    run_size);
30188a475bcbSad 		} else if (alignment <= chunksize)
30198a475bcbSad 			ret = huge_malloc(ceil_size);
30208a475bcbSad 		else
30218a475bcbSad 			ret = huge_palloc(alignment, ceil_size);
30228a475bcbSad 	}
30238a475bcbSad 
30248a475bcbSad 	assert(((uintptr_t)ret & (alignment - 1)) == 0);
30258a475bcbSad 	return (ret);
30268a475bcbSad }
30278a475bcbSad 
30288a475bcbSad static void *
icalloc(size_t size)30298a475bcbSad icalloc(size_t size)
30308a475bcbSad {
30318a475bcbSad 	void *ret;
30328a475bcbSad 
30338a475bcbSad 	if (size <= arena_maxclass) {
30348a475bcbSad 		ret = arena_malloc(choose_arena(), size);
30358a475bcbSad 		if (ret == NULL)
30368a475bcbSad 			return (NULL);
30378a475bcbSad 		memset(ret, 0, size);
30388a475bcbSad 	} else {
30398a475bcbSad 		/*
30408a475bcbSad 		 * The virtual memory system provides zero-filled pages, so
30418a475bcbSad 		 * there is no need to do so manually, unless opt_junk is
30428a475bcbSad 		 * enabled, in which case huge_malloc() fills huge allocations
30438a475bcbSad 		 * with junk.
30448a475bcbSad 		 */
30458a475bcbSad 		ret = huge_malloc(size);
30468a475bcbSad 		if (ret == NULL)
30478a475bcbSad 			return (NULL);
30488a475bcbSad 
3049bf5f78d5Sad 		if (OPT(junk))
30508a475bcbSad 			memset(ret, 0, size);
30518a475bcbSad #ifdef USE_BRK
30528a475bcbSad 		else if ((uintptr_t)ret >= (uintptr_t)brk_base
30538a475bcbSad 		    && (uintptr_t)ret < (uintptr_t)brk_max) {
30548a475bcbSad 			/*
30558a475bcbSad 			 * This may be a re-used brk chunk.  Therefore, zero
30568a475bcbSad 			 * the memory.
30578a475bcbSad 			 */
30588a475bcbSad 			memset(ret, 0, size);
30598a475bcbSad 		}
30608a475bcbSad #endif
30618a475bcbSad 	}
30628a475bcbSad 
30638a475bcbSad 	return (ret);
30648a475bcbSad }
30658a475bcbSad 
30668a475bcbSad static size_t
isalloc(const void * ptr)30678a475bcbSad isalloc(const void *ptr)
30688a475bcbSad {
30698a475bcbSad 	size_t ret;
30708a475bcbSad 	arena_chunk_t *chunk;
30718a475bcbSad 
30728a475bcbSad 	assert(ptr != NULL);
30738a475bcbSad 
30748a475bcbSad 	chunk = (arena_chunk_t *)CHUNK_ADDR2BASE(ptr);
30758a475bcbSad 	if (chunk != ptr) {
30768a475bcbSad 		/* Region. */
30778a475bcbSad 		assert(chunk->arena->magic == ARENA_MAGIC);
30788a475bcbSad 
30798a475bcbSad 		ret = arena_salloc(ptr);
30808a475bcbSad 	} else {
30818a475bcbSad 		chunk_node_t *node, key;
30828a475bcbSad 
30838a475bcbSad 		/* Chunk (huge allocation). */
30848a475bcbSad 
30858a475bcbSad 		malloc_mutex_lock(&chunks_mtx);
30868a475bcbSad 
30878a475bcbSad 		/* Extract from tree of huge allocations. */
3088bf5f78d5Sad 		key.chunk = __UNCONST(ptr);
3089562025fdSad 		node = rb_tree_find_node(&huge, &key);
30908a475bcbSad 		assert(node != NULL);
30918a475bcbSad 
30928a475bcbSad 		ret = node->size;
30938a475bcbSad 
30948a475bcbSad 		malloc_mutex_unlock(&chunks_mtx);
30958a475bcbSad 	}
30968a475bcbSad 
30978a475bcbSad 	return (ret);
30988a475bcbSad }
30998a475bcbSad 
31008a475bcbSad static void *
iralloc(void * ptr,size_t size)31018a475bcbSad iralloc(void *ptr, size_t size)
31028a475bcbSad {
31038a475bcbSad 	void *ret;
31048a475bcbSad 	size_t oldsize;
31058a475bcbSad 
31068a475bcbSad 	assert(ptr != NULL);
31078a475bcbSad 	assert(size != 0);
31088a475bcbSad 
31098a475bcbSad 	oldsize = isalloc(ptr);
31108a475bcbSad 
31118a475bcbSad 	if (size <= arena_maxclass)
31128a475bcbSad 		ret = arena_ralloc(ptr, size, oldsize);
31138a475bcbSad 	else
31148a475bcbSad 		ret = huge_ralloc(ptr, size, oldsize);
31158a475bcbSad 
31168a475bcbSad 	return (ret);
31178a475bcbSad }
31188a475bcbSad 
31198a475bcbSad static void
idalloc(void * ptr)31208a475bcbSad idalloc(void *ptr)
31218a475bcbSad {
31228a475bcbSad 	arena_chunk_t *chunk;
31238a475bcbSad 
31248a475bcbSad 	assert(ptr != NULL);
31258a475bcbSad 
31268a475bcbSad 	chunk = (arena_chunk_t *)CHUNK_ADDR2BASE(ptr);
31278a475bcbSad 	if (chunk != ptr) {
31288a475bcbSad 		/* Region. */
31298a475bcbSad 		arena_dalloc(chunk->arena, chunk, ptr);
31308a475bcbSad 	} else
31318a475bcbSad 		huge_dalloc(ptr);
31328a475bcbSad }
31338a475bcbSad 
31348a475bcbSad static void
malloc_print_stats(void)31358a475bcbSad malloc_print_stats(void)
31368a475bcbSad {
31378a475bcbSad 
3138bf5f78d5Sad 	if (OPT(print_stats)) {
31398a475bcbSad 		char s[UMAX2S_BUFSIZE];
31408a475bcbSad 		_malloc_message("___ Begin malloc statistics ___\n", "", "",
31418a475bcbSad 		    "");
31428a475bcbSad 		_malloc_message("Assertions ",
31438a475bcbSad #ifdef NDEBUG
31448a475bcbSad 		    "disabled",
31458a475bcbSad #else
31468a475bcbSad 		    "enabled",
31478a475bcbSad #endif
31488a475bcbSad 		    "\n", "");
31498a475bcbSad 		_malloc_message("Boolean MALLOC_OPTIONS: ",
31508a475bcbSad 		    opt_abort ? "A" : "a",
31518a475bcbSad 		    opt_junk ? "J" : "j",
31528a475bcbSad 		    opt_hint ? "H" : "h");
3153bf5f78d5Sad 		_malloc_message(OPT(utrace) ? "PU" : "Pu",
31548a475bcbSad 		    opt_sysv ? "V" : "v",
31558a475bcbSad 		    opt_xmalloc ? "X" : "x",
31568a475bcbSad 		    opt_zero ? "Z\n" : "z\n");
31578a475bcbSad 
3158d703a148Schristos 		_malloc_message("CPUs: ", size_t2s(ncpus, s), "\n", "");
3159d703a148Schristos 		_malloc_message("Pointer size: ", size_t2s(sizeof(void *), s),
31608a475bcbSad 		    "\n", "");
3161d703a148Schristos 		_malloc_message("Quantum size: ", size_t2s(quantum, s), "\n", "");
3162d703a148Schristos 		_malloc_message("Max small size: ", size_t2s(small_max, s), "\n",
31638a475bcbSad 		    "");
31648a475bcbSad 
3165d703a148Schristos 		_malloc_message("Chunk size: ", size_t2s(chunksize, s), "", "");
3166d703a148Schristos 		_malloc_message(" (2^", size_t2s((size_t)opt_chunk_2pow, s),
3167e1a2f47fSmatt 		    ")\n", "");
31688a475bcbSad 
31698a475bcbSad #ifdef MALLOC_STATS
31708a475bcbSad 		{
31718a475bcbSad 			size_t allocated, mapped;
31728a475bcbSad 			unsigned i;
31738a475bcbSad 			arena_t *arena;
31748a475bcbSad 
31758a475bcbSad 			/* Calculate and print allocated/mapped stats. */
31768a475bcbSad 
31778a475bcbSad 			/* arenas. */
3178bf5f78d5Sad 			for (i = 0, allocated = 0; i < ncpus; i++) {
31798a475bcbSad 				if (arenas[i] != NULL) {
31808a475bcbSad 					malloc_mutex_lock(&arenas[i]->mtx);
31818a475bcbSad 					allocated +=
31828a475bcbSad 					    arenas[i]->stats.allocated_small;
31838a475bcbSad 					allocated +=
31848a475bcbSad 					    arenas[i]->stats.allocated_large;
31858a475bcbSad 					malloc_mutex_unlock(&arenas[i]->mtx);
31868a475bcbSad 				}
31878a475bcbSad 			}
31888a475bcbSad 
31898a475bcbSad 			/* huge/base. */
31908a475bcbSad 			malloc_mutex_lock(&chunks_mtx);
31918a475bcbSad 			allocated += huge_allocated;
31928a475bcbSad 			mapped = stats_chunks.curchunks * chunksize;
31938a475bcbSad 			malloc_mutex_unlock(&chunks_mtx);
31948a475bcbSad 
31958a475bcbSad 			malloc_mutex_lock(&base_mtx);
31968a475bcbSad 			mapped += base_mapped;
31978a475bcbSad 			malloc_mutex_unlock(&base_mtx);
31988a475bcbSad 
31998a475bcbSad 			malloc_printf("Allocated: %zu, mapped: %zu\n",
32008a475bcbSad 			    allocated, mapped);
32018a475bcbSad 
32028a475bcbSad 			/* Print chunk stats. */
32038a475bcbSad 			{
32048a475bcbSad 				chunk_stats_t chunks_stats;
32058a475bcbSad 
32068a475bcbSad 				malloc_mutex_lock(&chunks_mtx);
32078a475bcbSad 				chunks_stats = stats_chunks;
32088a475bcbSad 				malloc_mutex_unlock(&chunks_mtx);
32098a475bcbSad 
32108a475bcbSad 				malloc_printf("chunks: nchunks   "
32118a475bcbSad 				    "highchunks    curchunks\n");
32128a475bcbSad 				malloc_printf("  %13llu%13lu%13lu\n",
32138a475bcbSad 				    chunks_stats.nchunks,
32148a475bcbSad 				    chunks_stats.highchunks,
32158a475bcbSad 				    chunks_stats.curchunks);
32168a475bcbSad 			}
32178a475bcbSad 
32188a475bcbSad 			/* Print chunk stats. */
32198a475bcbSad 			malloc_printf(
3220b79fded2Syamt 			    "huge: nmalloc      ndalloc      "
3221b79fded2Syamt 			    "nralloc    allocated\n");
3222b79fded2Syamt 			malloc_printf(" %12llu %12llu %12llu %12zu\n",
3223b79fded2Syamt 			    huge_nmalloc, huge_ndalloc, huge_nralloc,
3224b79fded2Syamt 			    huge_allocated);
32258a475bcbSad 
32268a475bcbSad 			/* Print stats for each arena. */
3227bf5f78d5Sad 			for (i = 0; i < ncpus; i++) {
32288a475bcbSad 				arena = arenas[i];
32298a475bcbSad 				if (arena != NULL) {
32308a475bcbSad 					malloc_printf(
3231e7a9e46bSad 					    "\narenas[%u] @ %p\n", i, arena);
32328a475bcbSad 					malloc_mutex_lock(&arena->mtx);
32338a475bcbSad 					stats_print(arena);
32348a475bcbSad 					malloc_mutex_unlock(&arena->mtx);
32358a475bcbSad 				}
32368a475bcbSad 			}
32378a475bcbSad 		}
32388a475bcbSad #endif /* #ifdef MALLOC_STATS */
32398a475bcbSad 		_malloc_message("--- End malloc statistics ---\n", "", "", "");
32408a475bcbSad 	}
32418a475bcbSad }
32428a475bcbSad 
32438a475bcbSad /*
3244bf5f78d5Sad  * libpthread might call malloc(3), so the malloc implementation has to take
3245bf5f78d5Sad  * pains to avoid infinite recursion during initialization.
32468a475bcbSad  */
32478a475bcbSad static inline bool
malloc_init(void)32488a475bcbSad malloc_init(void)
32498a475bcbSad {
32508a475bcbSad 
3251bf5f78d5Sad 	if (__predict_false(malloc_initialized == false))
32528a475bcbSad 		return (malloc_init_hard());
32538a475bcbSad 
32548a475bcbSad 	return (false);
32558a475bcbSad }
32568a475bcbSad 
32578a475bcbSad static bool
malloc_init_hard(void)32588a475bcbSad malloc_init_hard(void)
32598a475bcbSad {
32608a475bcbSad 	unsigned i, j;
32618de47c09Schristos 	ssize_t linklen;
32628a475bcbSad 	char buf[PATH_MAX + 1];
3263e7a9e46bSad 	const char *opts = "";
32641ff5a5dfSchristos 	int serrno;
32658a475bcbSad 
32668a475bcbSad 	malloc_mutex_lock(&init_lock);
32678a475bcbSad 	if (malloc_initialized) {
32688a475bcbSad 		/*
32698a475bcbSad 		 * Another thread initialized the allocator before this one
32708a475bcbSad 		 * acquired init_lock.
32718a475bcbSad 		 */
32728a475bcbSad 		malloc_mutex_unlock(&init_lock);
32738a475bcbSad 		return (false);
32748a475bcbSad 	}
32758a475bcbSad 
3276713ea189Schristos 	serrno = errno;
32778a475bcbSad 	/* Get number of CPUs. */
32788a475bcbSad 	{
32798a475bcbSad 		int mib[2];
32808a475bcbSad 		size_t len;
32818a475bcbSad 
32828a475bcbSad 		mib[0] = CTL_HW;
32838a475bcbSad 		mib[1] = HW_NCPU;
32848a475bcbSad 		len = sizeof(ncpus);
32858a475bcbSad 		if (sysctl(mib, 2, &ncpus, &len, (void *) 0, 0) == -1) {
32868a475bcbSad 			/* Error. */
32878a475bcbSad 			ncpus = 1;
32888a475bcbSad 		}
32898a475bcbSad 	}
32908a475bcbSad 
32918a475bcbSad 	/* Get page size. */
32928a475bcbSad 	{
32938a475bcbSad 		long result;
32948a475bcbSad 
3295bf5f78d5Sad 		result = getpagesize();
32968a475bcbSad 		assert(result != -1);
32978a475bcbSad 		pagesize = (unsigned) result;
32988a475bcbSad 
32998a475bcbSad 		/*
33008a475bcbSad 		 * We assume that pagesize is a power of 2 when calculating
33018a475bcbSad 		 * pagesize_mask and pagesize_2pow.
33028a475bcbSad 		 */
33038a475bcbSad 		assert(((result - 1) & result) == 0);
33048a475bcbSad 		pagesize_mask = result - 1;
33058a475bcbSad 		pagesize_2pow = ffs((int)result) - 1;
33068a475bcbSad 	}
33078a475bcbSad 
33088a475bcbSad 	for (i = 0; i < 3; i++) {
33098a475bcbSad 		/* Get runtime configuration. */
33108a475bcbSad 		switch (i) {
33118a475bcbSad 		case 0:
33128a475bcbSad 			if ((linklen = readlink("/etc/malloc.conf", buf,
33138a475bcbSad 			    sizeof(buf) - 1)) != -1) {
33148a475bcbSad 				/*
33158a475bcbSad 				 * Use the contents of the "/etc/malloc.conf"
33168a475bcbSad 				 * symbolic link's name.
33178a475bcbSad 				 */
33188a475bcbSad 				buf[linklen] = '\0';
33198a475bcbSad 				opts = buf;
33208a475bcbSad 			} else {
33218a475bcbSad 				/* No configuration specified. */
33228a475bcbSad 				buf[0] = '\0';
33238a475bcbSad 				opts = buf;
33248a475bcbSad 			}
33258a475bcbSad 			break;
33268a475bcbSad 		case 1:
332788261d4eSad 			if ((opts = getenv("MALLOC_OPTIONS")) != NULL &&
332888261d4eSad 			    issetugid() == 0) {
33298a475bcbSad 				/*
33308a475bcbSad 				 * Do nothing; opts is already initialized to
33318a475bcbSad 				 * the value of the MALLOC_OPTIONS environment
33328a475bcbSad 				 * variable.
33338a475bcbSad 				 */
33348a475bcbSad 			} else {
33358a475bcbSad 				/* No configuration specified. */
33368a475bcbSad 				buf[0] = '\0';
33378a475bcbSad 				opts = buf;
33388a475bcbSad 			}
33398a475bcbSad 			break;
33408a475bcbSad 		case 2:
33418a475bcbSad 			if (_malloc_options != NULL) {
33428a475bcbSad 				/*
33438a475bcbSad 				 * Use options that were compiled into the program.
33448a475bcbSad 				 */
33458a475bcbSad 				opts = _malloc_options;
33468a475bcbSad 			} else {
33478a475bcbSad 				/* No configuration specified. */
33488a475bcbSad 				buf[0] = '\0';
33498a475bcbSad 				opts = buf;
33508a475bcbSad 			}
33518a475bcbSad 			break;
33528a475bcbSad 		default:
33538a475bcbSad 			/* NOTREACHED */
3354687cd24eSyamt 			/* LINTED */
33558a475bcbSad 			assert(false);
33568a475bcbSad 		}
33578a475bcbSad 
33588a475bcbSad 		for (j = 0; opts[j] != '\0'; j++) {
33598a475bcbSad 			switch (opts[j]) {
33608a475bcbSad 			case 'a':
33618a475bcbSad 				opt_abort = false;
33628a475bcbSad 				break;
33638a475bcbSad 			case 'A':
33648a475bcbSad 				opt_abort = true;
33658a475bcbSad 				break;
33668a475bcbSad 			case 'h':
33678a475bcbSad 				opt_hint = false;
33688a475bcbSad 				break;
33698a475bcbSad 			case 'H':
33708a475bcbSad 				opt_hint = true;
33718a475bcbSad 				break;
33728a475bcbSad 			case 'j':
33738a475bcbSad 				opt_junk = false;
33748a475bcbSad 				break;
33758a475bcbSad 			case 'J':
33768a475bcbSad 				opt_junk = true;
33778a475bcbSad 				break;
33788a475bcbSad 			case 'k':
33798a475bcbSad 				/*
33808a475bcbSad 				 * Chunks always require at least one header
33818a475bcbSad 				 * page, so chunks can never be smaller than
33828a475bcbSad 				 * two pages.
33838a475bcbSad 				 */
33848a475bcbSad 				if (opt_chunk_2pow > pagesize_2pow + 1)
33858a475bcbSad 					opt_chunk_2pow--;
33868a475bcbSad 				break;
33878a475bcbSad 			case 'K':
33882360d084Slukem 				if (opt_chunk_2pow + 1 <
33892360d084Slukem 				    (int)(sizeof(size_t) << 3))
33908a475bcbSad 					opt_chunk_2pow++;
33918a475bcbSad 				break;
33928a475bcbSad 			case 'p':
33938a475bcbSad 				opt_print_stats = false;
33948a475bcbSad 				break;
33958a475bcbSad 			case 'P':
33968a475bcbSad 				opt_print_stats = true;
33978a475bcbSad 				break;
33988a475bcbSad 			case 'q':
33998a475bcbSad 				if (opt_quantum_2pow > QUANTUM_2POW_MIN)
34008a475bcbSad 					opt_quantum_2pow--;
34018a475bcbSad 				break;
34028a475bcbSad 			case 'Q':
34038a475bcbSad 				if (opt_quantum_2pow < pagesize_2pow - 1)
34048a475bcbSad 					opt_quantum_2pow++;
34058a475bcbSad 				break;
34068a475bcbSad 			case 's':
34078a475bcbSad 				if (opt_small_max_2pow > QUANTUM_2POW_MIN)
34088a475bcbSad 					opt_small_max_2pow--;
34098a475bcbSad 				break;
34108a475bcbSad 			case 'S':
34118a475bcbSad 				if (opt_small_max_2pow < pagesize_2pow - 1)
34128a475bcbSad 					opt_small_max_2pow++;
34138a475bcbSad 				break;
34148a475bcbSad 			case 'u':
34158a475bcbSad 				opt_utrace = false;
34168a475bcbSad 				break;
34178a475bcbSad 			case 'U':
34188a475bcbSad 				opt_utrace = true;
34198a475bcbSad 				break;
34208a475bcbSad 			case 'v':
34218a475bcbSad 				opt_sysv = false;
34228a475bcbSad 				break;
34238a475bcbSad 			case 'V':
34248a475bcbSad 				opt_sysv = true;
34258a475bcbSad 				break;
34268a475bcbSad 			case 'x':
34278a475bcbSad 				opt_xmalloc = false;
34288a475bcbSad 				break;
34298a475bcbSad 			case 'X':
34308a475bcbSad 				opt_xmalloc = true;
34318a475bcbSad 				break;
34328a475bcbSad 			case 'z':
34338a475bcbSad 				opt_zero = false;
34348a475bcbSad 				break;
34358a475bcbSad 			case 'Z':
34368a475bcbSad 				opt_zero = true;
34378a475bcbSad 				break;
34388a475bcbSad 			default: {
34398a475bcbSad 				char cbuf[2];
34408a475bcbSad 
34418a475bcbSad 				cbuf[0] = opts[j];
34428a475bcbSad 				cbuf[1] = '\0';
344386ef91b8Schristos 				_malloc_message(getprogname(),
34448a475bcbSad 				    ": (malloc) Unsupported character in "
34458a475bcbSad 				    "malloc options: '", cbuf, "'\n");
34468a475bcbSad 			}
34478a475bcbSad 			}
34488a475bcbSad 		}
34498a475bcbSad 	}
3450713ea189Schristos 	errno = serrno;
34518a475bcbSad 
34528a475bcbSad 	/* Take care to call atexit() only once. */
3453bf5f78d5Sad 	if (OPT(print_stats)) {
34548a475bcbSad 		/* Print statistics at exit. */
34558a475bcbSad 		atexit(malloc_print_stats);
34568a475bcbSad 	}
34578a475bcbSad 
34588a475bcbSad 	/* Set variables according to the value of opt_small_max_2pow. */
34598a475bcbSad 	if (opt_small_max_2pow < opt_quantum_2pow)
34608a475bcbSad 		opt_small_max_2pow = opt_quantum_2pow;
3461bf5f78d5Sad 	small_max = (1U << opt_small_max_2pow);
34628a475bcbSad 
34638a475bcbSad 	/* Set bin-related variables. */
34648a475bcbSad 	bin_maxclass = (pagesize >> 1);
34658a475bcbSad 	assert(opt_quantum_2pow >= TINY_MIN_2POW);
34668de47c09Schristos 	ntbins = (unsigned)(opt_quantum_2pow - TINY_MIN_2POW);
3467bf5f78d5Sad 	assert(ntbins <= (unsigned)opt_quantum_2pow);
34688de47c09Schristos 	nqbins = (unsigned)(small_max >> opt_quantum_2pow);
34698de47c09Schristos 	nsbins = (unsigned)(pagesize_2pow - opt_small_max_2pow - 1);
34708a475bcbSad 
34718a475bcbSad 	/* Set variables according to the value of opt_quantum_2pow. */
34728a475bcbSad 	quantum = (1 << opt_quantum_2pow);
34738a475bcbSad 	quantum_mask = quantum - 1;
34748a475bcbSad 	if (ntbins > 0)
34758a475bcbSad 		small_min = (quantum >> 1) + 1;
34768a475bcbSad 	else
34778a475bcbSad 		small_min = 1;
34788a475bcbSad 	assert(small_min <= quantum);
34798a475bcbSad 
34808a475bcbSad 	/* Set variables according to the value of opt_chunk_2pow. */
34818a475bcbSad 	chunksize = (1LU << opt_chunk_2pow);
34828a475bcbSad 	chunksize_mask = chunksize - 1;
34838de47c09Schristos 	chunksize_2pow = (unsigned)opt_chunk_2pow;
34848de47c09Schristos 	chunk_npages = (unsigned)(chunksize >> pagesize_2pow);
34858a475bcbSad 	{
34868a475bcbSad 		unsigned header_size;
34878a475bcbSad 
34888de47c09Schristos 		header_size = (unsigned)(sizeof(arena_chunk_t) +
34898de47c09Schristos 		    (sizeof(arena_chunk_map_t) * (chunk_npages - 1)));
34908a475bcbSad 		arena_chunk_header_npages = (header_size >> pagesize_2pow);
34918a475bcbSad 		if ((header_size & pagesize_mask) != 0)
34928a475bcbSad 			arena_chunk_header_npages++;
34938a475bcbSad 	}
34948a475bcbSad 	arena_maxclass = chunksize - (arena_chunk_header_npages <<
34958a475bcbSad 	    pagesize_2pow);
34968a475bcbSad 
34978a475bcbSad 	UTRACE(0, 0, 0);
34988a475bcbSad 
34998a475bcbSad #ifdef MALLOC_STATS
35008a475bcbSad 	memset(&stats_chunks, 0, sizeof(chunk_stats_t));
35018a475bcbSad #endif
35028a475bcbSad 
35038a475bcbSad 	/* Various sanity checks that regard configuration. */
35048a475bcbSad 	assert(quantum >= sizeof(void *));
35058a475bcbSad 	assert(quantum <= pagesize);
35068a475bcbSad 	assert(chunksize >= pagesize);
35078a475bcbSad 	assert(quantum * 4 <= chunksize);
35088a475bcbSad 
35098a475bcbSad 	/* Initialize chunks data. */
35108a475bcbSad 	malloc_mutex_init(&chunks_mtx);
3511562025fdSad 	rb_tree_init(&huge, &chunk_tree_ops);
35128a475bcbSad #ifdef USE_BRK
35138a475bcbSad 	malloc_mutex_init(&brk_mtx);
35148a475bcbSad 	brk_base = sbrk(0);
35158a475bcbSad 	brk_prev = brk_base;
35168a475bcbSad 	brk_max = brk_base;
35178a475bcbSad #endif
35188a475bcbSad #ifdef MALLOC_STATS
35198a475bcbSad 	huge_nmalloc = 0;
35208a475bcbSad 	huge_ndalloc = 0;
3521b79fded2Syamt 	huge_nralloc = 0;
35228a475bcbSad 	huge_allocated = 0;
35238a475bcbSad #endif
3524562025fdSad 	rb_tree_init(&old_chunks, &chunk_tree_ops);
35258a475bcbSad 
35268a475bcbSad 	/* Initialize base allocation data structures. */
35278a475bcbSad #ifdef MALLOC_STATS
35288a475bcbSad 	base_mapped = 0;
35298a475bcbSad #endif
35308a475bcbSad #ifdef USE_BRK
35318a475bcbSad 	/*
35328a475bcbSad 	 * Allocate a base chunk here, since it doesn't actually have to be
35338a475bcbSad 	 * chunk-aligned.  Doing this before allocating any other chunks allows
35348a475bcbSad 	 * the use of space that would otherwise be wasted.
35358a475bcbSad 	 */
35368a475bcbSad 	base_pages_alloc(0);
35378a475bcbSad #endif
35388a475bcbSad 	base_chunk_nodes = NULL;
35398a475bcbSad 	malloc_mutex_init(&base_mtx);
35408a475bcbSad 
35418a475bcbSad 	/* Allocate and initialize arenas. */
3542bf5f78d5Sad 	arenas = (arena_t **)base_alloc(sizeof(arena_t *) * ncpus);
35438a475bcbSad 	if (arenas == NULL) {
35448a475bcbSad 		malloc_mutex_unlock(&init_lock);
35458a475bcbSad 		return (true);
35468a475bcbSad 	}
35478a475bcbSad 	/*
35488a475bcbSad 	 * Zero the array.  In practice, this should always be pre-zeroed,
35498a475bcbSad 	 * since it was just mmap()ed, but let's be sure.
35508a475bcbSad 	 */
3551bf5f78d5Sad 	memset(arenas, 0, sizeof(arena_t *) * ncpus);
35528a475bcbSad 
35538a475bcbSad 	/*
35548a475bcbSad 	 * Initialize one arena here.  The rest are lazily created in
35558a475bcbSad 	 * arena_choose_hard().
35568a475bcbSad 	 */
3557bf5f78d5Sad 	if ((arenas[0] = arenas_extend()) == NULL) {
35588a475bcbSad 		malloc_mutex_unlock(&init_lock);
35598a475bcbSad 		return (true);
35608a475bcbSad 	}
35618a475bcbSad 
35628a475bcbSad 	malloc_mutex_init(&arenas_mtx);
35638a475bcbSad 
35648a475bcbSad 	malloc_initialized = true;
35658a475bcbSad 	malloc_mutex_unlock(&init_lock);
35668a475bcbSad 	return (false);
35678a475bcbSad }
35688a475bcbSad 
35698a475bcbSad /*
35708a475bcbSad  * End general internal functions.
35718a475bcbSad  */
35728a475bcbSad /******************************************************************************/
35738a475bcbSad /*
35748a475bcbSad  * Begin malloc(3)-compatible functions.
35758a475bcbSad  */
35768a475bcbSad 
35778a475bcbSad void *
malloc(size_t size)35788a475bcbSad malloc(size_t size)
35798a475bcbSad {
35808a475bcbSad 	void *ret;
35818a475bcbSad 
3582bf5f78d5Sad 	if (__predict_false(malloc_init())) {
35838a475bcbSad 		ret = NULL;
35848a475bcbSad 		goto RETURN;
35858a475bcbSad 	}
35868a475bcbSad 
3587bf5f78d5Sad 	if (__predict_false(size == 0)) {
3588bf5f78d5Sad 		if (NOT_OPT(sysv))
35898a475bcbSad 			size = 1;
35908a475bcbSad 		else {
35918a475bcbSad 			ret = NULL;
35928a475bcbSad 			goto RETURN;
35938a475bcbSad 		}
35948a475bcbSad 	}
35958a475bcbSad 
35968a475bcbSad 	ret = imalloc(size);
35978a475bcbSad 
35988a475bcbSad RETURN:
3599bf5f78d5Sad 	if (__predict_false(ret == NULL)) {
3600bf5f78d5Sad 		if (OPT(xmalloc)) {
360186ef91b8Schristos 			_malloc_message(getprogname(),
36028a475bcbSad 			    ": (malloc) Error in malloc(): out of memory\n", "",
36038a475bcbSad 			    "");
36048a475bcbSad 			abort();
36058a475bcbSad 		}
36068a475bcbSad 		errno = ENOMEM;
36078a475bcbSad 	}
36088a475bcbSad 
36098a475bcbSad 	UTRACE(0, size, ret);
36108a475bcbSad 	return (ret);
36118a475bcbSad }
36128a475bcbSad 
36138a475bcbSad int
posix_memalign(void ** memptr,size_t alignment,size_t size)36148a475bcbSad posix_memalign(void **memptr, size_t alignment, size_t size)
36158a475bcbSad {
36168a475bcbSad 	int ret;
36178a475bcbSad 	void *result;
36188a475bcbSad 
3619bf5f78d5Sad 	if (__predict_false(malloc_init()))
36208a475bcbSad 		result = NULL;
36218a475bcbSad 	else {
36228a475bcbSad 		/* Make sure that alignment is a large enough power of 2. */
36238a475bcbSad 		if (((alignment - 1) & alignment) != 0
36248a475bcbSad 		    || alignment < sizeof(void *)) {
3625bf5f78d5Sad 			if (OPT(xmalloc)) {
362686ef91b8Schristos 				_malloc_message(getprogname(),
36278a475bcbSad 				    ": (malloc) Error in posix_memalign(): "
36288a475bcbSad 				    "invalid alignment\n", "", "");
36298a475bcbSad 				abort();
36308a475bcbSad 			}
36318a475bcbSad 			result = NULL;
36328a475bcbSad 			ret = EINVAL;
36338a475bcbSad 			goto RETURN;
36348a475bcbSad 		}
36358a475bcbSad 
363657fcbaebSad 		if (size == 0) {
363757fcbaebSad 			if (NOT_OPT(sysv))
363857fcbaebSad 				size = 1;
363957fcbaebSad 			else {
364057fcbaebSad 				result = NULL;
364157fcbaebSad 				ret = 0;
364257fcbaebSad 				goto RETURN;
364357fcbaebSad 			}
364457fcbaebSad 		}
36458a475bcbSad 		result = ipalloc(alignment, size);
36468a475bcbSad 	}
36478a475bcbSad 
3648bf5f78d5Sad 	if (__predict_false(result == NULL)) {
3649bf5f78d5Sad 		if (OPT(xmalloc)) {
365086ef91b8Schristos 			_malloc_message(getprogname(),
36518a475bcbSad 			": (malloc) Error in posix_memalign(): out of memory\n",
36528a475bcbSad 			"", "");
36538a475bcbSad 			abort();
36548a475bcbSad 		}
36558a475bcbSad 		ret = ENOMEM;
36568a475bcbSad 		goto RETURN;
36578a475bcbSad 	}
36588a475bcbSad 
36598a475bcbSad 	*memptr = result;
36608a475bcbSad 	ret = 0;
36618a475bcbSad 
36628a475bcbSad RETURN:
36638a475bcbSad 	UTRACE(0, size, result);
36648a475bcbSad 	return (ret);
36658a475bcbSad }
36668a475bcbSad 
36678a475bcbSad void *
calloc(size_t num,size_t size)36688a475bcbSad calloc(size_t num, size_t size)
36698a475bcbSad {
36708a475bcbSad 	void *ret;
36718a475bcbSad 	size_t num_size;
36728a475bcbSad 
3673bf5f78d5Sad 	if (__predict_false(malloc_init())) {
36748a475bcbSad 		num_size = 0;
36758a475bcbSad 		ret = NULL;
36768a475bcbSad 		goto RETURN;
36778a475bcbSad 	}
36788a475bcbSad 
36798a475bcbSad 	num_size = num * size;
3680bf5f78d5Sad 	if (__predict_false(num_size == 0)) {
3681bf5f78d5Sad 		if (NOT_OPT(sysv) && ((num == 0) || (size == 0)))
36828a475bcbSad 			num_size = 1;
36838a475bcbSad 		else {
36848a475bcbSad 			ret = NULL;
36858a475bcbSad 			goto RETURN;
36868a475bcbSad 		}
36878a475bcbSad 	/*
36888a475bcbSad 	 * Try to avoid division here.  We know that it isn't possible to
36898a475bcbSad 	 * overflow during multiplication if neither operand uses any of the
36908a475bcbSad 	 * most significant half of the bits in a size_t.
36918a475bcbSad 	 */
3692e7a9e46bSad 	} else if ((unsigned long long)((num | size) &
3693e7a9e46bSad 	   ((unsigned long long)SIZE_T_MAX << (sizeof(size_t) << 2))) &&
3694e7a9e46bSad 	   (num_size / size != num)) {
36958a475bcbSad 		/* size_t overflow. */
36968a475bcbSad 		ret = NULL;
36978a475bcbSad 		goto RETURN;
36988a475bcbSad 	}
36998a475bcbSad 
37008a475bcbSad 	ret = icalloc(num_size);
37018a475bcbSad 
37028a475bcbSad RETURN:
3703a3628a91Sad 	if (__predict_false(ret == NULL)) {
3704bf5f78d5Sad 		if (OPT(xmalloc)) {
370586ef91b8Schristos 			_malloc_message(getprogname(),
37068a475bcbSad 			    ": (malloc) Error in calloc(): out of memory\n", "",
37078a475bcbSad 			    "");
37088a475bcbSad 			abort();
37098a475bcbSad 		}
37108a475bcbSad 		errno = ENOMEM;
37118a475bcbSad 	}
37128a475bcbSad 
37138a475bcbSad 	UTRACE(0, num_size, ret);
37148a475bcbSad 	return (ret);
37158a475bcbSad }
37168a475bcbSad 
37178a475bcbSad void *
realloc(void * ptr,size_t size)37188a475bcbSad realloc(void *ptr, size_t size)
37198a475bcbSad {
37208a475bcbSad 	void *ret;
37218a475bcbSad 
3722bf5f78d5Sad 	if (__predict_false(size == 0)) {
3723bf5f78d5Sad 		if (NOT_OPT(sysv))
37248a475bcbSad 			size = 1;
37258a475bcbSad 		else {
37268a475bcbSad 			if (ptr != NULL)
37278a475bcbSad 				idalloc(ptr);
37288a475bcbSad 			ret = NULL;
37298a475bcbSad 			goto RETURN;
37308a475bcbSad 		}
37318a475bcbSad 	}
37328a475bcbSad 
3733bf5f78d5Sad 	if (__predict_true(ptr != NULL)) {
37348a475bcbSad 		assert(malloc_initialized);
37358a475bcbSad 
37368a475bcbSad 		ret = iralloc(ptr, size);
37378a475bcbSad 
3738a3628a91Sad 		if (__predict_false(ret == NULL)) {
3739bf5f78d5Sad 			if (OPT(xmalloc)) {
374086ef91b8Schristos 				_malloc_message(getprogname(),
37418a475bcbSad 				    ": (malloc) Error in realloc(): out of "
37428a475bcbSad 				    "memory\n", "", "");
37438a475bcbSad 				abort();
37448a475bcbSad 			}
37458a475bcbSad 			errno = ENOMEM;
37468a475bcbSad 		}
37478a475bcbSad 	} else {
3748bf5f78d5Sad 		if (__predict_false(malloc_init()))
37498a475bcbSad 			ret = NULL;
37508a475bcbSad 		else
37518a475bcbSad 			ret = imalloc(size);
37528a475bcbSad 
3753a3628a91Sad 		if (__predict_false(ret == NULL)) {
3754bf5f78d5Sad 			if (OPT(xmalloc)) {
375586ef91b8Schristos 				_malloc_message(getprogname(),
37568a475bcbSad 				    ": (malloc) Error in realloc(): out of "
37578a475bcbSad 				    "memory\n", "", "");
37588a475bcbSad 				abort();
37598a475bcbSad 			}
37608a475bcbSad 			errno = ENOMEM;
37618a475bcbSad 		}
37628a475bcbSad 	}
37638a475bcbSad 
37648a475bcbSad RETURN:
37658a475bcbSad 	UTRACE(ptr, size, ret);
37668a475bcbSad 	return (ret);
37678a475bcbSad }
37688a475bcbSad 
37698a475bcbSad void
free(void * ptr)37708a475bcbSad free(void *ptr)
37718a475bcbSad {
37728a475bcbSad 
37738a475bcbSad 	UTRACE(ptr, 0, 0);
3774a3628a91Sad 	if (__predict_true(ptr != NULL)) {
37758a475bcbSad 		assert(malloc_initialized);
37768a475bcbSad 
37778a475bcbSad 		idalloc(ptr);
37788a475bcbSad 	}
37798a475bcbSad }
37808a475bcbSad 
37818a475bcbSad /*
37828a475bcbSad  * End malloc(3)-compatible functions.
37838a475bcbSad  */
37848a475bcbSad /******************************************************************************/
37858a475bcbSad /*
37868a475bcbSad  * Begin non-standard functions.
37878a475bcbSad  */
37888a475bcbSad size_t
malloc_usable_size(const void * ptr)37898a475bcbSad malloc_usable_size(const void *ptr)
37908a475bcbSad {
37918a475bcbSad 
37928a475bcbSad 	assert(ptr != NULL);
37938a475bcbSad 
37948a475bcbSad 	return (isalloc(ptr));
37958a475bcbSad }
37968a475bcbSad 
37978a475bcbSad /*
37988a475bcbSad  * End non-standard functions.
37998a475bcbSad  */
38008a475bcbSad /******************************************************************************/
38018a475bcbSad /*
38028a475bcbSad  * Begin library-private functions, used by threading libraries for protection
38038a475bcbSad  * of malloc during fork().  These functions are only called if the program is
38048a475bcbSad  * running in threaded mode, so there is no need to check whether the program
38058a475bcbSad  * is threaded here.
38068a475bcbSad  */
38078a475bcbSad 
38088a475bcbSad void
_malloc_prefork(void)38098a475bcbSad _malloc_prefork(void)
38108a475bcbSad {
38118a475bcbSad 	unsigned i;
38128a475bcbSad 
38138a475bcbSad 	/* Acquire all mutexes in a safe order. */
3814174eb28aSjoerg 	malloc_mutex_lock(&init_lock);
38158a475bcbSad 	malloc_mutex_lock(&arenas_mtx);
3816bf5f78d5Sad 	for (i = 0; i < ncpus; i++) {
38178a475bcbSad 		if (arenas[i] != NULL)
38188a475bcbSad 			malloc_mutex_lock(&arenas[i]->mtx);
38198a475bcbSad 	}
38208a475bcbSad 	malloc_mutex_lock(&chunks_mtx);
3821174eb28aSjoerg 	malloc_mutex_lock(&base_mtx);
3822174eb28aSjoerg #ifdef USE_BRK
3823174eb28aSjoerg 	malloc_mutex_lock(&brk_mtx);
3824174eb28aSjoerg #endif
38258a475bcbSad }
38268a475bcbSad 
38278a475bcbSad void
_malloc_postfork(void)38288a475bcbSad _malloc_postfork(void)
38298a475bcbSad {
38308a475bcbSad 	unsigned i;
38318a475bcbSad 
38328a475bcbSad 	/* Release all mutexes, now that fork() has completed. */
3833174eb28aSjoerg #ifdef USE_BRK
3834174eb28aSjoerg 	malloc_mutex_unlock(&brk_mtx);
3835174eb28aSjoerg #endif
3836174eb28aSjoerg 	malloc_mutex_unlock(&base_mtx);
38378a475bcbSad 	malloc_mutex_unlock(&chunks_mtx);
38388a475bcbSad 
3839bf5f78d5Sad 	for (i = ncpus; i-- > 0; ) {
38408a475bcbSad 		if (arenas[i] != NULL)
38418a475bcbSad 			malloc_mutex_unlock(&arenas[i]->mtx);
38428a475bcbSad 	}
38438a475bcbSad 	malloc_mutex_unlock(&arenas_mtx);
3844174eb28aSjoerg 	malloc_mutex_unlock(&init_lock);
38458a475bcbSad }
38468a475bcbSad 
38478409cf4aSjoerg void
_malloc_postfork_child(void)38488409cf4aSjoerg _malloc_postfork_child(void)
38498409cf4aSjoerg {
38508409cf4aSjoerg 	unsigned i;
38518409cf4aSjoerg 
38528409cf4aSjoerg 	/* Release all mutexes, now that fork() has completed. */
38538409cf4aSjoerg #ifdef USE_BRK
38548409cf4aSjoerg 	malloc_mutex_init(&brk_mtx);
38558409cf4aSjoerg #endif
38568409cf4aSjoerg 	malloc_mutex_init(&base_mtx);
38578409cf4aSjoerg 	malloc_mutex_init(&chunks_mtx);
38588409cf4aSjoerg 
3859bf5f78d5Sad 	for (i = ncpus; i-- > 0; ) {
38608409cf4aSjoerg 		if (arenas[i] != NULL)
38618409cf4aSjoerg 			malloc_mutex_init(&arenas[i]->mtx);
38628409cf4aSjoerg 	}
38638409cf4aSjoerg 	malloc_mutex_init(&arenas_mtx);
38648409cf4aSjoerg 	malloc_mutex_init(&init_lock);
38658409cf4aSjoerg }
38668409cf4aSjoerg 
38678a475bcbSad /*
38688a475bcbSad  * End library-private functions.
38698a475bcbSad  */
38708a475bcbSad /******************************************************************************/
3871