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