Browse Source

Add mutex to `virtual.Arena`; add `virtual.arena_temp_ignore`

gingerBill 2 years ago
parent
commit
8d6ce0b693
2 changed files with 26 additions and 1 deletions
  1. 21 0
      core/mem/virtual/arena.odin
  2. 5 1
      core/mem/virtual/virtual.odin

+ 21 - 0
core/mem/virtual/arena.odin

@@ -1,6 +1,7 @@
 package mem_virtual
 package mem_virtual
 
 
 import "core:mem"
 import "core:mem"
+import "core:sync"
 
 
 Arena_Kind :: enum uint {
 Arena_Kind :: enum uint {
 	Growing = 0, // Chained memory blocks (singly linked list).
 	Growing = 0, // Chained memory blocks (singly linked list).
@@ -15,6 +16,7 @@ Arena :: struct {
 	total_reserved:     uint,
 	total_reserved:     uint,
 	minimum_block_size: uint,
 	minimum_block_size: uint,
 	temp_count:         uint,
 	temp_count:         uint,
+	mutex:              sync.Mutex,
 }
 }
 
 
 
 
@@ -78,6 +80,8 @@ arena_alloc :: proc(arena: ^Arena, size: uint, alignment: uint, loc := #caller_l
 		return nil, nil
 		return nil, nil
 	}
 	}
 
 
