xref: /freebsd/contrib/jemalloc/src/arena.c (revision 8d20be1e22095c27faf8fe8b2f0d089739cc742e)
1 #define	JEMALLOC_ARENA_C_
2 #include "jemalloc/internal/jemalloc_internal.h"
3 
4 /******************************************************************************/
5 /* Data. */
6 
7 ssize_t		opt_lg_dirty_mult = LG_DIRTY_MULT_DEFAULT;
8 arena_bin_info_t	arena_bin_info[NBINS];
9 
10 JEMALLOC_ALIGNED(CACHELINE)
11 const uint8_t	small_size2bin[] = {
12 #define	S2B_8(i)	i,
13 #define	S2B_16(i)	S2B_8(i) S2B_8(i)
14 #define	S2B_32(i)	S2B_16(i) S2B_16(i)
15 #define	S2B_64(i)	S2B_32(i) S2B_32(i)
16 #define	S2B_128(i)	S2B_64(i) S2B_64(i)
17 #define	S2B_256(i)	S2B_128(i) S2B_128(i)
18 #define	S2B_512(i)	S2B_256(i) S2B_256(i)
19 #define	S2B_1024(i)	S2B_512(i) S2B_512(i)
20 #define	S2B_2048(i)	S2B_1024(i) S2B_1024(i)
21 #define	S2B_4096(i)	S2B_2048(i) S2B_2048(i)
22 #define	S2B_8192(i)	S2B_4096(i) S2B_4096(i)
23 #define	SIZE_CLASS(bin, delta, size)					\
24 	S2B_##delta(bin)
25 	SIZE_CLASSES
26 #undef S2B_8
27 #undef S2B_16
28 #undef S2B_32
29 #undef S2B_64
30 #undef S2B_128
31 #undef S2B_256
32 #undef S2B_512
33 #undef S2B_1024
34 #undef S2B_2048
35 #undef S2B_4096
36 #undef S2B_8192
37 #undef SIZE_CLASS
38 };
39 
40 /******************************************************************************/
41 /* Function prototypes for non-inline static functions. */
42 
43 static void	arena_avail_insert(arena_t *arena, arena_chunk_t *chunk,
44     size_t pageind, size_t npages, bool maybe_adjac_pred,
45     bool maybe_adjac_succ);
46 static void	arena_avail_remove(arena_t *arena, arena_chunk_t *chunk,
47     size_t pageind, size_t npages, bool maybe_adjac_pred,
48     bool maybe_adjac_succ);
49 static void	arena_run_split(arena_t *arena, arena_run_t *run, size_t size,
50     bool large, size_t binind, bool zero);
51 static arena_chunk_t *arena_chunk_alloc(arena_t *arena);
52 static void	arena_chunk_dealloc(arena_t *arena, arena_chunk_t *chunk);
53 static arena_run_t	*arena_run_alloc_helper(arena_t *arena, size_t size,
54     bool large, size_t binind, bool zero);
55 static arena_run_t *arena_run_alloc(arena_t *arena, size_t size, bool large,
56     size_t binind, bool zero);
57 static arena_chunk_t	*chunks_dirty_iter_cb(arena_chunk_tree_t *tree,
58     arena_chunk_t *chunk, void *arg);
59 static void	arena_purge(arena_t *arena, bool all);
60 static void	arena_run_dalloc(arena_t *arena, arena_run_t *run, bool dirty,
61     bool cleaned);
62 static void	arena_run_trim_head(arena_t *arena, arena_chunk_t *chunk,
63     arena_run_t *run, size_t oldsize, size_t newsize);
64 static void	arena_run_trim_tail(arena_t *arena, arena_chunk_t *chunk,
65     arena_run_t *run, size_t oldsize, size_t newsize, bool dirty);
66 static arena_run_t	*arena_bin_runs_first(arena_bin_t *bin);
67 static void	arena_bin_runs_insert(arena_bin_t *bin, arena_run_t *run);
68 static void	arena_bin_runs_remove(arena_bin_t *bin, arena_run_t *run);
69 static arena_run_t *arena_bin_nonfull_run_tryget(arena_bin_t *bin);
70 static arena_run_t *arena_bin_nonfull_run_get(arena_t *arena, arena_bin_t *bin);
71 static void	*arena_bin_malloc_hard(arena_t *arena, arena_bin_t *bin);
72 static void	arena_dissociate_bin_run(arena_chunk_t *chunk, arena_run_t *run,
73     arena_bin_t *bin);
74 static void	arena_dalloc_bin_run(arena_t *arena, arena_chunk_t *chunk,
75     arena_run_t *run, arena_bin_t *bin);
76 static void	arena_bin_lower_run(arena_t *arena, arena_chunk_t *chunk,
77     arena_run_t *run, arena_bin_t *bin);
78 static void	arena_ralloc_large_shrink(arena_t *arena, arena_chunk_t *chunk,
79     void *ptr, size_t oldsize, size_t size);
80 static bool	arena_ralloc_large_grow(arena_t *arena, arena_chunk_t *chunk,
81     void *ptr, size_t oldsize, size_t size, size_t extra, bool zero);
82 static bool	arena_ralloc_large(void *ptr, size_t oldsize, size_t size,
83     size_t extra, bool zero);
84 static size_t	bin_info_run_size_calc(arena_bin_info_t *bin_info,
85     size_t min_run_size);
86 static void	bin_info_init(void);
87 
88 /******************************************************************************/
89 
90 static inline int
91 arena_run_comp(arena_chunk_map_t *a, arena_chunk_map_t *b)
92 {
93 	uintptr_t a_mapelm = (uintptr_t)a;
94 	uintptr_t b_mapelm = (uintptr_t)b;
95 
96 	assert(a != NULL);
97 	assert(b != NULL);
98 
99 	return ((a_mapelm > b_mapelm) - (a_mapelm < b_mapelm));
100 }
101 
102 /* Generate red-black tree functions. */
103 rb_gen(static UNUSED, arena_run_tree_, arena_run_tree_t, arena_chunk_map_t,
104     u.rb_link, arena_run_comp)
105 
106 static inline int
107 arena_avail_comp(arena_chunk_map_t *a, arena_chunk_map_t *b)
108 {
109 	int ret;
110 	size_t a_size = a->bits & ~PAGE_MASK;
111 	size_t b_size = b->bits & ~PAGE_MASK;
112 
113 	ret = (a_size > b_size) - (a_size < b_size);
114 	if (ret == 0) {
115 		uintptr_t a_mapelm, b_mapelm;
116 
117 		if ((a->bits & CHUNK_MAP_KEY) != CHUNK_MAP_KEY)
118 			a_mapelm = (uintptr_t)a;
119 		else {
120 			/*
121 			 * Treat keys as though they are lower than anything
122 			 * else.
123 			 */
124 			a_mapelm = 0;
125 		}
126 		b_mapelm = (uintptr_t)b;
127 
128 		ret = (a_mapelm > b_mapelm) - (a_mapelm < b_mapelm);
129 	}
130 
131 	return (ret);
132 }
133 
134 /* Generate red-black tree functions. */
135 rb_gen(static UNUSED, arena_avail_tree_, arena_avail_tree_t, arena_chunk_map_t,
136     u.rb_link, arena_avail_comp)
137 
138 static inline int
139 arena_chunk_dirty_comp(arena_chunk_t *a, arena_chunk_t *b)
140 {
141 
142 	assert(a != NULL);
143 	assert(b != NULL);
144 
145 	/*
146 	 * Short-circuit for self comparison.  The following comparison code
147 	 * would come to the same result, but at the cost of executing the slow
148 	 * path.
149 	 */
150 	if (a == b)
151 		return (0);
152 
153 	/*
154 	 * Order such that chunks with higher fragmentation are "less than"
155 	 * those with lower fragmentation -- purging order is from "least" to
156 	 * "greatest".  Fragmentation is measured as:
157 	 *
158 	 *     mean current avail run size
159 	 *   --------------------------------
160 	 *   mean defragmented avail run size
161 	 *
162 	 *            navail
163 	 *         -----------
164 	 *         nruns_avail           nruns_avail-nruns_adjac
165 	 * = ========================= = -----------------------
166 	 *            navail                  nruns_avail
167 	 *    -----------------------
168 	 *    nruns_avail-nruns_adjac
169 	 *
170 	 * The following code multiplies away the denominator prior to
171 	 * comparison, in order to avoid division.
172 	 *
173 	 */
174 	{
175 		size_t a_val = (a->nruns_avail - a->nruns_adjac) *
176 		    b->nruns_avail;
177 		size_t b_val = (b->nruns_avail - b->nruns_adjac) *
178 		    a->nruns_avail;
179 
180 		if (a_val < b_val)
181 			return (1);
182 		if (a_val > b_val)
183 			return (-1);
184 	}
185 	/*
186 	 * Break ties by chunk address.  For fragmented chunks, report lower
187 	 * addresses as "lower", so that fragmentation reduction happens first
188 	 * at lower addresses.  However, use the opposite ordering for
189 	 * unfragmented chunks, in order to increase the chances of
190 	 * re-allocating dirty runs.
191 	 */
192 	{
193 		uintptr_t a_chunk = (uintptr_t)a;
194 		uintptr_t b_chunk = (uintptr_t)b;
195 		int ret = ((a_chunk > b_chunk) - (a_chunk < b_chunk));
196 		if (a->nruns_adjac == 0) {
197 			assert(b->nruns_adjac == 0);
198 			ret = -ret;
199 		}
200 		return (ret);
201 	}
202 }
203 
204 /* Generate red-black tree functions. */
205 rb_gen(static UNUSED, arena_chunk_dirty_, arena_chunk_tree_t, arena_chunk_t,
206     dirty_link, arena_chunk_dirty_comp)
207 
208 static inline bool
209 arena_avail_adjac_pred(arena_chunk_t *chunk, size_t pageind)
210 {
211 	bool ret;
212 
213 	if (pageind-1 < map_bias)
214 		ret = false;
215 	else {
216 		ret = (arena_mapbits_allocated_get(chunk, pageind-1) == 0);
217 		assert(ret == false || arena_mapbits_dirty_get(chunk,
218 		    pageind-1) != arena_mapbits_dirty_get(chunk, pageind));
219 	}
220 	return (ret);
221 }
222 
223 static inline bool
224 arena_avail_adjac_succ(arena_chunk_t *chunk, size_t pageind, size_t npages)
225 {
226 	bool ret;
227 
228 	if (pageind+npages == chunk_npages)
229 		ret = false;
230 	else {
231 		assert(pageind+npages < chunk_npages);
232 		ret = (arena_mapbits_allocated_get(chunk, pageind+npages) == 0);
233 		assert(ret == false || arena_mapbits_dirty_get(chunk, pageind)
234 		    != arena_mapbits_dirty_get(chunk, pageind+npages));
235 	}
236 	return (ret);
237 }
238 
239 static inline bool
240 arena_avail_adjac(arena_chunk_t *chunk, size_t pageind, size_t npages)
241 {
242 
243 	return (arena_avail_adjac_pred(chunk, pageind) ||
244 	    arena_avail_adjac_succ(chunk, pageind, npages));
245 }
246 
247 static void
248 arena_avail_insert(arena_t *arena, arena_chunk_t *chunk, size_t pageind,
249     size_t npages, bool maybe_adjac_pred, bool maybe_adjac_succ)
250 {
251 
252 	assert(npages == (arena_mapbits_unallocated_size_get(chunk, pageind) >>
253 	    LG_PAGE));
254 
255 	/*
256 	 * chunks_dirty is keyed by nruns_{avail,adjac}, so the chunk must be
257 	 * removed and reinserted even if the run to be inserted is clean.
258 	 */
259 	if (chunk->ndirty != 0)
260 		arena_chunk_dirty_remove(&arena->chunks_dirty, chunk);
261 
262 	if (maybe_adjac_pred && arena_avail_adjac_pred(chunk, pageind))
263 		chunk->nruns_adjac++;
264 	if (maybe_adjac_succ && arena_avail_adjac_succ(chunk, pageind, npages))
265 		chunk->nruns_adjac++;
266 	chunk->nruns_avail++;
267 	assert(chunk->nruns_avail > chunk->nruns_adjac);
268 
269 	if (arena_mapbits_dirty_get(chunk, pageind) != 0) {
270 		arena->ndirty += npages;
271 		chunk->ndirty += npages;
272 	}
273 	if (chunk->ndirty != 0)
274 		arena_chunk_dirty_insert(&arena->chunks_dirty, chunk);
275 
276 	arena_avail_tree_insert(&arena->runs_avail, arena_mapp_get(chunk,
277 	    pageind));
278 }
279 
280 static void
281 arena_avail_remove(arena_t *arena, arena_chunk_t *chunk, size_t pageind,
282     size_t npages, bool maybe_adjac_pred, bool maybe_adjac_succ)
283 {
284 
285 	assert(npages == (arena_mapbits_unallocated_size_get(chunk, pageind) >>
286 	    LG_PAGE));
287 
288 	/*
289 	 * chunks_dirty is keyed by nruns_{avail,adjac}, so the chunk must be
290 	 * removed and reinserted even if the run to be removed is clean.
291 	 */
292 	if (chunk->ndirty != 0)
293 		arena_chunk_dirty_remove(&arena->chunks_dirty, chunk);
294 
295 	if (maybe_adjac_pred && arena_avail_adjac_pred(chunk, pageind))
296 		chunk->nruns_adjac--;
297 	if (maybe_adjac_succ && arena_avail_adjac_succ(chunk, pageind, npages))
298 		chunk->nruns_adjac--;
299 	chunk->nruns_avail--;
300 	assert(chunk->nruns_avail > chunk->nruns_adjac || (chunk->nruns_avail
301 	    == 0 && chunk->nruns_adjac == 0));
302 
303 	if (arena_mapbits_dirty_get(chunk, pageind) != 0) {
304 		arena->ndirty -= npages;
305 		chunk->ndirty -= npages;
306 	}
307 	if (chunk->ndirty != 0)
308 		arena_chunk_dirty_insert(&arena->chunks_dirty, chunk);
309 
310 	arena_avail_tree_remove(&arena->runs_avail, arena_mapp_get(chunk,
311 	    pageind));
312 }
313 
314 static inline void *
315 arena_run_reg_alloc(arena_run_t *run, arena_bin_info_t *bin_info)
316 {
317 	void *ret;
318 	unsigned regind;
319 	bitmap_t *bitmap = (bitmap_t *)((uintptr_t)run +
320 	    (uintptr_t)bin_info->bitmap_offset);
321 
322 	assert(run->nfree > 0);
323 	assert(bitmap_full(bitmap, &bin_info->bitmap_info) == false);
324 
325 	regind = bitmap_sfu(bitmap, &bin_info->bitmap_info);
326 	ret = (void *)((uintptr_t)run + (uintptr_t)bin_info->reg0_offset +
327 	    (uintptr_t)(bin_info->reg_interval * regind));
328 	run->nfree--;
329 	if (regind == run->nextind)
330 		run->nextind++;
331 	assert(regind < run->nextind);
332 	return (ret);
333 }
334 
335 static inline void
336 arena_run_reg_dalloc(arena_run_t *run, void *ptr)
337 {
338 	arena_chunk_t *chunk = (arena_chunk_t *)CHUNK_ADDR2BASE(run);
339 	size_t pageind = ((uintptr_t)ptr - (uintptr_t)chunk) >> LG_PAGE;
340 	size_t mapbits = arena_mapbits_get(chunk, pageind);
341 	size_t binind = arena_ptr_small_binind_get(ptr, mapbits);
342 	arena_bin_info_t *bin_info = &arena_bin_info[binind];
343 	unsigned regind = arena_run_regind(run, bin_info, ptr);
344 	bitmap_t *bitmap = (bitmap_t *)((uintptr_t)run +
345 	    (uintptr_t)bin_info->bitmap_offset);
346 
347 	assert(run->nfree < bin_info->nregs);
348 	/* Freeing an interior pointer can cause assertion failure. */
349 	assert(((uintptr_t)ptr - ((uintptr_t)run +
350 	    (uintptr_t)bin_info->reg0_offset)) %
351 	    (uintptr_t)bin_info->reg_interval == 0);
352 	assert((uintptr_t)ptr >= (uintptr_t)run +
353 	    (uintptr_t)bin_info->reg0_offset);
354 	/* Freeing an unallocated pointer can cause assertion failure. */
355 	assert(bitmap_get(bitmap, &bin_info->bitmap_info, regind));
356 
357 	bitmap_unset(bitmap, &bin_info->bitmap_info, regind);
358 	run->nfree++;
359 }
360 
361 static inline void
362 arena_run_zero(arena_chunk_t *chunk, size_t run_ind, size_t npages)
363 {
364 
365 	VALGRIND_MAKE_MEM_UNDEFINED((void *)((uintptr_t)chunk + (run_ind <<
366 	    LG_PAGE)), (npages << LG_PAGE));
367 	memset((void *)((uintptr_t)chunk + (run_ind << LG_PAGE)), 0,
368 	    (npages << LG_PAGE));
369 }
370 
371 static inline void
372 arena_run_page_mark_zeroed(arena_chunk_t *chunk, size_t run_ind)
373 {
374 
375 	VALGRIND_MAKE_MEM_DEFINED((void *)((uintptr_t)chunk + (run_ind <<
376 	    LG_PAGE)), PAGE);
377 }
378 
379 static inline void
380 arena_run_page_validate_zeroed(arena_chunk_t *chunk, size_t run_ind)
381 {
382 	size_t i;
383 	UNUSED size_t *p = (size_t *)((uintptr_t)chunk + (run_ind << LG_PAGE));
384 
385 	arena_run_page_mark_zeroed(chunk, run_ind);
386 	for (i = 0; i < PAGE / sizeof(size_t); i++)
387 		assert(p[i] == 0);
388 }
389 
390 static void
391 arena_run_split(arena_t *arena, arena_run_t *run, size_t size, bool large,
392     size_t binind, bool zero)
393 {
394 	arena_chunk_t *chunk;
395 	size_t run_ind, total_pages, need_pages, rem_pages, i;
396 	size_t flag_dirty;
397 
398 	assert((large && binind == BININD_INVALID) || (large == false && binind
399 	    != BININD_INVALID));
400 
401 	chunk = (arena_chunk_t *)CHUNK_ADDR2BASE(run);
402 	run_ind = (unsigned)(((uintptr_t)run - (uintptr_t)chunk) >> LG_PAGE);
403 	flag_dirty = arena_mapbits_dirty_get(chunk, run_ind);
404 	total_pages = arena_mapbits_unallocated_size_get(chunk, run_ind) >>
405 	    LG_PAGE;
406 	assert(arena_mapbits_dirty_get(chunk, run_ind+total_pages-1) ==
407 	    flag_dirty);
408 	need_pages = (size >> LG_PAGE);
409 	assert(need_pages > 0);
410 	assert(need_pages <= total_pages);
411 	rem_pages = total_pages - need_pages;
412 
413 	arena_avail_remove(arena, chunk, run_ind, total_pages, true, true);
414 	if (config_stats) {
415 		/*
416 		 * Update stats_cactive if nactive is crossing a chunk
417 		 * multiple.
418 		 */
419 		size_t cactive_diff = CHUNK_CEILING((arena->nactive +
420 		    need_pages) << LG_PAGE) - CHUNK_CEILING(arena->nactive <<
421 		    LG_PAGE);
422 		if (cactive_diff != 0)
423 			stats_cactive_add(cactive_diff);
424 	}
425 	arena->nactive += need_pages;
426 
427 	/* Keep track of trailing unused pages for later use. */
428 	if (rem_pages > 0) {
429 		if (flag_dirty != 0) {
430 			arena_mapbits_unallocated_set(chunk, run_ind+need_pages,
431 			    (rem_pages << LG_PAGE), CHUNK_MAP_DIRTY);
432 			arena_mapbits_unallocated_set(chunk,
433 			    run_ind+total_pages-1, (rem_pages << LG_PAGE),
434 			    CHUNK_MAP_DIRTY);
435 		} else {
436 			arena_mapbits_unallocated_set(chunk, run_ind+need_pages,
437 			    (rem_pages << LG_PAGE),
438 			    arena_mapbits_unzeroed_get(chunk,
439 			    run_ind+need_pages));
440 			arena_mapbits_unallocated_set(chunk,
441 			    run_ind+total_pages-1, (rem_pages << LG_PAGE),
442 			    arena_mapbits_unzeroed_get(chunk,
443 			    run_ind+total_pages-1));
444 		}
445 		arena_avail_insert(arena, chunk, run_ind+need_pages, rem_pages,
446 		    false, true);
447 	}
448 
449 	/*
450 	 * Update the page map separately for large vs. small runs, since it is
451 	 * possible to avoid iteration for large mallocs.
452 	 */
453 	if (large) {
454 		if (zero) {
455 			if (flag_dirty == 0) {
456 				/*
457 				 * The run is clean, so some pages may be
458 				 * zeroed (i.e. never before touched).
459 				 */
460 				for (i = 0; i < need_pages; i++) {
461 					if (arena_mapbits_unzeroed_get(chunk,
462 					    run_ind+i) != 0) {
463 						arena_run_zero(chunk, run_ind+i,
464 						    1);
465 					} else if (config_debug) {
466 						arena_run_page_validate_zeroed(
467 						    chunk, run_ind+i);
468 					} else {
469 						arena_run_page_mark_zeroed(
470 						    chunk, run_ind+i);
471 					}
472 				}
473 			} else {
474 				/*
475 				 * The run is dirty, so all pages must be
476 				 * zeroed.
477 				 */
478 				arena_run_zero(chunk, run_ind, need_pages);
479 			}
480 		} else {
481 			VALGRIND_MAKE_MEM_UNDEFINED((void *)((uintptr_t)chunk +
482 			    (run_ind << LG_PAGE)), (need_pages << LG_PAGE));
483 		}
484 
485 		/*
486 		 * Set the last element first, in case the run only contains one
487 		 * page (i.e. both statements set the same element).
488 		 */
489 		arena_mapbits_large_set(chunk, run_ind+need_pages-1, 0,
490 		    flag_dirty);
491 		arena_mapbits_large_set(chunk, run_ind, size, flag_dirty);
492 	} else {
493 		assert(zero == false);
494 		/*
495 		 * Propagate the dirty and unzeroed flags to the allocated
496 		 * small run, so that arena_dalloc_bin_run() has the ability to
497 		 * conditionally trim clean pages.
498 		 */
499 		arena_mapbits_small_set(chunk, run_ind, 0, binind, flag_dirty);
500 		/*
501 		 * The first page will always be dirtied during small run
502 		 * initialization, so a validation failure here would not
503 		 * actually cause an observable failure.
504 		 */
505 		if (config_debug && flag_dirty == 0 &&
506 		    arena_mapbits_unzeroed_get(chunk, run_ind) == 0)
507 			arena_run_page_validate_zeroed(chunk, run_ind);
508 		for (i = 1; i < need_pages - 1; i++) {
509 			arena_mapbits_small_set(chunk, run_ind+i, i, binind, 0);
510 			if (config_debug && flag_dirty == 0 &&
511 			    arena_mapbits_unzeroed_get(chunk, run_ind+i) == 0) {
512 				arena_run_page_validate_zeroed(chunk,
513 				    run_ind+i);
514 			}
515 		}
516 		arena_mapbits_small_set(chunk, run_ind+need_pages-1,
517 		    need_pages-1, binind, flag_dirty);
518 		if (config_debug && flag_dirty == 0 &&
519 		    arena_mapbits_unzeroed_get(chunk, run_ind+need_pages-1) ==
520 		    0) {
521 			arena_run_page_validate_zeroed(chunk,
522 			    run_ind+need_pages-1);
523 		}
524 		VALGRIND_MAKE_MEM_UNDEFINED((void *)((uintptr_t)chunk +
525 		    (run_ind << LG_PAGE)), (need_pages << LG_PAGE));
526 	}
527 }
528 
529 static arena_chunk_t *
530 arena_chunk_alloc(arena_t *arena)
531 {
532 	arena_chunk_t *chunk;
533 	size_t i;
534 
535 	if (arena->spare != NULL) {
536 		chunk = arena->spare;
537 		arena->spare = NULL;
538 
539 		assert(arena_mapbits_allocated_get(chunk, map_bias) == 0);
540 		assert(arena_mapbits_allocated_get(chunk, chunk_npages-1) == 0);
541 		assert(arena_mapbits_unallocated_size_get(chunk, map_bias) ==
542 		    arena_maxclass);
543 		assert(arena_mapbits_unallocated_size_get(chunk,
544 		    chunk_npages-1) == arena_maxclass);
545 		assert(arena_mapbits_dirty_get(chunk, map_bias) ==
546 		    arena_mapbits_dirty_get(chunk, chunk_npages-1));
547 	} else {
548 		bool zero;
549 		size_t unzeroed;
550 
551 		zero = false;
552 		malloc_mutex_unlock(&arena->lock);
553 		chunk = (arena_chunk_t *)chunk_alloc(chunksize, chunksize,
554 		    false, &zero, arena->dss_prec);
555 		malloc_mutex_lock(&arena->lock);
556 		if (chunk == NULL)
557 			return (NULL);
558 		if (config_stats)
559 			arena->stats.mapped += chunksize;
560 
561 		chunk->arena = arena;
562 
563 		/*
564 		 * Claim that no pages are in use, since the header is merely
565 		 * overhead.
566 		 */
567 		chunk->ndirty = 0;
568 
569 		chunk->nruns_avail = 0;
570 		chunk->nruns_adjac = 0;
571 
572 		/*
573 		 * Initialize the map to contain one maximal free untouched run.
574 		 * Mark the pages as zeroed iff chunk_alloc() returned a zeroed
575 		 * chunk.
576 		 */
577 		unzeroed = zero ? 0 : CHUNK_MAP_UNZEROED;
578 		arena_mapbits_unallocated_set(chunk, map_bias, arena_maxclass,
579 		    unzeroed);
580 		/*
581 		 * There is no need to initialize the internal page map entries
582 		 * unless the chunk is not zeroed.
583 		 */
584 		if (zero == false) {
585 			VALGRIND_MAKE_MEM_UNDEFINED(
586 			    (void *)arena_mapp_get(chunk, map_bias+1),
587 			    (size_t)((uintptr_t) arena_mapp_get(chunk,
588 			    chunk_npages-1) - (uintptr_t)arena_mapp_get(chunk,
589 			    map_bias+1)));
590 			for (i = map_bias+1; i < chunk_npages-1; i++)
591 				arena_mapbits_unzeroed_set(chunk, i, unzeroed);
592 		} else {
593 			VALGRIND_MAKE_MEM_DEFINED(
594 			    (void *)arena_mapp_get(chunk, map_bias+1),
595 			    (size_t)((uintptr_t) arena_mapp_get(chunk,
596 			    chunk_npages-1) - (uintptr_t)arena_mapp_get(chunk,
597 			    map_bias+1)));
598 			if (config_debug) {
599 				for (i = map_bias+1; i < chunk_npages-1; i++) {
600 					assert(arena_mapbits_unzeroed_get(chunk,
601 					    i) == unzeroed);
602 				}
603 			}
604 		}
605 		arena_mapbits_unallocated_set(chunk, chunk_npages-1,
606 		    arena_maxclass, unzeroed);
607 	}
608 
609 	/* Insert the run into the runs_avail tree. */
610 	arena_avail_insert(arena, chunk, map_bias, chunk_npages-map_bias,
611 	    false, false);
612 
613 	return (chunk);
614 }
615 
616 static void
617 arena_chunk_dealloc(arena_t *arena, arena_chunk_t *chunk)
618 {
619 	assert(arena_mapbits_allocated_get(chunk, map_bias) == 0);
620 	assert(arena_mapbits_allocated_get(chunk, chunk_npages-1) == 0);
621 	assert(arena_mapbits_unallocated_size_get(chunk, map_bias) ==
622 	    arena_maxclass);
623 	assert(arena_mapbits_unallocated_size_get(chunk, chunk_npages-1) ==
624 	    arena_maxclass);
625 	assert(arena_mapbits_dirty_get(chunk, map_bias) ==
626 	    arena_mapbits_dirty_get(chunk, chunk_npages-1));
627 
628 	/*
629 	 * Remove run from the runs_avail tree, so that the arena does not use
630 	 * it.
631 	 */
632 	arena_avail_remove(arena, chunk, map_bias, chunk_npages-map_bias,
633 	    false, false);
634 
635 	if (arena->spare != NULL) {
636 		arena_chunk_t *spare = arena->spare;
637 
638 		arena->spare = chunk;
639 		malloc_mutex_unlock(&arena->lock);
640 		chunk_dealloc((void *)spare, chunksize, true);
641 		malloc_mutex_lock(&arena->lock);
642 		if (config_stats)
643 			arena->stats.mapped -= chunksize;
644 	} else
645 		arena->spare = chunk;
646 }
647 
648 static arena_run_t *
649 arena_run_alloc_helper(arena_t *arena, size_t size, bool large, size_t binind,
650     bool zero)
651 {
652 	arena_run_t *run;
653 	arena_chunk_map_t *mapelm, key;
654 
655 	key.bits = size | CHUNK_MAP_KEY;
656 	mapelm = arena_avail_tree_nsearch(&arena->runs_avail, &key);
657 	if (mapelm != NULL) {
658 		arena_chunk_t *run_chunk = CHUNK_ADDR2BASE(mapelm);
659 		size_t pageind = (((uintptr_t)mapelm -
660 		    (uintptr_t)run_chunk->map) / sizeof(arena_chunk_map_t))
661 		    + map_bias;
662 
663 		run = (arena_run_t *)((uintptr_t)run_chunk + (pageind <<
664 		    LG_PAGE));
665 		arena_run_split(arena, run, size, large, binind, zero);
666 		return (run);
667 	}
668 
669 	return (NULL);
670 }
671 
672 static arena_run_t *
673 arena_run_alloc(arena_t *arena, size_t size, bool large, size_t binind,
674     bool zero)
675 {
676 	arena_chunk_t *chunk;
677 	arena_run_t *run;
678 
679 	assert(size <= arena_maxclass);
680 	assert((size & PAGE_MASK) == 0);
681 	assert((large && binind == BININD_INVALID) || (large == false && binind
682 	    != BININD_INVALID));
683 
684 	/* Search the arena's chunks for the lowest best fit. */
685 	run = arena_run_alloc_helper(arena, size, large, binind, zero);
686 	if (run != NULL)
687 		return (run);
688 
689 	/*
690 	 * No usable runs.  Create a new chunk from which to allocate the run.
691 	 */
692 	chunk = arena_chunk_alloc(arena);
693 	if (chunk != NULL) {
694 		run = (arena_run_t *)((uintptr_t)chunk + (map_bias << LG_PAGE));
695 		arena_run_split(arena, run, size, large, binind, zero);
696 		return (run);
697 	}
698 
699 	/*
700 	 * arena_chunk_alloc() failed, but another thread may have made
701 	 * sufficient memory available while this one dropped arena->lock in
702 	 * arena_chunk_alloc(), so search one more time.
703 	 */
704 	return (arena_run_alloc_helper(arena, size, large, binind, zero));
705 }
706 
707 static inline void
708 arena_maybe_purge(arena_t *arena)
709 {
710 	size_t npurgeable, threshold;
711 
712 	/* Don't purge if the option is disabled. */
713 	if (opt_lg_dirty_mult < 0)
714 		return;
715 	/* Don't purge if all dirty pages are already being purged. */
716 	if (arena->ndirty <= arena->npurgatory)
717 		return;
718 	npurgeable = arena->ndirty - arena->npurgatory;
719 	threshold = (arena->nactive >> opt_lg_dirty_mult);
720 	/*
721 	 * Don't purge unless the number of purgeable pages exceeds the
722 	 * threshold.
723 	 */
724 	if (npurgeable <= threshold)
725 		return;
726 
727 	arena_purge(arena, false);
728 }
729 
730 static inline size_t
731 arena_chunk_purge(arena_t *arena, arena_chunk_t *chunk, bool all)
732 {
733 	size_t npurged;
734 	ql_head(arena_chunk_map_t) mapelms;
735 	arena_chunk_map_t *mapelm;
736 	size_t pageind, npages;
737 	size_t nmadvise;
738 
739 	ql_new(&mapelms);
740 
741 	/*
742 	 * If chunk is the spare, temporarily re-allocate it, 1) so that its
743 	 * run is reinserted into runs_avail, and 2) so that it cannot be
744 	 * completely discarded by another thread while arena->lock is dropped
745 	 * by this thread.  Note that the arena_run_dalloc() call will
746 	 * implicitly deallocate the chunk, so no explicit action is required
747 	 * in this function to deallocate the chunk.
748 	 *
749 	 * Note that once a chunk contains dirty pages, it cannot again contain
750 	 * a single run unless 1) it is a dirty run, or 2) this function purges
751 	 * dirty pages and causes the transition to a single clean run.  Thus
752 	 * (chunk == arena->spare) is possible, but it is not possible for
753 	 * this function to be called on the spare unless it contains a dirty
754 	 * run.
755 	 */
756 	if (chunk == arena->spare) {
757 		assert(arena_mapbits_dirty_get(chunk, map_bias) != 0);
758 		assert(arena_mapbits_dirty_get(chunk, chunk_npages-1) != 0);
759 
760 		arena_chunk_alloc(arena);
761 	}
762 
763 	if (config_stats)
764 		arena->stats.purged += chunk->ndirty;
765 
766 	/*
767 	 * Operate on all dirty runs if there is no clean/dirty run
768 	 * fragmentation.
769 	 */
770 	if (chunk->nruns_adjac == 0)
771 		all = true;
772 
773 	/*
774 	 * Temporarily allocate free dirty runs within chunk.  If all is false,
775 	 * only operate on dirty runs that are fragments; otherwise operate on
776 	 * all dirty runs.
777 	 */
778 	for (pageind = map_bias; pageind < chunk_npages; pageind += npages) {
779 		mapelm = arena_mapp_get(chunk, pageind);
780 		if (arena_mapbits_allocated_get(chunk, pageind) == 0) {
781 			size_t run_size =
782 			    arena_mapbits_unallocated_size_get(chunk, pageind);
783 
784 			npages = run_size >> LG_PAGE;
785 			assert(pageind + npages <= chunk_npages);
786 			assert(arena_mapbits_dirty_get(chunk, pageind) ==
787 			    arena_mapbits_dirty_get(chunk, pageind+npages-1));
788 
789 			if (arena_mapbits_dirty_get(chunk, pageind) != 0 &&
790 			    (all || arena_avail_adjac(chunk, pageind,
791 			    npages))) {
792 				arena_run_t *run = (arena_run_t *)((uintptr_t)
793 				    chunk + (uintptr_t)(pageind << LG_PAGE));
794 
795 				arena_run_split(arena, run, run_size, true,
796 				    BININD_INVALID, false);
797 				/* Append to list for later processing. */
798 				ql_elm_new(mapelm, u.ql_link);
799 				ql_tail_insert(&mapelms, mapelm, u.ql_link);
800 			}
801 		} else {
802 			/* Skip run. */
803 			if (arena_mapbits_large_get(chunk, pageind) != 0) {
804 				npages = arena_mapbits_large_size_get(chunk,
805 				    pageind) >> LG_PAGE;
806 			} else {
807 				size_t binind;
808 				arena_bin_info_t *bin_info;
809 				arena_run_t *run = (arena_run_t *)((uintptr_t)
810 				    chunk + (uintptr_t)(pageind << LG_PAGE));
811 
812 				assert(arena_mapbits_small_runind_get(chunk,
813 				    pageind) == 0);
814 				binind = arena_bin_index(arena, run->bin);
815 				bin_info = &arena_bin_info[binind];
816 				npages = bin_info->run_size >> LG_PAGE;
817 			}
818 		}
819 	}
820 	assert(pageind == chunk_npages);
821 	assert(chunk->ndirty == 0 || all == false);
822 	assert(chunk->nruns_adjac == 0);
823 
824 	malloc_mutex_unlock(&arena->lock);
825 	if (config_stats)
826 		nmadvise = 0;
827 	npurged = 0;
828 	ql_foreach(mapelm, &mapelms, u.ql_link) {
829 		bool unzeroed;
830 		size_t flag_unzeroed, i;
831 
832 		pageind = (((uintptr_t)mapelm - (uintptr_t)chunk->map) /
833 		    sizeof(arena_chunk_map_t)) + map_bias;
834 		npages = arena_mapbits_large_size_get(chunk, pageind) >>
835 		    LG_PAGE;
836 		assert(pageind + npages <= chunk_npages);
837 		unzeroed = pages_purge((void *)((uintptr_t)chunk + (pageind <<
838 		    LG_PAGE)), (npages << LG_PAGE));
839 		flag_unzeroed = unzeroed ? CHUNK_MAP_UNZEROED : 0;
840 		/*
841 		 * Set the unzeroed flag for all pages, now that pages_purge()
842 		 * has returned whether the pages were zeroed as a side effect
843 		 * of purging.  This chunk map modification is safe even though
844 		 * the arena mutex isn't currently owned by this thread,
845 		 * because the run is marked as allocated, thus protecting it
846 		 * from being modified by any other thread.  As long as these
847 		 * writes don't perturb the first and last elements'
848 		 * CHUNK_MAP_ALLOCATED bits, behavior is well defined.
849 		 */
850 		for (i = 0; i < npages; i++) {
851 			arena_mapbits_unzeroed_set(chunk, pageind+i,
852 			    flag_unzeroed);
853 		}
854 		npurged += npages;
855 		if (config_stats)
856 			nmadvise++;
857 	}
858 	malloc_mutex_lock(&arena->lock);
859 	if (config_stats)
860 		arena->stats.nmadvise += nmadvise;
861 
862 	/* Deallocate runs. */
863 	for (mapelm = ql_first(&mapelms); mapelm != NULL;
864 	    mapelm = ql_first(&mapelms)) {
865 		arena_run_t *run;
866 
867 		pageind = (((uintptr_t)mapelm - (uintptr_t)chunk->map) /
868 		    sizeof(arena_chunk_map_t)) + map_bias;
869 		run = (arena_run_t *)((uintptr_t)chunk + (uintptr_t)(pageind <<
870 		    LG_PAGE));
871 		ql_remove(&mapelms, mapelm, u.ql_link);
872 		arena_run_dalloc(arena, run, false, true);
873 	}
874 
875 	return (npurged);
876 }
877 
878 static arena_chunk_t *
879 chunks_dirty_iter_cb(arena_chunk_tree_t *tree, arena_chunk_t *chunk, void *arg)
880 {
881        size_t *ndirty = (size_t *)arg;
882 
883        assert(chunk->ndirty != 0);
884        *ndirty += chunk->ndirty;
885        return (NULL);
886 }
887 
888 static void
889 arena_purge(arena_t *arena, bool all)
890 {
891 	arena_chunk_t *chunk;
892 	size_t npurgatory;
893 	if (config_debug) {
894 		size_t ndirty = 0;
895 
896 		arena_chunk_dirty_iter(&arena->chunks_dirty, NULL,
897 		    chunks_dirty_iter_cb, (void *)&ndirty);
898 		assert(ndirty == arena->ndirty);
899 	}
900 	assert(arena->ndirty > arena->npurgatory || all);
901 	assert((arena->nactive >> opt_lg_dirty_mult) < (arena->ndirty -
902 	    arena->npurgatory) || all);
903 
904 	if (config_stats)
905 		arena->stats.npurge++;
906 
907 	/*
908 	 * Compute the minimum number of pages that this thread should try to
909 	 * purge, and add the result to arena->npurgatory.  This will keep
910 	 * multiple threads from racing to reduce ndirty below the threshold.
911 	 */
912 	{
913 		size_t npurgeable = arena->ndirty - arena->npurgatory;
914 
915 		if (all == false) {
916 			size_t threshold = (arena->nactive >>
917 			    opt_lg_dirty_mult);
918 
919 			npurgatory = npurgeable - threshold;
920 		} else
921 			npurgatory = npurgeable;
922 	}
923 	arena->npurgatory += npurgatory;
924 
925 	while (npurgatory > 0) {
926 		size_t npurgeable, npurged, nunpurged;
927 
928 		/* Get next chunk with dirty pages. */
929 		chunk = arena_chunk_dirty_first(&arena->chunks_dirty);
930 		if (chunk == NULL) {
931 			/*
932 			 * This thread was unable to purge as many pages as
933 			 * originally intended, due to races with other threads
934 			 * that either did some of the purging work, or re-used
935 			 * dirty pages.
936 			 */
937 			arena->npurgatory -= npurgatory;
938 			return;
939 		}
940 		npurgeable = chunk->ndirty;
941 		assert(npurgeable != 0);
942 
943 		if (npurgeable > npurgatory && chunk->nruns_adjac == 0) {
944 			/*
945 			 * This thread will purge all the dirty pages in chunk,
946 			 * so set npurgatory to reflect this thread's intent to
947 			 * purge the pages.  This tends to reduce the chances
948 			 * of the following scenario:
949 			 *
950 			 * 1) This thread sets arena->npurgatory such that
951 			 *    (arena->ndirty - arena->npurgatory) is at the
952 			 *    threshold.
953 			 * 2) This thread drops arena->lock.
954 			 * 3) Another thread causes one or more pages to be
955 			 *    dirtied, and immediately determines that it must
956 			 *    purge dirty pages.
957 			 *
958 			 * If this scenario *does* play out, that's okay,
959 			 * because all of the purging work being done really
960 			 * needs to happen.
961 			 */
962 			arena->npurgatory += npurgeable - npurgatory;
963 			npurgatory = npurgeable;
964 		}
965 
966 		/*
967 		 * Keep track of how many pages are purgeable, versus how many
968 		 * actually get purged, and adjust counters accordingly.
969 		 */
970 		arena->npurgatory -= npurgeable;
971 		npurgatory -= npurgeable;
972 		npurged = arena_chunk_purge(arena, chunk, all);
973 		nunpurged = npurgeable - npurged;
974 		arena->npurgatory += nunpurged;
975 		npurgatory += nunpurged;
976 	}
977 }
978 
979 void
980 arena_purge_all(arena_t *arena)
981 {
982 
983 	malloc_mutex_lock(&arena->lock);
984 	arena_purge(arena, true);
985 	malloc_mutex_unlock(&arena->lock);
986 }
987 
988 static void
989 arena_run_dalloc(arena_t *arena, arena_run_t *run, bool dirty, bool cleaned)
990 {
991 	arena_chunk_t *chunk;
992 	size_t size, run_ind, run_pages, flag_dirty;
993 
994 	chunk = (arena_chunk_t *)CHUNK_ADDR2BASE(run);
995 	run_ind = (size_t)(((uintptr_t)run - (uintptr_t)chunk) >> LG_PAGE);
996 	assert(run_ind >= map_bias);
997 	assert(run_ind < chunk_npages);
998 	if (arena_mapbits_large_get(chunk, run_ind) != 0) {
999 		size = arena_mapbits_large_size_get(chunk, run_ind);
1000 		assert(size == PAGE ||
1001 		    arena_mapbits_large_size_get(chunk,
1002 		    run_ind+(size>>LG_PAGE)-1) == 0);
1003 	} else {
1004 		size_t binind = arena_bin_index(arena, run->bin);
1005 		arena_bin_info_t *bin_info = &arena_bin_info[binind];
1006 		size = bin_info->run_size;
1007 	}
1008 	run_pages = (size >> LG_PAGE);
1009 	if (config_stats) {
1010 		/*
1011 		 * Update stats_cactive if nactive is crossing a chunk
1012 		 * multiple.
1013 		 */
1014 		size_t cactive_diff = CHUNK_CEILING(arena->nactive << LG_PAGE) -
1015 		    CHUNK_CEILING((arena->nactive - run_pages) << LG_PAGE);
1016 		if (cactive_diff != 0)
1017 			stats_cactive_sub(cactive_diff);
1018 	}
1019 	arena->nactive -= run_pages;
1020 
1021 	/*
1022 	 * The run is dirty if the caller claims to have dirtied it, as well as
1023 	 * if it was already dirty before being allocated and the caller
1024 	 * doesn't claim to have cleaned it.
1025 	 */
1026 	assert(arena_mapbits_dirty_get(chunk, run_ind) ==
1027 	    arena_mapbits_dirty_get(chunk, run_ind+run_pages-1));
1028 	if (cleaned == false && arena_mapbits_dirty_get(chunk, run_ind) != 0)
1029 		dirty = true;
1030 	flag_dirty = dirty ? CHUNK_MAP_DIRTY : 0;
1031 
1032 	/* Mark pages as unallocated in the chunk map. */
1033 	if (dirty) {
1034 		arena_mapbits_unallocated_set(chunk, run_ind, size,
1035 		    CHUNK_MAP_DIRTY);
1036 		arena_mapbits_unallocated_set(chunk, run_ind+run_pages-1, size,
1037 		    CHUNK_MAP_DIRTY);
1038 	} else {
1039 		arena_mapbits_unallocated_set(chunk, run_ind, size,
1040 		    arena_mapbits_unzeroed_get(chunk, run_ind));
1041 		arena_mapbits_unallocated_set(chunk, run_ind+run_pages-1, size,
1042 		    arena_mapbits_unzeroed_get(chunk, run_ind+run_pages-1));
1043 	}
1044 
1045 	/* Try to coalesce forward. */
1046 	if (run_ind + run_pages < chunk_npages &&
1047 	    arena_mapbits_allocated_get(chunk, run_ind+run_pages) == 0 &&
1048 	    arena_mapbits_dirty_get(chunk, run_ind+run_pages) == flag_dirty) {
1049 		size_t nrun_size = arena_mapbits_unallocated_size_get(chunk,
1050 		    run_ind+run_pages);
1051 		size_t nrun_pages = nrun_size >> LG_PAGE;
1052 
1053 		/*
1054 		 * Remove successor from runs_avail; the coalesced run is
1055 		 * inserted later.
1056 		 */
1057 		assert(arena_mapbits_unallocated_size_get(chunk,
1058 		    run_ind+run_pages+nrun_pages-1) == nrun_size);
1059 		assert(arena_mapbits_dirty_get(chunk,
1060 		    run_ind+run_pages+nrun_pages-1) == flag_dirty);
1061 		arena_avail_remove(arena, chunk, run_ind+run_pages, nrun_pages,
1062 		    false, true);
1063 
1064 		size += nrun_size;
1065 		run_pages += nrun_pages;
1066 
1067 		arena_mapbits_unallocated_size_set(chunk, run_ind, size);
1068 		arena_mapbits_unallocated_size_set(chunk, run_ind+run_pages-1,
1069 		    size);
1070 	}
1071 
1072 	/* Try to coalesce backward. */
1073 	if (run_ind > map_bias && arena_mapbits_allocated_get(chunk, run_ind-1)
1074 	    == 0 && arena_mapbits_dirty_get(chunk, run_ind-1) == flag_dirty) {
1075 		size_t prun_size = arena_mapbits_unallocated_size_get(chunk,
1076 		    run_ind-1);
1077 		size_t prun_pages = prun_size >> LG_PAGE;
1078 
1079 		run_ind -= prun_pages;
1080 
1081 		/*
1082 		 * Remove predecessor from runs_avail; the coalesced run is
1083 		 * inserted later.
1084 		 */
1085 		assert(arena_mapbits_unallocated_size_get(chunk, run_ind) ==
1086 		    prun_size);
1087 		assert(arena_mapbits_dirty_get(chunk, run_ind) == flag_dirty);
1088 		arena_avail_remove(arena, chunk, run_ind, prun_pages, true,
1089 		    false);
1090 
1091 		size += prun_size;
1092 		run_pages += prun_pages;
1093 
1094 		arena_mapbits_unallocated_size_set(chunk, run_ind, size);
1095 		arena_mapbits_unallocated_size_set(chunk, run_ind+run_pages-1,
1096 		    size);
1097 	}
1098 
1099 	/* Insert into runs_avail, now that coalescing is complete. */
1100 	assert(arena_mapbits_unallocated_size_get(chunk, run_ind) ==
1101 	    arena_mapbits_unallocated_size_get(chunk, run_ind+run_pages-1));
1102 	assert(arena_mapbits_dirty_get(chunk, run_ind) ==
1103 	    arena_mapbits_dirty_get(chunk, run_ind+run_pages-1));
1104 	arena_avail_insert(arena, chunk, run_ind, run_pages, true, true);
1105 
1106 	/* Deallocate chunk if it is now completely unused. */
1107 	if (size == arena_maxclass) {
1108 		assert(run_ind == map_bias);
1109 		assert(run_pages == (arena_maxclass >> LG_PAGE));
1110 		arena_chunk_dealloc(arena, chunk);
1111 	}
1112 
1113 	/*
1114 	 * It is okay to do dirty page processing here even if the chunk was
1115 	 * deallocated above, since in that case it is the spare.  Waiting
1116 	 * until after possible chunk deallocation to do dirty processing
1117 	 * allows for an old spare to be fully deallocated, thus decreasing the
1118 	 * chances of spuriously crossing the dirty page purging threshold.
1119 	 */
1120 	if (dirty)
1121 		arena_maybe_purge(arena);
1122 }
1123 
1124 static void
1125 arena_run_trim_head(arena_t *arena, arena_chunk_t *chunk, arena_run_t *run,
1126     size_t oldsize, size_t newsize)
1127 {
1128 	size_t pageind = ((uintptr_t)run - (uintptr_t)chunk) >> LG_PAGE;
1129 	size_t head_npages = (oldsize - newsize) >> LG_PAGE;
1130 	size_t flag_dirty = arena_mapbits_dirty_get(chunk, pageind);
1131 
1132 	assert(oldsize > newsize);
1133 
1134 	/*
1135 	 * Update the chunk map so that arena_run_dalloc() can treat the
1136 	 * leading run as separately allocated.  Set the last element of each
1137 	 * run first, in case of single-page runs.
1138 	 */
1139 	assert(arena_mapbits_large_size_get(chunk, pageind) == oldsize);
1140 	arena_mapbits_large_set(chunk, pageind+head_npages-1, 0, flag_dirty);
1141 	arena_mapbits_large_set(chunk, pageind, oldsize-newsize, flag_dirty);
1142 
1143 	if (config_debug) {
1144 		UNUSED size_t tail_npages = newsize >> LG_PAGE;
1145 		assert(arena_mapbits_large_size_get(chunk,
1146 		    pageind+head_npages+tail_npages-1) == 0);
1147 		assert(arena_mapbits_dirty_get(chunk,
1148 		    pageind+head_npages+tail_npages-1) == flag_dirty);
1149 	}
1150 	arena_mapbits_large_set(chunk, pageind+head_npages, newsize,
1151 	    flag_dirty);
1152 
1153 	arena_run_dalloc(arena, run, false, false);
1154 }
1155 
1156 static void
1157 arena_run_trim_tail(arena_t *arena, arena_chunk_t *chunk, arena_run_t *run,
1158     size_t oldsize, size_t newsize, bool dirty)
1159 {
1160 	size_t pageind = ((uintptr_t)run - (uintptr_t)chunk) >> LG_PAGE;
1161 	size_t head_npages = newsize >> LG_PAGE;
1162 	size_t flag_dirty = arena_mapbits_dirty_get(chunk, pageind);
1163 
1164 	assert(oldsize > newsize);
1165 
1166 	/*
1167 	 * Update the chunk map so that arena_run_dalloc() can treat the
1168 	 * trailing run as separately allocated.  Set the last element of each
1169 	 * run first, in case of single-page runs.
1170 	 */
1171 	assert(arena_mapbits_large_size_get(chunk, pageind) == oldsize);
1172 	arena_mapbits_large_set(chunk, pageind+head_npages-1, 0, flag_dirty);
1173 	arena_mapbits_large_set(chunk, pageind, newsize, flag_dirty);
1174 
1175 	if (config_debug) {
1176 		UNUSED size_t tail_npages = (oldsize - newsize) >> LG_PAGE;
1177 		assert(arena_mapbits_large_size_get(chunk,
1178 		    pageind+head_npages+tail_npages-1) == 0);
1179 		assert(arena_mapbits_dirty_get(chunk,
1180 		    pageind+head_npages+tail_npages-1) == flag_dirty);
1181 	}
1182 	arena_mapbits_large_set(chunk, pageind+head_npages, oldsize-newsize,
1183 	    flag_dirty);
1184 
1185 	arena_run_dalloc(arena, (arena_run_t *)((uintptr_t)run + newsize),
1186 	    dirty, false);
1187 }
1188 
1189 static arena_run_t *
1190 arena_bin_runs_first(arena_bin_t *bin)
1191 {
1192 	arena_chunk_map_t *mapelm = arena_run_tree_first(&bin->runs);
1193 	if (mapelm != NULL) {
1194 		arena_chunk_t *chunk;
1195 		size_t pageind;
1196 		arena_run_t *run;
1197 
1198 		chunk = (arena_chunk_t *)CHUNK_ADDR2BASE(mapelm);
1199 		pageind = ((((uintptr_t)mapelm - (uintptr_t)chunk->map) /
1200 		    sizeof(arena_chunk_map_t))) + map_bias;
1201 		run = (arena_run_t *)((uintptr_t)chunk + (uintptr_t)((pageind -
1202 		    arena_mapbits_small_runind_get(chunk, pageind)) <<
1203 		    LG_PAGE));
1204 		return (run);
1205 	}
1206 
1207 	return (NULL);
1208 }
1209 
1210 static void
1211 arena_bin_runs_insert(arena_bin_t *bin, arena_run_t *run)
1212 {
1213 	arena_chunk_t *chunk = CHUNK_ADDR2BASE(run);
1214 	size_t pageind = ((uintptr_t)run - (uintptr_t)chunk) >> LG_PAGE;
1215 	arena_chunk_map_t *mapelm = arena_mapp_get(chunk, pageind);
1216 
1217 	assert(arena_run_tree_search(&bin->runs, mapelm) == NULL);
1218 
1219 	arena_run_tree_insert(&bin->runs, mapelm);
1220 }
1221 
1222 static void
1223 arena_bin_runs_remove(arena_bin_t *bin, arena_run_t *run)
1224 {
1225 	arena_chunk_t *chunk = (arena_chunk_t *)CHUNK_ADDR2BASE(run);
1226 	size_t pageind = ((uintptr_t)run - (uintptr_t)chunk) >> LG_PAGE;
1227 	arena_chunk_map_t *mapelm = arena_mapp_get(chunk, pageind);
1228 
1229 	assert(arena_run_tree_search(&bin->runs, mapelm) != NULL);
1230 
1231 	arena_run_tree_remove(&bin->runs, mapelm);
1232 }
1233 
1234 static arena_run_t *
1235 arena_bin_nonfull_run_tryget(arena_bin_t *bin)
1236 {
1237 	arena_run_t *run = arena_bin_runs_first(bin);
1238 	if (run != NULL) {
1239 		arena_bin_runs_remove(bin, run);
1240 		if (config_stats)
1241 			bin->stats.reruns++;
1242 	}
1243 	return (run);
1244 }
1245 
1246 static arena_run_t *
1247 arena_bin_nonfull_run_get(arena_t *arena, arena_bin_t *bin)
1248 {
1249 	arena_run_t *run;
1250 	size_t binind;
1251 	arena_bin_info_t *bin_info;
1252 
1253 	/* Look for a usable run. */
1254 	run = arena_bin_nonfull_run_tryget(bin);
1255 	if (run != NULL)
1256 		return (run);
1257 	/* No existing runs have any space available. */
1258 
1259 	binind = arena_bin_index(arena, bin);
1260 	bin_info = &arena_bin_info[binind];
1261 
1262 	/* Allocate a new run. */
1263 	malloc_mutex_unlock(&bin->lock);
1264 	/******************************/
1265 	malloc_mutex_lock(&arena->lock);
1266 	run = arena_run_alloc(arena, bin_info->run_size, false, binind, false);
1267 	if (run != NULL) {
1268 		bitmap_t *bitmap = (bitmap_t *)((uintptr_t)run +
1269 		    (uintptr_t)bin_info->bitmap_offset);
1270 
1271 		/* Initialize run internals. */
1272 		run->bin = bin;
1273 		run->nextind = 0;
1274 		run->nfree = bin_info->nregs;
1275 		bitmap_init(bitmap, &bin_info->bitmap_info);
1276 	}
1277 	malloc_mutex_unlock(&arena->lock);
1278 	/********************************/
1279 	malloc_mutex_lock(&bin->lock);
1280 	if (run != NULL) {
1281 		if (config_stats) {
1282 			bin->stats.nruns++;
1283 			bin->stats.curruns++;
1284 		}
1285 		return (run);
1286 	}
1287 
1288 	/*
1289 	 * arena_run_alloc() failed, but another thread may have made
1290 	 * sufficient memory available while this one dropped bin->lock above,
1291 	 * so search one more time.
1292 	 */
1293 	run = arena_bin_nonfull_run_tryget(bin);
1294 	if (run != NULL)
1295 		return (run);
1296 
1297 	return (NULL);
1298 }
1299 
1300 /* Re-fill bin->runcur, then call arena_run_reg_alloc(). */
1301 static void *
1302 arena_bin_malloc_hard(arena_t *arena, arena_bin_t *bin)
1303 {
1304 	void *ret;
1305 	size_t binind;
1306 	arena_bin_info_t *bin_info;
1307 	arena_run_t *run;
1308 
1309 	binind = arena_bin_index(arena, bin);
1310 	bin_info = &arena_bin_info[binind];
1311 	bin->runcur = NULL;
1312 	run = arena_bin_nonfull_run_get(arena, bin);
1313 	if (bin->runcur != NULL && bin->runcur->nfree > 0) {
1314 		/*
1315 		 * Another thread updated runcur while this one ran without the
1316 		 * bin lock in arena_bin_nonfull_run_get().
1317 		 */
1318 		assert(bin->runcur->nfree > 0);
1319 		ret = arena_run_reg_alloc(bin->runcur, bin_info);
1320 		if (run != NULL) {
1321 			arena_chunk_t *chunk;
1322 
1323 			/*
1324 			 * arena_run_alloc() may have allocated run, or it may
1325 			 * have pulled run from the bin's run tree.  Therefore
1326 			 * it is unsafe to make any assumptions about how run
1327 			 * has previously been used, and arena_bin_lower_run()
1328 			 * must be called, as if a region were just deallocated
1329 			 * from the run.
1330 			 */
1331 			chunk = (arena_chunk_t *)CHUNK_ADDR2BASE(run);
1332 			if (run->nfree == bin_info->nregs)
1333 				arena_dalloc_bin_run(arena, chunk, run, bin);
1334 			else
1335 				arena_bin_lower_run(arena, chunk, run, bin);
1336 		}
1337 		return (ret);
1338 	}
1339 
1340 	if (run == NULL)
1341 		return (NULL);
1342 
1343 	bin->runcur = run;
1344 
1345 	assert(bin->runcur->nfree > 0);
1346 
1347 	return (arena_run_reg_alloc(bin->runcur, bin_info));
1348 }
1349 
1350 void
1351 arena_tcache_fill_small(arena_t *arena, tcache_bin_t *tbin, size_t binind,
1352     uint64_t prof_accumbytes)
1353 {
1354 	unsigned i, nfill;
1355 	arena_bin_t *bin;
1356 	arena_run_t *run;
1357 	void *ptr;
1358 
1359 	assert(tbin->ncached == 0);
1360 
1361 	if (config_prof && arena_prof_accum(arena, prof_accumbytes))
1362 		prof_idump();
1363 	bin = &arena->bins[binind];
1364 	malloc_mutex_lock(&bin->lock);
1365 	for (i = 0, nfill = (tcache_bin_info[binind].ncached_max >>
1366 	    tbin->lg_fill_div); i < nfill; i++) {
1367 		if ((run = bin->runcur) != NULL && run->nfree > 0)
1368 			ptr = arena_run_reg_alloc(run, &arena_bin_info[binind]);
1369 		else
1370 			ptr = arena_bin_malloc_hard(arena, bin);
1371 		if (ptr == NULL)
1372 			break;
1373 		if (config_fill && opt_junk) {
1374 			arena_alloc_junk_small(ptr, &arena_bin_info[binind],
1375 			    true);
1376 		}
1377 		/* Insert such that low regions get used first. */
1378 		tbin->avail[nfill - 1 - i] = ptr;
1379 	}
1380 	if (config_stats) {
1381 		bin->stats.allocated += i * arena_bin_info[binind].reg_size;
1382 		bin->stats.nmalloc += i;
1383 		bin->stats.nrequests += tbin->tstats.nrequests;
1384 		bin->stats.nfills++;
1385 		tbin->tstats.nrequests = 0;
1386 	}
1387 	malloc_mutex_unlock(&bin->lock);
1388 	tbin->ncached = i;
1389 }
1390 
1391 void
1392 arena_alloc_junk_small(void *ptr, arena_bin_info_t *bin_info, bool zero)
1393 {
1394 
1395 	if (zero) {
1396 		size_t redzone_size = bin_info->redzone_size;
1397 		memset((void *)((uintptr_t)ptr - redzone_size), 0xa5,
1398 		    redzone_size);
1399 		memset((void *)((uintptr_t)ptr + bin_info->reg_size), 0xa5,
1400 		    redzone_size);
1401 	} else {
1402 		memset((void *)((uintptr_t)ptr - bin_info->redzone_size), 0xa5,
1403 		    bin_info->reg_interval);
1404 	}
1405 }
1406 
1407 void
1408 arena_dalloc_junk_small(void *ptr, arena_bin_info_t *bin_info)
1409 {
1410 	size_t size = bin_info->reg_size;
1411 	size_t redzone_size = bin_info->redzone_size;
1412 	size_t i;
1413 	bool error = false;
1414 
1415 	for (i = 1; i <= redzone_size; i++) {
1416 		unsigned byte;
1417 		if ((byte = *(uint8_t *)((uintptr_t)ptr - i)) != 0xa5) {
1418 			error = true;
1419 			malloc_printf("<jemalloc>: Corrupt redzone "
1420 			    "%zu byte%s before %p (size %zu), byte=%#x\n", i,
1421 			    (i == 1) ? "" : "s", ptr, size, byte);
1422 		}
1423 	}
1424 	for (i = 0; i < redzone_size; i++) {
1425 		unsigned byte;
1426 		if ((byte = *(uint8_t *)((uintptr_t)ptr + size + i)) != 0xa5) {
1427 			error = true;
1428 			malloc_printf("<jemalloc>: Corrupt redzone "
1429 			    "%zu byte%s after end of %p (size %zu), byte=%#x\n",
1430 			    i, (i == 1) ? "" : "s", ptr, size, byte);
1431 		}
1432 	}
1433 	if (opt_abort && error)
1434 		abort();
1435 
1436 	memset((void *)((uintptr_t)ptr - redzone_size), 0x5a,
1437 	    bin_info->reg_interval);
1438 }
1439 
1440 void *
1441 arena_malloc_small(arena_t *arena, size_t size, bool zero)
1442 {
1443 	void *ret;
1444 	arena_bin_t *bin;
1445 	arena_run_t *run;
1446 	size_t binind;
1447 
1448 	binind = SMALL_SIZE2BIN(size);
1449 	assert(binind < NBINS);
1450 	bin = &arena->bins[binind];
1451 	size = arena_bin_info[binind].reg_size;
1452 
1453 	malloc_mutex_lock(&bin->lock);
1454 	if ((run = bin->runcur) != NULL && run->nfree > 0)
1455 		ret = arena_run_reg_alloc(run, &arena_bin_info[binind]);
1456 	else
1457 		ret = arena_bin_malloc_hard(arena, bin);
1458 
1459 	if (ret == NULL) {
1460 		malloc_mutex_unlock(&bin->lock);
1461 		return (NULL);
1462 	}
1463 
1464 	if (config_stats) {
1465 		bin->stats.allocated += size;
1466 		bin->stats.nmalloc++;
1467 		bin->stats.nrequests++;
1468 	}
1469 	malloc_mutex_unlock(&bin->lock);
1470 	if (config_prof && isthreaded == false && arena_prof_accum(arena, size))
1471 		prof_idump();
1472 
1473 	if (zero == false) {
1474 		if (config_fill) {
1475 			if (opt_junk) {
1476 				arena_alloc_junk_small(ret,
1477 				    &arena_bin_info[binind], false);
1478 			} else if (opt_zero)
1479 				memset(ret, 0, size);
1480 		}
1481 		VALGRIND_MAKE_MEM_UNDEFINED(ret, size);
1482 	} else {
1483 		if (config_fill && opt_junk) {
1484 			arena_alloc_junk_small(ret, &arena_bin_info[binind],
1485 			    true);
1486 		}
1487 		VALGRIND_MAKE_MEM_UNDEFINED(ret, size);
1488 		memset(ret, 0, size);
1489 	}
1490 
1491 	return (ret);
1492 }
1493 
1494 void *
1495 arena_malloc_large(arena_t *arena, size_t size, bool zero)
1496 {
1497 	void *ret;
1498 	UNUSED bool idump;
1499 
1500 	/* Large allocation. */
1501 	size = PAGE_CEILING(size);
1502 	malloc_mutex_lock(&arena->lock);
1503 	ret = (void *)arena_run_alloc(arena, size, true, BININD_INVALID, zero);
1504 	if (ret == NULL) {
1505 		malloc_mutex_unlock(&arena->lock);
1506 		return (NULL);
1507 	}
1508 	if (config_stats) {
1509 		arena->stats.nmalloc_large++;
1510 		arena->stats.nrequests_large++;
1511 		arena->stats.allocated_large += size;
1512 		arena->stats.lstats[(size >> LG_PAGE) - 1].nmalloc++;
1513 		arena->stats.lstats[(size >> LG_PAGE) - 1].nrequests++;
1514 		arena->stats.lstats[(size >> LG_PAGE) - 1].curruns++;
1515 	}
1516 	if (config_prof)
1517 		idump = arena_prof_accum_locked(arena, size);
1518 	malloc_mutex_unlock(&arena->lock);
1519 	if (config_prof && idump)
1520 		prof_idump();
1521 
1522 	if (zero == false) {
1523 		if (config_fill) {
1524 			if (opt_junk)
1525 				memset(ret, 0xa5, size);
1526 			else if (opt_zero)
1527 				memset(ret, 0, size);
1528 		}
1529 	}
1530 
1531 	return (ret);
1532 }
1533 
1534 /* Only handles large allocations that require more than page alignment. */
1535 void *
1536 arena_palloc(arena_t *arena, size_t size, size_t alignment, bool zero)
1537 {
1538 	void *ret;
1539 	size_t alloc_size, leadsize, trailsize;
1540 	arena_run_t *run;
1541 	arena_chunk_t *chunk;
1542 
1543 	assert((size & PAGE_MASK) == 0);
1544 
1545 	alignment = PAGE_CEILING(alignment);
1546 	alloc_size = size + alignment - PAGE;
1547 
1548 	malloc_mutex_lock(&arena->lock);
1549 	run = arena_run_alloc(arena, alloc_size, true, BININD_INVALID, zero);
1550 	if (run == NULL) {
1551 		malloc_mutex_unlock(&arena->lock);
1552 		return (NULL);
1553 	}
1554 	chunk = (arena_chunk_t *)CHUNK_ADDR2BASE(run);
1555 
1556 	leadsize = ALIGNMENT_CEILING((uintptr_t)run, alignment) -
1557 	    (uintptr_t)run;
1558 	assert(alloc_size >= leadsize + size);
1559 	trailsize = alloc_size - leadsize - size;
1560 	ret = (void *)((uintptr_t)run + leadsize);
1561 	if (leadsize != 0) {
1562 		arena_run_trim_head(arena, chunk, run, alloc_size, alloc_size -
1563 		    leadsize);
1564 	}
1565 	if (trailsize != 0) {
1566 		arena_run_trim_tail(arena, chunk, ret, size + trailsize, size,
1567 		    false);
1568 	}
1569 
1570 	if (config_stats) {
1571 		arena->stats.nmalloc_large++;
1572 		arena->stats.nrequests_large++;
1573 		arena->stats.allocated_large += size;
1574 		arena->stats.lstats[(size >> LG_PAGE) - 1].nmalloc++;
1575 		arena->stats.lstats[(size >> LG_PAGE) - 1].nrequests++;
1576 		arena->stats.lstats[(size >> LG_PAGE) - 1].curruns++;
1577 	}
1578 	malloc_mutex_unlock(&arena->lock);
1579 
1580 	if (config_fill && zero == false) {
1581 		if (opt_junk)
1582 			memset(ret, 0xa5, size);
1583 		else if (opt_zero)
1584 			memset(ret, 0, size);
1585 	}
1586 	return (ret);
1587 }
1588 
1589 void
1590 arena_prof_promoted(const void *ptr, size_t size)
1591 {
1592 	arena_chunk_t *chunk;
1593 	size_t pageind, binind;
1594 
1595 	cassert(config_prof);
1596 	assert(ptr != NULL);
1597 	assert(CHUNK_ADDR2BASE(ptr) != ptr);
1598 	assert(isalloc(ptr, false) == PAGE);
1599 	assert(isalloc(ptr, true) == PAGE);
1600 	assert(size <= SMALL_MAXCLASS);
1601 
1602 	chunk = (arena_chunk_t *)CHUNK_ADDR2BASE(ptr);
1603 	pageind = ((uintptr_t)ptr - (uintptr_t)chunk) >> LG_PAGE;
1604 	binind = SMALL_SIZE2BIN(size);
1605 	assert(binind < NBINS);
1606 	arena_mapbits_large_binind_set(chunk, pageind, binind);
1607 
1608 	assert(isalloc(ptr, false) == PAGE);
1609 	assert(isalloc(ptr, true) == size);
1610 }
1611 
1612 static void
1613 arena_dissociate_bin_run(arena_chunk_t *chunk, arena_run_t *run,
1614     arena_bin_t *bin)
1615 {
1616 
1617 	/* Dissociate run from bin. */
1618 	if (run == bin->runcur)
1619 		bin->runcur = NULL;
1620 	else {
1621 		size_t binind = arena_bin_index(chunk->arena, bin);
1622 		arena_bin_info_t *bin_info = &arena_bin_info[binind];
1623 
1624 		if (bin_info->nregs != 1) {
1625 			/*
1626 			 * This block's conditional is necessary because if the
1627 			 * run only contains one region, then it never gets
1628 			 * inserted into the non-full runs tree.
1629 			 */
1630 			arena_bin_runs_remove(bin, run);
1631 		}
1632 	}
1633 }
1634 
1635 static void
1636 arena_dalloc_bin_run(arena_t *arena, arena_chunk_t *chunk, arena_run_t *run,
1637     arena_bin_t *bin)
1638 {
1639 	size_t binind;
1640 	arena_bin_info_t *bin_info;
1641 	size_t npages, run_ind, past;
1642 
1643 	assert(run != bin->runcur);
1644 	assert(arena_run_tree_search(&bin->runs,
1645 	    arena_mapp_get(chunk, ((uintptr_t)run-(uintptr_t)chunk)>>LG_PAGE))
1646 	    == NULL);
1647 
1648 	binind = arena_bin_index(chunk->arena, run->bin);
1649 	bin_info = &arena_bin_info[binind];
1650 
1651 	malloc_mutex_unlock(&bin->lock);
1652 	/******************************/
1653 	npages = bin_info->run_size >> LG_PAGE;
1654 	run_ind = (size_t)(((uintptr_t)run - (uintptr_t)chunk) >> LG_PAGE);
1655 	past = (size_t)(PAGE_CEILING((uintptr_t)run +
1656 	    (uintptr_t)bin_info->reg0_offset + (uintptr_t)(run->nextind *
1657 	    bin_info->reg_interval - bin_info->redzone_size) -
1658 	    (uintptr_t)chunk) >> LG_PAGE);
1659 	malloc_mutex_lock(&arena->lock);
1660 
1661 	/*
1662 	 * If the run was originally clean, and some pages were never touched,
1663 	 * trim the clean pages before deallocating the dirty portion of the
1664 	 * run.
1665 	 */
1666 	assert(arena_mapbits_dirty_get(chunk, run_ind) ==
1667 	    arena_mapbits_dirty_get(chunk, run_ind+npages-1));
1668 	if (arena_mapbits_dirty_get(chunk, run_ind) == 0 && past - run_ind <
1669 	    npages) {
1670 		/* Trim clean pages.  Convert to large run beforehand. */
1671 		assert(npages > 0);
1672 		arena_mapbits_large_set(chunk, run_ind, bin_info->run_size, 0);
1673 		arena_mapbits_large_set(chunk, run_ind+npages-1, 0, 0);
1674 		arena_run_trim_tail(arena, chunk, run, (npages << LG_PAGE),
1675 		    ((past - run_ind) << LG_PAGE), false);
1676 		/* npages = past - run_ind; */
1677 	}
1678 	arena_run_dalloc(arena, run, true, false);
1679 	malloc_mutex_unlock(&arena->lock);
1680 	/****************************/
1681 	malloc_mutex_lock(&bin->lock);
1682 	if (config_stats)
1683 		bin->stats.curruns--;
1684 }
1685 
1686 static void
1687 arena_bin_lower_run(arena_t *arena, arena_chunk_t *chunk, arena_run_t *run,
1688     arena_bin_t *bin)
1689 {
1690 
1691 	/*
1692 	 * Make sure that if bin->runcur is non-NULL, it refers to the lowest
1693 	 * non-full run.  It is okay to NULL runcur out rather than proactively
1694 	 * keeping it pointing at the lowest non-full run.
1695 	 */
1696 	if ((uintptr_t)run < (uintptr_t)bin->runcur) {
1697 		/* Switch runcur. */
1698 		if (bin->runcur->nfree > 0)
1699 			arena_bin_runs_insert(bin, bin->runcur);
1700 		bin->runcur = run;
1701 		if (config_stats)
1702 			bin->stats.reruns++;
1703 	} else
1704 		arena_bin_runs_insert(bin, run);
1705 }
1706 
1707 void
1708 arena_dalloc_bin_locked(arena_t *arena, arena_chunk_t *chunk, void *ptr,
1709     arena_chunk_map_t *mapelm)
1710 {
1711 	size_t pageind;
1712 	arena_run_t *run;
1713 	arena_bin_t *bin;
1714 	arena_bin_info_t *bin_info;
1715 	size_t size, binind;
1716 
1717 	pageind = ((uintptr_t)ptr - (uintptr_t)chunk) >> LG_PAGE;
1718 	run = (arena_run_t *)((uintptr_t)chunk + (uintptr_t)((pageind -
1719 	    arena_mapbits_small_runind_get(chunk, pageind)) << LG_PAGE));
1720 	bin = run->bin;
1721 	binind = arena_ptr_small_binind_get(ptr, mapelm->bits);
1722 	bin_info = &arena_bin_info[binind];
1723 	if (config_fill || config_stats)
1724 		size = bin_info->reg_size;
1725 
1726 	if (config_fill && opt_junk)
1727 		arena_dalloc_junk_small(ptr, bin_info);
1728 
1729 	arena_run_reg_dalloc(run, ptr);
1730 	if (run->nfree == bin_info->nregs) {
1731 		arena_dissociate_bin_run(chunk, run, bin);
1732 		arena_dalloc_bin_run(arena, chunk, run, bin);
1733 	} else if (run->nfree == 1 && run != bin->runcur)
1734 		arena_bin_lower_run(arena, chunk, run, bin);
1735 
1736 	if (config_stats) {
1737 		bin->stats.allocated -= size;
1738 		bin->stats.ndalloc++;
1739 	}
1740 }
1741 
1742 void
1743 arena_dalloc_bin(arena_t *arena, arena_chunk_t *chunk, void *ptr,
1744     size_t pageind, arena_chunk_map_t *mapelm)
1745 {
1746 	arena_run_t *run;
1747 	arena_bin_t *bin;
1748 
1749 	run = (arena_run_t *)((uintptr_t)chunk + (uintptr_t)((pageind -
1750 	    arena_mapbits_small_runind_get(chunk, pageind)) << LG_PAGE));
1751 	bin = run->bin;
1752 	malloc_mutex_lock(&bin->lock);
1753 	arena_dalloc_bin_locked(arena, chunk, ptr, mapelm);
1754 	malloc_mutex_unlock(&bin->lock);
1755 }
1756 
1757 void
1758 arena_dalloc_small(arena_t *arena, arena_chunk_t *chunk, void *ptr,
1759     size_t pageind)
1760 {
1761 	arena_chunk_map_t *mapelm;
1762 
1763 	if (config_debug) {
1764 		/* arena_ptr_small_binind_get() does extra sanity checking. */
1765 		assert(arena_ptr_small_binind_get(ptr, arena_mapbits_get(chunk,
1766 		    pageind)) != BININD_INVALID);
1767 	}
1768 	mapelm = arena_mapp_get(chunk, pageind);
1769 	arena_dalloc_bin(arena, chunk, ptr, pageind, mapelm);
1770 }
1771 
1772 void
1773 arena_dalloc_large_locked(arena_t *arena, arena_chunk_t *chunk, void *ptr)
1774 {
1775 
1776 	if (config_fill || config_stats) {
1777 		size_t pageind = ((uintptr_t)ptr - (uintptr_t)chunk) >> LG_PAGE;
1778 		size_t size = arena_mapbits_large_size_get(chunk, pageind);
1779 
1780 		if (config_fill && config_stats && opt_junk)
1781 			memset(ptr, 0x5a, size);
1782 		if (config_stats) {
1783 			arena->stats.ndalloc_large++;
1784 			arena->stats.allocated_large -= size;
1785 			arena->stats.lstats[(size >> LG_PAGE) - 1].ndalloc++;
1786 			arena->stats.lstats[(size >> LG_PAGE) - 1].curruns--;
1787 		}
1788 	}
1789 
1790 	arena_run_dalloc(arena, (arena_run_t *)ptr, true, false);
1791 }
1792 
1793 void
1794 arena_dalloc_large(arena_t *arena, arena_chunk_t *chunk, void *ptr)
1795 {
1796 
1797 	malloc_mutex_lock(&arena->lock);
1798 	arena_dalloc_large_locked(arena, chunk, ptr);
1799 	malloc_mutex_unlock(&arena->lock);
1800 }
1801 
1802 static void
1803 arena_ralloc_large_shrink(arena_t *arena, arena_chunk_t *chunk, void *ptr,
1804     size_t oldsize, size_t size)
1805 {
1806 
1807 	assert(size < oldsize);
1808 
1809 	/*
1810 	 * Shrink the run, and make trailing pages available for other
1811 	 * allocations.
1812 	 */
1813 	malloc_mutex_lock(&arena->lock);
1814 	arena_run_trim_tail(arena, chunk, (arena_run_t *)ptr, oldsize, size,
1815 	    true);
1816 	if (config_stats) {
1817 		arena->stats.ndalloc_large++;
1818 		arena->stats.allocated_large -= oldsize;
1819 		arena->stats.lstats[(oldsize >> LG_PAGE) - 1].ndalloc++;
1820 		arena->stats.lstats[(oldsize >> LG_PAGE) - 1].curruns--;
1821 
1822 		arena->stats.nmalloc_large++;
1823 		arena->stats.nrequests_large++;
1824 		arena->stats.allocated_large += size;
1825 		arena->stats.lstats[(size >> LG_PAGE) - 1].nmalloc++;
1826 		arena->stats.lstats[(size >> LG_PAGE) - 1].nrequests++;
1827 		arena->stats.lstats[(size >> LG_PAGE) - 1].curruns++;
1828 	}
1829 	malloc_mutex_unlock(&arena->lock);
1830 }
1831 
1832 static bool
1833 arena_ralloc_large_grow(arena_t *arena, arena_chunk_t *chunk, void *ptr,
1834     size_t oldsize, size_t size, size_t extra, bool zero)
1835 {
1836 	size_t pageind = ((uintptr_t)ptr - (uintptr_t)chunk) >> LG_PAGE;
1837 	size_t npages = oldsize >> LG_PAGE;
1838 	size_t followsize;
1839 
1840 	assert(oldsize == arena_mapbits_large_size_get(chunk, pageind));
1841 
1842 	/* Try to extend the run. */
1843 	assert(size + extra > oldsize);
1844 	malloc_mutex_lock(&arena->lock);
1845 	if (pageind + npages < chunk_npages &&
1846 	    arena_mapbits_allocated_get(chunk, pageind+npages) == 0 &&
1847 	    (followsize = arena_mapbits_unallocated_size_get(chunk,
1848 	    pageind+npages)) >= size - oldsize) {
1849 		/*
1850 		 * The next run is available and sufficiently large.  Split the
1851 		 * following run, then merge the first part with the existing
1852 		 * allocation.
1853 		 */
1854 		size_t flag_dirty;
1855 		size_t splitsize = (oldsize + followsize <= size + extra)
1856 		    ? followsize : size + extra - oldsize;
1857 		arena_run_split(arena, (arena_run_t *)((uintptr_t)chunk +
1858 		    ((pageind+npages) << LG_PAGE)), splitsize, true,
1859 		    BININD_INVALID, zero);
1860 
1861 		size = oldsize + splitsize;
1862 		npages = size >> LG_PAGE;
1863 
1864 		/*
1865 		 * Mark the extended run as dirty if either portion of the run
1866 		 * was dirty before allocation.  This is rather pedantic,
1867 		 * because there's not actually any sequence of events that
1868 		 * could cause the resulting run to be passed to
1869 		 * arena_run_dalloc() with the dirty argument set to false
1870 		 * (which is when dirty flag consistency would really matter).
1871 		 */
1872 		flag_dirty = arena_mapbits_dirty_get(chunk, pageind) |
1873 		    arena_mapbits_dirty_get(chunk, pageind+npages-1);
1874 		arena_mapbits_large_set(chunk, pageind, size, flag_dirty);
1875 		arena_mapbits_large_set(chunk, pageind+npages-1, 0, flag_dirty);
1876 
1877 		if (config_stats) {
1878 			arena->stats.ndalloc_large++;
1879 			arena->stats.allocated_large -= oldsize;
1880 			arena->stats.lstats[(oldsize >> LG_PAGE) - 1].ndalloc++;
1881 			arena->stats.lstats[(oldsize >> LG_PAGE) - 1].curruns--;
1882 
1883 			arena->stats.nmalloc_large++;
1884 			arena->stats.nrequests_large++;
1885 			arena->stats.allocated_large += size;
1886 			arena->stats.lstats[(size >> LG_PAGE) - 1].nmalloc++;
1887 			arena->stats.lstats[(size >> LG_PAGE) - 1].nrequests++;
1888 			arena->stats.lstats[(size >> LG_PAGE) - 1].curruns++;
1889 		}
1890 		malloc_mutex_unlock(&arena->lock);
1891 		return (false);
1892 	}
1893 	malloc_mutex_unlock(&arena->lock);
1894 
1895 	return (true);
1896 }
1897 
1898 /*
1899  * Try to resize a large allocation, in order to avoid copying.  This will
1900  * always fail if growing an object, and the following run is already in use.
1901  */
1902 static bool
1903 arena_ralloc_large(void *ptr, size_t oldsize, size_t size, size_t extra,
1904     bool zero)
1905 {
1906 	size_t psize;
1907 
1908 	psize = PAGE_CEILING(size + extra);
1909 	if (psize == oldsize) {
1910 		/* Same size class. */
1911 		if (config_fill && opt_junk && size < oldsize) {
1912 			memset((void *)((uintptr_t)ptr + size), 0x5a, oldsize -
1913 			    size);
1914 		}
1915 		return (false);
1916 	} else {
1917 		arena_chunk_t *chunk;
1918 		arena_t *arena;
1919 
1920 		chunk = (arena_chunk_t *)CHUNK_ADDR2BASE(ptr);
1921 		arena = chunk->arena;
1922 
1923 		if (psize < oldsize) {
1924 			/* Fill before shrinking in order avoid a race. */
1925 			if (config_fill && opt_junk) {
1926 				memset((void *)((uintptr_t)ptr + size), 0x5a,
1927 				    oldsize - size);
1928 			}
1929 			arena_ralloc_large_shrink(arena, chunk, ptr, oldsize,
1930 			    psize);
1931 			return (false);
1932 		} else {
1933 			bool ret = arena_ralloc_large_grow(arena, chunk, ptr,
1934 			    oldsize, PAGE_CEILING(size),
1935 			    psize - PAGE_CEILING(size), zero);
1936 			if (config_fill && ret == false && zero == false &&
1937 			    opt_zero) {
1938 				memset((void *)((uintptr_t)ptr + oldsize), 0,
1939 				    size - oldsize);
1940 			}
1941 			return (ret);
1942 		}
1943 	}
1944 }
1945 
1946 void *
1947 arena_ralloc_no_move(void *ptr, size_t oldsize, size_t size, size_t extra,
1948     bool zero)
1949 {
1950 
1951 	/*
1952 	 * Avoid moving the allocation if the size class can be left the same.
1953 	 */
1954 	if (oldsize <= arena_maxclass) {
1955 		if (oldsize <= SMALL_MAXCLASS) {
1956 			assert(arena_bin_info[SMALL_SIZE2BIN(oldsize)].reg_size
1957 			    == oldsize);
1958 			if ((size + extra <= SMALL_MAXCLASS &&
1959 			    SMALL_SIZE2BIN(size + extra) ==
1960 			    SMALL_SIZE2BIN(oldsize)) || (size <= oldsize &&
1961 			    size + extra >= oldsize)) {
1962 				if (config_fill && opt_junk && size < oldsize) {
1963 					memset((void *)((uintptr_t)ptr + size),
1964 					    0x5a, oldsize - size);
1965 				}
1966 				return (ptr);
1967 			}
1968 		} else {
1969 			assert(size <= arena_maxclass);
1970 			if (size + extra > SMALL_MAXCLASS) {
1971 				if (arena_ralloc_large(ptr, oldsize, size,
1972 				    extra, zero) == false)
1973 					return (ptr);
1974 			}
1975 		}
1976 	}
1977 
1978 	/* Reallocation would require a move. */
1979 	return (NULL);
1980 }
1981 
1982 void *
1983 arena_ralloc(arena_t *arena, void *ptr, size_t oldsize, size_t size,
1984     size_t extra, size_t alignment, bool zero, bool try_tcache_alloc,
1985     bool try_tcache_dalloc)
1986 {
1987 	void *ret;
1988 	size_t copysize;
1989 
1990 	/* Try to avoid moving the allocation. */
1991 	ret = arena_ralloc_no_move(ptr, oldsize, size, extra, zero);
1992 	if (ret != NULL)
1993 		return (ret);
1994 
1995 	/*
1996 	 * size and oldsize are different enough that we need to move the
1997 	 * object.  In that case, fall back to allocating new space and
1998 	 * copying.
1999 	 */
2000 	if (alignment != 0) {
2001 		size_t usize = sa2u(size + extra, alignment);
2002 		if (usize == 0)
2003 			return (NULL);
2004 		ret = ipallocx(usize, alignment, zero, try_tcache_alloc, arena);
2005 	} else
2006 		ret = arena_malloc(arena, size + extra, zero, try_tcache_alloc);
2007 
2008 	if (ret == NULL) {
2009 		if (extra == 0)
2010 			return (NULL);
2011 		/* Try again, this time without extra. */
2012 		if (alignment != 0) {
2013 			size_t usize = sa2u(size, alignment);
2014 			if (usize == 0)
2015 				return (NULL);
2016 			ret = ipallocx(usize, alignment, zero, try_tcache_alloc,
2017 			    arena);
2018 		} else
2019 			ret = arena_malloc(arena, size, zero, try_tcache_alloc);
2020 
2021 		if (ret == NULL)
2022 			return (NULL);
2023 	}
2024 
2025 	/* Junk/zero-filling were already done by ipalloc()/arena_malloc(). */
2026 
2027 	/*
2028 	 * Copy at most size bytes (not size+extra), since the caller has no
2029 	 * expectation that the extra bytes will be reliably preserved.
2030 	 */
2031 	copysize = (size < oldsize) ? size : oldsize;
2032 	VALGRIND_MAKE_MEM_UNDEFINED(ret, copysize);
2033 	memcpy(ret, ptr, copysize);
2034 	iqallocx(ptr, try_tcache_dalloc);
2035 	return (ret);
2036 }
2037 
2038 dss_prec_t
2039 arena_dss_prec_get(arena_t *arena)
2040 {
2041 	dss_prec_t ret;
2042 
2043 	malloc_mutex_lock(&arena->lock);
2044 	ret = arena->dss_prec;
2045 	malloc_mutex_unlock(&arena->lock);
2046 	return (ret);
2047 }
2048 
2049 void
2050 arena_dss_prec_set(arena_t *arena, dss_prec_t dss_prec)
2051 {
2052 
2053 	malloc_mutex_lock(&arena->lock);
2054 	arena->dss_prec = dss_prec;
2055 	malloc_mutex_unlock(&arena->lock);
2056 }
2057 
2058 void
2059 arena_stats_merge(arena_t *arena, const char **dss, size_t *nactive,
2060     size_t *ndirty, arena_stats_t *astats, malloc_bin_stats_t *bstats,
2061     malloc_large_stats_t *lstats)
2062 {
2063 	unsigned i;
2064 
2065 	malloc_mutex_lock(&arena->lock);
2066 	*dss = dss_prec_names[arena->dss_prec];
2067 	*nactive += arena->nactive;
2068 	*ndirty += arena->ndirty;
2069 
2070 	astats->mapped += arena->stats.mapped;
2071 	astats->npurge += arena->stats.npurge;
2072 	astats->nmadvise += arena->stats.nmadvise;
2073 	astats->purged += arena->stats.purged;
2074 	astats->allocated_large += arena->stats.allocated_large;
2075 	astats->nmalloc_large += arena->stats.nmalloc_large;
2076 	astats->ndalloc_large += arena->stats.ndalloc_large;
2077 	astats->nrequests_large += arena->stats.nrequests_large;
2078 
2079 	for (i = 0; i < nlclasses; i++) {
2080 		lstats[i].nmalloc += arena->stats.lstats[i].nmalloc;
2081 		lstats[i].ndalloc += arena->stats.lstats[i].ndalloc;
2082 		lstats[i].nrequests += arena->stats.lstats[i].nrequests;
2083 		lstats[i].curruns += arena->stats.lstats[i].curruns;
2084 	}
2085 	malloc_mutex_unlock(&arena->lock);
2086 
2087 	for (i = 0; i < NBINS; i++) {
2088 		arena_bin_t *bin = &arena->bins[i];
2089 
2090 		malloc_mutex_lock(&bin->lock);
2091 		bstats[i].allocated += bin->stats.allocated;
2092 		bstats[i].nmalloc += bin->stats.nmalloc;
2093 		bstats[i].ndalloc += bin->stats.ndalloc;
2094 		bstats[i].nrequests += bin->stats.nrequests;
2095 		if (config_tcache) {
2096 			bstats[i].nfills += bin->stats.nfills;
2097 			bstats[i].nflushes += bin->stats.nflushes;
2098 		}
2099 		bstats[i].nruns += bin->stats.nruns;
2100 		bstats[i].reruns += bin->stats.reruns;
2101 		bstats[i].curruns += bin->stats.curruns;
2102 		malloc_mutex_unlock(&bin->lock);
2103 	}
2104 }
2105 
2106 bool
2107 arena_new(arena_t *arena, unsigned ind)
2108 {
2109 	unsigned i;
2110 	arena_bin_t *bin;
2111 
2112 	arena->ind = ind;
2113 	arena->nthreads = 0;
2114 
2115 	if (malloc_mutex_init(&arena->lock))
2116 		return (true);
2117 
2118 	if (config_stats) {
2119 		memset(&arena->stats, 0, sizeof(arena_stats_t));
2120 		arena->stats.lstats =
2121 		    (malloc_large_stats_t *)base_alloc(nlclasses *
2122 		    sizeof(malloc_large_stats_t));
2123 		if (arena->stats.lstats == NULL)
2124 			return (true);
2125 		memset(arena->stats.lstats, 0, nlclasses *
2126 		    sizeof(malloc_large_stats_t));
2127 		if (config_tcache)
2128 			ql_new(&arena->tcache_ql);
2129 	}
2130 
2131 	if (config_prof)
2132 		arena->prof_accumbytes = 0;
2133 
2134 	arena->dss_prec = chunk_dss_prec_get();
2135 
2136 	/* Initialize chunks. */
2137 	arena_chunk_dirty_new(&arena->chunks_dirty);
2138 	arena->spare = NULL;
2139 
2140 	arena->nactive = 0;
2141 	arena->ndirty = 0;
2142 	arena->npurgatory = 0;
2143 
2144 	arena_avail_tree_new(&arena->runs_avail);
2145 
2146 	/* Initialize bins. */
2147 	for (i = 0; i < NBINS; i++) {
2148 		bin = &arena->bins[i];
2149 		if (malloc_mutex_init(&bin->lock))
2150 			return (true);
2151 		bin->runcur = NULL;
2152 		arena_run_tree_new(&bin->runs);
2153 		if (config_stats)
2154 			memset(&bin->stats, 0, sizeof(malloc_bin_stats_t));
2155 	}
2156 
2157 	return (false);
2158 }
2159 
2160 /*
2161  * Calculate bin_info->run_size such that it meets the following constraints:
2162  *
2163  *   *) bin_info->run_size >= min_run_size
2164  *   *) bin_info->run_size <= arena_maxclass
2165  *   *) run header overhead <= RUN_MAX_OVRHD (or header overhead relaxed).
2166  *   *) bin_info->nregs <= RUN_MAXREGS
2167  *
2168  * bin_info->nregs, bin_info->bitmap_offset, and bin_info->reg0_offset are also
2169  * calculated here, since these settings are all interdependent.
2170  */
2171 static size_t
2172 bin_info_run_size_calc(arena_bin_info_t *bin_info, size_t min_run_size)
2173 {
2174 	size_t pad_size;
2175 	size_t try_run_size, good_run_size;
2176 	uint32_t try_nregs, good_nregs;
2177 	uint32_t try_hdr_size, good_hdr_size;
2178 	uint32_t try_bitmap_offset, good_bitmap_offset;
2179 	uint32_t try_ctx0_offset, good_ctx0_offset;
2180 	uint32_t try_redzone0_offset, good_redzone0_offset;
2181 
2182 	assert(min_run_size >= PAGE);
2183 	assert(min_run_size <= arena_maxclass);
2184 
2185 	/*
2186 	 * Determine redzone size based on minimum alignment and minimum
2187 	 * redzone size.  Add padding to the end of the run if it is needed to
2188 	 * align the regions.  The padding allows each redzone to be half the
2189 	 * minimum alignment; without the padding, each redzone would have to
2190 	 * be twice as large in order to maintain alignment.
2191 	 */
2192 	if (config_fill && opt_redzone) {
2193 		size_t align_min = ZU(1) << (ffs(bin_info->reg_size) - 1);
2194 		if (align_min <= REDZONE_MINSIZE) {
2195 			bin_info->redzone_size = REDZONE_MINSIZE;
2196 			pad_size = 0;
2197 		} else {
2198 			bin_info->redzone_size = align_min >> 1;
2199 			pad_size = bin_info->redzone_size;
2200 		}
2201 	} else {
2202 		bin_info->redzone_size = 0;
2203 		pad_size = 0;
2204 	}
2205 	bin_info->reg_interval = bin_info->reg_size +
2206 	    (bin_info->redzone_size << 1);
2207 
2208 	/*
2209 	 * Calculate known-valid settings before entering the run_size
2210 	 * expansion loop, so that the first part of the loop always copies
2211 	 * valid settings.
2212 	 *
2213 	 * The do..while loop iteratively reduces the number of regions until
2214 	 * the run header and the regions no longer overlap.  A closed formula
2215 	 * would be quite messy, since there is an interdependency between the
2216 	 * header's mask length and the number of regions.
2217 	 */
2218 	try_run_size = min_run_size;
2219 	try_nregs = ((try_run_size - sizeof(arena_run_t)) /
2220 	    bin_info->reg_interval)
2221 	    + 1; /* Counter-act try_nregs-- in loop. */
2222 	if (try_nregs > RUN_MAXREGS) {
2223 		try_nregs = RUN_MAXREGS
2224 		    + 1; /* Counter-act try_nregs-- in loop. */
2225 	}
2226 	do {
2227 		try_nregs--;
2228 		try_hdr_size = sizeof(arena_run_t);
2229 		/* Pad to a long boundary. */
2230 		try_hdr_size = LONG_CEILING(try_hdr_size);
2231 		try_bitmap_offset = try_hdr_size;
2232 		/* Add space for bitmap. */
2233 		try_hdr_size += bitmap_size(try_nregs);
2234 		if (config_prof && opt_prof && prof_promote == false) {
2235 			/* Pad to a quantum boundary. */
2236 			try_hdr_size = QUANTUM_CEILING(try_hdr_size);
2237 			try_ctx0_offset = try_hdr_size;
2238 			/* Add space for one (prof_ctx_t *) per region. */
2239 			try_hdr_size += try_nregs * sizeof(prof_ctx_t *);
2240 		} else
2241 			try_ctx0_offset = 0;
2242 		try_redzone0_offset = try_run_size - (try_nregs *
2243 		    bin_info->reg_interval) - pad_size;
2244 	} while (try_hdr_size > try_redzone0_offset);
2245 
2246 	/* run_size expansion loop. */
2247 	do {
2248 		/*
2249 		 * Copy valid settings before trying more aggressive settings.
2250 		 */
2251 		good_run_size = try_run_size;
2252 		good_nregs = try_nregs;
2253 		good_hdr_size = try_hdr_size;
2254 		good_bitmap_offset = try_bitmap_offset;
2255 		good_ctx0_offset = try_ctx0_offset;
2256 		good_redzone0_offset = try_redzone0_offset;
2257 
2258 		/* Try more aggressive settings. */
2259 		try_run_size += PAGE;
2260 		try_nregs = ((try_run_size - sizeof(arena_run_t) - pad_size) /
2261 		    bin_info->reg_interval)
2262 		    + 1; /* Counter-act try_nregs-- in loop. */
2263 		if (try_nregs > RUN_MAXREGS) {
2264 			try_nregs = RUN_MAXREGS
2265 			    + 1; /* Counter-act try_nregs-- in loop. */
2266 		}
2267 		do {
2268 			try_nregs--;
2269 			try_hdr_size = sizeof(arena_run_t);
2270 			/* Pad to a long boundary. */
2271 			try_hdr_size = LONG_CEILING(try_hdr_size);
2272 			try_bitmap_offset = try_hdr_size;
2273 			/* Add space for bitmap. */
2274 			try_hdr_size += bitmap_size(try_nregs);
2275 			if (config_prof && opt_prof && prof_promote == false) {
2276 				/* Pad to a quantum boundary. */
2277 				try_hdr_size = QUANTUM_CEILING(try_hdr_size);
2278 				try_ctx0_offset = try_hdr_size;
2279 				/*
2280 				 * Add space for one (prof_ctx_t *) per region.
2281 				 */
2282 				try_hdr_size += try_nregs *
2283 				    sizeof(prof_ctx_t *);
2284 			}
2285 			try_redzone0_offset = try_run_size - (try_nregs *
2286 			    bin_info->reg_interval) - pad_size;
2287 		} while (try_hdr_size > try_redzone0_offset);
2288 	} while (try_run_size <= arena_maxclass
2289 	    && try_run_size <= arena_maxclass
2290 	    && RUN_MAX_OVRHD * (bin_info->reg_interval << 3) >
2291 	    RUN_MAX_OVRHD_RELAX
2292 	    && (try_redzone0_offset << RUN_BFP) > RUN_MAX_OVRHD * try_run_size
2293 	    && try_nregs < RUN_MAXREGS);
2294 
2295 	assert(good_hdr_size <= good_redzone0_offset);
2296 
2297 	/* Copy final settings. */
2298 	bin_info->run_size = good_run_size;
2299 	bin_info->nregs = good_nregs;
2300 	bin_info->bitmap_offset = good_bitmap_offset;
2301 	bin_info->ctx0_offset = good_ctx0_offset;
2302 	bin_info->reg0_offset = good_redzone0_offset + bin_info->redzone_size;
2303 
2304 	assert(bin_info->reg0_offset - bin_info->redzone_size + (bin_info->nregs
2305 	    * bin_info->reg_interval) + pad_size == bin_info->run_size);
2306 
2307 	return (good_run_size);
2308 }
2309 
2310 static void
2311 bin_info_init(void)
2312 {
2313 	arena_bin_info_t *bin_info;
2314 	size_t prev_run_size = PAGE;
2315 
2316 #define	SIZE_CLASS(bin, delta, size)					\
2317 	bin_info = &arena_bin_info[bin];				\
2318 	bin_info->reg_size = size;					\
2319 	prev_run_size = bin_info_run_size_calc(bin_info, prev_run_size);\
2320 	bitmap_info_init(&bin_info->bitmap_info, bin_info->nregs);
2321 	SIZE_CLASSES
2322 #undef SIZE_CLASS
2323 }
2324 
2325 void
2326 arena_boot(void)
2327 {
2328 	size_t header_size;
2329 	unsigned i;
2330 
2331 	/*
2332 	 * Compute the header size such that it is large enough to contain the
2333 	 * page map.  The page map is biased to omit entries for the header
2334 	 * itself, so some iteration is necessary to compute the map bias.
2335 	 *
2336 	 * 1) Compute safe header_size and map_bias values that include enough
2337 	 *    space for an unbiased page map.
2338 	 * 2) Refine map_bias based on (1) to omit the header pages in the page
2339 	 *    map.  The resulting map_bias may be one too small.
2340 	 * 3) Refine map_bias based on (2).  The result will be >= the result
2341 	 *    from (2), and will always be correct.
2342 	 */
2343 	map_bias = 0;
2344 	for (i = 0; i < 3; i++) {
2345 		header_size = offsetof(arena_chunk_t, map) +
2346 		    (sizeof(arena_chunk_map_t) * (chunk_npages-map_bias));
2347 		map_bias = (header_size >> LG_PAGE) + ((header_size & PAGE_MASK)
2348 		    != 0);
2349 	}
2350 	assert(map_bias > 0);
2351 
2352 	arena_maxclass = chunksize - (map_bias << LG_PAGE);
2353 
2354 	bin_info_init();
2355 }
2356 
2357 void
2358 arena_prefork(arena_t *arena)
2359 {
2360 	unsigned i;
2361 
2362 	malloc_mutex_prefork(&arena->lock);
2363 	for (i = 0; i < NBINS; i++)
2364 		malloc_mutex_prefork(&arena->bins[i].lock);
2365 }
2366 
2367 void
2368 arena_postfork_parent(arena_t *arena)
2369 {
2370 	unsigned i;
2371 
2372 	for (i = 0; i < NBINS; i++)
2373 		malloc_mutex_postfork_parent(&arena->bins[i].lock);
2374 	malloc_mutex_postfork_parent(&arena->lock);
2375 }
2376 
2377 void
2378 arena_postfork_child(arena_t *arena)
2379 {
2380 	unsigned i;
2381 
2382 	for (i = 0; i < NBINS; i++)
2383 		malloc_mutex_postfork_child(&arena->bins[i].lock);
2384 	malloc_mutex_postfork_child(&arena->lock);
2385 }
2386