#include "internal.h"
void
rack_init(rack_t *rack, rack_type_t type, uint32_t num_magazines, uint32_t debug_flags)
{
rack->type = type;
rack->rg[0].nextgen = &rack->rg[1];
rack->rg[1].nextgen = &rack->rg[0];
rack->region_generation = &rack->rg[0];
rack->region_generation->hashed_regions = rack->initial_regions;
rack->region_generation->num_regions_allocated = INITIAL_NUM_REGIONS;
rack->region_generation->num_regions_allocated_shift = INITIAL_NUM_REGIONS_SHIFT;
memset(rack->initial_regions, '\0', sizeof(region_t) * INITIAL_NUM_REGIONS);
rack->cookie = (uintptr_t)malloc_entropy[0];
if (type == RACK_TYPE_SMALL) {
rack->cookie = ~rack->cookie;
}
rack->debug_flags = debug_flags;
rack->num_magazines = num_magazines;
rack->num_regions = 0;
rack->num_regions_dealloc = 0;
rack->magazines = NULL;
if (num_magazines > 0) {
size_t magsize = round_page_quanta(sizeof(magazine_t) * (num_magazines + 1));
magazine_t *magazines = mvm_allocate_pages(magsize, 0,
MALLOC_ADD_GUARD_PAGE_FLAGS|DISABLE_ASLR, VM_MEMORY_MALLOC);
if (!magazines) {
MALLOC_REPORT_FATAL_ERROR(0, "unable to allocate magazine array");
}
rack->magazines = &magazines[1];
rack->num_magazines_mask_shift = 0;
int i = 1;
while (i <= (num_magazines - 1)) {
rack->num_magazines_mask_shift++;
i <<= 1;
}
rack->num_magazines_mask = i - 1;
rack->last_madvise = 0;
_malloc_lock_init(&rack->region_lock);
_malloc_lock_init(&rack->magazines[DEPOT_MAGAZINE_INDEX].magazine_lock);
for (int i=0; i < rack->num_magazines; i++) {
_malloc_lock_init(&rack->magazines[i].magazine_lock);
}
}
}
void
rack_destroy_regions(rack_t *rack, size_t region_size)
{
for (int i=0; i < rack->region_generation->num_regions_allocated; i++) {
if ((rack->region_generation->hashed_regions[i] != HASHRING_OPEN_ENTRY) &&
(rack->region_generation->hashed_regions[i] != HASHRING_REGION_DEALLOCATED))
{
mvm_deallocate_pages(rack->region_generation->hashed_regions[i], region_size, MALLOC_FIX_GUARD_PAGE_FLAGS(rack->debug_flags));
rack->region_generation->hashed_regions[i] = HASHRING_REGION_DEALLOCATED;
}
}
}
void
rack_destroy(rack_t *rack)
{
if (rack->region_generation->hashed_regions != rack->initial_regions) {
size_t size = round_page_quanta(rack->region_generation->num_regions_allocated * sizeof(region_t));
mvm_deallocate_pages(rack->region_generation->hashed_regions, size, 0);
}
if (rack->num_magazines > 0) {
size_t size = round_page_quanta(sizeof(magazine_t) * (rack->num_magazines + 1));
mvm_deallocate_pages(&rack->magazines[-1], size, MALLOC_ADD_GUARD_PAGE_FLAGS);
rack->magazines = NULL;
}
}
void
rack_region_insert(rack_t *rack, region_t region)
{
_malloc_lock_lock(&rack->region_lock);
if (rack->region_generation->num_regions_allocated < (2 * rack->num_regions)) {
region_t *new_regions;
size_t new_size;
size_t new_shift = rack->region_generation->num_regions_allocated_shift; new_regions = hash_regions_grow_no_lock(rack->region_generation->hashed_regions,
rack->region_generation->num_regions_allocated, &new_shift, &new_size);
rack->region_generation->nextgen->hashed_regions = new_regions;
rack->region_generation->nextgen->num_regions_allocated = new_size;
rack->region_generation->nextgen->num_regions_allocated_shift = new_shift;
OSMemoryBarrier();
rack->region_generation = rack->region_generation->nextgen;
}
hash_region_insert_no_lock(rack->region_generation->hashed_regions,
rack->region_generation->num_regions_allocated,
rack->region_generation->num_regions_allocated_shift,
region);
rack->num_regions++;
_malloc_lock_unlock(&rack->region_lock);
}
bool
rack_region_remove(rack_t *rack, region_t region, region_trailer_t *trailer)
{
bool rv = true;
rack_region_lock(rack);
rgnhdl_t pSlot = hash_lookup_region_no_lock(
rack->region_generation->hashed_regions,
rack->region_generation->num_regions_allocated,
rack->region_generation->num_regions_allocated_shift,
region);
if ((trailer->dispose_flags & RACK_DISPOSE_DELAY) != 0) {
trailer->dispose_flags |= RACK_DISPOSE_NEEDED;
rv = false;
}
if (NULL == pSlot) {
malloc_zone_error(rack->debug_flags, true,
"tiny_free_try_depot_unmap_no_lock hash lookup failed: %p\n",
region);
rv = false;
} else {
*pSlot = HASHRING_REGION_DEALLOCATED;
#ifdef __LP64__
OSAtomicIncrement64((int64_t *)&rack->num_regions_dealloc);
#else
OSAtomicIncrement32((int32_t *)&rack->num_regions_dealloc);
#endif
}
rack_region_unlock(rack);
return rv;
}
bool
rack_region_maybe_dispose(rack_t *rack, region_t region, size_t region_size,
region_trailer_t *trailer)
{
bool rv = false;
rack_region_lock(rack);
if ((trailer->dispose_flags & RACK_DISPOSE_NEEDED) != 0) {
mvm_deallocate_pages((void *)region, region_size,
MALLOC_FIX_GUARD_PAGE_FLAGS(rack->debug_flags));
rv = true;
} else {
trailer->dispose_flags &= ~RACK_DISPOSE_DELAY;
}
rack_region_unlock(rack);
return rv;
}