98 lines
3.0 KiB
C++
98 lines
3.0 KiB
C++
// #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<Arena*> free_table[Arena_Reserve_Count];
|
|
|
|
#if ARENA_DEBUG
|
|
Array<Arena*> 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 committed_bytes (ArrayView<Arena*> arenas) {
|
|
s64 sum = 0;
|
|
|
|
for (s64 i = 0; i < arenas.count; i += 1) {
|
|
sum += arena_usage_committed_bytes(arenas[i]);
|
|
}
|
|
|
|
return sum;
|
|
}
|