aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorgingerBill <bill@gingerbill.org>2021-10-03 12:41:24 +0100
committergingerBill <bill@gingerbill.org>2021-10-03 12:41:24 +0100
commita437c95fedde23f1c8785c51a5669cbd1a81bb2b (patch)
tree48662f8bf52889f959beda0dd43af842e4f0b1df
parent8fe70978ff9621b0923f043db3925eeda7d658f8 (diff)
Remove mutex from `Growing_Arena`; Add `Growing_Arena_Temp`
-rw-r--r--core/mem/virtual/arena.odin97
1 files 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