blob: cc3e2ca6ccda2b63ac0676c48cfc8e4226d98b44 [file] [log] [blame]
Jason Evanse476f8a2010-01-16 09:53:50 -08001#define JEMALLOC_ARENA_C_
Jason Evansb0fd5012010-01-17 01:49:20 -08002#include "internal/jemalloc_internal.h"
Jason Evanse476f8a2010-01-16 09:53:50 -08003
4/******************************************************************************/
5/* Data. */
6
7size_t opt_lg_qspace_max = LG_QSPACE_MAX_DEFAULT;
8size_t opt_lg_cspace_max = LG_CSPACE_MAX_DEFAULT;
9size_t opt_lg_medium_max = LG_MEDIUM_MAX_DEFAULT;
10ssize_t opt_lg_dirty_mult = LG_DIRTY_MULT_DEFAULT;
11uint8_t const *small_size2bin;
12
13/* Various bin-related settings. */
14unsigned nqbins;
15unsigned ncbins;
16unsigned nsbins;
17unsigned nmbins;
18unsigned nbins;
19unsigned mbin0;
20size_t qspace_max;
21size_t cspace_min;
22size_t cspace_max;
23size_t sspace_min;
24size_t sspace_max;
25size_t medium_max;
26
27size_t lg_mspace;
28size_t mspace_mask;
29
30/*
31 * const_small_size2bin is a static constant lookup table that in the common
32 * case can be used as-is for small_size2bin. For dynamically linked programs,
33 * this avoids a page of memory overhead per process.
34 */
35#define S2B_1(i) i,
36#define S2B_2(i) S2B_1(i) S2B_1(i)
37#define S2B_4(i) S2B_2(i) S2B_2(i)
38#define S2B_8(i) S2B_4(i) S2B_4(i)
39#define S2B_16(i) S2B_8(i) S2B_8(i)
40#define S2B_32(i) S2B_16(i) S2B_16(i)
41#define S2B_64(i) S2B_32(i) S2B_32(i)
42#define S2B_128(i) S2B_64(i) S2B_64(i)
43#define S2B_256(i) S2B_128(i) S2B_128(i)
44/*
45 * The number of elements in const_small_size2bin is dependent on page size
46 * and on the definition for SUBPAGE. If SUBPAGE changes, the '- 255' must also
47 * change, along with the addition/removal of static lookup table element
48 * definitions.
49 */
50static const uint8_t const_small_size2bin[STATIC_PAGE_SIZE - 255] = {
51 S2B_1(0xffU) /* 0 */
52#if (LG_QUANTUM == 4)
53/* 64-bit system ************************/
54# ifdef JEMALLOC_TINY
55 S2B_2(0) /* 2 */
56 S2B_2(1) /* 4 */
57 S2B_4(2) /* 8 */
58 S2B_8(3) /* 16 */
59# define S2B_QMIN 3
60# else
61 S2B_16(0) /* 16 */
62# define S2B_QMIN 0
63# endif
64 S2B_16(S2B_QMIN + 1) /* 32 */
65 S2B_16(S2B_QMIN + 2) /* 48 */
66 S2B_16(S2B_QMIN + 3) /* 64 */
67 S2B_16(S2B_QMIN + 4) /* 80 */
68 S2B_16(S2B_QMIN + 5) /* 96 */
69 S2B_16(S2B_QMIN + 6) /* 112 */
70 S2B_16(S2B_QMIN + 7) /* 128 */
71# define S2B_CMIN (S2B_QMIN + 8)
72#else
73/* 32-bit system ************************/
74# ifdef JEMALLOC_TINY
75 S2B_2(0) /* 2 */
76 S2B_2(1) /* 4 */
77 S2B_4(2) /* 8 */
78# define S2B_QMIN 2
79# else
80 S2B_8(0) /* 8 */
81# define S2B_QMIN 0
82# endif
83 S2B_8(S2B_QMIN + 1) /* 16 */
84 S2B_8(S2B_QMIN + 2) /* 24 */
85 S2B_8(S2B_QMIN + 3) /* 32 */
86 S2B_8(S2B_QMIN + 4) /* 40 */
87 S2B_8(S2B_QMIN + 5) /* 48 */
88 S2B_8(S2B_QMIN + 6) /* 56 */
89 S2B_8(S2B_QMIN + 7) /* 64 */
90 S2B_8(S2B_QMIN + 8) /* 72 */
91 S2B_8(S2B_QMIN + 9) /* 80 */
92 S2B_8(S2B_QMIN + 10) /* 88 */
93 S2B_8(S2B_QMIN + 11) /* 96 */
94 S2B_8(S2B_QMIN + 12) /* 104 */
95 S2B_8(S2B_QMIN + 13) /* 112 */
96 S2B_8(S2B_QMIN + 14) /* 120 */
97 S2B_8(S2B_QMIN + 15) /* 128 */
98# define S2B_CMIN (S2B_QMIN + 16)
99#endif
100/****************************************/
101 S2B_64(S2B_CMIN + 0) /* 192 */
102 S2B_64(S2B_CMIN + 1) /* 256 */
103 S2B_64(S2B_CMIN + 2) /* 320 */
104 S2B_64(S2B_CMIN + 3) /* 384 */
105 S2B_64(S2B_CMIN + 4) /* 448 */
106 S2B_64(S2B_CMIN + 5) /* 512 */
107# define S2B_SMIN (S2B_CMIN + 6)
108 S2B_256(S2B_SMIN + 0) /* 768 */
109 S2B_256(S2B_SMIN + 1) /* 1024 */
110 S2B_256(S2B_SMIN + 2) /* 1280 */
111 S2B_256(S2B_SMIN + 3) /* 1536 */
112 S2B_256(S2B_SMIN + 4) /* 1792 */
113 S2B_256(S2B_SMIN + 5) /* 2048 */
114 S2B_256(S2B_SMIN + 6) /* 2304 */
115 S2B_256(S2B_SMIN + 7) /* 2560 */
116 S2B_256(S2B_SMIN + 8) /* 2816 */
117 S2B_256(S2B_SMIN + 9) /* 3072 */
118 S2B_256(S2B_SMIN + 10) /* 3328 */
119 S2B_256(S2B_SMIN + 11) /* 3584 */
120 S2B_256(S2B_SMIN + 12) /* 3840 */
121#if (STATIC_PAGE_SHIFT == 13)
122 S2B_256(S2B_SMIN + 13) /* 4096 */
123 S2B_256(S2B_SMIN + 14) /* 4352 */
124 S2B_256(S2B_SMIN + 15) /* 4608 */
125 S2B_256(S2B_SMIN + 16) /* 4864 */
126 S2B_256(S2B_SMIN + 17) /* 5120 */
127 S2B_256(S2B_SMIN + 18) /* 5376 */
128 S2B_256(S2B_SMIN + 19) /* 5632 */
129 S2B_256(S2B_SMIN + 20) /* 5888 */
130 S2B_256(S2B_SMIN + 21) /* 6144 */
131 S2B_256(S2B_SMIN + 22) /* 6400 */
132 S2B_256(S2B_SMIN + 23) /* 6656 */
133 S2B_256(S2B_SMIN + 24) /* 6912 */
134 S2B_256(S2B_SMIN + 25) /* 7168 */
135 S2B_256(S2B_SMIN + 26) /* 7424 */
136 S2B_256(S2B_SMIN + 27) /* 7680 */
137 S2B_256(S2B_SMIN + 28) /* 7936 */
138#endif
139};
140#undef S2B_1
141#undef S2B_2
142#undef S2B_4
143#undef S2B_8
144#undef S2B_16
145#undef S2B_32
146#undef S2B_64
147#undef S2B_128
148#undef S2B_256
149#undef S2B_QMIN
150#undef S2B_CMIN
151#undef S2B_SMIN
152
153/******************************************************************************/
154/* Function prototypes for non-inline static functions. */
155
156static void arena_run_split(arena_t *arena, arena_run_t *run, size_t size,
157 bool large, bool zero);
158static arena_chunk_t *arena_chunk_alloc(arena_t *arena);
159static void arena_chunk_dealloc(arena_t *arena, arena_chunk_t *chunk);
160static arena_run_t *arena_run_alloc(arena_t *arena, size_t size, bool large,
161 bool zero);
162static void arena_purge(arena_t *arena);
163static void arena_run_dalloc(arena_t *arena, arena_run_t *run, bool dirty);
164static void arena_run_trim_head(arena_t *arena, arena_chunk_t *chunk,
165 arena_run_t *run, size_t oldsize, size_t newsize);
166static void arena_run_trim_tail(arena_t *arena, arena_chunk_t *chunk,
167 arena_run_t *run, size_t oldsize, size_t newsize, bool dirty);
168static arena_run_t *arena_bin_nonfull_run_get(arena_t *arena, arena_bin_t *bin);
169static void *arena_bin_malloc_hard(arena_t *arena, arena_bin_t *bin);
170static size_t arena_bin_run_size_calc(arena_bin_t *bin, size_t min_run_size);
171static void *arena_malloc_large(arena_t *arena, size_t size, bool zero);
172static bool arena_is_large(const void *ptr);
173static void arena_dalloc_bin_run(arena_t *arena, arena_chunk_t *chunk,
174 arena_run_t *run, arena_bin_t *bin);
175static void arena_ralloc_large_shrink(arena_t *arena, arena_chunk_t *chunk,
176 void *ptr, size_t size, size_t oldsize);
177static bool arena_ralloc_large_grow(arena_t *arena, arena_chunk_t *chunk,
178 void *ptr, size_t size, size_t oldsize);
179static bool arena_ralloc_large(void *ptr, size_t size, size_t oldsize);
180#ifdef JEMALLOC_TINY
181static size_t pow2_ceil(size_t x);
182#endif
183static bool small_size2bin_init(void);
184#ifdef JEMALLOC_DEBUG
185static void small_size2bin_validate(void);
186#endif
187static bool small_size2bin_init_hard(void);
188
189/******************************************************************************/
190
191static inline int
192arena_chunk_comp(arena_chunk_t *a, arena_chunk_t *b)
193{
194 uintptr_t a_chunk = (uintptr_t)a;
195 uintptr_t b_chunk = (uintptr_t)b;
196
197 assert(a != NULL);
198 assert(b != NULL);
199
200 return ((a_chunk > b_chunk) - (a_chunk < b_chunk));
201}
202
203/* Wrap red-black tree macros in functions. */
204rb_wrap(static JEMALLOC_ATTR(unused), arena_chunk_tree_dirty_,
205 arena_chunk_tree_t, arena_chunk_t, link_dirty, arena_chunk_comp)
206
207static inline int
208arena_run_comp(arena_chunk_map_t *a, arena_chunk_map_t *b)
209{
210 uintptr_t a_mapelm = (uintptr_t)a;
211 uintptr_t b_mapelm = (uintptr_t)b;
212
213 assert(a != NULL);
214 assert(b != NULL);
215
216 return ((a_mapelm > b_mapelm) - (a_mapelm < b_mapelm));
217}
218
219/* Wrap red-black tree macros in functions. */
220rb_wrap(static JEMALLOC_ATTR(unused), arena_run_tree_, arena_run_tree_t,
221 arena_chunk_map_t, link, arena_run_comp)
222
223static inline int
224arena_avail_comp(arena_chunk_map_t *a, arena_chunk_map_t *b)
225{
226 int ret;
227 size_t a_size = a->bits & ~PAGE_MASK;
228 size_t b_size = b->bits & ~PAGE_MASK;
229
230 ret = (a_size > b_size) - (a_size < b_size);
231 if (ret == 0) {
232 uintptr_t a_mapelm, b_mapelm;
233
234 if ((a->bits & CHUNK_MAP_KEY) != CHUNK_MAP_KEY)
235 a_mapelm = (uintptr_t)a;
236 else {
237 /*
238 * Treat keys as though they are lower than anything
239 * else.
240 */
241 a_mapelm = 0;
242 }
243 b_mapelm = (uintptr_t)b;
244
245 ret = (a_mapelm > b_mapelm) - (a_mapelm < b_mapelm);
246 }
247
248 return (ret);
249}
250
251/* Wrap red-black tree macros in functions. */
252rb_wrap(static JEMALLOC_ATTR(unused), arena_avail_tree_, arena_avail_tree_t,
253 arena_chunk_map_t, link, arena_avail_comp)
254
255static inline void
256arena_run_rc_incr(arena_run_t *run, arena_bin_t *bin, const void *ptr)
257{
258 arena_chunk_t *chunk;
259 arena_t *arena;
260 size_t pagebeg, pageend, i;
261
262 chunk = (arena_chunk_t *)CHUNK_ADDR2BASE(ptr);
263 arena = chunk->arena;
264 pagebeg = ((uintptr_t)ptr - (uintptr_t)chunk) >> PAGE_SHIFT;
265 pageend = ((uintptr_t)ptr + (uintptr_t)(bin->reg_size - 1) -
266 (uintptr_t)chunk) >> PAGE_SHIFT;
267
268 for (i = pagebeg; i <= pageend; i++) {
269 size_t mapbits = chunk->map[i].bits;
270
271 if (mapbits & CHUNK_MAP_DIRTY) {
272 assert((mapbits & CHUNK_MAP_RC_MASK) == 0);
273 chunk->ndirty--;
274 arena->ndirty--;
275 mapbits ^= CHUNK_MAP_DIRTY;
276 }
277 assert((mapbits & CHUNK_MAP_RC_MASK) != CHUNK_MAP_RC_MASK);
278 mapbits += CHUNK_MAP_RC_ONE;
279 chunk->map[i].bits = mapbits;
280 }
281}
282
283static inline void
284arena_run_rc_decr(arena_run_t *run, arena_bin_t *bin, const void *ptr)
285{
286 arena_chunk_t *chunk;
287 arena_t *arena;
288 size_t pagebeg, pageend, mapbits, i;
289 bool dirtier = false;
290
291 chunk = (arena_chunk_t *)CHUNK_ADDR2BASE(ptr);
292 arena = chunk->arena;
293 pagebeg = ((uintptr_t)ptr - (uintptr_t)chunk) >> PAGE_SHIFT;
294 pageend = ((uintptr_t)ptr + (uintptr_t)(bin->reg_size - 1) -
295 (uintptr_t)chunk) >> PAGE_SHIFT;
296
297 /* First page. */
298 mapbits = chunk->map[pagebeg].bits;
299 mapbits -= CHUNK_MAP_RC_ONE;
300 if ((mapbits & CHUNK_MAP_RC_MASK) == 0) {
301 dirtier = true;
302 assert((mapbits & CHUNK_MAP_DIRTY) == 0);
303 mapbits |= CHUNK_MAP_DIRTY;
304 chunk->ndirty++;
305 arena->ndirty++;
306 }
307 chunk->map[pagebeg].bits = mapbits;
308
309 if (pageend - pagebeg >= 1) {
310 /*
311 * Interior pages are completely consumed by the object being
312 * deallocated, which means that the pages can be
313 * unconditionally marked dirty.
314 */
315 for (i = pagebeg + 1; i < pageend; i++) {
316 mapbits = chunk->map[i].bits;
317 mapbits -= CHUNK_MAP_RC_ONE;
318 assert((mapbits & CHUNK_MAP_RC_MASK) == 0);
319 dirtier = true;
320 assert((mapbits & CHUNK_MAP_DIRTY) == 0);
321 mapbits |= CHUNK_MAP_DIRTY;
322 chunk->ndirty++;
323 arena->ndirty++;
324 chunk->map[i].bits = mapbits;
325 }
326
327 /* Last page. */
328 mapbits = chunk->map[pageend].bits;
329 mapbits -= CHUNK_MAP_RC_ONE;
330 if ((mapbits & CHUNK_MAP_RC_MASK) == 0) {
331 dirtier = true;
332 assert((mapbits & CHUNK_MAP_DIRTY) == 0);
333 mapbits |= CHUNK_MAP_DIRTY;
334 chunk->ndirty++;
335 arena->ndirty++;
336 }
337 chunk->map[pageend].bits = mapbits;
338 }
339
340 if (dirtier) {
341 if (chunk->dirtied == false) {
342 arena_chunk_tree_dirty_insert(&arena->chunks_dirty,
343 chunk);
344 chunk->dirtied = true;
345 }
346
347 /* Enforce opt_lg_dirty_mult. */
348 if (opt_lg_dirty_mult >= 0 && (arena->nactive >>
349 opt_lg_dirty_mult) < arena->ndirty)
350 arena_purge(arena);
351 }
352}
353
354static inline void *
355arena_run_reg_alloc(arena_run_t *run, arena_bin_t *bin)
356{
357 void *ret;
358 unsigned i, mask, bit, regind;
359
360 assert(run->magic == ARENA_RUN_MAGIC);
361 assert(run->regs_minelm < bin->regs_mask_nelms);
362
363 /*
364 * Move the first check outside the loop, so that run->regs_minelm can
365 * be updated unconditionally, without the possibility of updating it
366 * multiple times.
367 */
368 i = run->regs_minelm;
369 mask = run->regs_mask[i];
370 if (mask != 0) {
371 /* Usable allocation found. */
372 bit = ffs((int)mask) - 1;
373
374 regind = ((i << (LG_SIZEOF_INT + 3)) + bit);
375 assert(regind < bin->nregs);
376 ret = (void *)(((uintptr_t)run) + bin->reg0_offset
377 + (bin->reg_size * regind));
378
379 /* Clear bit. */
380 mask ^= (1U << bit);
381 run->regs_mask[i] = mask;
382
383 arena_run_rc_incr(run, bin, ret);
384
385 return (ret);
386 }
387
388 for (i++; i < bin->regs_mask_nelms; i++) {
389 mask = run->regs_mask[i];
390 if (mask != 0) {
391 /* Usable allocation found. */
392 bit = ffs((int)mask) - 1;
393
394 regind = ((i << (LG_SIZEOF_INT + 3)) + bit);
395 assert(regind < bin->nregs);
396 ret = (void *)(((uintptr_t)run) + bin->reg0_offset
397 + (bin->reg_size * regind));
398
399 /* Clear bit. */
400 mask ^= (1U << bit);
401 run->regs_mask[i] = mask;
402
403 /*
404 * Make a note that nothing before this element
405 * contains a free region.
406 */
407 run->regs_minelm = i; /* Low payoff: + (mask == 0); */
408
409 arena_run_rc_incr(run, bin, ret);
410
411 return (ret);
412 }
413 }
414 /* Not reached. */
415 assert(0);
416 return (NULL);
417}
418
419static inline void
420arena_run_reg_dalloc(arena_run_t *run, arena_bin_t *bin, void *ptr, size_t size)
421{
422 unsigned shift, diff, regind, elm, bit;
423
424 assert(run->magic == ARENA_RUN_MAGIC);
425
426 /*
427 * Avoid doing division with a variable divisor if possible. Using
428 * actual division here can reduce allocator throughput by over 20%!
429 */
430 diff = (unsigned)((uintptr_t)ptr - (uintptr_t)run - bin->reg0_offset);
431
432 /* Rescale (factor powers of 2 out of the numerator and denominator). */
433 shift = ffs(size) - 1;
434 diff >>= shift;
435 size >>= shift;
436
437 if (size == 1) {
438 /* The divisor was a power of 2. */
439 regind = diff;
440 } else {
441 /*
442 * To divide by a number D that is not a power of two we
443 * multiply by (2^21 / D) and then right shift by 21 positions.
444 *
445 * X / D
446 *
447 * becomes
448 *
449 * (X * size_invs[D - 3]) >> SIZE_INV_SHIFT
450 *
451 * We can omit the first three elements, because we never
452 * divide by 0, and 1 and 2 are both powers of two, which are
453 * handled above.
454 */
455#define SIZE_INV_SHIFT 21
456#define SIZE_INV(s) (((1U << SIZE_INV_SHIFT) / (s)) + 1)
457 static const unsigned size_invs[] = {
458 SIZE_INV(3),
459 SIZE_INV(4), SIZE_INV(5), SIZE_INV(6), SIZE_INV(7),
460 SIZE_INV(8), SIZE_INV(9), SIZE_INV(10), SIZE_INV(11),
461 SIZE_INV(12), SIZE_INV(13), SIZE_INV(14), SIZE_INV(15),
462 SIZE_INV(16), SIZE_INV(17), SIZE_INV(18), SIZE_INV(19),
463 SIZE_INV(20), SIZE_INV(21), SIZE_INV(22), SIZE_INV(23),
464 SIZE_INV(24), SIZE_INV(25), SIZE_INV(26), SIZE_INV(27),
465 SIZE_INV(28), SIZE_INV(29), SIZE_INV(30), SIZE_INV(31)
466 };
467
468 if (size <= ((sizeof(size_invs) / sizeof(unsigned)) + 2))
469 regind = (diff * size_invs[size - 3]) >> SIZE_INV_SHIFT;
470 else
471 regind = diff / size;
472#undef SIZE_INV
473#undef SIZE_INV_SHIFT
474 }
475 assert(diff == regind * size);
476 assert(regind < bin->nregs);
477
478 elm = regind >> (LG_SIZEOF_INT + 3);
479 if (elm < run->regs_minelm)
480 run->regs_minelm = elm;
481 bit = regind - (elm << (LG_SIZEOF_INT + 3));
482 assert((run->regs_mask[elm] & (1U << bit)) == 0);
483 run->regs_mask[elm] |= (1U << bit);
484
485 arena_run_rc_decr(run, bin, ptr);
486}
487
488static void
489arena_run_split(arena_t *arena, arena_run_t *run, size_t size, bool large,
490 bool zero)
491{
492 arena_chunk_t *chunk;
493 size_t old_ndirty, run_ind, total_pages, need_pages, rem_pages, i;
494
495 chunk = (arena_chunk_t *)CHUNK_ADDR2BASE(run);
496 old_ndirty = chunk->ndirty;
497 run_ind = (unsigned)(((uintptr_t)run - (uintptr_t)chunk)
498 >> PAGE_SHIFT);
499 total_pages = (chunk->map[run_ind].bits & ~PAGE_MASK) >>
500 PAGE_SHIFT;
501 need_pages = (size >> PAGE_SHIFT);
502 assert(need_pages > 0);
503 assert(need_pages <= total_pages);
504 rem_pages = total_pages - need_pages;
505
506 arena_avail_tree_remove(&arena->runs_avail, &chunk->map[run_ind]);
507 arena->nactive += need_pages;
508
509 /* Keep track of trailing unused pages for later use. */
510 if (rem_pages > 0) {
511 chunk->map[run_ind+need_pages].bits = (rem_pages <<
512 PAGE_SHIFT) | (chunk->map[run_ind+need_pages].bits &
513 CHUNK_MAP_FLAGS_MASK);
514 chunk->map[run_ind+total_pages-1].bits = (rem_pages <<
515 PAGE_SHIFT) | (chunk->map[run_ind+total_pages-1].bits &
516 CHUNK_MAP_FLAGS_MASK);
517 arena_avail_tree_insert(&arena->runs_avail,
518 &chunk->map[run_ind+need_pages]);
519 }
520
521 for (i = 0; i < need_pages; i++) {
522 /* Zero if necessary. */
523 if (zero) {
524 if ((chunk->map[run_ind + i].bits & CHUNK_MAP_ZEROED)
525 == 0) {
526 memset((void *)((uintptr_t)chunk + ((run_ind
527 + i) << PAGE_SHIFT)), 0, PAGE_SIZE);
528 /* CHUNK_MAP_ZEROED is cleared below. */
529 }
530 }
531
532 /* Update dirty page accounting. */
533 if (chunk->map[run_ind + i].bits & CHUNK_MAP_DIRTY) {
534 chunk->ndirty--;
535 arena->ndirty--;
536 /* CHUNK_MAP_DIRTY is cleared below. */
537 }
538
539 /* Initialize the chunk map. */
540 if (large) {
541 chunk->map[run_ind + i].bits = CHUNK_MAP_LARGE
542 | CHUNK_MAP_ALLOCATED;
543 } else {
544 chunk->map[run_ind + i].bits = (i << CHUNK_MAP_PG_SHIFT)
545 | CHUNK_MAP_ALLOCATED;
546 }
547 }
548
549 if (large) {
550 /*
551 * Set the run size only in the first element for large runs.
552 * This is primarily a debugging aid, since the lack of size
553 * info for trailing pages only matters if the application
554 * tries to operate on an interior pointer.
555 */
556 chunk->map[run_ind].bits |= size;
557 } else {
558 /*
559 * Initialize the first page's refcount to 1, so that the run
560 * header is protected from dirty page purging.
561 */
562 chunk->map[run_ind].bits += CHUNK_MAP_RC_ONE;
563 }
564}
565
566static arena_chunk_t *
567arena_chunk_alloc(arena_t *arena)
568{
569 arena_chunk_t *chunk;
570 size_t i;
571
572 if (arena->spare != NULL) {
573 chunk = arena->spare;
574 arena->spare = NULL;
575 } else {
Jason Evans41631d02010-01-24 17:13:07 -0800576 bool zero;
577 size_t zeroed;
578
579 zero = false;
580 chunk = (arena_chunk_t *)chunk_alloc(chunksize, &zero);
Jason Evanse476f8a2010-01-16 09:53:50 -0800581 if (chunk == NULL)
582 return (NULL);
583#ifdef JEMALLOC_STATS
584 arena->stats.mapped += chunksize;
585#endif
586
587 chunk->arena = arena;
588 chunk->dirtied = false;
589
590 /*
591 * Claim that no pages are in use, since the header is merely
592 * overhead.
593 */
594 chunk->ndirty = 0;
595
596 /*
597 * Initialize the map to contain one maximal free untouched run.
Jason Evans41631d02010-01-24 17:13:07 -0800598 * Mark the pages as zeroed iff chunk_alloc() returned a zeroed
599 * chunk.
Jason Evanse476f8a2010-01-16 09:53:50 -0800600 */
Jason Evans41631d02010-01-24 17:13:07 -0800601 zeroed = zero ? CHUNK_MAP_ZEROED : 0;
Jason Evanse476f8a2010-01-16 09:53:50 -0800602 for (i = 0; i < arena_chunk_header_npages; i++)
603 chunk->map[i].bits = 0;
Jason Evans41631d02010-01-24 17:13:07 -0800604 chunk->map[i].bits = arena_maxclass | zeroed;
605 for (i++; i < chunk_npages-1; i++)
606 chunk->map[i].bits = zeroed;
607 chunk->map[chunk_npages-1].bits = arena_maxclass | zeroed;
Jason Evanse476f8a2010-01-16 09:53:50 -0800608 }
609
610 /* Insert the run into the runs_avail tree. */
611 arena_avail_tree_insert(&arena->runs_avail,
612 &chunk->map[arena_chunk_header_npages]);
613
614 return (chunk);
615}
616
617static void
618arena_chunk_dealloc(arena_t *arena, arena_chunk_t *chunk)
619{
620
621 if (arena->spare != NULL) {
622 if (arena->spare->dirtied) {
623 arena_chunk_tree_dirty_remove(
624 &chunk->arena->chunks_dirty, arena->spare);
625 arena->ndirty -= arena->spare->ndirty;
626 }
627 chunk_dealloc((void *)arena->spare, chunksize);
628#ifdef JEMALLOC_STATS
629 arena->stats.mapped -= chunksize;
630#endif
631 }
632
633 /*
634 * Remove run from runs_avail, regardless of whether this chunk
635 * will be cached, so that the arena does not use it. Dirty page
636 * flushing only uses the chunks_dirty tree, so leaving this chunk in
637 * the chunks_* trees is sufficient for that purpose.
638 */
639 arena_avail_tree_remove(&arena->runs_avail,
640 &chunk->map[arena_chunk_header_npages]);
641
642 arena->spare = chunk;
643}
644
645static arena_run_t *
646arena_run_alloc(arena_t *arena, size_t size, bool large, bool zero)
647{
648 arena_chunk_t *chunk;
649 arena_run_t *run;
650 arena_chunk_map_t *mapelm, key;
651
652 assert(size <= arena_maxclass);
653 assert((size & PAGE_MASK) == 0);
654
655 /* Search the arena's chunks for the lowest best fit. */
656 key.bits = size | CHUNK_MAP_KEY;
657 mapelm = arena_avail_tree_nsearch(&arena->runs_avail, &key);
658 if (mapelm != NULL) {
659 arena_chunk_t *run_chunk = CHUNK_ADDR2BASE(mapelm);
660 size_t pageind = ((uintptr_t)mapelm - (uintptr_t)run_chunk->map)
661 / sizeof(arena_chunk_map_t);
662
663 run = (arena_run_t *)((uintptr_t)run_chunk + (pageind
664 << PAGE_SHIFT));
665 arena_run_split(arena, run, size, large, zero);
666 return (run);
667 }
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 return (NULL);
675 run = (arena_run_t *)((uintptr_t)chunk + (arena_chunk_header_npages <<
676 PAGE_SHIFT));
677 /* Update page map. */
678 arena_run_split(arena, run, size, large, zero);
679 return (run);
680}
681
682static void
683arena_purge(arena_t *arena)
684{
685 arena_chunk_t *chunk;
686 size_t i, npages;
687#ifdef JEMALLOC_DEBUG
688 size_t ndirty = 0;
689
690 rb_foreach_begin(arena_chunk_t, link_dirty, &arena->chunks_dirty,
691 chunk) {
692 assert(chunk->dirtied);
693 ndirty += chunk->ndirty;
694 } rb_foreach_end(arena_chunk_t, link_dirty, &arena->chunks_dirty, chunk)
695 assert(ndirty == arena->ndirty);
696#endif
697 assert((arena->nactive >> opt_lg_dirty_mult) < arena->ndirty);
698
699#ifdef JEMALLOC_STATS
700 arena->stats.npurge++;
701#endif
702
703 /*
704 * Iterate downward through chunks until enough dirty memory has been
705 * purged. Terminate as soon as possible in order to minimize the
706 * number of system calls, even if a chunk has only been partially
707 * purged.
708 */
709
710 while ((arena->nactive >> (opt_lg_dirty_mult + 1)) < arena->ndirty) {
711 chunk = arena_chunk_tree_dirty_last(&arena->chunks_dirty);
712 assert(chunk != NULL);
713
714 for (i = chunk_npages - 1; chunk->ndirty > 0; i--) {
715 assert(i >= arena_chunk_header_npages);
716 if (chunk->map[i].bits & CHUNK_MAP_DIRTY) {
717 chunk->map[i].bits ^= CHUNK_MAP_DIRTY;
718 /* Find adjacent dirty run(s). */
719 for (npages = 1; i > arena_chunk_header_npages
720 && (chunk->map[i - 1].bits &
721 CHUNK_MAP_DIRTY); npages++) {
722 i--;
723 chunk->map[i].bits ^= CHUNK_MAP_DIRTY;
724 }
725 chunk->ndirty -= npages;
726 arena->ndirty -= npages;
727
728 madvise((void *)((uintptr_t)chunk + (i <<
729 PAGE_SHIFT)), (npages << PAGE_SHIFT),
730 MADV_DONTNEED);
731#ifdef JEMALLOC_STATS
732 arena->stats.nmadvise++;
733 arena->stats.purged += npages;
734#endif
735 if ((arena->nactive >> (opt_lg_dirty_mult + 1))
736 >= arena->ndirty)
737 break;
738 }
739 }
740
741 if (chunk->ndirty == 0) {
742 arena_chunk_tree_dirty_remove(&arena->chunks_dirty,
743 chunk);
744 chunk->dirtied = false;
745 }
746 }
747}
748
749static void
750arena_run_dalloc(arena_t *arena, arena_run_t *run, bool dirty)
751{
752 arena_chunk_t *chunk;
753 size_t size, run_ind, run_pages;
754
755 chunk = (arena_chunk_t *)CHUNK_ADDR2BASE(run);
756 run_ind = (size_t)(((uintptr_t)run - (uintptr_t)chunk)
757 >> PAGE_SHIFT);
758 assert(run_ind >= arena_chunk_header_npages);
759 assert(run_ind < chunk_npages);
760 if ((chunk->map[run_ind].bits & CHUNK_MAP_LARGE) != 0)
761 size = chunk->map[run_ind].bits & ~PAGE_MASK;
762 else
763 size = run->bin->run_size;
764 run_pages = (size >> PAGE_SHIFT);
765 arena->nactive -= run_pages;
766
767 /* Mark pages as unallocated in the chunk map. */
768 if (dirty) {
769 size_t i;
770
771 for (i = 0; i < run_pages; i++) {
772 /*
773 * When (dirty == true), *all* pages within the run
774 * need to have their dirty bits set, because only
775 * small runs can create a mixture of clean/dirty
776 * pages, but such runs are passed to this function
777 * with (dirty == false).
778 */
779 assert((chunk->map[run_ind + i].bits & CHUNK_MAP_DIRTY)
780 == 0);
781 chunk->ndirty++;
782 arena->ndirty++;
783 chunk->map[run_ind + i].bits = CHUNK_MAP_DIRTY;
784 }
785 } else {
786 size_t i;
787
788 for (i = 0; i < run_pages; i++) {
789 chunk->map[run_ind + i].bits &= ~(CHUNK_MAP_LARGE |
790 CHUNK_MAP_ALLOCATED);
791 }
792 }
793 chunk->map[run_ind].bits = size | (chunk->map[run_ind].bits &
794 CHUNK_MAP_FLAGS_MASK);
795 chunk->map[run_ind+run_pages-1].bits = size |
796 (chunk->map[run_ind+run_pages-1].bits & CHUNK_MAP_FLAGS_MASK);
797
798 /* Try to coalesce forward. */
799 if (run_ind + run_pages < chunk_npages &&
800 (chunk->map[run_ind+run_pages].bits & CHUNK_MAP_ALLOCATED) == 0) {
801 size_t nrun_size = chunk->map[run_ind+run_pages].bits &
802 ~PAGE_MASK;
803
804 /*
805 * Remove successor from runs_avail; the coalesced run is
806 * inserted later.
807 */
808 arena_avail_tree_remove(&arena->runs_avail,
809 &chunk->map[run_ind+run_pages]);
810
811 size += nrun_size;
812 run_pages = size >> PAGE_SHIFT;
813
814 assert((chunk->map[run_ind+run_pages-1].bits & ~PAGE_MASK)
815 == nrun_size);
816 chunk->map[run_ind].bits = size | (chunk->map[run_ind].bits &
817 CHUNK_MAP_FLAGS_MASK);
818 chunk->map[run_ind+run_pages-1].bits = size |
819 (chunk->map[run_ind+run_pages-1].bits &
820 CHUNK_MAP_FLAGS_MASK);
821 }
822
823 /* Try to coalesce backward. */
824 if (run_ind > arena_chunk_header_npages && (chunk->map[run_ind-1].bits &
825 CHUNK_MAP_ALLOCATED) == 0) {
826 size_t prun_size = chunk->map[run_ind-1].bits & ~PAGE_MASK;
827
828 run_ind -= prun_size >> PAGE_SHIFT;
829
830 /*
831 * Remove predecessor from runs_avail; the coalesced run is
832 * inserted later.
833 */
834 arena_avail_tree_remove(&arena->runs_avail,
835 &chunk->map[run_ind]);
836
837 size += prun_size;
838 run_pages = size >> PAGE_SHIFT;
839
840 assert((chunk->map[run_ind].bits & ~PAGE_MASK) == prun_size);
841 chunk->map[run_ind].bits = size | (chunk->map[run_ind].bits &
842 CHUNK_MAP_FLAGS_MASK);
843 chunk->map[run_ind+run_pages-1].bits = size |
844 (chunk->map[run_ind+run_pages-1].bits &
845 CHUNK_MAP_FLAGS_MASK);
846 }
847
848 /* Insert into runs_avail, now that coalescing is complete. */
849 arena_avail_tree_insert(&arena->runs_avail, &chunk->map[run_ind]);
850
Jason Evans4fb7f512010-01-27 18:27:09 -0800851 /*
852 * Deallocate chunk if it is now completely unused. The bit
853 * manipulation checks whether the first run is unallocated and extends
854 * to the end of the chunk.
855 */
Jason Evanse476f8a2010-01-16 09:53:50 -0800856 if ((chunk->map[arena_chunk_header_npages].bits & (~PAGE_MASK |
857 CHUNK_MAP_ALLOCATED)) == arena_maxclass)
858 arena_chunk_dealloc(arena, chunk);
859
Jason Evans4fb7f512010-01-27 18:27:09 -0800860 /*
861 * It is okay to do dirty page processing even if the chunk was
862 * deallocated above, since in that case it is the spare. Waiting
863 * until after possible chunk deallocation to do dirty processing
864 * allows for an old spare to be fully deallocated, thus decreasing the
865 * chances of spuriously crossing the dirty page purging threshold.
866 */
Jason Evanse476f8a2010-01-16 09:53:50 -0800867 if (dirty) {
868 if (chunk->dirtied == false) {
869 arena_chunk_tree_dirty_insert(&arena->chunks_dirty,
870 chunk);
871 chunk->dirtied = true;
872 }
873
874 /* Enforce opt_lg_dirty_mult. */
875 if (opt_lg_dirty_mult >= 0 && (arena->nactive >>
876 opt_lg_dirty_mult) < arena->ndirty)
877 arena_purge(arena);
878 }
879}
880
881static void
882arena_run_trim_head(arena_t *arena, arena_chunk_t *chunk, arena_run_t *run,
883 size_t oldsize, size_t newsize)
884{
885 size_t pageind = ((uintptr_t)run - (uintptr_t)chunk) >> PAGE_SHIFT;
886 size_t head_npages = (oldsize - newsize) >> PAGE_SHIFT;
887
888 assert(oldsize > newsize);
889
890 /*
891 * Update the chunk map so that arena_run_dalloc() can treat the
892 * leading run as separately allocated.
893 */
894 assert((chunk->map[pageind].bits & CHUNK_MAP_DIRTY) == 0);
895 chunk->map[pageind].bits = (oldsize - newsize) | CHUNK_MAP_LARGE |
896 CHUNK_MAP_ALLOCATED;
897 assert((chunk->map[pageind+head_npages].bits & CHUNK_MAP_DIRTY) == 0);
898 chunk->map[pageind+head_npages].bits = newsize | CHUNK_MAP_LARGE |
899 CHUNK_MAP_ALLOCATED;
900
901 arena_run_dalloc(arena, run, false);
902}
903
904static void
905arena_run_trim_tail(arena_t *arena, arena_chunk_t *chunk, arena_run_t *run,
906 size_t oldsize, size_t newsize, bool dirty)
907{
908 size_t pageind = ((uintptr_t)run - (uintptr_t)chunk) >> PAGE_SHIFT;
909 size_t npages = newsize >> PAGE_SHIFT;
910
911 assert(oldsize > newsize);
912
913 /*
914 * Update the chunk map so that arena_run_dalloc() can treat the
915 * trailing run as separately allocated.
916 */
917 assert((chunk->map[pageind].bits & CHUNK_MAP_DIRTY) == 0);
918 chunk->map[pageind].bits = newsize | CHUNK_MAP_LARGE |
919 CHUNK_MAP_ALLOCATED;
920 assert((chunk->map[pageind+npages].bits & CHUNK_MAP_DIRTY) == 0);
921 chunk->map[pageind+npages].bits = (oldsize - newsize) | CHUNK_MAP_LARGE
922 | CHUNK_MAP_ALLOCATED;
923
924 arena_run_dalloc(arena, (arena_run_t *)((uintptr_t)run + newsize),
925 dirty);
926}
927
928static arena_run_t *
929arena_bin_nonfull_run_get(arena_t *arena, arena_bin_t *bin)
930{
931 arena_chunk_map_t *mapelm;
932 arena_run_t *run;
933 unsigned i, remainder;
934
935 /* Look for a usable run. */
936 mapelm = arena_run_tree_first(&bin->runs);
937 if (mapelm != NULL) {
938 arena_chunk_t *chunk;
939 size_t pageind;
940
941 /* run is guaranteed to have available space. */
942 arena_run_tree_remove(&bin->runs, mapelm);
943
944 chunk = (arena_chunk_t *)CHUNK_ADDR2BASE(mapelm);
945 pageind = (((uintptr_t)mapelm - (uintptr_t)chunk->map) /
946 sizeof(arena_chunk_map_t));
947 run = (arena_run_t *)((uintptr_t)chunk + (uintptr_t)((pageind -
948 ((mapelm->bits & CHUNK_MAP_PG_MASK) >> CHUNK_MAP_PG_SHIFT))
949 << PAGE_SHIFT));
950#ifdef JEMALLOC_STATS
951 bin->stats.reruns++;
952#endif
953 return (run);
954 }
955 /* No existing runs have any space available. */
956
957 /* Allocate a new run. */
958 run = arena_run_alloc(arena, bin->run_size, false, false);
959 if (run == NULL)
960 return (NULL);
961
962 /* Initialize run internals. */
963 run->bin = bin;
964
965 for (i = 0; i < bin->regs_mask_nelms - 1; i++)
966 run->regs_mask[i] = UINT_MAX;
967 remainder = bin->nregs & ((1U << (LG_SIZEOF_INT + 3)) - 1);
968 if (remainder == 0)
969 run->regs_mask[i] = UINT_MAX;
970 else {
971 /* The last element has spare bits that need to be unset. */
972 run->regs_mask[i] = (UINT_MAX >> ((1U << (LG_SIZEOF_INT + 3))
973 - remainder));
974 }
975
976 run->regs_minelm = 0;
977
978 run->nfree = bin->nregs;
979#ifdef JEMALLOC_DEBUG
980 run->magic = ARENA_RUN_MAGIC;
981#endif
982
983#ifdef JEMALLOC_STATS
984 bin->stats.nruns++;
985 bin->stats.curruns++;
986 if (bin->stats.curruns > bin->stats.highruns)
987 bin->stats.highruns = bin->stats.curruns;
988#endif
989 return (run);
990}
991
992/* bin->runcur must have space available before this function is called. */
993static inline void *
994arena_bin_malloc_easy(arena_t *arena, arena_bin_t *bin, arena_run_t *run)
995{
996 void *ret;
997
998 assert(run->magic == ARENA_RUN_MAGIC);
999 assert(run->nfree > 0);
1000
1001 ret = arena_run_reg_alloc(run, bin);
1002 assert(ret != NULL);
1003 run->nfree--;
1004
1005 return (ret);
1006}
1007
1008/* Re-fill bin->runcur, then call arena_bin_malloc_easy(). */
1009static void *
1010arena_bin_malloc_hard(arena_t *arena, arena_bin_t *bin)
1011{
1012
1013 bin->runcur = arena_bin_nonfull_run_get(arena, bin);
1014 if (bin->runcur == NULL)
1015 return (NULL);
1016 assert(bin->runcur->magic == ARENA_RUN_MAGIC);
1017 assert(bin->runcur->nfree > 0);
1018
1019 return (arena_bin_malloc_easy(arena, bin, bin->runcur));
1020}
1021
1022#ifdef JEMALLOC_TCACHE
1023void
1024arena_tcache_fill(arena_t *arena, tcache_bin_t *tbin, size_t binind)
1025{
1026 unsigned i, nfill;
1027 arena_bin_t *bin;
1028 arena_run_t *run;
1029 void *ptr;
1030
1031 assert(tbin->ncached == 0);
1032
1033 bin = &arena->bins[binind];
1034 malloc_mutex_lock(&arena->lock);
1035 for (i = 0, nfill = (tcache_nslots >> 1); i < nfill; i++) {
1036 if ((run = bin->runcur) != NULL && run->nfree > 0)
1037 ptr = arena_bin_malloc_easy(arena, bin, run);
1038 else
1039 ptr = arena_bin_malloc_hard(arena, bin);
1040 if (ptr == NULL) {
1041 if (i > 0) {
1042 /*
1043 * Move valid pointers to the base of
1044 * tbin->slots.
1045 */
1046 memmove(&tbin->slots[0],
1047 &tbin->slots[nfill - i],
1048 i * sizeof(void *));
1049 }
1050 break;
1051 }
1052 /*
1053 * Fill slots such that the objects lowest in memory come last.
1054 * This causes tcache to use low objects first.
1055 */
1056 tbin->slots[nfill - 1 - i] = ptr;
1057 }
1058#ifdef JEMALLOC_STATS
1059 bin->stats.nfills++;
1060 bin->stats.nrequests += tbin->tstats.nrequests;
1061 if (bin->reg_size <= small_maxclass) {
1062 arena->stats.nmalloc_small += (i - tbin->ncached);
1063 arena->stats.allocated_small += (i - tbin->ncached) *
1064 bin->reg_size;
1065 arena->stats.nmalloc_small += tbin->tstats.nrequests;
1066 } else {
1067 arena->stats.nmalloc_medium += (i - tbin->ncached);
1068 arena->stats.allocated_medium += (i - tbin->ncached) *
1069 bin->reg_size;
1070 arena->stats.nmalloc_medium += tbin->tstats.nrequests;
1071 }
1072 tbin->tstats.nrequests = 0;
1073#endif
1074 malloc_mutex_unlock(&arena->lock);
1075 tbin->ncached = i;
1076 if (tbin->ncached > tbin->high_water)
1077 tbin->high_water = tbin->ncached;
1078}
1079#endif
1080
1081/*
1082 * Calculate bin->run_size such that it meets the following constraints:
1083 *
1084 * *) bin->run_size >= min_run_size
1085 * *) bin->run_size <= arena_maxclass
1086 * *) bin->run_size <= RUN_MAX_SMALL
1087 * *) run header overhead <= RUN_MAX_OVRHD (or header overhead relaxed).
1088 * *) run header size < PAGE_SIZE
1089 *
1090 * bin->nregs, bin->regs_mask_nelms, and bin->reg0_offset are
1091 * also calculated here, since these settings are all interdependent.
1092 */
1093static size_t
1094arena_bin_run_size_calc(arena_bin_t *bin, size_t min_run_size)
1095{
1096 size_t try_run_size, good_run_size;
1097 unsigned good_nregs, good_mask_nelms, good_reg0_offset;
1098 unsigned try_nregs, try_mask_nelms, try_reg0_offset;
1099
1100 assert(min_run_size >= PAGE_SIZE);
1101 assert(min_run_size <= arena_maxclass);
1102 assert(min_run_size <= RUN_MAX_SMALL);
1103
1104 /*
1105 * Calculate known-valid settings before entering the run_size
1106 * expansion loop, so that the first part of the loop always copies
1107 * valid settings.
1108 *
1109 * The do..while loop iteratively reduces the number of regions until
1110 * the run header and the regions no longer overlap. A closed formula
1111 * would be quite messy, since there is an interdependency between the
1112 * header's mask length and the number of regions.
1113 */
1114 try_run_size = min_run_size;
1115 try_nregs = ((try_run_size - sizeof(arena_run_t)) / bin->reg_size)
1116 + 1; /* Counter-act try_nregs-- in loop. */
1117 do {
1118 try_nregs--;
1119 try_mask_nelms = (try_nregs >> (LG_SIZEOF_INT + 3)) +
1120 ((try_nregs & ((1U << (LG_SIZEOF_INT + 3)) - 1)) ? 1 : 0);
1121 try_reg0_offset = try_run_size - (try_nregs * bin->reg_size);
1122 } while (sizeof(arena_run_t) + (sizeof(unsigned) * (try_mask_nelms - 1))
1123 > try_reg0_offset);
1124
1125 /* run_size expansion loop. */
1126 do {
1127 /*
1128 * Copy valid settings before trying more aggressive settings.
1129 */
1130 good_run_size = try_run_size;
1131 good_nregs = try_nregs;
1132 good_mask_nelms = try_mask_nelms;
1133 good_reg0_offset = try_reg0_offset;
1134
1135 /* Try more aggressive settings. */
1136 try_run_size += PAGE_SIZE;
1137 try_nregs = ((try_run_size - sizeof(arena_run_t)) /
1138 bin->reg_size) + 1; /* Counter-act try_nregs-- in loop. */
1139 do {
1140 try_nregs--;
1141 try_mask_nelms = (try_nregs >> (LG_SIZEOF_INT + 3)) +
1142 ((try_nregs & ((1U << (LG_SIZEOF_INT + 3)) - 1)) ?
1143 1 : 0);
1144 try_reg0_offset = try_run_size - (try_nregs *
1145 bin->reg_size);
1146 } while (sizeof(arena_run_t) + (sizeof(unsigned) *
1147 (try_mask_nelms - 1)) > try_reg0_offset);
1148 } while (try_run_size <= arena_maxclass && try_run_size <= RUN_MAX_SMALL
1149 && RUN_MAX_OVRHD * (bin->reg_size << 3) > RUN_MAX_OVRHD_RELAX
1150 && (try_reg0_offset << RUN_BFP) > RUN_MAX_OVRHD * try_run_size
1151 && (sizeof(arena_run_t) + (sizeof(unsigned) * (try_mask_nelms - 1)))
1152 < PAGE_SIZE);
1153
1154 assert(sizeof(arena_run_t) + (sizeof(unsigned) * (good_mask_nelms - 1))
1155 <= good_reg0_offset);
1156 assert((good_mask_nelms << (LG_SIZEOF_INT + 3)) >= good_nregs);
1157
1158 /* Copy final settings. */
1159 bin->run_size = good_run_size;
1160 bin->nregs = good_nregs;
1161 bin->regs_mask_nelms = good_mask_nelms;
1162 bin->reg0_offset = good_reg0_offset;
1163
1164 return (good_run_size);
1165}
1166
1167void *
1168arena_malloc_small(arena_t *arena, size_t size, bool zero)
1169{
1170 void *ret;
1171 arena_bin_t *bin;
1172 arena_run_t *run;
1173 size_t binind;
1174
1175 binind = small_size2bin[size];
1176 assert(binind < mbin0);
1177 bin = &arena->bins[binind];
1178 size = bin->reg_size;
1179
1180 malloc_mutex_lock(&arena->lock);
1181 if ((run = bin->runcur) != NULL && run->nfree > 0)
1182 ret = arena_bin_malloc_easy(arena, bin, run);
1183 else
1184 ret = arena_bin_malloc_hard(arena, bin);
1185
1186 if (ret == NULL) {
1187 malloc_mutex_unlock(&arena->lock);
1188 return (NULL);
1189 }
1190
1191#ifdef JEMALLOC_STATS
1192# ifdef JEMALLOC_TCACHE
1193 if (isthreaded == false) {
1194# endif
1195 bin->stats.nrequests++;
1196 arena->stats.nmalloc_small++;
1197# ifdef JEMALLOC_TCACHE
1198 }
1199# endif
1200 arena->stats.allocated_small += size;
1201#endif
1202 malloc_mutex_unlock(&arena->lock);
1203
1204 if (zero == false) {
1205#ifdef JEMALLOC_FILL
1206 if (opt_junk)
1207 memset(ret, 0xa5, size);
1208 else if (opt_zero)
1209 memset(ret, 0, size);
1210#endif
1211 } else
1212 memset(ret, 0, size);
1213
1214 return (ret);
1215}
1216
1217void *
1218arena_malloc_medium(arena_t *arena, size_t size, bool zero)
1219{
1220 void *ret;
1221 arena_bin_t *bin;
1222 arena_run_t *run;
1223 size_t binind;
1224
1225 size = MEDIUM_CEILING(size);
1226 binind = mbin0 + ((size - medium_min) >> lg_mspace);
1227 assert(binind < nbins);
1228 bin = &arena->bins[binind];
1229 assert(bin->reg_size == size);
1230
1231 malloc_mutex_lock(&arena->lock);
1232 if ((run = bin->runcur) != NULL && run->nfree > 0)
1233 ret = arena_bin_malloc_easy(arena, bin, run);
1234 else
1235 ret = arena_bin_malloc_hard(arena, bin);
1236
1237 if (ret == NULL) {
1238 malloc_mutex_unlock(&arena->lock);
1239 return (NULL);
1240 }
1241
1242#ifdef JEMALLOC_STATS
1243# ifdef JEMALLOC_TCACHE
1244 if (isthreaded == false) {
1245# endif
1246 bin->stats.nrequests++;
1247 arena->stats.nmalloc_medium++;
1248# ifdef JEMALLOC_TCACHE
1249 }
1250# endif
1251 arena->stats.allocated_medium += size;
1252#endif
1253 malloc_mutex_unlock(&arena->lock);
1254
1255 if (zero == false) {
1256#ifdef JEMALLOC_FILL
1257 if (opt_junk)
1258 memset(ret, 0xa5, size);
1259 else if (opt_zero)
1260 memset(ret, 0, size);
1261#endif
1262 } else
1263 memset(ret, 0, size);
1264
1265 return (ret);
1266}
1267
1268static void *
1269arena_malloc_large(arena_t *arena, size_t size, bool zero)
1270{
1271 void *ret;
1272
1273 /* Large allocation. */
1274 size = PAGE_CEILING(size);
1275 malloc_mutex_lock(&arena->lock);
1276 ret = (void *)arena_run_alloc(arena, size, true, zero);
1277 if (ret == NULL) {
1278 malloc_mutex_unlock(&arena->lock);
1279 return (NULL);
1280 }
1281#ifdef JEMALLOC_STATS
1282 arena->stats.nmalloc_large++;
1283 arena->stats.allocated_large += size;
1284 arena->stats.lstats[(size >> PAGE_SHIFT) - 1].nrequests++;
1285 arena->stats.lstats[(size >> PAGE_SHIFT) - 1].curruns++;
1286 if (arena->stats.lstats[(size >> PAGE_SHIFT) - 1].curruns >
1287 arena->stats.lstats[(size >> PAGE_SHIFT) - 1].highruns) {
1288 arena->stats.lstats[(size >> PAGE_SHIFT) - 1].highruns =
1289 arena->stats.lstats[(size >> PAGE_SHIFT) - 1].curruns;
1290 }
1291#endif
1292 malloc_mutex_unlock(&arena->lock);
1293
1294 if (zero == false) {
1295#ifdef JEMALLOC_FILL
1296 if (opt_junk)
1297 memset(ret, 0xa5, size);
1298 else if (opt_zero)
1299 memset(ret, 0, size);
1300#endif
1301 }
1302
1303 return (ret);
1304}
1305
1306void *
1307arena_malloc(size_t size, bool zero)
1308{
1309
1310 assert(size != 0);
1311 assert(QUANTUM_CEILING(size) <= arena_maxclass);
1312
1313 if (size <= bin_maxclass) {
1314#ifdef JEMALLOC_TCACHE
1315 tcache_t *tcache;
1316
1317 if ((tcache = tcache_get()) != NULL)
1318 return (tcache_alloc(tcache, size, zero));
1319#endif
1320 if (size <= small_maxclass)
1321 return (arena_malloc_small(choose_arena(), size, zero));
1322 else {
1323 return (arena_malloc_medium(choose_arena(), size,
1324 zero));
1325 }
1326 } else
1327 return (arena_malloc_large(choose_arena(), size, zero));
1328}
1329
1330/* Only handles large allocations that require more than page alignment. */
1331void *
1332arena_palloc(arena_t *arena, size_t alignment, size_t size, size_t alloc_size)
1333{
1334 void *ret;
1335 size_t offset;
1336 arena_chunk_t *chunk;
1337
1338 assert((size & PAGE_MASK) == 0);
1339 assert((alignment & PAGE_MASK) == 0);
1340
1341 malloc_mutex_lock(&arena->lock);
1342 ret = (void *)arena_run_alloc(arena, alloc_size, true, false);
1343 if (ret == NULL) {
1344 malloc_mutex_unlock(&arena->lock);
1345 return (NULL);
1346 }
1347
1348 chunk = (arena_chunk_t *)CHUNK_ADDR2BASE(ret);
1349
1350 offset = (uintptr_t)ret & (alignment - 1);
1351 assert((offset & PAGE_MASK) == 0);
1352 assert(offset < alloc_size);
1353 if (offset == 0)
1354 arena_run_trim_tail(arena, chunk, ret, alloc_size, size, false);
1355 else {
1356 size_t leadsize, trailsize;
1357
1358 leadsize = alignment - offset;
1359 if (leadsize > 0) {
1360 arena_run_trim_head(arena, chunk, ret, alloc_size,
1361 alloc_size - leadsize);
1362 ret = (void *)((uintptr_t)ret + leadsize);
1363 }
1364
1365 trailsize = alloc_size - leadsize - size;
1366 if (trailsize != 0) {
1367 /* Trim trailing space. */
1368 assert(trailsize < alloc_size);
1369 arena_run_trim_tail(arena, chunk, ret, size + trailsize,
1370 size, false);
1371 }
1372 }
1373
1374#ifdef JEMALLOC_STATS
1375 arena->stats.nmalloc_large++;
1376 arena->stats.allocated_large += size;
1377 arena->stats.lstats[(size >> PAGE_SHIFT) - 1].nrequests++;
1378 arena->stats.lstats[(size >> PAGE_SHIFT) - 1].curruns++;
1379 if (arena->stats.lstats[(size >> PAGE_SHIFT) - 1].curruns >
1380 arena->stats.lstats[(size >> PAGE_SHIFT) - 1].highruns) {
1381 arena->stats.lstats[(size >> PAGE_SHIFT) - 1].highruns =
1382 arena->stats.lstats[(size >> PAGE_SHIFT) - 1].curruns;
1383 }
1384#endif
1385 malloc_mutex_unlock(&arena->lock);
1386
1387#ifdef JEMALLOC_FILL
1388 if (opt_junk)
1389 memset(ret, 0xa5, size);
1390 else if (opt_zero)
1391 memset(ret, 0, size);
1392#endif
1393 return (ret);
1394}
1395
1396static bool
1397arena_is_large(const void *ptr)
1398{
1399 arena_chunk_t *chunk;
1400 size_t pageind, mapbits;
1401
1402 assert(ptr != NULL);
1403 assert(CHUNK_ADDR2BASE(ptr) != ptr);
1404
1405 chunk = (arena_chunk_t *)CHUNK_ADDR2BASE(ptr);
1406 pageind = (((uintptr_t)ptr - (uintptr_t)chunk) >> PAGE_SHIFT);
1407 mapbits = chunk->map[pageind].bits;
1408 assert((mapbits & CHUNK_MAP_ALLOCATED) != 0);
1409 return ((mapbits & CHUNK_MAP_LARGE) != 0);
1410}
1411
1412/* Return the size of the allocation pointed to by ptr. */
1413size_t
1414arena_salloc(const void *ptr)
1415{
1416 size_t ret;
1417 arena_chunk_t *chunk;
1418 size_t pageind, mapbits;
1419
1420 assert(ptr != NULL);
1421 assert(CHUNK_ADDR2BASE(ptr) != ptr);
1422
1423 chunk = (arena_chunk_t *)CHUNK_ADDR2BASE(ptr);
1424 pageind = (((uintptr_t)ptr - (uintptr_t)chunk) >> PAGE_SHIFT);
1425 mapbits = chunk->map[pageind].bits;
1426 assert((mapbits & CHUNK_MAP_ALLOCATED) != 0);
1427 if ((mapbits & CHUNK_MAP_LARGE) == 0) {
1428 arena_run_t *run = (arena_run_t *)((uintptr_t)chunk +
1429 (uintptr_t)((pageind - ((mapbits & CHUNK_MAP_PG_MASK) >>
1430 CHUNK_MAP_PG_SHIFT)) << PAGE_SHIFT));
1431 assert(run->magic == ARENA_RUN_MAGIC);
1432 ret = run->bin->reg_size;
1433 } else {
1434 ret = mapbits & ~PAGE_MASK;
1435 assert(ret != 0);
1436 }
1437
1438 return (ret);
1439}
1440
1441static void
1442arena_dalloc_bin_run(arena_t *arena, arena_chunk_t *chunk, arena_run_t *run,
1443 arena_bin_t *bin)
1444{
1445 size_t run_ind;
1446
1447 /* Deallocate run. */
1448 if (run == bin->runcur)
1449 bin->runcur = NULL;
1450 else if (bin->nregs != 1) {
1451 size_t run_pageind = (((uintptr_t)run -
1452 (uintptr_t)chunk)) >> PAGE_SHIFT;
1453 arena_chunk_map_t *run_mapelm =
1454 &chunk->map[run_pageind];
1455 /*
1456 * This block's conditional is necessary because if the
1457 * run only contains one region, then it never gets
1458 * inserted into the non-full runs tree.
1459 */
1460 arena_run_tree_remove(&bin->runs, run_mapelm);
1461 }
1462 /*
1463 * Mark the first page as dirty. The dirty bit for every other page in
1464 * the run is already properly set, which means we can call
1465 * arena_run_dalloc(..., false), thus potentially avoiding the needless
1466 * creation of many dirty pages.
1467 */
1468 run_ind = (size_t)(((uintptr_t)run - (uintptr_t)chunk) >> PAGE_SHIFT);
1469 assert((chunk->map[run_ind].bits & CHUNK_MAP_DIRTY) == 0);
1470 chunk->map[run_ind].bits |= CHUNK_MAP_DIRTY;
1471 chunk->ndirty++;
1472 arena->ndirty++;
1473
1474#ifdef JEMALLOC_DEBUG
1475 run->magic = 0;
1476#endif
1477 arena_run_dalloc(arena, run, false);
1478#ifdef JEMALLOC_STATS
1479 bin->stats.curruns--;
1480#endif
1481
1482 if (chunk->dirtied == false) {
1483 arena_chunk_tree_dirty_insert(&arena->chunks_dirty, chunk);
1484 chunk->dirtied = true;
1485 }
1486 /* Enforce opt_lg_dirty_mult. */
1487 if (opt_lg_dirty_mult >= 0 && (arena->nactive >> opt_lg_dirty_mult) <
1488 arena->ndirty)
1489 arena_purge(arena);
1490}
1491
1492void
1493arena_dalloc_bin(arena_t *arena, arena_chunk_t *chunk, void *ptr,
1494 arena_chunk_map_t *mapelm)
1495{
1496 size_t pageind;
1497 arena_run_t *run;
1498 arena_bin_t *bin;
1499 size_t size;
1500
1501 pageind = (((uintptr_t)ptr - (uintptr_t)chunk) >> PAGE_SHIFT);
1502 run = (arena_run_t *)((uintptr_t)chunk + (uintptr_t)((pageind -
1503 ((mapelm->bits & CHUNK_MAP_PG_MASK) >> CHUNK_MAP_PG_SHIFT)) <<
1504 PAGE_SHIFT));
1505 assert(run->magic == ARENA_RUN_MAGIC);
1506 bin = run->bin;
1507 size = bin->reg_size;
1508
1509#ifdef JEMALLOC_FILL
1510 if (opt_junk)
1511 memset(ptr, 0x5a, size);
1512#endif
1513
1514 arena_run_reg_dalloc(run, bin, ptr, size);
1515 run->nfree++;
1516
1517 if (run->nfree == bin->nregs)
1518 arena_dalloc_bin_run(arena, chunk, run, bin);
1519 else if (run->nfree == 1 && run != bin->runcur) {
1520 /*
1521 * Make sure that bin->runcur always refers to the lowest
1522 * non-full run, if one exists.
1523 */
1524 if (bin->runcur == NULL)
1525 bin->runcur = run;
1526 else if ((uintptr_t)run < (uintptr_t)bin->runcur) {
1527 /* Switch runcur. */
1528 if (bin->runcur->nfree > 0) {
1529 arena_chunk_t *runcur_chunk =
1530 CHUNK_ADDR2BASE(bin->runcur);
1531 size_t runcur_pageind =
1532 (((uintptr_t)bin->runcur -
1533 (uintptr_t)runcur_chunk)) >> PAGE_SHIFT;
1534 arena_chunk_map_t *runcur_mapelm =
1535 &runcur_chunk->map[runcur_pageind];
1536
1537 /* Insert runcur. */
1538 arena_run_tree_insert(&bin->runs,
1539 runcur_mapelm);
1540 }
1541 bin->runcur = run;
1542 } else {
1543 size_t run_pageind = (((uintptr_t)run -
1544 (uintptr_t)chunk)) >> PAGE_SHIFT;
1545 arena_chunk_map_t *run_mapelm =
1546 &chunk->map[run_pageind];
1547
1548 assert(arena_run_tree_search(&bin->runs, run_mapelm) ==
1549 NULL);
1550 arena_run_tree_insert(&bin->runs, run_mapelm);
1551 }
1552 }
1553
1554#ifdef JEMALLOC_STATS
1555 if (size <= small_maxclass) {
1556 arena->stats.allocated_small -= size;
1557 arena->stats.ndalloc_small++;
1558 } else {
1559 arena->stats.allocated_medium -= size;
1560 arena->stats.ndalloc_medium++;
1561 }
1562#endif
1563}
1564
1565#ifdef JEMALLOC_STATS
1566void
Jason Evansb34e8682010-01-17 17:35:19 -08001567arena_stats_merge(arena_t *arena, size_t *nactive, size_t *ndirty,
1568 arena_stats_t *astats, malloc_bin_stats_t *bstats,
1569 malloc_large_stats_t *lstats)
1570{
Jason Evans3c234352010-01-27 13:10:55 -08001571 unsigned i;
Jason Evansb34e8682010-01-17 17:35:19 -08001572
1573 *nactive += arena->nactive;
1574 *ndirty += arena->ndirty;
1575
Jason Evans4201af02010-01-24 02:53:40 -08001576 astats->mapped += arena->stats.mapped;
Jason Evansb34e8682010-01-17 17:35:19 -08001577 astats->npurge += arena->stats.npurge;
1578 astats->nmadvise += arena->stats.nmadvise;
1579 astats->purged += arena->stats.purged;
1580 astats->allocated_small += arena->stats.allocated_small;
1581 astats->nmalloc_small += arena->stats.nmalloc_small;
1582 astats->ndalloc_small += arena->stats.ndalloc_small;
1583 astats->allocated_medium += arena->stats.allocated_medium;
1584 astats->nmalloc_medium += arena->stats.nmalloc_medium;
1585 astats->ndalloc_medium += arena->stats.ndalloc_medium;
1586 astats->allocated_large += arena->stats.allocated_large;
1587 astats->nmalloc_large += arena->stats.nmalloc_large;
1588 astats->ndalloc_large += arena->stats.ndalloc_large;
1589
1590 for (i = 0; i < nbins; i++) {
1591 bstats[i].nrequests += arena->bins[i].stats.nrequests;
1592#ifdef JEMALLOC_TCACHE
1593 bstats[i].nfills += arena->bins[i].stats.nfills;
1594 bstats[i].nflushes += arena->bins[i].stats.nflushes;
1595#endif
1596 bstats[i].nruns += arena->bins[i].stats.nruns;
1597 bstats[i].reruns += arena->bins[i].stats.reruns;
1598 bstats[i].highruns += arena->bins[i].stats.highruns;
1599 bstats[i].curruns += arena->bins[i].stats.curruns;
1600 }
1601
Jason Evans3c234352010-01-27 13:10:55 -08001602 for (i = 0; i < nlclasses; i++) {
Jason Evansb34e8682010-01-17 17:35:19 -08001603 lstats[i].nrequests += arena->stats.lstats[i].nrequests;
1604 lstats[i].highruns += arena->stats.lstats[i].highruns;
1605 lstats[i].curruns += arena->stats.lstats[i].curruns;
1606 }
1607}
Jason Evanse476f8a2010-01-16 09:53:50 -08001608#endif
1609
1610void
1611arena_dalloc_large(arena_t *arena, arena_chunk_t *chunk, void *ptr)
1612{
Jason Evans13668262010-01-31 03:57:29 -08001613
Jason Evanse476f8a2010-01-16 09:53:50 -08001614 /* Large allocation. */
1615 malloc_mutex_lock(&arena->lock);
1616
1617#ifdef JEMALLOC_FILL
Jason Evans990d10c2010-01-31 03:49:35 -08001618# ifndef JEMALLOC_STATS
Jason Evanse476f8a2010-01-16 09:53:50 -08001619 if (opt_junk)
Jason Evans990d10c2010-01-31 03:49:35 -08001620# endif
Jason Evanse476f8a2010-01-16 09:53:50 -08001621#endif
1622 {
1623#if (defined(JEMALLOC_FILL) || defined(JEMALLOC_STATS))
1624 size_t pageind = ((uintptr_t)ptr - (uintptr_t)chunk) >>
1625 PAGE_SHIFT;
1626 size_t size = chunk->map[pageind].bits & ~PAGE_MASK;
1627#endif
1628
1629#ifdef JEMALLOC_FILL
Jason Evans990d10c2010-01-31 03:49:35 -08001630# ifdef JEMALLOC_STATS
Jason Evanse476f8a2010-01-16 09:53:50 -08001631 if (opt_junk)
Jason Evans990d10c2010-01-31 03:49:35 -08001632# endif
Jason Evanse476f8a2010-01-16 09:53:50 -08001633 memset(ptr, 0x5a, size);
1634#endif
1635#ifdef JEMALLOC_STATS
Jason Evans990d10c2010-01-31 03:49:35 -08001636 arena->stats.ndalloc_large++;
Jason Evanse476f8a2010-01-16 09:53:50 -08001637 arena->stats.allocated_large -= size;
1638 arena->stats.lstats[(size >> PAGE_SHIFT) - 1].curruns--;
1639#endif
1640 }
Jason Evanse476f8a2010-01-16 09:53:50 -08001641
1642 arena_run_dalloc(arena, (arena_run_t *)ptr, true);
1643 malloc_mutex_unlock(&arena->lock);
1644}
1645
1646static void
1647arena_ralloc_large_shrink(arena_t *arena, arena_chunk_t *chunk, void *ptr,
1648 size_t size, size_t oldsize)
1649{
1650
1651 assert(size < oldsize);
1652
1653 /*
1654 * Shrink the run, and make trailing pages available for other
1655 * allocations.
1656 */
1657 malloc_mutex_lock(&arena->lock);
1658 arena_run_trim_tail(arena, chunk, (arena_run_t *)ptr, oldsize, size,
1659 true);
1660#ifdef JEMALLOC_STATS
Jason Evans990d10c2010-01-31 03:49:35 -08001661 arena->stats.ndalloc_large++;
1662 arena->stats.allocated_large -= oldsize;
1663 arena->stats.lstats[(oldsize >> PAGE_SHIFT) - 1].curruns--;
1664
1665 arena->stats.nmalloc_large++;
1666 arena->stats.allocated_large += size;
1667 arena->stats.lstats[(size >> PAGE_SHIFT) - 1].nrequests++;
1668 arena->stats.lstats[(size >> PAGE_SHIFT) - 1].curruns++;
1669 if (arena->stats.lstats[(size >> PAGE_SHIFT) - 1].curruns >
1670 arena->stats.lstats[(size >> PAGE_SHIFT) - 1].highruns) {
1671 arena->stats.lstats[(size >> PAGE_SHIFT) - 1].highruns =
1672 arena->stats.lstats[(size >> PAGE_SHIFT) - 1].curruns;
Jason Evanse476f8a2010-01-16 09:53:50 -08001673 }
Jason Evanse476f8a2010-01-16 09:53:50 -08001674#endif
1675 malloc_mutex_unlock(&arena->lock);
1676}
1677
1678static bool
1679arena_ralloc_large_grow(arena_t *arena, arena_chunk_t *chunk, void *ptr,
1680 size_t size, size_t oldsize)
1681{
1682 size_t pageind = ((uintptr_t)ptr - (uintptr_t)chunk) >> PAGE_SHIFT;
1683 size_t npages = oldsize >> PAGE_SHIFT;
1684
1685 assert(oldsize == (chunk->map[pageind].bits & ~PAGE_MASK));
1686
1687 /* Try to extend the run. */
1688 assert(size > oldsize);
1689 malloc_mutex_lock(&arena->lock);
1690 if (pageind + npages < chunk_npages && (chunk->map[pageind+npages].bits
1691 & CHUNK_MAP_ALLOCATED) == 0 && (chunk->map[pageind+npages].bits &
1692 ~PAGE_MASK) >= size - oldsize) {
1693 /*
1694 * The next run is available and sufficiently large. Split the
1695 * following run, then merge the first part with the existing
1696 * allocation.
1697 */
1698 arena_run_split(arena, (arena_run_t *)((uintptr_t)chunk +
1699 ((pageind+npages) << PAGE_SHIFT)), size - oldsize, true,
1700 false);
1701
1702 chunk->map[pageind].bits = size | CHUNK_MAP_LARGE |
1703 CHUNK_MAP_ALLOCATED;
1704 chunk->map[pageind+npages].bits = CHUNK_MAP_LARGE |
1705 CHUNK_MAP_ALLOCATED;
1706
1707#ifdef JEMALLOC_STATS
Jason Evans990d10c2010-01-31 03:49:35 -08001708 arena->stats.ndalloc_large++;
1709 arena->stats.allocated_large -= oldsize;
1710 arena->stats.lstats[(oldsize >> PAGE_SHIFT) - 1].curruns--;
1711
1712 arena->stats.nmalloc_large++;
1713 arena->stats.allocated_large += size;
1714 arena->stats.lstats[(size >> PAGE_SHIFT) - 1].nrequests++;
1715 arena->stats.lstats[(size >> PAGE_SHIFT) - 1].curruns++;
1716 if (arena->stats.lstats[(size >> PAGE_SHIFT) - 1].curruns >
1717 arena->stats.lstats[(size >> PAGE_SHIFT) - 1].highruns) {
1718 arena->stats.lstats[(size >> PAGE_SHIFT) - 1].highruns =
1719 arena->stats.lstats[(size >> PAGE_SHIFT) - 1].curruns;
1720 }
Jason Evanse476f8a2010-01-16 09:53:50 -08001721#endif
1722 malloc_mutex_unlock(&arena->lock);
1723 return (false);
1724 }
1725 malloc_mutex_unlock(&arena->lock);
1726
1727 return (true);
1728}
1729
1730/*
1731 * Try to resize a large allocation, in order to avoid copying. This will
1732 * always fail if growing an object, and the following run is already in use.
1733 */
1734static bool
1735arena_ralloc_large(void *ptr, size_t size, size_t oldsize)
1736{
1737 size_t psize;
1738
1739 psize = PAGE_CEILING(size);
1740 if (psize == oldsize) {
1741 /* Same size class. */
1742#ifdef JEMALLOC_FILL
1743 if (opt_junk && size < oldsize) {
1744 memset((void *)((uintptr_t)ptr + size), 0x5a, oldsize -
1745 size);
1746 }
1747#endif
1748 return (false);
1749 } else {
1750 arena_chunk_t *chunk;
1751 arena_t *arena;
1752
1753 chunk = (arena_chunk_t *)CHUNK_ADDR2BASE(ptr);
1754 arena = chunk->arena;
1755 assert(arena->magic == ARENA_MAGIC);
1756
1757 if (psize < oldsize) {
1758#ifdef JEMALLOC_FILL
1759 /* Fill before shrinking in order avoid a race. */
1760 if (opt_junk) {
1761 memset((void *)((uintptr_t)ptr + size), 0x5a,
1762 oldsize - size);
1763 }
1764#endif
1765 arena_ralloc_large_shrink(arena, chunk, ptr, psize,
1766 oldsize);
1767 return (false);
1768 } else {
1769 bool ret = arena_ralloc_large_grow(arena, chunk, ptr,
1770 psize, oldsize);
1771#ifdef JEMALLOC_FILL
1772 if (ret == false && opt_zero) {
1773 memset((void *)((uintptr_t)ptr + oldsize), 0,
1774 size - oldsize);
1775 }
1776#endif
1777 return (ret);
1778 }
1779 }
1780}
1781
1782void *
1783arena_ralloc(void *ptr, size_t size, size_t oldsize)
1784{
1785 void *ret;
1786 size_t copysize;
1787
1788 /*
1789 * Try to avoid moving the allocation.
1790 *
1791 * posix_memalign() can cause allocation of "large" objects that are
1792 * smaller than bin_maxclass (in order to meet alignment requirements).
1793 * Therefore, do not assume that (oldsize <= bin_maxclass) indicates
1794 * ptr refers to a bin-allocated object.
1795 */
1796 if (oldsize <= arena_maxclass) {
1797 if (arena_is_large(ptr) == false ) {
1798 if (size <= small_maxclass) {
1799 if (oldsize <= small_maxclass &&
1800 small_size2bin[size] ==
1801 small_size2bin[oldsize])
1802 goto IN_PLACE;
1803 } else if (size <= bin_maxclass) {
1804 if (small_maxclass < oldsize && oldsize <=
1805 bin_maxclass && MEDIUM_CEILING(size) ==
1806 MEDIUM_CEILING(oldsize))
1807 goto IN_PLACE;
1808 }
1809 } else {
1810 assert(size <= arena_maxclass);
1811 if (size > bin_maxclass) {
1812 if (arena_ralloc_large(ptr, size, oldsize) ==
1813 false)
1814 return (ptr);
1815 }
1816 }
1817 }
1818
1819 /* Try to avoid moving the allocation. */
1820 if (size <= small_maxclass) {
1821 if (oldsize <= small_maxclass && small_size2bin[size] ==
1822 small_size2bin[oldsize])
1823 goto IN_PLACE;
1824 } else if (size <= bin_maxclass) {
1825 if (small_maxclass < oldsize && oldsize <= bin_maxclass &&
1826 MEDIUM_CEILING(size) == MEDIUM_CEILING(oldsize))
1827 goto IN_PLACE;
1828 } else {
1829 if (bin_maxclass < oldsize && oldsize <= arena_maxclass) {
1830 assert(size > bin_maxclass);
1831 if (arena_ralloc_large(ptr, size, oldsize) == false)
1832 return (ptr);
1833 }
1834 }
1835
1836 /*
1837 * If we get here, then size and oldsize are different enough that we
1838 * need to move the object. In that case, fall back to allocating new
1839 * space and copying.
1840 */
1841 ret = arena_malloc(size, false);
1842 if (ret == NULL)
1843 return (NULL);
1844
1845 /* Junk/zero-filling were already done by arena_malloc(). */
1846 copysize = (size < oldsize) ? size : oldsize;
1847 memcpy(ret, ptr, copysize);
1848 idalloc(ptr);
1849 return (ret);
1850IN_PLACE:
1851#ifdef JEMALLOC_FILL
1852 if (opt_junk && size < oldsize)
1853 memset((void *)((uintptr_t)ptr + size), 0x5a, oldsize - size);
1854 else if (opt_zero && size > oldsize)
1855 memset((void *)((uintptr_t)ptr + oldsize), 0, size - oldsize);
1856#endif
1857 return (ptr);
1858}
1859
1860bool
1861arena_new(arena_t *arena, unsigned ind)
1862{
1863 unsigned i;
1864 arena_bin_t *bin;
1865 size_t prev_run_size;
1866
1867 if (malloc_mutex_init(&arena->lock))
1868 return (true);
1869
1870#ifdef JEMALLOC_STATS
1871 memset(&arena->stats, 0, sizeof(arena_stats_t));
1872 arena->stats.lstats = (malloc_large_stats_t *)base_alloc(
1873 sizeof(malloc_large_stats_t) * ((chunksize - PAGE_SIZE) >>
1874 PAGE_SHIFT));
1875 if (arena->stats.lstats == NULL)
1876 return (true);
1877 memset(arena->stats.lstats, 0, sizeof(malloc_large_stats_t) *
1878 ((chunksize - PAGE_SIZE) >> PAGE_SHIFT));
1879# ifdef JEMALLOC_TCACHE
1880 ql_new(&arena->tcache_ql);
1881# endif
1882#endif
1883
1884#ifdef JEMALLOC_TRACE
1885 if (opt_trace) {
1886 /* "jemtr.<pid>.<arena>" */
1887 char buf[UMAX2S_BUFSIZE];
1888 char filename[6 + UMAX2S_BUFSIZE + 1 + UMAX2S_BUFSIZE + 1];
1889 char *s;
1890 unsigned i, slen;
1891
1892 arena->trace_buf_end = 0;
1893
1894 i = 0;
1895
1896 s = "jemtr.";
1897 slen = strlen(s);
1898 memcpy(&filename[i], s, slen);
1899 i += slen;
1900
1901 s = umax2s(getpid(), 10, buf);
1902 slen = strlen(s);
1903 memcpy(&filename[i], s, slen);
1904 i += slen;
1905
1906 s = ".";
1907 slen = strlen(s);
1908 memcpy(&filename[i], s, slen);
1909 i += slen;
1910
1911 s = umax2s(ind, 10, buf);
1912 slen = strlen(s);
1913 memcpy(&filename[i], s, slen);
1914 i += slen;
1915
1916 filename[i] = '\0';
1917
1918 arena->trace_fd = creat(filename, 0644);
1919 if (arena->trace_fd == -1) {
1920 malloc_write4("<jemalloc>",
1921 ": creat(\"", filename, "\", O_RDWR) failed\n");
1922 abort();
1923 }
1924 }
1925#endif
1926
1927 /* Initialize chunks. */
1928 arena_chunk_tree_dirty_new(&arena->chunks_dirty);
1929 arena->spare = NULL;
1930
1931 arena->nactive = 0;
1932 arena->ndirty = 0;
1933
1934 arena_avail_tree_new(&arena->runs_avail);
1935
1936 /* Initialize bins. */
1937 prev_run_size = PAGE_SIZE;
1938
1939 i = 0;
1940#ifdef JEMALLOC_TINY
1941 /* (2^n)-spaced tiny bins. */
1942 for (; i < ntbins; i++) {
1943 bin = &arena->bins[i];
1944 bin->runcur = NULL;
1945 arena_run_tree_new(&bin->runs);
1946
1947 bin->reg_size = (1U << (LG_TINY_MIN + i));
1948
1949 prev_run_size = arena_bin_run_size_calc(bin, prev_run_size);
1950
1951#ifdef JEMALLOC_STATS
1952 memset(&bin->stats, 0, sizeof(malloc_bin_stats_t));
1953#endif
1954 }
1955#endif
1956
1957 /* Quantum-spaced bins. */
1958 for (; i < ntbins + nqbins; i++) {
1959 bin = &arena->bins[i];
1960 bin->runcur = NULL;
1961 arena_run_tree_new(&bin->runs);
1962
1963 bin->reg_size = (i - ntbins + 1) << LG_QUANTUM;
1964
1965 prev_run_size = arena_bin_run_size_calc(bin, prev_run_size);
1966
1967#ifdef JEMALLOC_STATS
1968 memset(&bin->stats, 0, sizeof(malloc_bin_stats_t));
1969#endif
1970 }
1971
1972 /* Cacheline-spaced bins. */
1973 for (; i < ntbins + nqbins + ncbins; i++) {
1974 bin = &arena->bins[i];
1975 bin->runcur = NULL;
1976 arena_run_tree_new(&bin->runs);
1977
1978 bin->reg_size = cspace_min + ((i - (ntbins + nqbins)) <<
1979 LG_CACHELINE);
1980
1981 prev_run_size = arena_bin_run_size_calc(bin, prev_run_size);
1982
1983#ifdef JEMALLOC_STATS
1984 memset(&bin->stats, 0, sizeof(malloc_bin_stats_t));
1985#endif
1986 }
1987
1988 /* Subpage-spaced bins. */
1989 for (; i < ntbins + nqbins + ncbins + nsbins; i++) {
1990 bin = &arena->bins[i];
1991 bin->runcur = NULL;
1992 arena_run_tree_new(&bin->runs);
1993
1994 bin->reg_size = sspace_min + ((i - (ntbins + nqbins + ncbins))
1995 << LG_SUBPAGE);
1996
1997 prev_run_size = arena_bin_run_size_calc(bin, prev_run_size);
1998
1999#ifdef JEMALLOC_STATS
2000 memset(&bin->stats, 0, sizeof(malloc_bin_stats_t));
2001#endif
2002 }
2003
2004 /* Medium bins. */
2005 for (; i < nbins; i++) {
2006 bin = &arena->bins[i];
2007 bin->runcur = NULL;
2008 arena_run_tree_new(&bin->runs);
2009
2010 bin->reg_size = medium_min + ((i - (ntbins + nqbins + ncbins +
2011 nsbins)) << lg_mspace);
2012
2013 prev_run_size = arena_bin_run_size_calc(bin, prev_run_size);
2014
2015#ifdef JEMALLOC_STATS
2016 memset(&bin->stats, 0, sizeof(malloc_bin_stats_t));
2017#endif
2018 }
2019
2020#ifdef JEMALLOC_DEBUG
2021 arena->magic = ARENA_MAGIC;
2022#endif
2023
2024 return (false);
2025}
2026
2027#ifdef JEMALLOC_TINY
2028/* Compute the smallest power of 2 that is >= x. */
2029static size_t
2030pow2_ceil(size_t x)
2031{
2032
2033 x--;
2034 x |= x >> 1;
2035 x |= x >> 2;
2036 x |= x >> 4;
2037 x |= x >> 8;
2038 x |= x >> 16;
2039#if (SIZEOF_PTR == 8)
2040 x |= x >> 32;
2041#endif
2042 x++;
2043 return (x);
2044}
2045#endif
2046
2047#ifdef JEMALLOC_DEBUG
2048static void
2049small_size2bin_validate(void)
2050{
2051 size_t i, size, binind;
2052
2053 assert(small_size2bin[0] == 0xffU);
2054 i = 1;
2055# ifdef JEMALLOC_TINY
2056 /* Tiny. */
2057 for (; i < (1U << LG_TINY_MIN); i++) {
2058 size = pow2_ceil(1U << LG_TINY_MIN);
2059 binind = ffs((int)(size >> (LG_TINY_MIN + 1)));
2060 assert(small_size2bin[i] == binind);
2061 }
2062 for (; i < qspace_min; i++) {
2063 size = pow2_ceil(i);
2064 binind = ffs((int)(size >> (LG_TINY_MIN + 1)));
2065 assert(small_size2bin[i] == binind);
2066 }
2067# endif
2068 /* Quantum-spaced. */
2069 for (; i <= qspace_max; i++) {
2070 size = QUANTUM_CEILING(i);
2071 binind = ntbins + (size >> LG_QUANTUM) - 1;
2072 assert(small_size2bin[i] == binind);
2073 }
2074 /* Cacheline-spaced. */
2075 for (; i <= cspace_max; i++) {
2076 size = CACHELINE_CEILING(i);
2077 binind = ntbins + nqbins + ((size - cspace_min) >>
2078 LG_CACHELINE);
2079 assert(small_size2bin[i] == binind);
2080 }
2081 /* Sub-page. */
2082 for (; i <= sspace_max; i++) {
2083 size = SUBPAGE_CEILING(i);
2084 binind = ntbins + nqbins + ncbins + ((size - sspace_min)
2085 >> LG_SUBPAGE);
2086 assert(small_size2bin[i] == binind);
2087 }
2088}
2089#endif
2090
2091static bool
2092small_size2bin_init(void)
2093{
2094
2095 if (opt_lg_qspace_max != LG_QSPACE_MAX_DEFAULT
2096 || opt_lg_cspace_max != LG_CSPACE_MAX_DEFAULT
2097 || sizeof(const_small_size2bin) != small_maxclass + 1)
2098 return (small_size2bin_init_hard());
2099
2100 small_size2bin = const_small_size2bin;
2101#ifdef JEMALLOC_DEBUG
2102 assert(sizeof(const_small_size2bin) == small_maxclass + 1);
2103 small_size2bin_validate();
2104#endif
2105 return (false);
2106}
2107
2108static bool
2109small_size2bin_init_hard(void)
2110{
2111 size_t i, size, binind;
2112 uint8_t *custom_small_size2bin;
2113
2114 assert(opt_lg_qspace_max != LG_QSPACE_MAX_DEFAULT
2115 || opt_lg_cspace_max != LG_CSPACE_MAX_DEFAULT
2116 || sizeof(const_small_size2bin) != small_maxclass + 1);
2117
2118 custom_small_size2bin = (uint8_t *)base_alloc(small_maxclass + 1);
2119 if (custom_small_size2bin == NULL)
2120 return (true);
2121
2122 custom_small_size2bin[0] = 0xffU;
2123 i = 1;
2124#ifdef JEMALLOC_TINY
2125 /* Tiny. */
2126 for (; i < (1U << LG_TINY_MIN); i++) {
2127 size = pow2_ceil(1U << LG_TINY_MIN);
2128 binind = ffs((int)(size >> (LG_TINY_MIN + 1)));
2129 custom_small_size2bin[i] = binind;
2130 }
2131 for (; i < qspace_min; i++) {
2132 size = pow2_ceil(i);
2133 binind = ffs((int)(size >> (LG_TINY_MIN + 1)));
2134 custom_small_size2bin[i] = binind;
2135 }
2136#endif
2137 /* Quantum-spaced. */
2138 for (; i <= qspace_max; i++) {
2139 size = QUANTUM_CEILING(i);
2140 binind = ntbins + (size >> LG_QUANTUM) - 1;
2141 custom_small_size2bin[i] = binind;
2142 }
2143 /* Cacheline-spaced. */
2144 for (; i <= cspace_max; i++) {
2145 size = CACHELINE_CEILING(i);
2146 binind = ntbins + nqbins + ((size - cspace_min) >>
2147 LG_CACHELINE);
2148 custom_small_size2bin[i] = binind;
2149 }
2150 /* Sub-page. */
2151 for (; i <= sspace_max; i++) {
2152 size = SUBPAGE_CEILING(i);
2153 binind = ntbins + nqbins + ncbins + ((size - sspace_min) >>
2154 LG_SUBPAGE);
2155 custom_small_size2bin[i] = binind;
2156 }
2157
2158 small_size2bin = custom_small_size2bin;
2159#ifdef JEMALLOC_DEBUG
2160 small_size2bin_validate();
2161#endif
2162 return (false);
2163}
2164
2165bool
Jason Evansa0bf2422010-01-29 14:30:41 -08002166arena_boot(void)
Jason Evanse476f8a2010-01-16 09:53:50 -08002167{
Jason Evansa0bf2422010-01-29 14:30:41 -08002168 size_t header_size;
Jason Evanse476f8a2010-01-16 09:53:50 -08002169
2170 /* Set variables according to the value of opt_lg_[qc]space_max. */
2171 qspace_max = (1U << opt_lg_qspace_max);
2172 cspace_min = CACHELINE_CEILING(qspace_max);
2173 if (cspace_min == qspace_max)
2174 cspace_min += CACHELINE;
2175 cspace_max = (1U << opt_lg_cspace_max);
2176 sspace_min = SUBPAGE_CEILING(cspace_max);
2177 if (sspace_min == cspace_max)
2178 sspace_min += SUBPAGE;
2179 assert(sspace_min < PAGE_SIZE);
2180 sspace_max = PAGE_SIZE - SUBPAGE;
2181 medium_max = (1U << opt_lg_medium_max);
2182
2183#ifdef JEMALLOC_TINY
2184 assert(LG_QUANTUM >= LG_TINY_MIN);
2185#endif
2186 assert(ntbins <= LG_QUANTUM);
2187 nqbins = qspace_max >> LG_QUANTUM;
2188 ncbins = ((cspace_max - cspace_min) >> LG_CACHELINE) + 1;
2189 nsbins = ((sspace_max - sspace_min) >> LG_SUBPAGE) + 1;
2190
2191 /*
2192 * Compute medium size class spacing and the number of medium size
2193 * classes. Limit spacing to no more than pagesize, but if possible
2194 * use the smallest spacing that does not exceed NMBINS_MAX medium size
2195 * classes.
2196 */
2197 lg_mspace = LG_SUBPAGE;
2198 nmbins = ((medium_max - medium_min) >> lg_mspace) + 1;
2199 while (lg_mspace < PAGE_SHIFT && nmbins > NMBINS_MAX) {
2200 lg_mspace = lg_mspace + 1;
2201 nmbins = ((medium_max - medium_min) >> lg_mspace) + 1;
2202 }
2203 mspace_mask = (1U << lg_mspace) - 1U;
2204
2205 mbin0 = ntbins + nqbins + ncbins + nsbins;
2206 nbins = mbin0 + nmbins;
2207 /*
2208 * The small_size2bin lookup table uses uint8_t to encode each bin
2209 * index, so we cannot support more than 256 small size classes. This
2210 * limit is difficult to exceed (not even possible with 16B quantum and
2211 * 4KiB pages), and such configurations are impractical, but
2212 * nonetheless we need to protect against this case in order to avoid
2213 * undefined behavior.
2214 */
2215 if (mbin0 > 256) {
2216 char line_buf[UMAX2S_BUFSIZE];
2217 malloc_write4("<jemalloc>: Too many small size classes (",
2218 umax2s(mbin0, 10, line_buf), " > max 256)\n", "");
2219 abort();
2220 }
2221
2222 if (small_size2bin_init())
2223 return (true);
2224
Jason Evanse476f8a2010-01-16 09:53:50 -08002225 /*
2226 * Compute the header size such that it is large enough to contain the
2227 * page map.
2228 */
2229 header_size = sizeof(arena_chunk_t) +
2230 (sizeof(arena_chunk_map_t) * (chunk_npages - 1));
2231 arena_chunk_header_npages = (header_size >> PAGE_SHIFT) +
2232 ((header_size & PAGE_MASK) != 0);
2233 arena_maxclass = chunksize - (arena_chunk_header_npages << PAGE_SHIFT);
Jason Evansa0bf2422010-01-29 14:30:41 -08002234
2235 return (false);
Jason Evanse476f8a2010-01-16 09:53:50 -08002236}