From a437c95fedde23f1c8785c51a5669cbd1a81bb2b Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sun, 3 Oct 2021 12:41:24 +0100 Subject: [PATCH] Remove mutex from `Growing_Arena`; Add `Growing_Arena_Temp` --- core/mem/virtual/arena.odin | 97 ++++++++++++++++++++++++++++--------- 1 file changed, 73 insertions(+), 24 deletions(-) diff --git a/core/mem/virtual/arena.odin b/core/mem/virtual/arena.odin index 3df96d35d..c11ca0306 100644 --- a/core/mem/virtual/arena.odin +++ b/core/mem/virtual/arena.odin @@ -1,7 +1,6 @@ package mem_virtual import "core:mem" -import sync "core:sync/sync2" Growing_Arena :: struct { curr_block: ^Memory_Block, @@ -9,12 +8,10 @@ Growing_Arena :: struct { total_allocated: int, minimum_block_size: int, - - ignore_mutex: bool, - mutex: sync.Mutex, + temp_count: int, } -DEFAULT_MINIMUM_BLOCK_SIZE :: 8*1024*1024 +DEFAULT_MINIMUM_BLOCK_SIZE :: 1024*1024 // 1 KiB should be enough DEFAULT_PAGE_SIZE := 4096 growing_arena_alloc :: proc(arena: ^Growing_Arena, min_size: int, alignment: int) -> (data: []byte, err: mem.Allocator_Error) { @@ -30,11 +27,7 @@ growing_arena_alloc :: proc(arena: ^Growing_Arena, min_size: int, alignment: int assert(mem.is_power_of_two(uintptr(alignment))) - mutex := &arena.mutex - if !arena.ignore_mutex { - sync.mutex_lock(mutex) - } - + size := 0 if arena.curr_block != nil { size = min_size + align_forward_offset(arena, alignment) @@ -62,27 +55,41 @@ growing_arena_alloc :: proc(arena: ^Growing_Arena, min_size: int, alignment: int assert(curr_block.used <= curr_block.size) arena.total_used += size - if !arena.ignore_mutex { - sync.mutex_unlock(mutex) - } - return ptr[:min_size], nil } +growing_arena_free_last_memory_block :: proc(arena: ^Growing_Arena) { + free_block := arena.curr_block + arena.curr_block = free_block.prev + memory_dealloc(free_block) +} + growing_arena_free_all :: proc(arena: ^Growing_Arena) { - mutex := &arena.mutex - if !arena.ignore_mutex { - sync.mutex_lock(mutex) - } for arena.curr_block != nil { - free_block := arena.curr_block - arena.curr_block = free_block.prev - memory_dealloc(free_block) + growing_arena_free_last_memory_block(arena) } arena.total_used = 0 - if !arena.ignore_mutex { - sync.mutex_unlock(mutex) - } +} + +growing_arena_bootstrap_new_by_offset :: proc($T: typeid, offset_to_arena: uintptr, minimum_block_size := DEFAULT_MINIMUM_BLOCK_SIZE) -> (ptr: ^T, err: mem.Allocator_Error) { + bootstrap: Growing_Arena + bootstrap.minimum_block_size = minimum_block_size + + data := growing_arena_alloc(&bootstrap, size_of(T), align_of(T)) or_return + + ptr = (^T)(raw_data(data)) + + (^Growing_Arena)(uintptr(ptr) + offset_to_arena)^ = bootstrap + + return +} + +growing_arena_bootstrap_new_by_name :: proc($T: typeid, $field_name: string, minimum_block_size := DEFAULT_MINIMUM_BLOCK_SIZE) -> (ptr: ^T, err: mem.Allocator_Error) { + return growing_arena_bootstrap_new_by_offset(T, offset_of_by_string(T, field_name), minimum_block_size) +} +growing_arena_bootstrap_new :: proc{ + growing_arena_bootstrap_new_by_offset, + growing_arena_bootstrap_new_by_name, } growing_arena_allocator :: proc(arena: ^Growing_Arena) -> mem.Allocator { @@ -114,4 +121,46 @@ growing_arena_allocator_proc :: proc(allocator_data: rawptr, mode: mem.Allocator err = .Mode_Not_Implemented return +} + +Growing_Arena_Temp :: struct { + arena: ^Growing_Arena, + block: ^Memory_Block, + used: int, +} + +growing_arena_temp_begin :: proc(arena: ^Growing_Arena) -> (temp: Growing_Arena_Temp) { + temp.arena = arena + temp.block = arena.curr_block + if arena.curr_block != nil { + temp.used = arena.curr_block.used + } + arena.temp_count += 1 + return +} + +growing_arena_temp_end :: proc(temp: Growing_Arena_Temp, loc := #caller_location) { + assert(temp.arena != nil, "nil arena", loc) + arena := temp.arena + + for arena.curr_block != temp.block { + growing_arena_free_last_memory_block(arena) + } + + if block := arena.curr_block; block != nil { + + assert(block.used >= temp.used, "out of order use of growing_arena_temp_end", loc) + amount_to_zero := min(block.used-temp.used, block.size-block.used) + + block.used = temp.used + + mem.zero_slice(block.base[block.used:][:amount_to_zero]) + } + + assert(arena.temp_count > 0, "double-use of growing_arena_temp_end", loc) + arena.temp_count -= 1 +} + +growing_arena_check_temp :: proc(arena: ^Growing_Arena, loc := #caller_location) { + assert(condition = arena.temp_count == 0, loc = loc) } \ No newline at end of file