1*1208bc7eSAndroid Build Coastguard Worker #define JEMALLOC_BASE_C_
2*1208bc7eSAndroid Build Coastguard Worker #include "jemalloc/internal/jemalloc_preamble.h"
3*1208bc7eSAndroid Build Coastguard Worker #include "jemalloc/internal/jemalloc_internal_includes.h"
4*1208bc7eSAndroid Build Coastguard Worker
5*1208bc7eSAndroid Build Coastguard Worker #include "jemalloc/internal/assert.h"
6*1208bc7eSAndroid Build Coastguard Worker #include "jemalloc/internal/extent_mmap.h"
7*1208bc7eSAndroid Build Coastguard Worker #include "jemalloc/internal/mutex.h"
8*1208bc7eSAndroid Build Coastguard Worker #include "jemalloc/internal/sz.h"
9*1208bc7eSAndroid Build Coastguard Worker
10*1208bc7eSAndroid Build Coastguard Worker /******************************************************************************/
11*1208bc7eSAndroid Build Coastguard Worker /* Data. */
12*1208bc7eSAndroid Build Coastguard Worker
13*1208bc7eSAndroid Build Coastguard Worker static base_t *b0;
14*1208bc7eSAndroid Build Coastguard Worker
15*1208bc7eSAndroid Build Coastguard Worker metadata_thp_mode_t opt_metadata_thp = METADATA_THP_DEFAULT;
16*1208bc7eSAndroid Build Coastguard Worker
17*1208bc7eSAndroid Build Coastguard Worker const char *metadata_thp_mode_names[] = {
18*1208bc7eSAndroid Build Coastguard Worker "disabled",
19*1208bc7eSAndroid Build Coastguard Worker "auto",
20*1208bc7eSAndroid Build Coastguard Worker "always"
21*1208bc7eSAndroid Build Coastguard Worker };
22*1208bc7eSAndroid Build Coastguard Worker
23*1208bc7eSAndroid Build Coastguard Worker /******************************************************************************/
24*1208bc7eSAndroid Build Coastguard Worker
25*1208bc7eSAndroid Build Coastguard Worker static inline bool
metadata_thp_madvise(void)26*1208bc7eSAndroid Build Coastguard Worker metadata_thp_madvise(void) {
27*1208bc7eSAndroid Build Coastguard Worker return (metadata_thp_enabled() &&
28*1208bc7eSAndroid Build Coastguard Worker (init_system_thp_mode == thp_mode_default));
29*1208bc7eSAndroid Build Coastguard Worker }
30*1208bc7eSAndroid Build Coastguard Worker
31*1208bc7eSAndroid Build Coastguard Worker static void *
base_map(tsdn_t * tsdn,extent_hooks_t * extent_hooks,unsigned ind,size_t size)32*1208bc7eSAndroid Build Coastguard Worker base_map(tsdn_t *tsdn, extent_hooks_t *extent_hooks, unsigned ind, size_t size) {
33*1208bc7eSAndroid Build Coastguard Worker void *addr;
34*1208bc7eSAndroid Build Coastguard Worker bool zero = true;
35*1208bc7eSAndroid Build Coastguard Worker bool commit = true;
36*1208bc7eSAndroid Build Coastguard Worker
37*1208bc7eSAndroid Build Coastguard Worker /* Use huge page sizes and alignment regardless of opt_metadata_thp. */
38*1208bc7eSAndroid Build Coastguard Worker assert(size == HUGEPAGE_CEILING(size));
39*1208bc7eSAndroid Build Coastguard Worker size_t alignment = HUGEPAGE;
40*1208bc7eSAndroid Build Coastguard Worker if (extent_hooks == &extent_hooks_default) {
41*1208bc7eSAndroid Build Coastguard Worker addr = extent_alloc_mmap(NULL, size, alignment, &zero, &commit);
42*1208bc7eSAndroid Build Coastguard Worker } else {
43*1208bc7eSAndroid Build Coastguard Worker /* No arena context as we are creating new arenas. */
44*1208bc7eSAndroid Build Coastguard Worker tsd_t *tsd = tsdn_null(tsdn) ? tsd_fetch() : tsdn_tsd(tsdn);
45*1208bc7eSAndroid Build Coastguard Worker pre_reentrancy(tsd, NULL);
46*1208bc7eSAndroid Build Coastguard Worker addr = extent_hooks->alloc(extent_hooks, NULL, size, alignment,
47*1208bc7eSAndroid Build Coastguard Worker &zero, &commit, ind);
48*1208bc7eSAndroid Build Coastguard Worker post_reentrancy(tsd);
49*1208bc7eSAndroid Build Coastguard Worker }
50*1208bc7eSAndroid Build Coastguard Worker
51*1208bc7eSAndroid Build Coastguard Worker return addr;
52*1208bc7eSAndroid Build Coastguard Worker }
53*1208bc7eSAndroid Build Coastguard Worker
54*1208bc7eSAndroid Build Coastguard Worker static void
base_unmap(tsdn_t * tsdn,extent_hooks_t * extent_hooks,unsigned ind,void * addr,size_t size)55*1208bc7eSAndroid Build Coastguard Worker base_unmap(tsdn_t *tsdn, extent_hooks_t *extent_hooks, unsigned ind, void *addr,
56*1208bc7eSAndroid Build Coastguard Worker size_t size) {
57*1208bc7eSAndroid Build Coastguard Worker /*
58*1208bc7eSAndroid Build Coastguard Worker * Cascade through dalloc, decommit, purge_forced, and purge_lazy,
59*1208bc7eSAndroid Build Coastguard Worker * stopping at first success. This cascade is performed for consistency
60*1208bc7eSAndroid Build Coastguard Worker * with the cascade in extent_dalloc_wrapper() because an application's
61*1208bc7eSAndroid Build Coastguard Worker * custom hooks may not support e.g. dalloc. This function is only ever
62*1208bc7eSAndroid Build Coastguard Worker * called as a side effect of arena destruction, so although it might
63*1208bc7eSAndroid Build Coastguard Worker * seem pointless to do anything besides dalloc here, the application
64*1208bc7eSAndroid Build Coastguard Worker * may in fact want the end state of all associated virtual memory to be
65*1208bc7eSAndroid Build Coastguard Worker * in some consistent-but-allocated state.
66*1208bc7eSAndroid Build Coastguard Worker */
67*1208bc7eSAndroid Build Coastguard Worker if (extent_hooks == &extent_hooks_default) {
68*1208bc7eSAndroid Build Coastguard Worker if (!extent_dalloc_mmap(addr, size)) {
69*1208bc7eSAndroid Build Coastguard Worker goto label_done;
70*1208bc7eSAndroid Build Coastguard Worker }
71*1208bc7eSAndroid Build Coastguard Worker if (!pages_decommit(addr, size)) {
72*1208bc7eSAndroid Build Coastguard Worker goto label_done;
73*1208bc7eSAndroid Build Coastguard Worker }
74*1208bc7eSAndroid Build Coastguard Worker if (!pages_purge_forced(addr, size)) {
75*1208bc7eSAndroid Build Coastguard Worker goto label_done;
76*1208bc7eSAndroid Build Coastguard Worker }
77*1208bc7eSAndroid Build Coastguard Worker if (!pages_purge_lazy(addr, size)) {
78*1208bc7eSAndroid Build Coastguard Worker goto label_done;
79*1208bc7eSAndroid Build Coastguard Worker }
80*1208bc7eSAndroid Build Coastguard Worker /* Nothing worked. This should never happen. */
81*1208bc7eSAndroid Build Coastguard Worker not_reached();
82*1208bc7eSAndroid Build Coastguard Worker } else {
83*1208bc7eSAndroid Build Coastguard Worker tsd_t *tsd = tsdn_null(tsdn) ? tsd_fetch() : tsdn_tsd(tsdn);
84*1208bc7eSAndroid Build Coastguard Worker pre_reentrancy(tsd, NULL);
85*1208bc7eSAndroid Build Coastguard Worker if (extent_hooks->dalloc != NULL &&
86*1208bc7eSAndroid Build Coastguard Worker !extent_hooks->dalloc(extent_hooks, addr, size, true,
87*1208bc7eSAndroid Build Coastguard Worker ind)) {
88*1208bc7eSAndroid Build Coastguard Worker goto label_post_reentrancy;
89*1208bc7eSAndroid Build Coastguard Worker }
90*1208bc7eSAndroid Build Coastguard Worker if (extent_hooks->decommit != NULL &&
91*1208bc7eSAndroid Build Coastguard Worker !extent_hooks->decommit(extent_hooks, addr, size, 0, size,
92*1208bc7eSAndroid Build Coastguard Worker ind)) {
93*1208bc7eSAndroid Build Coastguard Worker goto label_post_reentrancy;
94*1208bc7eSAndroid Build Coastguard Worker }
95*1208bc7eSAndroid Build Coastguard Worker if (extent_hooks->purge_forced != NULL &&
96*1208bc7eSAndroid Build Coastguard Worker !extent_hooks->purge_forced(extent_hooks, addr, size, 0,
97*1208bc7eSAndroid Build Coastguard Worker size, ind)) {
98*1208bc7eSAndroid Build Coastguard Worker goto label_post_reentrancy;
99*1208bc7eSAndroid Build Coastguard Worker }
100*1208bc7eSAndroid Build Coastguard Worker if (extent_hooks->purge_lazy != NULL &&
101*1208bc7eSAndroid Build Coastguard Worker !extent_hooks->purge_lazy(extent_hooks, addr, size, 0, size,
102*1208bc7eSAndroid Build Coastguard Worker ind)) {
103*1208bc7eSAndroid Build Coastguard Worker goto label_post_reentrancy;
104*1208bc7eSAndroid Build Coastguard Worker }
105*1208bc7eSAndroid Build Coastguard Worker /* Nothing worked. That's the application's problem. */
106*1208bc7eSAndroid Build Coastguard Worker label_post_reentrancy:
107*1208bc7eSAndroid Build Coastguard Worker post_reentrancy(tsd);
108*1208bc7eSAndroid Build Coastguard Worker }
109*1208bc7eSAndroid Build Coastguard Worker label_done:
110*1208bc7eSAndroid Build Coastguard Worker if (metadata_thp_madvise()) {
111*1208bc7eSAndroid Build Coastguard Worker /* Set NOHUGEPAGE after unmap to avoid kernel defrag. */
112*1208bc7eSAndroid Build Coastguard Worker assert(((uintptr_t)addr & HUGEPAGE_MASK) == 0 &&
113*1208bc7eSAndroid Build Coastguard Worker (size & HUGEPAGE_MASK) == 0);
114*1208bc7eSAndroid Build Coastguard Worker pages_nohuge(addr, size);
115*1208bc7eSAndroid Build Coastguard Worker }
116*1208bc7eSAndroid Build Coastguard Worker }
117*1208bc7eSAndroid Build Coastguard Worker
118*1208bc7eSAndroid Build Coastguard Worker static void
base_extent_init(size_t * extent_sn_next,extent_t * extent,void * addr,size_t size)119*1208bc7eSAndroid Build Coastguard Worker base_extent_init(size_t *extent_sn_next, extent_t *extent, void *addr,
120*1208bc7eSAndroid Build Coastguard Worker size_t size) {
121*1208bc7eSAndroid Build Coastguard Worker size_t sn;
122*1208bc7eSAndroid Build Coastguard Worker
123*1208bc7eSAndroid Build Coastguard Worker sn = *extent_sn_next;
124*1208bc7eSAndroid Build Coastguard Worker (*extent_sn_next)++;
125*1208bc7eSAndroid Build Coastguard Worker
126*1208bc7eSAndroid Build Coastguard Worker extent_binit(extent, addr, size, sn);
127*1208bc7eSAndroid Build Coastguard Worker }
128*1208bc7eSAndroid Build Coastguard Worker
129*1208bc7eSAndroid Build Coastguard Worker static size_t
base_get_num_blocks(base_t * base,bool with_new_block)130*1208bc7eSAndroid Build Coastguard Worker base_get_num_blocks(base_t *base, bool with_new_block) {
131*1208bc7eSAndroid Build Coastguard Worker base_block_t *b = base->blocks;
132*1208bc7eSAndroid Build Coastguard Worker assert(b != NULL);
133*1208bc7eSAndroid Build Coastguard Worker
134*1208bc7eSAndroid Build Coastguard Worker size_t n_blocks = with_new_block ? 2 : 1;
135*1208bc7eSAndroid Build Coastguard Worker while (b->next != NULL) {
136*1208bc7eSAndroid Build Coastguard Worker n_blocks++;
137*1208bc7eSAndroid Build Coastguard Worker b = b->next;
138*1208bc7eSAndroid Build Coastguard Worker }
139*1208bc7eSAndroid Build Coastguard Worker
140*1208bc7eSAndroid Build Coastguard Worker return n_blocks;
141*1208bc7eSAndroid Build Coastguard Worker }
142*1208bc7eSAndroid Build Coastguard Worker
143*1208bc7eSAndroid Build Coastguard Worker static void
base_auto_thp_switch(tsdn_t * tsdn,base_t * base)144*1208bc7eSAndroid Build Coastguard Worker base_auto_thp_switch(tsdn_t *tsdn, base_t *base) {
145*1208bc7eSAndroid Build Coastguard Worker assert(opt_metadata_thp == metadata_thp_auto);
146*1208bc7eSAndroid Build Coastguard Worker malloc_mutex_assert_owner(tsdn, &base->mtx);
147*1208bc7eSAndroid Build Coastguard Worker if (base->auto_thp_switched) {
148*1208bc7eSAndroid Build Coastguard Worker return;
149*1208bc7eSAndroid Build Coastguard Worker }
150*1208bc7eSAndroid Build Coastguard Worker /* Called when adding a new block. */
151*1208bc7eSAndroid Build Coastguard Worker bool should_switch;
152*1208bc7eSAndroid Build Coastguard Worker if (base_ind_get(base) != 0) {
153*1208bc7eSAndroid Build Coastguard Worker should_switch = (base_get_num_blocks(base, true) ==
154*1208bc7eSAndroid Build Coastguard Worker BASE_AUTO_THP_THRESHOLD);
155*1208bc7eSAndroid Build Coastguard Worker } else {
156*1208bc7eSAndroid Build Coastguard Worker should_switch = (base_get_num_blocks(base, true) ==
157*1208bc7eSAndroid Build Coastguard Worker BASE_AUTO_THP_THRESHOLD_A0);
158*1208bc7eSAndroid Build Coastguard Worker }
159*1208bc7eSAndroid Build Coastguard Worker if (!should_switch) {
160*1208bc7eSAndroid Build Coastguard Worker return;
161*1208bc7eSAndroid Build Coastguard Worker }
162*1208bc7eSAndroid Build Coastguard Worker
163*1208bc7eSAndroid Build Coastguard Worker base->auto_thp_switched = true;
164*1208bc7eSAndroid Build Coastguard Worker assert(!config_stats || base->n_thp == 0);
165*1208bc7eSAndroid Build Coastguard Worker /* Make the initial blocks THP lazily. */
166*1208bc7eSAndroid Build Coastguard Worker base_block_t *block = base->blocks;
167*1208bc7eSAndroid Build Coastguard Worker while (block != NULL) {
168*1208bc7eSAndroid Build Coastguard Worker assert((block->size & HUGEPAGE_MASK) == 0);
169*1208bc7eSAndroid Build Coastguard Worker pages_huge(block, block->size);
170*1208bc7eSAndroid Build Coastguard Worker if (config_stats) {
171*1208bc7eSAndroid Build Coastguard Worker base->n_thp += HUGEPAGE_CEILING(block->size -
172*1208bc7eSAndroid Build Coastguard Worker extent_bsize_get(&block->extent)) >> LG_HUGEPAGE;
173*1208bc7eSAndroid Build Coastguard Worker }
174*1208bc7eSAndroid Build Coastguard Worker block = block->next;
175*1208bc7eSAndroid Build Coastguard Worker assert(block == NULL || (base_ind_get(base) == 0));
176*1208bc7eSAndroid Build Coastguard Worker }
177*1208bc7eSAndroid Build Coastguard Worker }
178*1208bc7eSAndroid Build Coastguard Worker
179*1208bc7eSAndroid Build Coastguard Worker static void *
base_extent_bump_alloc_helper(extent_t * extent,size_t * gap_size,size_t size,size_t alignment)180*1208bc7eSAndroid Build Coastguard Worker base_extent_bump_alloc_helper(extent_t *extent, size_t *gap_size, size_t size,
181*1208bc7eSAndroid Build Coastguard Worker size_t alignment) {
182*1208bc7eSAndroid Build Coastguard Worker void *ret;
183*1208bc7eSAndroid Build Coastguard Worker
184*1208bc7eSAndroid Build Coastguard Worker assert(alignment == ALIGNMENT_CEILING(alignment, QUANTUM));
185*1208bc7eSAndroid Build Coastguard Worker assert(size == ALIGNMENT_CEILING(size, alignment));
186*1208bc7eSAndroid Build Coastguard Worker
187*1208bc7eSAndroid Build Coastguard Worker *gap_size = ALIGNMENT_CEILING((uintptr_t)extent_addr_get(extent),
188*1208bc7eSAndroid Build Coastguard Worker alignment) - (uintptr_t)extent_addr_get(extent);
189*1208bc7eSAndroid Build Coastguard Worker ret = (void *)((uintptr_t)extent_addr_get(extent) + *gap_size);
190*1208bc7eSAndroid Build Coastguard Worker assert(extent_bsize_get(extent) >= *gap_size + size);
191*1208bc7eSAndroid Build Coastguard Worker extent_binit(extent, (void *)((uintptr_t)extent_addr_get(extent) +
192*1208bc7eSAndroid Build Coastguard Worker *gap_size + size), extent_bsize_get(extent) - *gap_size - size,
193*1208bc7eSAndroid Build Coastguard Worker extent_sn_get(extent));
194*1208bc7eSAndroid Build Coastguard Worker return ret;
195*1208bc7eSAndroid Build Coastguard Worker }
196*1208bc7eSAndroid Build Coastguard Worker
197*1208bc7eSAndroid Build Coastguard Worker static void
base_extent_bump_alloc_post(base_t * base,extent_t * extent,size_t gap_size,void * addr,size_t size)198*1208bc7eSAndroid Build Coastguard Worker base_extent_bump_alloc_post(base_t *base, extent_t *extent, size_t gap_size,
199*1208bc7eSAndroid Build Coastguard Worker void *addr, size_t size) {
200*1208bc7eSAndroid Build Coastguard Worker if (extent_bsize_get(extent) > 0) {
201*1208bc7eSAndroid Build Coastguard Worker /*
202*1208bc7eSAndroid Build Coastguard Worker * Compute the index for the largest size class that does not
203*1208bc7eSAndroid Build Coastguard Worker * exceed extent's size.
204*1208bc7eSAndroid Build Coastguard Worker */
205*1208bc7eSAndroid Build Coastguard Worker szind_t index_floor =
206*1208bc7eSAndroid Build Coastguard Worker sz_size2index(extent_bsize_get(extent) + 1) - 1;
207*1208bc7eSAndroid Build Coastguard Worker extent_heap_insert(&base->avail[index_floor], extent);
208*1208bc7eSAndroid Build Coastguard Worker }
209*1208bc7eSAndroid Build Coastguard Worker
210*1208bc7eSAndroid Build Coastguard Worker if (config_stats) {
211*1208bc7eSAndroid Build Coastguard Worker base->allocated += size;
212*1208bc7eSAndroid Build Coastguard Worker /*
213*1208bc7eSAndroid Build Coastguard Worker * Add one PAGE to base_resident for every page boundary that is
214*1208bc7eSAndroid Build Coastguard Worker * crossed by the new allocation. Adjust n_thp similarly when
215*1208bc7eSAndroid Build Coastguard Worker * metadata_thp is enabled.
216*1208bc7eSAndroid Build Coastguard Worker */
217*1208bc7eSAndroid Build Coastguard Worker base->resident += PAGE_CEILING((uintptr_t)addr + size) -
218*1208bc7eSAndroid Build Coastguard Worker PAGE_CEILING((uintptr_t)addr - gap_size);
219*1208bc7eSAndroid Build Coastguard Worker assert(base->allocated <= base->resident);
220*1208bc7eSAndroid Build Coastguard Worker assert(base->resident <= base->mapped);
221*1208bc7eSAndroid Build Coastguard Worker if (metadata_thp_madvise() && (opt_metadata_thp ==
222*1208bc7eSAndroid Build Coastguard Worker metadata_thp_always || base->auto_thp_switched)) {
223*1208bc7eSAndroid Build Coastguard Worker base->n_thp += (HUGEPAGE_CEILING((uintptr_t)addr + size)
224*1208bc7eSAndroid Build Coastguard Worker - HUGEPAGE_CEILING((uintptr_t)addr - gap_size)) >>
225*1208bc7eSAndroid Build Coastguard Worker LG_HUGEPAGE;
226*1208bc7eSAndroid Build Coastguard Worker assert(base->mapped >= base->n_thp << LG_HUGEPAGE);
227*1208bc7eSAndroid Build Coastguard Worker }
228*1208bc7eSAndroid Build Coastguard Worker }
229*1208bc7eSAndroid Build Coastguard Worker }
230*1208bc7eSAndroid Build Coastguard Worker
231*1208bc7eSAndroid Build Coastguard Worker static void *
base_extent_bump_alloc(base_t * base,extent_t * extent,size_t size,size_t alignment)232*1208bc7eSAndroid Build Coastguard Worker base_extent_bump_alloc(base_t *base, extent_t *extent, size_t size,
233*1208bc7eSAndroid Build Coastguard Worker size_t alignment) {
234*1208bc7eSAndroid Build Coastguard Worker void *ret;
235*1208bc7eSAndroid Build Coastguard Worker size_t gap_size;
236*1208bc7eSAndroid Build Coastguard Worker
237*1208bc7eSAndroid Build Coastguard Worker ret = base_extent_bump_alloc_helper(extent, &gap_size, size, alignment);
238*1208bc7eSAndroid Build Coastguard Worker base_extent_bump_alloc_post(base, extent, gap_size, ret, size);
239*1208bc7eSAndroid Build Coastguard Worker return ret;
240*1208bc7eSAndroid Build Coastguard Worker }
241*1208bc7eSAndroid Build Coastguard Worker
242*1208bc7eSAndroid Build Coastguard Worker /*
243*1208bc7eSAndroid Build Coastguard Worker * Allocate a block of virtual memory that is large enough to start with a
244*1208bc7eSAndroid Build Coastguard Worker * base_block_t header, followed by an object of specified size and alignment.
245*1208bc7eSAndroid Build Coastguard Worker * On success a pointer to the initialized base_block_t header is returned.
246*1208bc7eSAndroid Build Coastguard Worker */
247*1208bc7eSAndroid Build Coastguard Worker static base_block_t *
base_block_alloc(tsdn_t * tsdn,base_t * base,extent_hooks_t * extent_hooks,unsigned ind,pszind_t * pind_last,size_t * extent_sn_next,size_t size,size_t alignment)248*1208bc7eSAndroid Build Coastguard Worker base_block_alloc(tsdn_t *tsdn, base_t *base, extent_hooks_t *extent_hooks,
249*1208bc7eSAndroid Build Coastguard Worker unsigned ind, pszind_t *pind_last, size_t *extent_sn_next, size_t size,
250*1208bc7eSAndroid Build Coastguard Worker size_t alignment) {
251*1208bc7eSAndroid Build Coastguard Worker alignment = ALIGNMENT_CEILING(alignment, QUANTUM);
252*1208bc7eSAndroid Build Coastguard Worker size_t usize = ALIGNMENT_CEILING(size, alignment);
253*1208bc7eSAndroid Build Coastguard Worker size_t header_size = sizeof(base_block_t);
254*1208bc7eSAndroid Build Coastguard Worker size_t gap_size = ALIGNMENT_CEILING(header_size, alignment) -
255*1208bc7eSAndroid Build Coastguard Worker header_size;
256*1208bc7eSAndroid Build Coastguard Worker /*
257*1208bc7eSAndroid Build Coastguard Worker * Create increasingly larger blocks in order to limit the total number
258*1208bc7eSAndroid Build Coastguard Worker * of disjoint virtual memory ranges. Choose the next size in the page
259*1208bc7eSAndroid Build Coastguard Worker * size class series (skipping size classes that are not a multiple of
260*1208bc7eSAndroid Build Coastguard Worker * HUGEPAGE), or a size large enough to satisfy the requested size and
261*1208bc7eSAndroid Build Coastguard Worker * alignment, whichever is larger.
262*1208bc7eSAndroid Build Coastguard Worker */
263*1208bc7eSAndroid Build Coastguard Worker size_t min_block_size = HUGEPAGE_CEILING(sz_psz2u(header_size + gap_size
264*1208bc7eSAndroid Build Coastguard Worker + usize));
265*1208bc7eSAndroid Build Coastguard Worker pszind_t pind_next = (*pind_last + 1 < NPSIZES) ? *pind_last + 1 :
266*1208bc7eSAndroid Build Coastguard Worker *pind_last;
267*1208bc7eSAndroid Build Coastguard Worker size_t next_block_size = HUGEPAGE_CEILING(sz_pind2sz(pind_next));
268*1208bc7eSAndroid Build Coastguard Worker size_t block_size = (min_block_size > next_block_size) ? min_block_size
269*1208bc7eSAndroid Build Coastguard Worker : next_block_size;
270*1208bc7eSAndroid Build Coastguard Worker base_block_t *block = (base_block_t *)base_map(tsdn, extent_hooks, ind,
271*1208bc7eSAndroid Build Coastguard Worker block_size);
272*1208bc7eSAndroid Build Coastguard Worker if (block == NULL) {
273*1208bc7eSAndroid Build Coastguard Worker return NULL;
274*1208bc7eSAndroid Build Coastguard Worker }
275*1208bc7eSAndroid Build Coastguard Worker
276*1208bc7eSAndroid Build Coastguard Worker if (metadata_thp_madvise()) {
277*1208bc7eSAndroid Build Coastguard Worker void *addr = (void *)block;
278*1208bc7eSAndroid Build Coastguard Worker assert(((uintptr_t)addr & HUGEPAGE_MASK) == 0 &&
279*1208bc7eSAndroid Build Coastguard Worker (block_size & HUGEPAGE_MASK) == 0);
280*1208bc7eSAndroid Build Coastguard Worker if (opt_metadata_thp == metadata_thp_always) {
281*1208bc7eSAndroid Build Coastguard Worker pages_huge(addr, block_size);
282*1208bc7eSAndroid Build Coastguard Worker } else if (opt_metadata_thp == metadata_thp_auto &&
283*1208bc7eSAndroid Build Coastguard Worker base != NULL) {
284*1208bc7eSAndroid Build Coastguard Worker /* base != NULL indicates this is not a new base. */
285*1208bc7eSAndroid Build Coastguard Worker malloc_mutex_lock(tsdn, &base->mtx);
286*1208bc7eSAndroid Build Coastguard Worker base_auto_thp_switch(tsdn, base);
287*1208bc7eSAndroid Build Coastguard Worker if (base->auto_thp_switched) {
288*1208bc7eSAndroid Build Coastguard Worker pages_huge(addr, block_size);
289*1208bc7eSAndroid Build Coastguard Worker }
290*1208bc7eSAndroid Build Coastguard Worker malloc_mutex_unlock(tsdn, &base->mtx);
291*1208bc7eSAndroid Build Coastguard Worker }
292*1208bc7eSAndroid Build Coastguard Worker }
293*1208bc7eSAndroid Build Coastguard Worker
294*1208bc7eSAndroid Build Coastguard Worker *pind_last = sz_psz2ind(block_size);
295*1208bc7eSAndroid Build Coastguard Worker block->size = block_size;
296*1208bc7eSAndroid Build Coastguard Worker block->next = NULL;
297*1208bc7eSAndroid Build Coastguard Worker assert(block_size >= header_size);
298*1208bc7eSAndroid Build Coastguard Worker base_extent_init(extent_sn_next, &block->extent,
299*1208bc7eSAndroid Build Coastguard Worker (void *)((uintptr_t)block + header_size), block_size - header_size);
300*1208bc7eSAndroid Build Coastguard Worker return block;
301*1208bc7eSAndroid Build Coastguard Worker }
302*1208bc7eSAndroid Build Coastguard Worker
303*1208bc7eSAndroid Build Coastguard Worker /*
304*1208bc7eSAndroid Build Coastguard Worker * Allocate an extent that is at least as large as specified size, with
305*1208bc7eSAndroid Build Coastguard Worker * specified alignment.
306*1208bc7eSAndroid Build Coastguard Worker */
307*1208bc7eSAndroid Build Coastguard Worker static extent_t *
base_extent_alloc(tsdn_t * tsdn,base_t * base,size_t size,size_t alignment)308*1208bc7eSAndroid Build Coastguard Worker base_extent_alloc(tsdn_t *tsdn, base_t *base, size_t size, size_t alignment) {
309*1208bc7eSAndroid Build Coastguard Worker malloc_mutex_assert_owner(tsdn, &base->mtx);
310*1208bc7eSAndroid Build Coastguard Worker
311*1208bc7eSAndroid Build Coastguard Worker extent_hooks_t *extent_hooks = base_extent_hooks_get(base);
312*1208bc7eSAndroid Build Coastguard Worker /*
313*1208bc7eSAndroid Build Coastguard Worker * Drop mutex during base_block_alloc(), because an extent hook will be
314*1208bc7eSAndroid Build Coastguard Worker * called.
315*1208bc7eSAndroid Build Coastguard Worker */
316*1208bc7eSAndroid Build Coastguard Worker malloc_mutex_unlock(tsdn, &base->mtx);
317*1208bc7eSAndroid Build Coastguard Worker base_block_t *block = base_block_alloc(tsdn, base, extent_hooks,
318*1208bc7eSAndroid Build Coastguard Worker base_ind_get(base), &base->pind_last, &base->extent_sn_next, size,
319*1208bc7eSAndroid Build Coastguard Worker alignment);
320*1208bc7eSAndroid Build Coastguard Worker malloc_mutex_lock(tsdn, &base->mtx);
321*1208bc7eSAndroid Build Coastguard Worker if (block == NULL) {
322*1208bc7eSAndroid Build Coastguard Worker return NULL;
323*1208bc7eSAndroid Build Coastguard Worker }
324*1208bc7eSAndroid Build Coastguard Worker block->next = base->blocks;
325*1208bc7eSAndroid Build Coastguard Worker base->blocks = block;
326*1208bc7eSAndroid Build Coastguard Worker if (config_stats) {
327*1208bc7eSAndroid Build Coastguard Worker base->allocated += sizeof(base_block_t);
328*1208bc7eSAndroid Build Coastguard Worker base->resident += PAGE_CEILING(sizeof(base_block_t));
329*1208bc7eSAndroid Build Coastguard Worker base->mapped += block->size;
330*1208bc7eSAndroid Build Coastguard Worker if (metadata_thp_madvise() &&
331*1208bc7eSAndroid Build Coastguard Worker !(opt_metadata_thp == metadata_thp_auto
332*1208bc7eSAndroid Build Coastguard Worker && !base->auto_thp_switched)) {
333*1208bc7eSAndroid Build Coastguard Worker assert(base->n_thp > 0);
334*1208bc7eSAndroid Build Coastguard Worker base->n_thp += HUGEPAGE_CEILING(sizeof(base_block_t)) >>
335*1208bc7eSAndroid Build Coastguard Worker LG_HUGEPAGE;
336*1208bc7eSAndroid Build Coastguard Worker }
337*1208bc7eSAndroid Build Coastguard Worker assert(base->allocated <= base->resident);
338*1208bc7eSAndroid Build Coastguard Worker assert(base->resident <= base->mapped);
339*1208bc7eSAndroid Build Coastguard Worker assert(base->n_thp << LG_HUGEPAGE <= base->mapped);
340*1208bc7eSAndroid Build Coastguard Worker }
341*1208bc7eSAndroid Build Coastguard Worker return &block->extent;
342*1208bc7eSAndroid Build Coastguard Worker }
343*1208bc7eSAndroid Build Coastguard Worker
344*1208bc7eSAndroid Build Coastguard Worker base_t *
b0get(void)345*1208bc7eSAndroid Build Coastguard Worker b0get(void) {
346*1208bc7eSAndroid Build Coastguard Worker return b0;
347*1208bc7eSAndroid Build Coastguard Worker }
348*1208bc7eSAndroid Build Coastguard Worker
349*1208bc7eSAndroid Build Coastguard Worker base_t *
base_new(tsdn_t * tsdn,unsigned ind,extent_hooks_t * extent_hooks)350*1208bc7eSAndroid Build Coastguard Worker base_new(tsdn_t *tsdn, unsigned ind, extent_hooks_t *extent_hooks) {
351*1208bc7eSAndroid Build Coastguard Worker pszind_t pind_last = 0;
352*1208bc7eSAndroid Build Coastguard Worker size_t extent_sn_next = 0;
353*1208bc7eSAndroid Build Coastguard Worker base_block_t *block = base_block_alloc(tsdn, NULL, extent_hooks, ind,
354*1208bc7eSAndroid Build Coastguard Worker &pind_last, &extent_sn_next, sizeof(base_t), QUANTUM);
355*1208bc7eSAndroid Build Coastguard Worker if (block == NULL) {
356*1208bc7eSAndroid Build Coastguard Worker return NULL;
357*1208bc7eSAndroid Build Coastguard Worker }
358*1208bc7eSAndroid Build Coastguard Worker
359*1208bc7eSAndroid Build Coastguard Worker size_t gap_size;
360*1208bc7eSAndroid Build Coastguard Worker size_t base_alignment = CACHELINE;
361*1208bc7eSAndroid Build Coastguard Worker size_t base_size = ALIGNMENT_CEILING(sizeof(base_t), base_alignment);
362*1208bc7eSAndroid Build Coastguard Worker base_t *base = (base_t *)base_extent_bump_alloc_helper(&block->extent,
363*1208bc7eSAndroid Build Coastguard Worker &gap_size, base_size, base_alignment);
364*1208bc7eSAndroid Build Coastguard Worker base->ind = ind;
365*1208bc7eSAndroid Build Coastguard Worker atomic_store_p(&base->extent_hooks, extent_hooks, ATOMIC_RELAXED);
366*1208bc7eSAndroid Build Coastguard Worker if (malloc_mutex_init(&base->mtx, "base", WITNESS_RANK_BASE,
367*1208bc7eSAndroid Build Coastguard Worker malloc_mutex_rank_exclusive)) {
368*1208bc7eSAndroid Build Coastguard Worker base_unmap(tsdn, extent_hooks, ind, block, block->size);
369*1208bc7eSAndroid Build Coastguard Worker return NULL;
370*1208bc7eSAndroid Build Coastguard Worker }
371*1208bc7eSAndroid Build Coastguard Worker base->pind_last = pind_last;
372*1208bc7eSAndroid Build Coastguard Worker base->extent_sn_next = extent_sn_next;
373*1208bc7eSAndroid Build Coastguard Worker base->blocks = block;
374*1208bc7eSAndroid Build Coastguard Worker base->auto_thp_switched = false;
375*1208bc7eSAndroid Build Coastguard Worker for (szind_t i = 0; i < NSIZES; i++) {
376*1208bc7eSAndroid Build Coastguard Worker extent_heap_new(&base->avail[i]);
377*1208bc7eSAndroid Build Coastguard Worker }
378*1208bc7eSAndroid Build Coastguard Worker if (config_stats) {
379*1208bc7eSAndroid Build Coastguard Worker base->allocated = sizeof(base_block_t);
380*1208bc7eSAndroid Build Coastguard Worker base->resident = PAGE_CEILING(sizeof(base_block_t));
381*1208bc7eSAndroid Build Coastguard Worker base->mapped = block->size;
382*1208bc7eSAndroid Build Coastguard Worker base->n_thp = (opt_metadata_thp == metadata_thp_always) &&
383*1208bc7eSAndroid Build Coastguard Worker metadata_thp_madvise() ? HUGEPAGE_CEILING(sizeof(base_block_t))
384*1208bc7eSAndroid Build Coastguard Worker >> LG_HUGEPAGE : 0;
385*1208bc7eSAndroid Build Coastguard Worker assert(base->allocated <= base->resident);
386*1208bc7eSAndroid Build Coastguard Worker assert(base->resident <= base->mapped);
387*1208bc7eSAndroid Build Coastguard Worker assert(base->n_thp << LG_HUGEPAGE <= base->mapped);
388*1208bc7eSAndroid Build Coastguard Worker }
389*1208bc7eSAndroid Build Coastguard Worker base_extent_bump_alloc_post(base, &block->extent, gap_size, base,
390*1208bc7eSAndroid Build Coastguard Worker base_size);
391*1208bc7eSAndroid Build Coastguard Worker
392*1208bc7eSAndroid Build Coastguard Worker return base;
393*1208bc7eSAndroid Build Coastguard Worker }
394*1208bc7eSAndroid Build Coastguard Worker
395*1208bc7eSAndroid Build Coastguard Worker void
base_delete(tsdn_t * tsdn,base_t * base)396*1208bc7eSAndroid Build Coastguard Worker base_delete(tsdn_t *tsdn, base_t *base) {
397*1208bc7eSAndroid Build Coastguard Worker extent_hooks_t *extent_hooks = base_extent_hooks_get(base);
398*1208bc7eSAndroid Build Coastguard Worker base_block_t *next = base->blocks;
399*1208bc7eSAndroid Build Coastguard Worker do {
400*1208bc7eSAndroid Build Coastguard Worker base_block_t *block = next;
401*1208bc7eSAndroid Build Coastguard Worker next = block->next;
402*1208bc7eSAndroid Build Coastguard Worker base_unmap(tsdn, extent_hooks, base_ind_get(base), block,
403*1208bc7eSAndroid Build Coastguard Worker block->size);
404*1208bc7eSAndroid Build Coastguard Worker } while (next != NULL);
405*1208bc7eSAndroid Build Coastguard Worker }
406*1208bc7eSAndroid Build Coastguard Worker
407*1208bc7eSAndroid Build Coastguard Worker extent_hooks_t *
base_extent_hooks_get(base_t * base)408*1208bc7eSAndroid Build Coastguard Worker base_extent_hooks_get(base_t *base) {
409*1208bc7eSAndroid Build Coastguard Worker return (extent_hooks_t *)atomic_load_p(&base->extent_hooks,
410*1208bc7eSAndroid Build Coastguard Worker ATOMIC_ACQUIRE);
411*1208bc7eSAndroid Build Coastguard Worker }
412*1208bc7eSAndroid Build Coastguard Worker
413*1208bc7eSAndroid Build Coastguard Worker extent_hooks_t *
base_extent_hooks_set(base_t * base,extent_hooks_t * extent_hooks)414*1208bc7eSAndroid Build Coastguard Worker base_extent_hooks_set(base_t *base, extent_hooks_t *extent_hooks) {
415*1208bc7eSAndroid Build Coastguard Worker extent_hooks_t *old_extent_hooks = base_extent_hooks_get(base);
416*1208bc7eSAndroid Build Coastguard Worker atomic_store_p(&base->extent_hooks, extent_hooks, ATOMIC_RELEASE);
417*1208bc7eSAndroid Build Coastguard Worker return old_extent_hooks;
418*1208bc7eSAndroid Build Coastguard Worker }
419*1208bc7eSAndroid Build Coastguard Worker
420*1208bc7eSAndroid Build Coastguard Worker static void *
base_alloc_impl(tsdn_t * tsdn,base_t * base,size_t size,size_t alignment,size_t * esn)421*1208bc7eSAndroid Build Coastguard Worker base_alloc_impl(tsdn_t *tsdn, base_t *base, size_t size, size_t alignment,
422*1208bc7eSAndroid Build Coastguard Worker size_t *esn) {
423*1208bc7eSAndroid Build Coastguard Worker alignment = QUANTUM_CEILING(alignment);
424*1208bc7eSAndroid Build Coastguard Worker size_t usize = ALIGNMENT_CEILING(size, alignment);
425*1208bc7eSAndroid Build Coastguard Worker size_t asize = usize + alignment - QUANTUM;
426*1208bc7eSAndroid Build Coastguard Worker
427*1208bc7eSAndroid Build Coastguard Worker extent_t *extent = NULL;
428*1208bc7eSAndroid Build Coastguard Worker malloc_mutex_lock(tsdn, &base->mtx);
429*1208bc7eSAndroid Build Coastguard Worker for (szind_t i = sz_size2index(asize); i < NSIZES; i++) {
430*1208bc7eSAndroid Build Coastguard Worker extent = extent_heap_remove_first(&base->avail[i]);
431*1208bc7eSAndroid Build Coastguard Worker if (extent != NULL) {
432*1208bc7eSAndroid Build Coastguard Worker /* Use existing space. */
433*1208bc7eSAndroid Build Coastguard Worker break;
434*1208bc7eSAndroid Build Coastguard Worker }
435*1208bc7eSAndroid Build Coastguard Worker }
436*1208bc7eSAndroid Build Coastguard Worker if (extent == NULL) {
437*1208bc7eSAndroid Build Coastguard Worker /* Try to allocate more space. */
438*1208bc7eSAndroid Build Coastguard Worker extent = base_extent_alloc(tsdn, base, usize, alignment);
439*1208bc7eSAndroid Build Coastguard Worker }
440*1208bc7eSAndroid Build Coastguard Worker void *ret;
441*1208bc7eSAndroid Build Coastguard Worker if (extent == NULL) {
442*1208bc7eSAndroid Build Coastguard Worker ret = NULL;
443*1208bc7eSAndroid Build Coastguard Worker goto label_return;
444*1208bc7eSAndroid Build Coastguard Worker }
445*1208bc7eSAndroid Build Coastguard Worker
446*1208bc7eSAndroid Build Coastguard Worker ret = base_extent_bump_alloc(base, extent, usize, alignment);
447*1208bc7eSAndroid Build Coastguard Worker if (esn != NULL) {
448*1208bc7eSAndroid Build Coastguard Worker *esn = extent_sn_get(extent);
449*1208bc7eSAndroid Build Coastguard Worker }
450*1208bc7eSAndroid Build Coastguard Worker label_return:
451*1208bc7eSAndroid Build Coastguard Worker malloc_mutex_unlock(tsdn, &base->mtx);
452*1208bc7eSAndroid Build Coastguard Worker return ret;
453*1208bc7eSAndroid Build Coastguard Worker }
454*1208bc7eSAndroid Build Coastguard Worker
455*1208bc7eSAndroid Build Coastguard Worker /*
456*1208bc7eSAndroid Build Coastguard Worker * base_alloc() returns zeroed memory, which is always demand-zeroed for the
457*1208bc7eSAndroid Build Coastguard Worker * auto arenas, in order to make multi-page sparse data structures such as radix
458*1208bc7eSAndroid Build Coastguard Worker * tree nodes efficient with respect to physical memory usage. Upon success a
459*1208bc7eSAndroid Build Coastguard Worker * pointer to at least size bytes with specified alignment is returned. Note
460*1208bc7eSAndroid Build Coastguard Worker * that size is rounded up to the nearest multiple of alignment to avoid false
461*1208bc7eSAndroid Build Coastguard Worker * sharing.
462*1208bc7eSAndroid Build Coastguard Worker */
463*1208bc7eSAndroid Build Coastguard Worker void *
base_alloc(tsdn_t * tsdn,base_t * base,size_t size,size_t alignment)464*1208bc7eSAndroid Build Coastguard Worker base_alloc(tsdn_t *tsdn, base_t *base, size_t size, size_t alignment) {
465*1208bc7eSAndroid Build Coastguard Worker return base_alloc_impl(tsdn, base, size, alignment, NULL);
466*1208bc7eSAndroid Build Coastguard Worker }
467*1208bc7eSAndroid Build Coastguard Worker
468*1208bc7eSAndroid Build Coastguard Worker extent_t *
base_alloc_extent(tsdn_t * tsdn,base_t * base)469*1208bc7eSAndroid Build Coastguard Worker base_alloc_extent(tsdn_t *tsdn, base_t *base) {
470*1208bc7eSAndroid Build Coastguard Worker size_t esn;
471*1208bc7eSAndroid Build Coastguard Worker extent_t *extent = base_alloc_impl(tsdn, base, sizeof(extent_t),
472*1208bc7eSAndroid Build Coastguard Worker CACHELINE, &esn);
473*1208bc7eSAndroid Build Coastguard Worker if (extent == NULL) {
474*1208bc7eSAndroid Build Coastguard Worker return NULL;
475*1208bc7eSAndroid Build Coastguard Worker }
476*1208bc7eSAndroid Build Coastguard Worker extent_esn_set(extent, esn);
477*1208bc7eSAndroid Build Coastguard Worker return extent;
478*1208bc7eSAndroid Build Coastguard Worker }
479*1208bc7eSAndroid Build Coastguard Worker
480*1208bc7eSAndroid Build Coastguard Worker void
base_stats_get(tsdn_t * tsdn,base_t * base,size_t * allocated,size_t * resident,size_t * mapped,size_t * n_thp)481*1208bc7eSAndroid Build Coastguard Worker base_stats_get(tsdn_t *tsdn, base_t *base, size_t *allocated, size_t *resident,
482*1208bc7eSAndroid Build Coastguard Worker size_t *mapped, size_t *n_thp) {
483*1208bc7eSAndroid Build Coastguard Worker cassert(config_stats);
484*1208bc7eSAndroid Build Coastguard Worker
485*1208bc7eSAndroid Build Coastguard Worker malloc_mutex_lock(tsdn, &base->mtx);
486*1208bc7eSAndroid Build Coastguard Worker assert(base->allocated <= base->resident);
487*1208bc7eSAndroid Build Coastguard Worker assert(base->resident <= base->mapped);
488*1208bc7eSAndroid Build Coastguard Worker *allocated = base->allocated;
489*1208bc7eSAndroid Build Coastguard Worker *resident = base->resident;
490*1208bc7eSAndroid Build Coastguard Worker *mapped = base->mapped;
491*1208bc7eSAndroid Build Coastguard Worker *n_thp = base->n_thp;
492*1208bc7eSAndroid Build Coastguard Worker malloc_mutex_unlock(tsdn, &base->mtx);
493*1208bc7eSAndroid Build Coastguard Worker }
494*1208bc7eSAndroid Build Coastguard Worker
495*1208bc7eSAndroid Build Coastguard Worker void
base_prefork(tsdn_t * tsdn,base_t * base)496*1208bc7eSAndroid Build Coastguard Worker base_prefork(tsdn_t *tsdn, base_t *base) {
497*1208bc7eSAndroid Build Coastguard Worker malloc_mutex_prefork(tsdn, &base->mtx);
498*1208bc7eSAndroid Build Coastguard Worker }
499*1208bc7eSAndroid Build Coastguard Worker
500*1208bc7eSAndroid Build Coastguard Worker void
base_postfork_parent(tsdn_t * tsdn,base_t * base)501*1208bc7eSAndroid Build Coastguard Worker base_postfork_parent(tsdn_t *tsdn, base_t *base) {
502*1208bc7eSAndroid Build Coastguard Worker malloc_mutex_postfork_parent(tsdn, &base->mtx);
503*1208bc7eSAndroid Build Coastguard Worker }
504*1208bc7eSAndroid Build Coastguard Worker
505*1208bc7eSAndroid Build Coastguard Worker void
base_postfork_child(tsdn_t * tsdn,base_t * base)506*1208bc7eSAndroid Build Coastguard Worker base_postfork_child(tsdn_t *tsdn, base_t *base) {
507*1208bc7eSAndroid Build Coastguard Worker malloc_mutex_postfork_child(tsdn, &base->mtx);
508*1208bc7eSAndroid Build Coastguard Worker }
509*1208bc7eSAndroid Build Coastguard Worker
510*1208bc7eSAndroid Build Coastguard Worker bool
base_boot(tsdn_t * tsdn)511*1208bc7eSAndroid Build Coastguard Worker base_boot(tsdn_t *tsdn) {
512*1208bc7eSAndroid Build Coastguard Worker b0 = base_new(tsdn, 0, (extent_hooks_t *)&extent_hooks_default);
513*1208bc7eSAndroid Build Coastguard Worker return (b0 == NULL);
514*1208bc7eSAndroid Build Coastguard Worker }
515