diff --git a/core/mem/virtual/arena.odin b/core/mem/virtual/arena.odin index d4d84e5b3..d8949cb10 100644 --- a/core/mem/virtual/arena.odin +++ b/core/mem/virtual/arena.odin @@ -12,9 +12,8 @@ Growing_Arena :: struct { } 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) { +growing_arena_alloc :: proc(arena: ^Growing_Arena, min_size: int, alignment: int) -> (data: []byte, err: Allocator_Error) { align_forward_offset :: proc(arena: ^Growing_Arena, alignment: int) -> int #no_bounds_check { alignment_offset := 0 ptr := uintptr(arena.curr_block.base[arena.curr_block.used:]) @@ -71,7 +70,7 @@ growing_arena_free_all :: proc(arena: ^Growing_Arena) { arena.total_used = 0 } -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) { +growing_arena_bootstrap_new_by_offset :: proc($T: typeid, offset_to_arena: uintptr, minimum_block_size := DEFAULT_MINIMUM_BLOCK_SIZE) -> (ptr: ^T, err: Allocator_Error) { bootstrap: Growing_Arena bootstrap.minimum_block_size = minimum_block_size @@ -84,7 +83,7 @@ growing_arena_bootstrap_new_by_offset :: proc($T: typeid, offset_to_arena: uintp 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) { +growing_arena_bootstrap_new_by_name :: proc($T: typeid, $field_name: string, minimum_block_size := DEFAULT_MINIMUM_BLOCK_SIZE) -> (ptr: ^T, err: 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{ @@ -99,7 +98,7 @@ growing_arena_allocator :: proc(arena: ^Growing_Arena) -> mem.Allocator { growing_arena_allocator_proc :: proc(allocator_data: rawptr, mode: mem.Allocator_Mode, size, alignment: int, old_memory: rawptr, old_size: int, - location := #caller_location) -> (data: []byte, err: mem.Allocator_Error) { + location := #caller_location) -> (data: []byte, err: Allocator_Error) { arena := (^Growing_Arena)(allocator_data) switch mode { @@ -160,4 +159,4 @@ growing_arena_temp_end :: proc(temp: Growing_Arena_Temp, loc := #caller_location growing_arena_check_temp :: proc(arena: ^Growing_Arena, loc := #caller_location) { assert(arena.temp_count == 0, "Growing_Arena_Temp not been ended", loc) -} \ No newline at end of file +} diff --git a/core/mem/virtual/virtual.odin b/core/mem/virtual/virtual.odin index 83a4e8783..a78917ae1 100644 --- a/core/mem/virtual/virtual.odin +++ b/core/mem/virtual/virtual.odin @@ -3,6 +3,39 @@ package mem_virtual import "core:mem" import sync "core:sync/sync2" +DEFAULT_PAGE_SIZE := uint(4096) + +Allocator_Error :: mem.Allocator_Error + +reserve :: proc(size: uint) -> (data: []byte, err: Allocator_Error) { + return _reserve(size) +} + +commit :: proc(data: rawptr, size: uint) { + _commit(data, size) +} + +reserve_and_commit :: proc(size: uint) -> (data: []byte, err: Allocator_Error) { + data = _reserve(size) or_return + commit(raw_data(data), size) + return +} + + +decommit :: proc(data: rawptr, size: uint) { + _decommit(data, size) +} + +release :: proc(data: rawptr, size: uint) { + _release(data, size) +} + +protect :: proc(data: rawptr, size: uint) -> bool { + return _protect(data, size) +} + + + Memory_Block :: struct { prev: ^Memory_Block, base: [^]byte, @@ -11,18 +44,23 @@ Memory_Block :: struct { } -memory_alloc :: proc(size: int) -> (block: ^Memory_Block, err: mem.Allocator_Error) { +memory_alloc :: proc(size: int) -> (block: ^Memory_Block, err: Allocator_Error) { + align_formula :: proc "contextless" (size, align: uint) -> uint { + result := size + align-1 + return result - result%align + } + page_size := DEFAULT_PAGE_SIZE - total_size := size + size_of(Platform_Memory_Block) + total_size := uint(size + size_of(Platform_Memory_Block)) base_offset := uintptr(size_of(Platform_Memory_Block)) protect_offset := uintptr(0) do_protection := false { // overflow protection - rounded_size := mem.align_formula(size, page_size) - total_size = rounded_size + 2*page_size - base_offset = uintptr(page_size + rounded_size - size) + rounded_size := align_formula(uint(size), page_size) + total_size = uint(rounded_size + 2*page_size) + base_offset = uintptr(page_size + rounded_size - uint(size)) protect_offset = uintptr(page_size + rounded_size) do_protection = true } @@ -35,7 +73,7 @@ memory_alloc :: proc(size: int) -> (block: ^Memory_Block, err: mem.Allocator_Err assert(pmblock.block.prev == nil) if (do_protection) { - platform_memory_protect(rawptr(uintptr(pmblock) + protect_offset), page_size) + protect(rawptr(uintptr(pmblock) + protect_offset), page_size) } pmblock.block.size = size @@ -67,10 +105,26 @@ memory_dealloc :: proc(block_to_free: ^Memory_Block) { Platform_Memory_Block :: struct { block: Memory_Block, - total_size: int, + total_size: uint, prev, next: ^Platform_Memory_Block, } +platform_memory_alloc :: proc(total_size: uint) -> (block: ^Platform_Memory_Block, err: Allocator_Error) { + total_size := total_size + total_size = max(total_size, size_of(Platform_Memory_Block)) + data := reserve_and_commit(total_size) or_return + block = (^Platform_Memory_Block)(raw_data(data)) + block.total_size = total_size + return +} + + +platform_memory_free :: proc(block: ^Platform_Memory_Block) { + if block != nil { + release(block, block.total_size) + } +} + @(private) global_memory_block_mutex: sync.Mutex @(private) @@ -78,7 +132,7 @@ global_platform_memory_block_sentinel: Platform_Memory_Block @(private) global_platform_memory_block_sentinel_set: bool -@(init) +@(private, init) platform_memory_init :: proc() { if !global_platform_memory_block_sentinel_set { _platform_memory_init() @@ -87,16 +141,3 @@ platform_memory_init :: proc() { global_platform_memory_block_sentinel_set = true } } - -platform_memory_alloc :: proc(block_size: int) -> (^Platform_Memory_Block, mem.Allocator_Error) { - return _platform_memory_alloc(block_size) -} - - -platform_memory_free :: proc(block: ^Platform_Memory_Block) { - _platform_memory_free(block) -} - -platform_memory_protect :: proc(memory: rawptr, size: int) { - _platform_memory_protect(memory, size) -} diff --git a/core/mem/virtual/virtual_windows.odin b/core/mem/virtual/virtual_windows.odin index 58dff6d3c..fb28eb117 100644 --- a/core/mem/virtual/virtual_windows.odin +++ b/core/mem/virtual/virtual_windows.odin @@ -2,8 +2,6 @@ //+private package mem_virtual -import "core:mem" - foreign import Kernel32 "system:Kernel32.lib" LPSYSTEM_INFO :: ^SYSTEM_INFO @@ -60,28 +58,38 @@ foreign Kernel32 { } +_reserve :: proc(size: uint) -> (data: []byte, err: Allocator_Error) { + result := VirtualAlloc(nil, size, MEM_RELEASE, PAGE_READWRITE) + if result == nil { + err = .Out_Of_Memory + return + } + data = ([^]byte)(result)[:size] + return +} + +_commit :: proc(data: rawptr, size: uint) { + VirtualAlloc(data, size, MEM_COMMIT, PAGE_READWRITE) +} +_decommit :: proc(data: rawptr, size: uint) { + VirtualFree(data, size, MEM_DECOMMIT) +} +_release :: proc(data: rawptr, size: uint) { + VirtualFree(data, 0, MEM_RELEASE) +} +_protect :: proc(data: rawptr, size: uint) -> bool { + old_protect: u32 + ok := VirtualProtect(data, size, PAGE_NOACCESS, &old_protect) + return bool(ok) +} + + + _platform_memory_init :: proc() { sys_info: SYSTEM_INFO GetSystemInfo(&sys_info) - DEFAULT_PAGE_SIZE = max(DEFAULT_PAGE_SIZE, int(sys_info.dwPageSize)) - assert(mem.is_power_of_two(uintptr(DEFAULT_PAGE_SIZE))) + DEFAULT_PAGE_SIZE = max(DEFAULT_PAGE_SIZE, uint(sys_info.dwPageSize)) + + // is power of two + assert(DEFAULT_PAGE_SIZE != 0 && (DEFAULT_PAGE_SIZE & (DEFAULT_PAGE_SIZE-1)) == 0) } - -_platform_memory_alloc :: proc(total_size: int) -> (pmblock: ^Platform_Memory_Block, err: mem.Allocator_Error) { - pmblock = (^Platform_Memory_Block)(VirtualAlloc(nil, uint(total_size), MEM_RESERVE|MEM_COMMIT, PAGE_READWRITE)) - if pmblock == nil { - err = .Out_Of_Memory - } - return -} - - -_platform_memory_free :: proc(block: ^Platform_Memory_Block) { - VirtualFree(block, 0, MEM_RELEASE) -} - -_platform_memory_protect :: proc(memory: rawptr, size: int) -> bool { - old_protect: u32 - ok := VirtualProtect(memory, uint(size), PAGE_NOACCESS, &old_protect) - return bool(ok) -} \ No newline at end of file