allocates and returns a block of size bytes, to be freed with Free() L < arena->mu
| 432 | // allocates and returns a block of size bytes, to be freed with Free() |
| 433 | // L < arena->mu |
| 434 | static void *DoAllocWithArena(size_t request, LowLevelAlloc::Arena *arena) { |
| 435 | void *result = 0; |
| 436 | if (request != 0) { |
| 437 | AllocList *s; // will point to region that satisfies request |
| 438 | ArenaLock section(arena); |
| 439 | ArenaInit(arena); |
| 440 | // round up with header |
| 441 | size_t req_rnd = RoundUp(request + sizeof (s->header), arena->roundup); |
| 442 | for (;;) { // loop until we find a suitable region |
| 443 | // find the minimum levels that a block of this size must have |
| 444 | int i = LLA_SkiplistLevels(req_rnd, arena->min_size, false) - 1; |
| 445 | if (i < arena->freelist.levels) { // potential blocks exist |
| 446 | AllocList *before = &arena->freelist; // predecessor of s |
| 447 | while ((s = Next(i, before, arena)) != 0 && s->header.size < req_rnd) { |
| 448 | before = s; |
| 449 | } |
| 450 | if (s != 0) { // we found a region |
| 451 | break; |
| 452 | } |
| 453 | } |
| 454 | // we unlock before mmap() both because mmap() may call a callback hook, |
| 455 | // and because it may be slow. |
| 456 | arena->mu.Unlock(); |
| 457 | // mmap generous 64K chunks to decrease |
| 458 | // the chances/impact of fragmentation: |
| 459 | size_t new_pages_size = RoundUp(req_rnd, arena->pagesize * 16); |
| 460 | void *new_pages; |
| 461 | if ((arena->flags & LowLevelAlloc::kAsyncSignalSafe) != 0) { |
| 462 | new_pages = MallocHook::UnhookedMMap(0, new_pages_size, |
| 463 | PROT_WRITE|PROT_READ, MAP_ANONYMOUS|MAP_PRIVATE, -1, 0); |
| 464 | } else { |
| 465 | new_pages = mmap(0, new_pages_size, |
| 466 | PROT_WRITE|PROT_READ, MAP_ANONYMOUS|MAP_PRIVATE, -1, 0); |
| 467 | } |
| 468 | RAW_CHECK(new_pages != MAP_FAILED, "mmap error"); |
| 469 | arena->mu.Lock(); |
| 470 | s = reinterpret_cast<AllocList *>(new_pages); |
| 471 | s->header.size = new_pages_size; |
| 472 | // Pretend the block is allocated; call AddToFreelist() to free it. |
| 473 | s->header.magic = Magic(kMagicAllocated, &s->header); |
| 474 | s->header.arena = arena; |
| 475 | AddToFreelist(&s->levels, arena); // insert new region into free list |
| 476 | } |
| 477 | AllocList *prev[kMaxLevel]; |
| 478 | LLA_SkiplistDelete(&arena->freelist, s, prev); // remove from free list |
| 479 | // s points to the first free region that's big enough |
| 480 | if (req_rnd + arena->min_size <= s->header.size) { // big enough to split |
| 481 | AllocList *n = reinterpret_cast<AllocList *> |
| 482 | (req_rnd + reinterpret_cast<char *>(s)); |
| 483 | n->header.size = s->header.size - req_rnd; |
| 484 | n->header.magic = Magic(kMagicAllocated, &n->header); |
| 485 | n->header.arena = arena; |
| 486 | s->header.size = req_rnd; |
| 487 | AddToFreelist(&n->levels, arena); |
| 488 | } |
| 489 | s->header.magic = Magic(kMagicAllocated, &s->header); |
| 490 | RAW_CHECK(s->header.arena == arena, ""); |
| 491 | arena->allocation_count++; |
no test coverage detected