+	sync.mutex_guard(&arena.mutex)
+
 	switch arena.kind {
 	switch arena.kind {
 	case .Growing:
 	case .Growing:
 		if arena.curr_block == nil || (safe_add(arena.curr_block.used, size) or_else 0) > arena.curr_block.reserved {
 		if arena.curr_block == nil || (safe_add(arena.curr_block.used, size) or_else 0) > arena.curr_block.reserved {
@@ -116,6 +120,8 @@ arena_alloc :: proc(arena: ^Arena, size: uint, alignment: uint, loc := #caller_l
 }
 }
 
 
 arena_static_reset_to :: proc(arena: ^Arena, pos: uint, loc := #caller_location) -> bool {
 arena_static_reset_to :: proc(arena: ^Arena, pos: uint, loc := #caller_location) -> bool {
+	sync.mutex_guard(&arena.mutex)
+
 	if arena.curr_block != nil {
 	if arena.curr_block != nil {
 		assert(arena.kind != .Growing, "expected a non .Growing arena", loc)
 		assert(arena.kind != .Growing, "expected a non .Growing arena", loc)
 
 
@@ -135,6 +141,7 @@ arena_static_reset_to :: proc(arena: ^Arena, pos: uint, loc := #caller_location)
 }
 }
 
 
 arena_growing_free_last_memory_block :: proc(arena: ^Arena, loc := #caller_location) {
 arena_growing_free_last_memory_block :: proc(arena: ^Arena, loc := #caller_location) {
+	sync.mutex_guard(&arena.mutex)
 	if free_block := arena.curr_block; free_block != nil {
 	if free_block := arena.curr_block; free_block != nil {
 		assert(arena.kind == .Growing, "expected a .Growing arena", loc)
 		assert(arena.kind == .Growing, "expected a .Growing arena", loc)
 		arena.curr_block = free_block.prev
 		arena.curr_block = free_block.prev
@@ -145,6 +152,7 @@ arena_growing_free_last_memory_block :: proc(arena: ^Arena, loc := #caller_locat
 arena_free_all :: proc(arena: ^Arena) {
 arena_free_all :: proc(arena: ^Arena) {
 	switch arena.kind {
 	switch arena.kind {
 	case .Growing:
 	case .Growing:
+		sync.mutex_guard(&arena.mutex)
 		for arena.curr_block != nil {
 		for arena.curr_block != nil {
 			arena_growing_free_last_memory_block(arena)
 			arena_growing_free_last_memory_block(arena)
 		}
 		}
@@ -287,6 +295,8 @@ Arena_Temp :: struct {
 @(require_results)
 @(require_results)
 arena_temp_begin :: proc(arena: ^Arena, loc := #caller_location) -> (temp: Arena_Temp) {
 arena_temp_begin :: proc(arena: ^Arena, loc := #caller_location) -> (temp: Arena_Temp) {
 	assert(arena != nil, "nil arena", loc)
 	assert(arena != nil, "nil arena", loc)
+	sync.mutex_guard(&arena.mutex)
+
 	temp.arena = arena
 	temp.arena = arena
 	temp.block = arena.curr_block
 	temp.block = arena.curr_block
 	if arena.curr_block != nil {
 	if arena.curr_block != nil {
@@ -299,6 +309,7 @@ arena_temp_begin :: proc(arena: ^Arena, loc := #caller_location) -> (temp: Arena
 arena_temp_end :: proc(temp: Arena_Temp, loc := #caller_location) {
 arena_temp_end :: proc(temp: Arena_Temp, loc := #caller_location) {
 	assert(temp.arena != nil, "nil arena", loc)
 	assert(temp.arena != nil, "nil arena", loc)
 	arena := temp.arena
 	arena := temp.arena
+	sync.mutex_guard(&arena.mutex)
 
 
 	memory_block_found := false
 	memory_block_found := false
 	for block := arena.curr_block; block != nil; block = block.prev {
 	for block := arena.curr_block; block != nil; block = block.prev {
@@ -326,6 +337,16 @@ arena_temp_end :: proc(temp: Arena_Temp, loc := #caller_location) {
 	arena.temp_count -= 1
 	arena.temp_count -= 1
 }
 }
 
 
+// Ignore the use of a `arena_temp_begin` entirely
+arena_temp_ignore :: proc(temp: Arena_Temp, loc := #caller_location) {
+	assert(temp.arena != nil, "nil arena", loc)
+	arena := temp.arena
+	sync.mutex_guard(&arena.mutex)
+
+	assert(arena.temp_count > 0, "double-use of arena_temp_end", loc)
+	arena.temp_count -= 1
+}
+
 arena_check_temp :: proc(arena: ^Arena, loc := #caller_location) {
 arena_check_temp :: proc(arena: ^Arena, loc := #caller_location) {
 	assert(arena.temp_count == 0, "Arena_Temp not been ended", loc)
 	assert(arena.temp_count == 0, "Arena_Temp not been ended", loc)
 }
 }

+ 5 - 1
core/mem/virtual/virtual.odin

@@ -7,6 +7,7 @@ DEFAULT_PAGE_SIZE := uint(4096)
 
 
 Allocator_Error :: mem.Allocator_Error
 Allocator_Error :: mem.Allocator_Error
 
 
+@(require_results)
 reserve :: proc "contextless" (size: uint) -> (data: []byte, err: Allocator_Error) {
 reserve :: proc "contextless" (size: uint) -> (data: []byte, err: Allocator_Error) {
 	return _reserve(size)
 	return _reserve(size)
 }
 }
@@ -15,6 +16,7 @@ commit :: proc "contextless" (data: rawptr, size: uint) -> Allocator_Error {
 	return _commit(data, size)
 	return _commit(data, size)
 }
 }
 
 
+@(require_results)
 reserve_and_commit :: proc "contextless" (size: uint) -> (data: []byte, err: Allocator_Error) {
 reserve_and_commit :: proc "contextless" (size: uint) -> (data: []byte, err: Allocator_Error) {
 	data = reserve(size) or_return
 	data = reserve(size) or_return
 	commit(raw_data(data), size) or_return
 	commit(raw_data(data), size) or_return
@@ -57,6 +59,7 @@ Memory_Block_Flag :: enum u32 {
 Memory_Block_Flags :: distinct bit_set[Memory_Block_Flag; u32]
 Memory_Block_Flags :: distinct bit_set[Memory_Block_Flag; u32]
 
 
 
 
+@(require_results)
 memory_block_alloc :: proc(committed, reserved: uint, flags: Memory_Block_Flags) -> (block: ^Memory_Block, err: Allocator_Error) {
 memory_block_alloc :: proc(committed, reserved: uint, flags: Memory_Block_Flags) -> (block: ^Memory_Block, err: Allocator_Error) {
 	align_formula :: proc "contextless" (size, align: uint) -> uint {
 	align_formula :: proc "contextless" (size, align: uint) -> uint {
 		result := size + align-1
 		result := size + align-1
@@ -100,6 +103,7 @@ memory_block_alloc :: proc(committed, reserved: uint, flags: Memory_Block_Flags)
 	return &pmblock.block, nil
 	return &pmblock.block, nil
 }
 }
 
 
+@(require_results)
 alloc_from_memory_block :: proc(block: ^Memory_Block, min_size, alignment: uint) -> (data: []byte, err: Allocator_Error) {
 alloc_from_memory_block :: proc(block: ^Memory_Block, min_size, alignment: uint) -> (data: []byte, err: Allocator_Error) {
 	calc_alignment_offset :: proc "contextless" (block: ^Memory_Block, alignment: uintptr) -> uint {
 	calc_alignment_offset :: proc "contextless" (block: ^Memory_Block, alignment: uintptr) -> uint {
 		alignment_offset := uint(0)
 		alignment_offset := uint(0)
@@ -160,7 +164,7 @@ memory_block_dealloc :: proc(block_to_free: ^Memory_Block) {
 
 
 
 
 
 
-@(private)
+@(private, require_results)
 safe_add :: #force_inline proc "contextless" (x, y: uint) -> (uint, bool) {
 safe_add :: #force_inline proc "contextless" (x, y: uint) -> (uint, bool) {
 	z, did_overflow := intrinsics.overflow_add(x, y)
 	z, did_overflow := intrinsics.overflow_add(x, y)
 	return z, !did_overflow
 	return z, !did_overflow