Rolled my own virtual memory baseline interface

Mostly use the core library's functionality but wanted a nicer wrap for my use case
This commit is contained in:
Edward R. Gonzalez 2024-03-06 16:45:12 -05:00
parent 0656a41cf7
commit 3ab6bb8616
2 changed files with 144 additions and 0 deletions

View File

@ -0,0 +1,112 @@
/* Virtual Memory OS Interface
This is an alternative to the virtual core library provided by odin, suppport setting the base address among other things.
*/
package sectr
import core_virtual "core:mem/virtual"
import "core:os"
VirtualMemoryRegionHeader :: struct {
committed : uint,
reserved : uint,
reserve_start : [^]byte,
}
VirtualMemoryRegion :: struct {
using base_address : ^VirtualMemoryRegionHeader
}
virtual_get_page_size :: proc "contextless" () -> int {
@static page_size := 0
if page_size == 0 {
page_size = os.get_page_size()
}
return page_size
}
virtual_reserve_remaining :: proc "contextless" ( using vmem : VirtualMemoryRegion ) -> uint {
header_offset := cast(uint) (uintptr(reserve_start) - uintptr(vmem.base_address))
return reserved - header_offset
}
@(require_results)
virtual_commit :: proc "contextless" ( using vmem : VirtualMemoryRegion, size : uint ) -> ( alloc_error : AllocatorError )
{
if size < committed {
return .None
}
page_size := uint(virtual_get_page_size())
to_commit := memory_align_formula( size, page_size )
alloc_error = core_virtual.commit( base_address, to_commit )
if alloc_error != .None {
return alloc_error
}
base_address.committed = size
return alloc_error
}
virtual_decommit :: proc "contextless" ( vmem : VirtualMemoryRegion, size : uint ) {
core_virtual.decommit( vmem.base_address, size )
}
virtual_protect :: proc "contextless" ( vmem : VirtualMemoryRegion, region : []byte, flags : VirtualProtectFlags ) -> b32
{
page_size := virtual_get_page_size()
if len(region) % page_size != 0 {
return false
}
return cast(b32) core_virtual.protect( raw_data(region), len(region), flags )
}
@(require_results)
virtual_reserve :: proc "contextless" ( base_address : uintptr, size : uint ) -> ( VirtualMemoryRegion, AllocatorError ) {
page_size := uint(virtual_get_page_size())
to_reserve := memory_align_formula( size, page_size )
return virtual__reserve( base_address, to_reserve )
}
@(require_results)
virtual_reserve_and_commit :: proc "contextless" (
base_address : uintptr, reserve_size, commit_size : uint
) -> ( vmem : VirtualMemoryRegion, alloc_error : AllocatorError )
{
if reserve_size < commit_size {
alloc_error = .Invalid_Argument
return
}
vmem, alloc_error = virtual_reserve( base_address, reserve_size )
if alloc_error != .None {
return
}
alloc_error = virtual_commit( vmem, commit_size )
return
}
virtual_release :: proc "contextless" ( vmem : VirtualMemoryRegion ) {
core_virtual.release( vmem.base_address, vmem.reserved )
}
// If the OS is not windows, we just use the library's interface which does not support base_address.
when ODIN_OS != OS_Type.Windows {
virtual__reserve :: proc "contextless" ( base_address : uintptr, size : uint ) -> ( vmem : VirtualMemoryRegion, alloc_error : AllocatorError )
{
// Ignoring the base address, add an os specific impl if you want it.
data : []byte
data, alloc_error := core_virtual.reserve( size ) or_return
vmem.base_address := cast( ^VirtualMemoryRegionHeader ) raw_data(data)
vmem.reserve_start = memory_after_header(vmem.base_address)
vmem.reserved = len(data)
vmem.committed = 0
return
}
} // END: ODIN_OS != runtime.Odin_OS_Type.Windows

View File

@ -0,0 +1,32 @@
/* Windows Virtual Memory
Windows is the only os getting special vmem definitions
since I want full control of it for debug purposes.
*/
package sectr
import "core:mem/virtual"
import win32 "core:sys/windows"
when ODIN_OS == OS_Type.Windows {
@(require_results)
virtual__reserve ::
proc "contextless" ( base_address : uintptr, size : uint ) -> ( vmem : VirtualMemoryRegion, alloc_error : AllocatorError )
{
header_size :: cast(uint) size_of(VirtualMemoryRegion)
result := win32.VirtualAlloc( rawptr(base_address), header_size + size, win32.MEM_RESERVE, win32.PAGE_READWRITE )
if result == nil {
alloc_error = .Out_Of_Memory
return
}
vmem.base_address = cast(^VirtualMemoryRegionHeader) result
vmem.reserve_start = memory_after_header(vmem.base_address)
vmem.reserved = size
vmem.committed = 0
alloc_error = .None
return
}
} // END: ODIN_OS == runtime.Odin_OS_Type.Windows