mirror of
https://github.com/Ed94/Odin.git
synced 2026-08-06 15:48:51 +00:00
Add virtual.map_file
This commit is contained in:
@@ -0,0 +1,47 @@
|
|||||||
|
package mem_virtual
|
||||||
|
|
||||||
|
import "core:os"
|
||||||
|
|
||||||
|
Mapped_File_Error :: enum {
|
||||||
|
None,
|
||||||
|
Open_Failure,
|
||||||
|
Stat_Failure,
|
||||||
|
Negative_Size,
|
||||||
|
Too_Large_Size,
|
||||||
|
Map_Failure,
|
||||||
|
}
|
||||||
|
|
||||||
|
Mapped_File_Flag :: enum u32 {
|
||||||
|
Read,
|
||||||
|
Write,
|
||||||
|
}
|
||||||
|
Mapped_File_Flags :: distinct bit_set[Mapped_File_Flag; u32]
|
||||||
|
|
||||||
|
map_file :: proc{
|
||||||
|
map_file_from_path,
|
||||||
|
map_file_from_file_descriptor,
|
||||||
|
}
|
||||||
|
|
||||||
|
map_file_from_path :: proc(filename: string, flags: Mapped_File_Flags) -> (data: []byte, error: Mapped_File_Error) {
|
||||||
|
fd, err := os.open(filename, os.O_RDWR)
|
||||||
|
if err != 0 {
|
||||||
|
return nil, .Open_Failure
|
||||||
|
}
|
||||||
|
defer os.close(fd)
|
||||||
|
|
||||||
|
return map_file_from_file_descriptor(uintptr(fd), flags)
|
||||||
|
}
|
||||||
|
|
||||||
|
map_file_from_file_descriptor :: proc(fd: uintptr, flags: Mapped_File_Flags) -> (data: []byte, error: Mapped_File_Error) {
|
||||||
|
size, os_err := os.file_size(os.Handle(fd))
|
||||||
|
if os_err != 0 {
|
||||||
|
return nil, .Stat_Failure
|
||||||
|
}
|
||||||
|
if size < 0 {
|
||||||
|
return nil, .Negative_Size
|
||||||
|
}
|
||||||
|
if size != i64(int(size)) {
|
||||||
|
return nil, .Too_Large_Size
|
||||||
|
}
|
||||||
|
return _map_file(fd, size, flags)
|
||||||
|
}
|
||||||
@@ -22,3 +22,7 @@ _protect :: proc "contextless" (data: rawptr, size: uint, flags: Protect_Flags)
|
|||||||
_platform_memory_init :: proc() {
|
_platform_memory_init :: proc() {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_map_file :: proc "contextless" (fd: uintptr, size: i64, flags: Mapped_File_Flags) -> (data: []byte, error: Mapped_File_Error) {
|
||||||
|
return nil, .Map_Failure
|
||||||
|
}
|
||||||
|
|||||||
@@ -146,3 +146,20 @@ _platform_memory_init :: proc() {
|
|||||||
// is power of two
|
// is power of two
|
||||||
assert(DEFAULT_PAGE_SIZE != 0 && (DEFAULT_PAGE_SIZE & (DEFAULT_PAGE_SIZE-1)) == 0)
|
assert(DEFAULT_PAGE_SIZE != 0 && (DEFAULT_PAGE_SIZE & (DEFAULT_PAGE_SIZE-1)) == 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
_map_file :: proc "contextless" (fd: uintptr, size: i64, flags: Mapped_File_Flags) -> (data: []byte, error: Mapped_File_Error) {
|
||||||
|
prot, mflags: c.int
|
||||||
|
if .Read in flags {
|
||||||
|
prot |= PROT_READ
|
||||||
|
}
|
||||||
|
if .Write in flags {
|
||||||
|
prot |= PROT_WRITE
|
||||||
|
}
|
||||||
|
mflags |= MAP_SHARED
|
||||||
|
addr := _mmap(nil, c.size_t(size), prot, mflags, i32(fd), 0)
|
||||||
|
if addr == nil {
|
||||||
|
return nil, .Map_Failure
|
||||||
|
}
|
||||||
|
return ([^]byte)(addr)[:size], nil
|
||||||
|
}
|
||||||
|
|||||||
@@ -48,3 +48,21 @@ _platform_memory_init :: proc() {
|
|||||||
// is power of two
|
// is power of two
|
||||||
assert(DEFAULT_PAGE_SIZE != 0 && (DEFAULT_PAGE_SIZE & (DEFAULT_PAGE_SIZE-1)) == 0)
|
assert(DEFAULT_PAGE_SIZE != 0 && (DEFAULT_PAGE_SIZE & (DEFAULT_PAGE_SIZE-1)) == 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
_map_file :: proc "contextless" (fd: uintptr, size: i64, flags: Mapped_File_Flags) -> (data: []byte, error: Mapped_File_Error) {
|
||||||
|
prot: linux.Mem_Protection
|
||||||
|
if .Read in flags {
|
||||||
|
prot += {.READ}
|
||||||
|
}
|
||||||
|
if .Write in flags {
|
||||||
|
prot += {.WRITE}
|
||||||
|
}
|
||||||
|
|
||||||
|
flags := linux.Map_Flags{.SHARED}
|
||||||
|
addr, errno := linux.mmap(0, uint(size), prot, flags, linux.Fd(fd), offset=0)
|
||||||
|
if addr == nil || error != nil {
|
||||||
|
return nil, .Map_Failure
|
||||||
|
}
|
||||||
|
return ([^]byte)(addr)[:size], nil
|
||||||
|
}
|
||||||
|
|||||||
@@ -2,6 +2,8 @@
|
|||||||
//+private
|
//+private
|
||||||
package mem_virtual
|
package mem_virtual
|
||||||
|
|
||||||
|
import "core:os"
|
||||||
|
|
||||||
foreign import Kernel32 "system:Kernel32.lib"
|
foreign import Kernel32 "system:Kernel32.lib"
|
||||||
|
|
||||||
LPSYSTEM_INFO :: ^SYSTEM_INFO
|
LPSYSTEM_INFO :: ^SYSTEM_INFO
|
||||||
@@ -50,6 +52,11 @@ PAGE_WRITECOPY :: 0x08
|
|||||||
PAGE_TARGETS_INVALID :: 0x40000000
|
PAGE_TARGETS_INVALID :: 0x40000000
|
||||||
PAGE_TARGETS_NO_UPDATE :: 0x40000000
|
PAGE_TARGETS_NO_UPDATE :: 0x40000000
|
||||||
|
|
||||||
|
SECTION_MAP_WRITE :: 0x0002
|
||||||
|
SECTION_MAP_READ :: 0x0004
|
||||||
|
FILE_MAP_WRITE :: SECTION_MAP_WRITE
|
||||||
|
FILE_MAP_READ :: SECTION_MAP_READ
|
||||||
|
|
||||||
ERROR_INVALID_ADDRESS :: 487
|
ERROR_INVALID_ADDRESS :: 487
|
||||||
ERROR_COMMITMENT_LIMIT :: 1455
|
ERROR_COMMITMENT_LIMIT :: 1455
|
||||||
|
|
||||||
@@ -60,9 +67,24 @@ foreign Kernel32 {
|
|||||||
VirtualFree :: proc(lpAddress: rawptr, dwSize: uint, dwFreeType: u32) -> b32 ---
|
VirtualFree :: proc(lpAddress: rawptr, dwSize: uint, dwFreeType: u32) -> b32 ---
|
||||||
VirtualProtect :: proc(lpAddress: rawptr, dwSize: uint, flNewProtect: u32, lpflOldProtect: ^u32) -> b32 ---
|
VirtualProtect :: proc(lpAddress: rawptr, dwSize: uint, flNewProtect: u32, lpflOldProtect: ^u32) -> b32 ---
|
||||||
GetLastError :: proc() -> u32 ---
|
GetLastError :: proc() -> u32 ---
|
||||||
|
|
||||||
|
CreateFileMappingW :: proc(
|
||||||
|
hFile: rawptr,
|
||||||
|
lpFileMappingAttributes: rawptr,
|
||||||
|
flProtect: u32,
|
||||||
|
dwMaximumSizeHigh: u32,
|
||||||
|
dwMaximumSizeLow: u32,
|
||||||
|
lpName: [^]u16,
|
||||||
|
) -> rawptr ---
|
||||||
|
|
||||||
|
MapViewOfFile :: proc(
|
||||||
|
hFileMappingObject: rawptr,
|
||||||
|
dwDesiredAccess: u32,
|
||||||
|
dwFileOffsetHigh: u32,
|
||||||
|
dwFileOffsetLow: u32,
|
||||||
|
dwNumberOfBytesToMap: uint,
|
||||||
|
) -> rawptr ---
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
_reserve :: proc "contextless" (size: uint) -> (data: []byte, err: Allocator_Error) {
|
_reserve :: proc "contextless" (size: uint) -> (data: []byte, err: Allocator_Error) {
|
||||||
result := VirtualAlloc(nil, size, MEM_RESERVE, PAGE_READWRITE)
|
result := VirtualAlloc(nil, size, MEM_RESERVE, PAGE_READWRITE)
|
||||||
if result == nil {
|
if result == nil {
|
||||||
@@ -125,3 +147,33 @@ _platform_memory_init :: proc() {
|
|||||||
// is power of two
|
// is power of two
|
||||||
assert(DEFAULT_PAGE_SIZE != 0 && (DEFAULT_PAGE_SIZE & (DEFAULT_PAGE_SIZE-1)) == 0)
|
assert(DEFAULT_PAGE_SIZE != 0 && (DEFAULT_PAGE_SIZE & (DEFAULT_PAGE_SIZE-1)) == 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
_map_file :: proc "contextless" (fd: os.Handle, size: i64, flags: Mapped_File_Flags) -> (data: []byte, error: Mapped_File_Error) {
|
||||||
|
page_flags: u32
|
||||||
|
if flags == {.Read} {
|
||||||
|
page_flags = PAGE_READONLY
|
||||||
|
} else if flags == {.Write} {
|
||||||
|
page_flags = PAGE_READWRITE
|
||||||
|
} else if flags == {.Read, .Write} {
|
||||||
|
page_flags = PAGE_READWRITE
|
||||||
|
} else {
|
||||||
|
page_flags = PAGE_NOACCESS
|
||||||
|
}
|
||||||
|
maximum_size := transmute([2]u32)size
|
||||||
|
handle := CreateFileMappingW(rawptr(fd), nil, page_flags, maximum_size[1], maximum_size[0], nil)
|
||||||
|
if handle == nil {
|
||||||
|
return nil, .Map_Failure
|
||||||
|
}
|
||||||
|
|
||||||
|
desired_access: u32
|
||||||
|
if .Read in flags {
|
||||||
|
desired_access |= FILE_MAP_READ
|
||||||
|
}
|
||||||
|
if .Write in flags {
|
||||||
|
desired_access |= FILE_MAP_WRITE
|
||||||
|
}
|
||||||
|
|
||||||
|
file_data := MapViewOfFile(handle, desired_access, 0, 0, uint(size))
|
||||||
|
return ([^]byte)(file_data)[:size], nil
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user