فهرست منبع

Remove mutex from `Growing_Arena`; Add `Growing_Arena_Temp`

gingerBill 4 سال پیش
والد
کامیت
a437c95fed
1فایلهای تغییر یافته به همراه73 افزوده شده و 24 حذف شده
  1. 73 24
      core/mem/virtual/arena.odin

+ 73 - 24
core/mem/virtual/arena.odin

@@ -1,7 +1,6 @@
 package mem_virtual
 package mem_virtual
 
 
 import "core:mem"
 import "core:mem"
-import sync "core:sync/sync2"
 
 
 Growing_Arena :: struct {
 Growing_Arena :: struct {
 	curr_block:      ^Memory_Block,
 	curr_block:      ^Memory_Block,
@@ -9,12 +8,10 @@ Growing_Arena :: struct {
 	total_allocated: int,
 	total_allocated: int,
 	
 	
 	minimum_block_size: 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
 DEFAULT_PAGE_SIZE := 4096
 
 
 growing_arena_alloc :: proc(arena: ^Growing_Arena, min_size: int, alignment: int) -> (data: []byte, err: mem.Allocator_Error) {
 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)))
 	assert(mem.is_power_of_two(uintptr(alignment)))
 	
 	
-	mutex := &arena.mutex
-	if !arena.ignore_mutex {
-		sync.mutex_lock(mutex)
-	}
-	
+
 	size := 0
 	size := 0
 	if arena.curr_block != nil {
 	if arena.curr_block != nil {
 		size = min_size + align_forward_offset(arena, alignment)
 		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)
 	assert(curr_block.used <= curr_block.size)
 	arena.total_used += size
 	arena.total_used += size
 	
 	
-	if !arena.ignore_mutex {
-		sync.mutex_unlock(mutex)
-	}
-	
 	return ptr[:min_size], nil
 	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) {
 growing_arena_free_all :: proc(arena: ^Growing_Arena) {
-	mutex := &arena.mutex
-	if !arena.ignore_mutex {
-		sync.mutex_lock(mutex)
-	}
 	for arena.curr_block != nil {
 	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
 	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 {
 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
 	err = .Mode_Not_Implemented
 	return 
 	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)
 }
 }