int yr_arena_create( size_t initial_size, int flags, YR_ARENA** arena) { YR_ARENA* new_arena; YR_ARENA_PAGE* new_page; *arena = NULL; new_arena = (YR_ARENA*) yr_malloc(sizeof(YR_ARENA)); if (new_arena == NULL) return ERROR_INSUFFICIENT_MEMORY; new_page = _yr_arena_new_page(initial_size); if (new_page == NULL) { yr_free(new_arena); return ERROR_INSUFFICIENT_MEMORY; } new_arena->page_list_head = new_page; new_arena->current_page = new_page; new_arena->flags = flags | ARENA_FLAGS_COALESCED; *arena = new_arena; return ERROR_SUCCESS; }
int yr_arena_allocate_memory( YR_ARENA* arena, size_t size, void** allocated_memory) { size_t new_page_size; void* new_page_address; YR_ARENA_PAGE* new_page; if (size > free_space(arena->current_page)) { // Requested space is bigger than current page's empty space, // lets calculate the size for a new page. new_page_size = arena->current_page->size * 2; while (new_page_size < size) new_page_size *= 2; if (arena->current_page->used == 0) { // Current page is not used at all, it can be reallocated. new_page_address = yr_realloc( arena->current_page->address, new_page_size); if (new_page_address == NULL) return ERROR_INSUFICIENT_MEMORY; arena->current_page->address = new_page_address; arena->current_page->size = new_page_size; } else { if (arena->flags & ARENA_FLAGS_FIXED_SIZE) return ERROR_INSUFICIENT_MEMORY; new_page = _yr_arena_new_page(new_page_size); if (new_page == NULL) return ERROR_INSUFICIENT_MEMORY; new_page->prev = arena->current_page; arena->current_page->next = new_page; arena->current_page = new_page; arena->flags &= ~ARENA_FLAGS_COALESCED; } } *allocated_memory = arena->current_page->address + \ arena->current_page->used; arena->current_page->used += size; return ERROR_SUCCESS; }
int yr_arena_coalesce( YR_ARENA* arena) { YR_ARENA_PAGE* page; YR_ARENA_PAGE* big_page; YR_ARENA_PAGE* next_page; YR_RELOC* reloc; uint8_t** reloc_address; uint8_t* reloc_target; size_t total_size = 0; page = arena->page_list_head; while(page != NULL) { total_size += page->used; page = page->next; } // Create a new page that will contain the entire arena. big_page = _yr_arena_new_page(total_size); if (big_page == NULL) return ERROR_INSUFFICIENT_MEMORY; // Copy data from current pages to the big page and adjust relocs. page = arena->page_list_head; while (page != NULL) { page->new_address = big_page->address + big_page->used; memcpy(page->new_address, page->address, page->used); reloc = page->reloc_list_head; while (reloc != NULL) { reloc->offset += (uint32_t) big_page->used; reloc = reloc->next; } if (big_page->reloc_list_head == NULL) big_page->reloc_list_head = page->reloc_list_head; if (big_page->reloc_list_tail != NULL) big_page->reloc_list_tail->next = page->reloc_list_head; if (page->reloc_list_tail != NULL) big_page->reloc_list_tail = page->reloc_list_tail; big_page->used += page->used; page = page->next; } // Relocate pointers. reloc = big_page->reloc_list_head; while (reloc != NULL) { reloc_address = (uint8_t**) (big_page->address + reloc->offset); reloc_target = *reloc_address; if (reloc_target != NULL) { page = _yr_arena_page_for_address(arena, reloc_target); assert(page != NULL); *reloc_address = page->new_address + (reloc_target - page->address); } reloc = reloc->next; } // Release current pages. page = arena->page_list_head; while(page != NULL) { next_page = page->next; yr_free(page->address); yr_free(page); page = next_page; } arena->page_list_head = big_page; arena->current_page = big_page; arena->flags |= ARENA_FLAGS_COALESCED; return ERROR_SUCCESS; }
int yr_arena_duplicate( YR_ARENA* arena, YR_ARENA** duplicated) { YR_RELOC* reloc; YR_RELOC* new_reloc; YR_ARENA_PAGE* page; YR_ARENA_PAGE* new_page; YR_ARENA* new_arena; uint8_t** reloc_address; uint8_t* reloc_target; // Only coalesced arenas can be duplicated. assert(arena->flags & ARENA_FLAGS_COALESCED); new_arena = (YR_ARENA*) yr_malloc(sizeof(YR_ARENA)); if (new_arena == NULL) return ERROR_INSUFICIENT_MEMORY; page = arena->page_list_head; new_page = _yr_arena_new_page(page->size); if (new_page == NULL) { yr_free(new_arena); return ERROR_INSUFICIENT_MEMORY; } memcpy(new_page->address, page->address, page->size); new_page->used = page->used; reloc = page->reloc_list_head; while (reloc != NULL) { new_reloc = yr_malloc(sizeof(YR_RELOC)); if (new_reloc == NULL) return ERROR_INSUFICIENT_MEMORY; new_reloc->offset = reloc->offset; new_reloc->next = NULL; if (new_page->reloc_list_head == NULL) new_page->reloc_list_head = new_reloc; if (new_page->reloc_list_tail != NULL) new_page->reloc_list_tail->next = new_reloc; new_page->reloc_list_tail = new_reloc; reloc_address = (uint8_t**) (new_page->address + new_reloc->offset); reloc_target = *reloc_address; if (reloc_target != NULL) { assert(reloc_target >= page->address); assert(reloc_target < page->address + page->used); *reloc_address = reloc_target - \ page->address + \ new_page->address; } reloc = reloc->next; } new_arena->page_list_head = new_page; new_arena->current_page = new_page; new_arena->flags |= ARENA_FLAGS_COALESCED; *duplicated = new_arena; return ERROR_SUCCESS; }