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