// #TODO: #Arena_Free_List #garbage_collection in `release_arena` // [ ] Garbage collection if we have >> 64 in a particular table for a while. // There should be some parameters regarding what the upper limit for idle // committed pages should be and a heuristic for maximum number of arenas waiting struct Arena_Free_List { Mutex mutex; s32 in_flight_count[Arena_Reserve_Count]; Array free_table[Arena_Reserve_Count]; #if ARENA_DEBUG Array in_flight[Arena_Reserve_Count]; #endif b32 initialized; }; global Arena_Free_List* arena_free_list; // Only call once from main thread! void initialize_arena_free_list (Allocator allocator) { mutex_init(&arena_free_list->mutex); Assert(arena_free_list != nullptr); if (arena_free_list->initialized) return; for (s32 i = 0; i < Arena_Reserve_Count; i += 1) { arena_free_list->in_flight_count[i] = 0; arena_free_list->free_table[i].allocator = allocator; array_reserve(arena_free_list->free_table[i], 64); #if ARENA_DEBUG arena_free_list->in_flight[i].allocator = allocator; array_reserve(arena_free_list->in_flight[i], 64); #endif } arena_free_list->initialized = true; } Arena* next_arena (Arena_Reserve reserve_size) { Assert(arena_free_list != nullptr); Arena* arena; lock_guard(&arena_free_list->mutex); s64 reserve_index = (s64)reserve_size; if (!arena_free_list->free_table[reserve_index].count) { arena = bootstrap_arena(reserve_size, ARENA_DEFAULT_COMMIT_PAGE_COUNT); } else { arena = pop(arena_free_list->free_table[reserve_index]); } #if ARENA_DEBUG array_add(arena_free_list->in_flight[reserve_index], arena); #endif arena_free_list->in_flight_count[reserve_index] += 1; Assert(arena != nullptr); return arena; } void release_arena (Arena* arena, bool delete_extra_pages) { Assert(arena_free_list != nullptr); Assert(arena != nullptr); Assert(arena_is_bootstrapped(arena)); // Only put into free table if arena is bootstrapped? lock_guard(&arena_free_list->mutex); s64 reserve_index = (s64)arena->reserve_size; #if ARENA_DEBUG array_unordered_remove_by_value(arena_free_list->in_flight[reserve_index], arena, 1); // BUILD_DEBUG! #endif arena_reset_keeping_memory(arena); if (delete_extra_pages) { free_pages_down_to(arena, arena->initial_commit_page_count); } array_add(arena_free_list->free_table[reserve_index], arena); arena_free_list->in_flight_count[reserve_index] -= 1; // #TODO #garbage_collection // if (arena_free_table[reserve_index].count > 64) { // s64 arenas_to_delete_count = arena_free_table[reserve_index].count - 64; // while (arenas_to_delete_count > 0) { // arena_delete(arena_free_table[arena_free_table.count-1]); // array_unordered_remove_by_index(..); // arenas_to_delete_count -= 1; // } // } } s64 bytes_in_use (ArrayView arenas) { // does not include overhead from committed pages! s64 sum = 0; for (s64 i = 0; i < arenas.count; i += 1) { sum += arena_usage_bytes(arenas[i]); } return sum; } s64 committed_bytes (ArrayView arenas) { s64 sum = 0; for (s64 i = 0; i < arenas.count; i += 1) { sum += arena_usage_committed_bytes(arenas[i]); } return sum; }