Compare commits
3 Commits
a0ddc3c26e
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
| aef68be7e2 | |||
| 32b69d50cb | |||
| e632bc4c78 |
@@ -39,6 +39,11 @@ AllocatorOp :: enum u32 {
|
||||
Rewind,
|
||||
SavePoint,
|
||||
Query, // Must always be implemented
|
||||
Is_Owner,
|
||||
Startup,
|
||||
Shutdown,
|
||||
Thread_Start,
|
||||
Thread_Stop,
|
||||
}
|
||||
AllocatorQueryFlag :: enum u64 {
|
||||
Alloc,
|
||||
@@ -47,27 +52,29 @@ AllocatorQueryFlag :: enum u64 {
|
||||
|
||||
Shrink,
|
||||
Grow,
|
||||
Resize, // Supports both grow and shrink
|
||||
|
||||
Rewind, // Ability to rewind to a save point (ex: arenas, stack), must also be able to save such a point
|
||||
|
||||
// Actually_Resize,
|
||||
// Is_This_Yours,
|
||||
Actually_Resize,
|
||||
Multiple_Threads,
|
||||
Is_Owner,
|
||||
|
||||
Hint_Fast_Bump,
|
||||
Hint_General_Heap,
|
||||
Hint_Per_Frame_Temporary,
|
||||
Hint_Debug_Support,
|
||||
}
|
||||
AllocatorError :: Odin_AllocatorError
|
||||
// AllocatorError :: enum i32 {
|
||||
// None = 0,
|
||||
// Out_Of_Memory = 1,
|
||||
// Invalid_Pointer = 2,
|
||||
// Invalid_Argument = 3,
|
||||
// Mode_Not_Implemented = 4,
|
||||
// }
|
||||
AllocatorQueryFlags :: bit_set[AllocatorQueryFlag; u64]
|
||||
|
||||
// AllocatorError :: Odin_AllocatorError
|
||||
AllocatorError :: enum byte {
|
||||
None = 0,
|
||||
Out_Of_Memory = 1,
|
||||
Invalid_Pointer = 2,
|
||||
Invalid_Argument = 3,
|
||||
Mode_Not_Implemented = 4,
|
||||
Owner = 5,
|
||||
}
|
||||
AllocatorSP :: struct {
|
||||
type_sig: AllocatorProc,
|
||||
slot: int,
|
||||
@@ -177,9 +184,6 @@ odin_allocator_mode_to_allocator_op :: #force_inline proc "contextless" (mode: O
|
||||
panic_contextless("Impossible path")
|
||||
}
|
||||
|
||||
// TODO(Ed): Change to DEFAULT_ALIGNMENT
|
||||
MEMORY_ALIGNMENT_DEFAULT :: 2 * size_of(rawptr)
|
||||
|
||||
allocatorinfo :: #force_inline proc(ainfo := context.allocator) -> AllocatorInfo { return transmute(AllocatorInfo) ainfo }
|
||||
allocator :: #force_inline proc(ainfo: AllocatorInfo) -> Odin_Allocator { return transmute(Odin_Allocator) ainfo }
|
||||
|
||||
@@ -202,11 +206,10 @@ mem_rewind :: proc(ainfo := context.allocator, save_point: AllocatorSP, loc := #
|
||||
}
|
||||
mem_save_point :: proc(ainfo := context.allocator, loc := #caller_location) -> AllocatorSP {
|
||||
assert(ainfo.procedure != nil)
|
||||
out: AllocatorProc_Out
|
||||
resolve_allocator_proc(ainfo.procedure)({data = ainfo.data, op = .SavePoint, loc = loc}, & out)
|
||||
out: AllocatorProc_Out; resolve_allocator_proc(ainfo.procedure)({data = ainfo.data, op = .SavePoint, loc = loc}, & out)
|
||||
return out.save_point
|
||||
}
|
||||
mem_alloc :: proc(size: int, alignment: int = MEMORY_ALIGNMENT_DEFAULT, no_zero: bool = false, ainfo: $Type = context.allocator, loc := #caller_location) -> ([]byte, AllocatorError) {
|
||||
mem_alloc :: proc(size: int, alignment: int = DEFAULT_ALIGNMENT, no_zero: bool = false, ainfo: $Type = context.allocator, loc := #caller_location) -> ([]byte, AllocatorError) {
|
||||
assert(ainfo.procedure != nil)
|
||||
input := AllocatorProc_In {
|
||||
data = ainfo.data,
|
||||
@@ -215,11 +218,10 @@ mem_alloc :: proc(size: int, alignment: int = MEMORY_ALIGNMENT_DEFAULT, no_zero:
|
||||
alignment = alignment,
|
||||
loc = loc,
|
||||
}
|
||||
output: AllocatorProc_Out
|
||||
resolve_allocator_proc(ainfo.procedure)(input, & output)
|
||||
output: AllocatorProc_Out; resolve_allocator_proc(ainfo.procedure)(input, & output)
|
||||
return output.allocation, output.error
|
||||
}
|
||||
mem_grow :: proc(mem: []byte, size: int, alignment: int = MEMORY_ALIGNMENT_DEFAULT, no_zero: bool = false, ainfo := context.allocator, loc := #caller_location) -> ([]byte, AllocatorError) {
|
||||
mem_grow :: proc(mem: []byte, size: int, alignment: int = DEFAULT_ALIGNMENT, no_zero: bool = false, ainfo := context.allocator, loc := #caller_location) -> ([]byte, AllocatorError) {
|
||||
assert(ainfo.procedure != nil)
|
||||
input := AllocatorProc_In {
|
||||
data = ainfo.data,
|
||||
@@ -229,11 +231,10 @@ mem_grow :: proc(mem: []byte, size: int, alignment: int = MEMORY_ALIGNMENT_DEFAU
|
||||
old_allocation = mem,
|
||||
loc = loc,
|
||||
}
|
||||
output: AllocatorProc_Out
|
||||
resolve_allocator_proc(ainfo.procedure)(input, & output)
|
||||
output: AllocatorProc_Out; resolve_allocator_proc(ainfo.procedure)(input, & output)
|
||||
return output.allocation, output.error
|
||||
}
|
||||
mem_resize :: proc(mem: []byte, size: int, alignment: int = MEMORY_ALIGNMENT_DEFAULT, no_zero: bool = false, ainfo := context.allocator, loc := #caller_location) -> ([]byte, AllocatorError) {
|
||||
mem_resize :: proc(mem: []byte, size: int, alignment: int = DEFAULT_ALIGNMENT, no_zero: bool = false, ainfo := context.allocator, loc := #caller_location) -> ([]byte, AllocatorError) {
|
||||
assert(ainfo.procedure != nil)
|
||||
input := AllocatorProc_In {
|
||||
data = ainfo.data,
|
||||
@@ -243,11 +244,10 @@ mem_resize :: proc(mem: []byte, size: int, alignment: int = MEMORY_ALIGNMENT_DEF
|
||||
old_allocation = mem,
|
||||
loc = loc,
|
||||
}
|
||||
output: AllocatorProc_Out
|
||||
resolve_allocator_proc(ainfo.procedure)(input, & output)
|
||||
output: AllocatorProc_Out; resolve_allocator_proc(ainfo.procedure)(input, & output)
|
||||
return output.allocation, output.error
|
||||
}
|
||||
mem_shrink :: proc(mem: []byte, size: int, alignment: int = MEMORY_ALIGNMENT_DEFAULT, no_zero: bool = false, ainfo := context.allocator, loc := #caller_location) -> ([]byte, AllocatorError) {
|
||||
mem_shrink :: proc(mem: []byte, size: int, alignment: int = DEFAULT_ALIGNMENT, no_zero: bool = false, ainfo := context.allocator, loc := #caller_location) -> ([]byte, AllocatorError) {
|
||||
assert(ainfo.procedure != nil)
|
||||
input := AllocatorProc_In {
|
||||
data = ainfo.data,
|
||||
@@ -257,12 +257,11 @@ mem_shrink :: proc(mem: []byte, size: int, alignment: int = MEMORY_ALIGNMENT_DEF
|
||||
old_allocation = mem,
|
||||
loc = loc,
|
||||
}
|
||||
output: AllocatorProc_Out
|
||||
resolve_allocator_proc(ainfo.procedure)(input, & output)
|
||||
output: AllocatorProc_Out; resolve_allocator_proc(ainfo.procedure)(input, & output)
|
||||
return output.allocation, output.error
|
||||
}
|
||||
|
||||
alloc_type :: proc($Type: typeid, alignment: int = MEMORY_ALIGNMENT_DEFAULT, no_zero: bool = false, ainfo := context.allocator, loc := #caller_location) -> (^Type, AllocatorError) {
|
||||
alloc_type :: proc($Type: typeid, alignment: int = DEFAULT_ALIGNMENT, no_zero: bool = false, ainfo := context.allocator, loc := #caller_location) -> (^Type, AllocatorError) {
|
||||
assert(ainfo.procedure != nil)
|
||||
input := AllocatorProc_In {
|
||||
data = ainfo.data,
|
||||
@@ -271,11 +270,10 @@ alloc_type :: proc($Type: typeid, alignment: int = MEMORY_ALIGNMENT_DEFAULT, no
|
||||
alignment = alignment,
|
||||
loc = loc,
|
||||
}
|
||||
output: AllocatorProc_Out
|
||||
resolve_allocator_proc(ainfo.procedure)(input, & output)
|
||||
output: AllocatorProc_Out; resolve_allocator_proc(ainfo.procedure)(input, & output)
|
||||
return transmute(^Type) raw_data(output.allocation), output.error
|
||||
}
|
||||
alloc_slice :: proc($SliceType: typeid / []$Type, num: int, alignment: int = MEMORY_ALIGNMENT_DEFAULT, no_zero: bool = false, ainfo := context.allocator, loc := #caller_location) -> ([]Type, AllocatorError) {
|
||||
alloc_slice :: proc($SliceType: typeid / []$Type, num: int, alignment: int = DEFAULT_ALIGNMENT, no_zero: bool = false, ainfo := context.allocator, loc := #caller_location) -> ([]Type, AllocatorError) {
|
||||
assert(ainfo.procedure != nil)
|
||||
input := AllocatorProc_In {
|
||||
data = ainfo.data,
|
||||
@@ -284,7 +282,6 @@ alloc_slice :: proc($SliceType: typeid / []$Type, num: int, alignment: int = MEM
|
||||
alignment = alignment,
|
||||
loc = loc,
|
||||
}
|
||||
output: AllocatorProc_Out
|
||||
resolve_allocator_proc(ainfo.procedure)(input, & output)
|
||||
output: AllocatorProc_Out; resolve_allocator_proc(ainfo.procedure)(input, & output)
|
||||
return transmute([]Type) slice(raw_data(output.allocation), num), output.error
|
||||
}
|
||||
|
||||
@@ -2,13 +2,13 @@ package grime
|
||||
|
||||
// TODO(Ed): Below should be defined per-package?
|
||||
|
||||
ensure :: #force_inline proc(condition: bool, msg: string, location := #caller_location) -> bool {
|
||||
if condition do return true
|
||||
ensure :: #force_inline proc(condition: bool, msg := #caller_expression, location := #caller_location) -> bool {
|
||||
if condition == false do return false
|
||||
log_print( msg, LoggerLevel.Warning, location )
|
||||
when ODIN_DEBUG == false do return false
|
||||
when ODIN_DEBUG == false do return true
|
||||
else {
|
||||
debug_trap()
|
||||
return false
|
||||
return true
|
||||
}
|
||||
}
|
||||
// TODO(Ed) : Setup exit codes!
|
||||
|
||||
@@ -79,8 +79,8 @@ array_set_capacity :: proc( self : ^Array( $ Type ), new_capacity: int) -> Alloc
|
||||
header_size :: size_of(ArrayHeader(Type))
|
||||
new_size := header_size + new_capacity * size_of(Type)
|
||||
old_size := header_size + self.capacity * size_of(Type)
|
||||
new_mem, result_code := mem_resize( slice(transmute(^u8)self.header, old_size), new_size, MEMORY_ALIGNMENT_DEFAULT, ainfo = self.backing )
|
||||
if ensure( result_code != AllocatorError.None, "Failed to allocate for new array capacity" ) {
|
||||
new_mem, result_code := mem_resize( slice(transmute(^u8)self.header, old_size), new_size, DEFAULT_ALIGNMENT, ainfo = self.backing )
|
||||
if ensure( result_code == AllocatorError.None, "Failed to allocate for new array capacity" ) {
|
||||
log_print( "Failed to allocate for new array capacity", level = LoggerLevel.Warning )
|
||||
return result_code
|
||||
}
|
||||
@@ -175,7 +175,7 @@ array_fill :: proc(self: Array($Type), begin, end: u64, value: Type) -> bool {
|
||||
}
|
||||
|
||||
// Will push value into the array (will not grow if at capacity, use append instead for when that matters)
|
||||
array_push_back :: #force_inline proc "contextless" (self: Array($Type)) -> bool {
|
||||
array_push :: #force_inline proc "contextless" (self: Array($Type)) -> bool {
|
||||
if self.num == self.capacity { return false }
|
||||
self.data[self.num] = value
|
||||
self.num += 1
|
||||
|
||||
@@ -17,7 +17,7 @@ farena_init :: proc "contextless" (arena: ^FArena, backing: []byte) {
|
||||
arena.used = 0
|
||||
}
|
||||
@require_results
|
||||
farena_push :: proc "contextless" (arena: ^FArena, $Type: typeid, amount: int, alignment: int = MEMORY_ALIGNMENT_DEFAULT, loc := #caller_location) -> ([]Type, AllocatorError) {
|
||||
farena_push :: proc "contextless" (arena: ^FArena, $Type: typeid, amount: int, alignment: int = DEFAULT_ALIGNMENT, loc := #caller_location) -> ([]Type, AllocatorError) {
|
||||
assert_contextless(arena != nil)
|
||||
if amount == 0 {
|
||||
return {}, .None
|
||||
@@ -32,7 +32,7 @@ farena_push :: proc "contextless" (arena: ^FArena, $Type: typeid, amount: int, a
|
||||
return slice(cursor(arena.mem)[arena.used:], amount), .None
|
||||
}
|
||||
@require_results
|
||||
farena_grow :: proc "contextless" (arena: ^FArena, old_allocation: []byte, requested_size: int, alignment: int = MEMORY_ALIGNMENT_DEFAULT, should_zero: bool = true, loc := #caller_location) -> (allocation: []byte, err: AllocatorError) {
|
||||
farena_grow :: proc "contextless" (arena: ^FArena, old_allocation: []byte, requested_size: int, alignment: int = DEFAULT_ALIGNMENT, should_zero: bool = true, loc := #caller_location) -> (allocation: []byte, err: AllocatorError) {
|
||||
assert_contextless(arena != nil)
|
||||
if len(old_allocation) == 0 {
|
||||
return {}, .Invalid_Argument
|
||||
@@ -58,7 +58,7 @@ farena_grow :: proc "contextless" (arena: ^FArena, old_allocation: []byte, reque
|
||||
return
|
||||
}
|
||||
@require_results
|
||||
farena_shirnk :: proc "contextless" (arena: ^FArena, old_allocation: []byte, requested_size: int, alignment: int = MEMORY_ALIGNMENT_DEFAULT, loc := #caller_location) -> (allocation: []byte, err: AllocatorError) {
|
||||
farena_shirnk :: proc "contextless" (arena: ^FArena, old_allocation: []byte, requested_size: int, alignment: int = DEFAULT_ALIGNMENT, loc := #caller_location) -> (allocation: []byte, err: AllocatorError) {
|
||||
assert_contextless(arena != nil)
|
||||
if len(old_allocation) == 0 {
|
||||
return {}, .Invalid_Argument
|
||||
@@ -70,7 +70,7 @@ farena_shirnk :: proc "contextless" (arena: ^FArena, old_allocation: []byte, req
|
||||
return old_allocation[:requested_size], .None
|
||||
}
|
||||
// Calculate shrinkage
|
||||
aligned_original := align_pow2(len(old_allocation), MEMORY_ALIGNMENT_DEFAULT)
|
||||
aligned_original := align_pow2(len(old_allocation), DEFAULT_ALIGNMENT)
|
||||
aligned_new := align_pow2(requested_size, alignment)
|
||||
arena.used -= (aligned_original - aligned_new)
|
||||
return old_allocation[:requested_size], .None
|
||||
@@ -85,6 +85,13 @@ farena_rewind :: #force_inline proc "contextless" (arena: ^FArena, save_point: A
|
||||
arena.used = save_point.slot
|
||||
}
|
||||
farena_save :: #force_inline proc "contextless" (arena: FArena) -> AllocatorSP { return AllocatorSP { type_sig = farena_allocator_proc, slot = arena.used } }
|
||||
farena_is_owner :: #force_inline proc "contextless" (arena: FArena, memory: []byte) -> bool {
|
||||
p0 := transmute(uintptr) cursor(memory)
|
||||
p1 := transmute(uintptr) end(memory)
|
||||
arena_p0 := transmute(uintptr) cursor(arena.mem)
|
||||
arena_p1 := cast(uintptr) arena.used
|
||||
return arena_p0 <= p0 && arena_p1 >= p1
|
||||
}
|
||||
farena_allocator_proc :: proc(input: AllocatorProc_In, output: ^AllocatorProc_Out) {
|
||||
assert_contextless(output != nil)
|
||||
assert_contextless(input.data != nil)
|
||||
@@ -115,12 +122,16 @@ farena_allocator_proc :: proc(input: AllocatorProc_In, output: ^AllocatorProc_Ou
|
||||
output.save_point = farena_save(arena^)
|
||||
return
|
||||
case .Query:
|
||||
output.features = {.Alloc, .Reset, .Grow, .Shrink, .Rewind}
|
||||
output.features = {.Alloc, .Reset, .Grow, .Shrink, .Rewind, .Actually_Resize, .Is_Owner, .Hint_Fast_Bump}
|
||||
output.max_alloc = len(arena.mem) - arena.used
|
||||
output.min_alloc = 0
|
||||
output.left = output.max_alloc
|
||||
output.save_point = farena_save(arena^)
|
||||
return
|
||||
case .Is_Owner:
|
||||
output.error = farena_is_owner(arena ^, input.old_allocation) ? .Owner : .None
|
||||
case .Startup, .Shutdown, .Thread_Start, .Thread_Stop:
|
||||
output.error = .Mode_Not_Implemented
|
||||
}
|
||||
panic_contextless("Impossible path")
|
||||
}
|
||||
@@ -132,40 +143,38 @@ farena_odin_allocator_proc :: proc(
|
||||
old_memory : rawptr,
|
||||
old_size : int,
|
||||
location : SourceCodeLocation = #caller_location
|
||||
) -> ( data : []byte, alloc_error : AllocatorError)
|
||||
) -> ( data : []byte, error : Odin_AllocatorError)
|
||||
{
|
||||
error_: AllocatorError
|
||||
assert_contextless(allocator_data != nil)
|
||||
arena := transmute(^FArena) allocator_data
|
||||
switch mode {
|
||||
case .Alloc, .Alloc_Non_Zeroed:
|
||||
data, alloc_error = farena_push(arena, byte, size, alignment, location)
|
||||
data, error_ = farena_push(arena, byte, size, alignment, location)
|
||||
if mode == .Alloc {
|
||||
zero(data)
|
||||
}
|
||||
return
|
||||
case .Free:
|
||||
return {}, .Mode_Not_Implemented
|
||||
case .Free_All:
|
||||
farena_reset(arena)
|
||||
return
|
||||
case .Resize, .Resize_Non_Zeroed:
|
||||
if (size > old_size) do data, alloc_error = farena_grow (arena, slice(cursor(old_memory), old_size), size, alignment, mode == .Resize)
|
||||
else do data, alloc_error = farena_shirnk(arena, slice(cursor(old_memory), old_size), size, alignment)
|
||||
return
|
||||
if (size > old_size) do data, error_ = farena_grow (arena, slice(cursor(old_memory), old_size), size, alignment, mode == .Resize)
|
||||
else do data, error_ = farena_shirnk(arena, slice(cursor(old_memory), old_size), size, alignment)
|
||||
case .Query_Features:
|
||||
set := (^Odin_AllocatorModeSet)(old_memory)
|
||||
if set != nil {
|
||||
set^ = {.Alloc, .Alloc_Non_Zeroed, .Free_All, .Resize, .Resize_Non_Zeroed, .Query_Features, .Query_Info}
|
||||
}
|
||||
return
|
||||
case .Query_Info:
|
||||
info := (^Odin_AllocatorQueryInfo)(old_memory)
|
||||
info.pointer = transmute(rawptr) farena_save(arena^).slot
|
||||
info.size = len(arena.mem) - arena.used
|
||||
info.alignment = MEMORY_ALIGNMENT_DEFAULT
|
||||
info.alignment = DEFAULT_ALIGNMENT
|
||||
return to_bytes(info), nil
|
||||
}
|
||||
panic_contextless("Impossible path")
|
||||
error = transmute(Odin_AllocatorError) error_
|
||||
return
|
||||
}
|
||||
when ODIN_DEBUG {
|
||||
farena_ainfo :: #force_inline proc "contextless" (arena: ^FArena) -> AllocatorInfo { return AllocatorInfo{proc_id = .FArena, data = arena} }
|
||||
|
||||
@@ -31,7 +31,7 @@ ktl_populate_slice_a2_str :: #force_inline proc(kt: ^[]KTL_Slot(string), backing
|
||||
raw_bytes, error := mem_alloc(size_of(KTL_Slot(string)) * len(values), ainfo = backing); assert(error == .None);
|
||||
kt^ = slice( transmute([^]KTL_Slot(string)) cursor(raw_bytes), len(raw_bytes) / size_of(KTL_Slot(string)) )
|
||||
for id in 0 ..< len(values) {
|
||||
mem_copy_non_overlapping(& kt[id].value, & values[id][1], size_of(string))
|
||||
mem_copy(& kt[id].value, & values[id][1], size_of(string))
|
||||
hash64_fnv1a(& kt[id].key, transmute([]byte) values[id][0])
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,9 +11,9 @@ import "base:intrinsics"
|
||||
// mem_copy :: intrinsics.mem_copy_non_overlapping
|
||||
// mem_copy_overlapping :: intrinsics.mem_copy
|
||||
|
||||
mem_zero :: #force_inline proc "contextless" (data: rawptr, len: int) { intrinsics.mem_zero (data, len) }
|
||||
mem_copy_non_overlapping :: #force_inline proc "contextless" (dst, src: rawptr, len: int) { intrinsics.mem_copy_non_overlapping(dst, src, len) }
|
||||
mem_copy :: #force_inline proc "contextless" (dst, src: rawptr, len: int) { intrinsics.mem_copy (dst, src, len) }
|
||||
mem_zero :: #force_inline proc "contextless" (data: rawptr, len: int) { intrinsics.mem_zero (data, len) }
|
||||
mem_copy :: #force_inline proc "contextless" (dst, src: rawptr, len: int) { intrinsics.mem_copy_non_overlapping(dst, src, len) }
|
||||
mem_copy_overlapping :: #force_inline proc "contextless" (dst, src: rawptr, len: int) { intrinsics.mem_copy (dst, src, len) }
|
||||
|
||||
import "base:runtime"
|
||||
Assertion_Failure_Proc :: runtime.Assertion_Failure_Proc
|
||||
@@ -40,6 +40,9 @@ import "core:log"
|
||||
Logger_Full_Timestamp_Opts :: log.Full_Timestamp_Opts
|
||||
|
||||
import "core:mem"
|
||||
DEFAULT_ALIGNMENT :: mem.DEFAULT_ALIGNMENT
|
||||
DEFAULT_PAGE_SIZE :: mem.DEFAULT_PAGE_SIZE
|
||||
|
||||
Odin_Allocator :: mem.Allocator
|
||||
Odin_AllocatorError :: mem.Allocator_Error
|
||||
Odin_AllocatorQueryInfo :: mem.Allocator_Query_Info
|
||||
@@ -141,8 +144,8 @@ copy :: proc {
|
||||
mem_copy,
|
||||
slice_copy,
|
||||
}
|
||||
copy_non_overlapping :: proc {
|
||||
mem_copy_non_overlapping,
|
||||
copy_overlapping :: proc {
|
||||
mem_copy_overlapping,
|
||||
slice_copy_overlapping,
|
||||
}
|
||||
fill :: proc {
|
||||
|
||||
@@ -22,7 +22,6 @@ VArenaFlags :: bit_set[VArenaFlag; u32]
|
||||
VArenaFlag :: enum u32 {
|
||||
No_Large_Pages,
|
||||
}
|
||||
|
||||
VArena :: struct {
|
||||
using vmem: VirtualMemoryRegion,
|
||||
commit_size: int,
|
||||
@@ -41,18 +40,18 @@ varena_make :: proc(to_reserve, commit_size: int, base_address: uintptr, flags:
|
||||
verify( to_reserve >= commit_size, "Attempted to commit more than there is to reserve" )
|
||||
vmem : VirtualMemoryRegion
|
||||
vmem, alloc_error = virtual_reserve_and_commit( base_address, uint(to_reserve), uint(commit_size) )
|
||||
if ensure(vmem.base_address == nil || alloc_error != .None, "Failed to allocate requested virtual memory for virtual arena") {
|
||||
if ensure(vmem.base_address != nil && alloc_error == .None, "Failed to allocate requested virtual memory for virtual arena") {
|
||||
return
|
||||
}
|
||||
arena = transmute(^VArena) vmem.base_address;
|
||||
arena.vmem = vmem
|
||||
arena.commit_used = align_pow2(size_of(arena), MEMORY_ALIGNMENT_DEFAULT)
|
||||
arena.commit_used = align_pow2(size_of(arena), DEFAULT_ALIGNMENT)
|
||||
arena.flags = flags
|
||||
return
|
||||
}
|
||||
varena_alloc :: proc(self: ^VArena,
|
||||
size: int,
|
||||
alignment: int = MEMORY_ALIGNMENT_DEFAULT,
|
||||
size: int,
|
||||
alignment: int = DEFAULT_ALIGNMENT,
|
||||
zero_memory := true,
|
||||
location := #caller_location
|
||||
) -> (data: []byte, alloc_error: AllocatorError)
|
||||
@@ -60,7 +59,7 @@ varena_alloc :: proc(self: ^VArena,
|
||||
verify( alignment & (alignment - 1) == 0, "Non-power of two alignment", location = location )
|
||||
page_size := uint(virtual_get_page_size())
|
||||
requested_size := uint(size)
|
||||
if ensure(requested_size == 0, "Requested 0 size") do return nil, .Invalid_Argument
|
||||
if ensure(requested_size > 0, "Requested 0 size") do return nil, .Invalid_Argument
|
||||
// ensure( requested_size > page_size, "Requested less than a page size, going to allocate a page size")
|
||||
// requested_size = max(requested_size, page_size)
|
||||
|
||||
@@ -104,14 +103,14 @@ varena_alloc :: proc(self: ^VArena,
|
||||
}
|
||||
return
|
||||
}
|
||||
varena_grow :: #force_inline proc(self: ^VArena, old_memory: []byte, requested_size: int, alignment: int = MEMORY_ALIGNMENT_DEFAULT, should_zero := true, loc := #caller_location
|
||||
varena_grow :: #force_inline proc(self: ^VArena, old_memory: []byte, requested_size: int, alignment: int = DEFAULT_ALIGNMENT, zero_memory := true, loc := #caller_location
|
||||
) -> (data: []byte, error: AllocatorError)
|
||||
{
|
||||
if ensure(old_memory == nil, "Growing without old_memory?") {
|
||||
data, error = varena_alloc(self, requested_size, alignment, should_zero, loc)
|
||||
if ensure(old_memory != nil, "Growing without old_memory?") {
|
||||
data, error = varena_alloc(self, requested_size, alignment, zero_memory, loc)
|
||||
return
|
||||
}
|
||||
if ensure(requested_size == len(old_memory), "Requested grow when none needed") {
|
||||
if ensure(requested_size != len(old_memory), "Requested grow when none needed") {
|
||||
data = old_memory
|
||||
return
|
||||
}
|
||||
@@ -137,19 +136,19 @@ varena_grow :: #force_inline proc(self: ^VArena, old_memory: []byte, requested_s
|
||||
{
|
||||
// Give it new memory and copy the old over. Old memory is unrecoverable until clear.
|
||||
new_region : []byte
|
||||
new_region, error = varena_alloc( self, requested_size, alignment, should_zero, loc )
|
||||
if ensure(new_region == nil || error != .None, "Failed to grab new region") {
|
||||
new_region, error = varena_alloc( self, requested_size, alignment, zero_memory, loc )
|
||||
if ensure(new_region != nil && error == .None, "Failed to grab new region") {
|
||||
data = old_memory
|
||||
return
|
||||
}
|
||||
copy_non_overlapping( cursor(new_region), cursor(old_memory), len(old_memory) )
|
||||
copy( cursor(new_region), cursor(old_memory), len(old_memory) )
|
||||
data = new_region
|
||||
// log_print_fmt("varena resize (new): old: %p %v new: %p %v", old_memory, old_size, (& data[0]), size)
|
||||
return
|
||||
}
|
||||
new_region : []byte
|
||||
new_region, error = varena_alloc( self, requested_size - len(old_memory), alignment, should_zero, loc)
|
||||
if ensure(new_region == nil || error != .None, "Failed to grab new region") {
|
||||
new_region, error = varena_alloc( self, requested_size - len(old_memory), alignment, zero_memory, loc)
|
||||
if ensure(new_region != nil && error == .None, "Failed to grab new region") {
|
||||
data = old_memory
|
||||
return
|
||||
}
|
||||
@@ -159,7 +158,7 @@ varena_grow :: #force_inline proc(self: ^VArena, old_memory: []byte, requested_s
|
||||
}
|
||||
varena_shrink :: proc(self: ^VArena, memory: []byte, requested_size: int, loc := #caller_location) -> (data: []byte, error: AllocatorError) {
|
||||
if requested_size == len(memory) { return memory, .None }
|
||||
if ensure(memory == nil, "Shrinking without old_memory?") do return memory, .Invalid_Argument
|
||||
if ensure(memory != nil, "Shrinking without old_memory?") do return memory, .Invalid_Argument
|
||||
current_offset := self.reserve_start[self.commit_used:]
|
||||
shrink_amount := len(memory) - requested_size
|
||||
if shrink_amount < 0 { return memory, .None }
|
||||
@@ -205,12 +204,16 @@ varena_allocator_proc :: proc(input: AllocatorProc_In, output: ^AllocatorProc_Ou
|
||||
varena_rewind(arena, input.save_point)
|
||||
case .SavePoint:
|
||||
output.save_point = varena_save(arena)
|
||||
case .Is_Owner:
|
||||
output.error = .Mode_Not_Implemented
|
||||
case .Query:
|
||||
output.features = {.Alloc, .Reset, .Grow, .Shrink, .Rewind}
|
||||
output.features = {.Alloc, .Reset, .Grow, .Shrink, .Rewind, .Actually_Resize, .Hint_Fast_Bump, .Is_Owner}
|
||||
output.max_alloc = int(arena.reserved) - arena.commit_used
|
||||
output.min_alloc = 0
|
||||
output.left = output.max_alloc
|
||||
output.save_point = varena_save(arena)
|
||||
case .Startup, .Shutdown, .Thread_Start, .Thread_Stop:
|
||||
output.error = .Mode_Not_Implemented
|
||||
}
|
||||
}
|
||||
varena_odin_allocator_proc :: proc(
|
||||
@@ -221,21 +224,21 @@ varena_odin_allocator_proc :: proc(
|
||||
old_memory : rawptr,
|
||||
old_size : int,
|
||||
location : SourceCodeLocation = #caller_location
|
||||
) -> (data: []byte, alloc_error: AllocatorError)
|
||||
) -> (data: []byte, error: Odin_AllocatorError)
|
||||
{
|
||||
error_: AllocatorError
|
||||
arena := transmute( ^VArena) allocator_data
|
||||
page_size := uint(virtual_get_page_size())
|
||||
switch mode {
|
||||
case .Alloc, .Alloc_Non_Zeroed:
|
||||
data, alloc_error = varena_alloc( arena, size, alignment, (mode == .Alloc), location )
|
||||
return
|
||||
data, error_ = varena_alloc( arena, size, alignment, (mode == .Alloc), location )
|
||||
case .Free:
|
||||
alloc_error = .Mode_Not_Implemented
|
||||
error = .Mode_Not_Implemented
|
||||
case .Free_All:
|
||||
varena_reset( arena )
|
||||
case .Resize, .Resize_Non_Zeroed:
|
||||
if size > old_size do varena_grow (arena, slice(cursor(old_memory), old_size), size, alignment, (mode == .Alloc), location)
|
||||
else do varena_shrink(arena, slice(cursor(old_memory), old_size), size, location)
|
||||
if size > old_size do data, error_ = varena_grow (arena, slice(cursor(old_memory), old_size), size, alignment, (mode == .Alloc), location)
|
||||
else do data, error_ = varena_shrink(arena, slice(cursor(old_memory), old_size), size, location)
|
||||
case .Query_Features:
|
||||
set := cast( ^Odin_AllocatorModeSet) old_memory
|
||||
if set != nil do (set ^) = {.Alloc, .Alloc_Non_Zeroed, .Free_All, .Resize, .Query_Features}
|
||||
@@ -243,9 +246,10 @@ varena_odin_allocator_proc :: proc(
|
||||
info := (^Odin_AllocatorQueryInfo)(old_memory)
|
||||
info.pointer = transmute(rawptr) varena_save(arena).slot
|
||||
info.size = cast(int) arena.reserved
|
||||
info.alignment = MEMORY_ALIGNMENT_DEFAULT
|
||||
info.alignment = DEFAULT_ALIGNMENT
|
||||
return to_bytes(info), nil
|
||||
}
|
||||
error = transmute(Odin_AllocatorError) error_
|
||||
return
|
||||
}
|
||||
|
||||
@@ -263,12 +267,12 @@ else {
|
||||
varena_allocator :: #force_inline proc "contextless" (arena: ^VArena) -> Odin_Allocator { return transmute(Odin_Allocator) AllocatorInfo{procedure = varena_allocator_proc, data = arena} }
|
||||
}
|
||||
|
||||
varena_push_item :: #force_inline proc(va: ^VArena, $Type: typeid, alignment: int = MEMORY_ALIGNMENT_DEFAULT, should_zero := true, location := #caller_location
|
||||
varena_push_item :: #force_inline proc(va: ^VArena, $Type: typeid, alignment: int = DEFAULT_ALIGNMENT, should_zero := true, location := #caller_location
|
||||
) -> (^Type, AllocatorError) {
|
||||
raw, error := varena_alloc(va, size_of(Type), alignment, should_zero, location)
|
||||
return transmute(^Type) cursor(raw), error
|
||||
}
|
||||
varena_push_slice :: #force_inline proc(va: ^VArena, $Type: typeid, amount: int, alignment: int = MEMORY_ALIGNMENT_DEFAULT, should_zero := true, location := #caller_location
|
||||
varena_push_slice :: #force_inline proc(va: ^VArena, $Type: typeid, amount: int, alignment: int = DEFAULT_ALIGNMENT, should_zero := true, location := #caller_location
|
||||
) -> ([]Type, AllocatorError) {
|
||||
raw, error := varena_alloc(va, size_of(Type) * amount, alignment, should_zero, location)
|
||||
return slice(transmute([^]Type) cursor(raw), len(raw) / size_of(Type)), error
|
||||
|
||||
@@ -18,14 +18,12 @@ Arena :: struct {
|
||||
flags: ArenaFlags,
|
||||
}
|
||||
|
||||
arena_make :: proc(reserve_size : int = Mega * 64, commit_size : int = Mega * 64, base_addr: uintptr = 0, flags: ArenaFlags = {}) -> ^Arena {
|
||||
header_size := align_pow2(size_of(Arena), MEMORY_ALIGNMENT_DEFAULT)
|
||||
arena_make :: proc(reserve_size : int = Mega * 64, commit_size : int = Mega * 64, base_addr: uintptr = 0, flags: ArenaFlags = {}) -> (^Arena, AllocatorError) {
|
||||
header_size := align_pow2(size_of(Arena), DEFAULT_ALIGNMENT)
|
||||
current, error := varena_make(reserve_size, commit_size, base_addr, transmute(VArenaFlags) flags)
|
||||
assert(error == .None)
|
||||
assert(current != nil)
|
||||
if ensure(error == .None) do return nil, error
|
||||
arena: ^Arena; arena, error = varena_push_item(current, Arena, 1)
|
||||
assert(error == .None)
|
||||
assert(arena != nil)
|
||||
if ensure(error == .None) do return nil, error
|
||||
arena^ = Arena {
|
||||
backing = current,
|
||||
prev = nil,
|
||||
@@ -34,9 +32,9 @@ arena_make :: proc(reserve_size : int = Mega * 64, commit_size : int = Mega * 64
|
||||
pos = header_size,
|
||||
flags = flags,
|
||||
}
|
||||
return arena
|
||||
return arena, .None
|
||||
}
|
||||
arena_alloc :: proc(arena: ^Arena, size: int, alignment: int = MEMORY_ALIGNMENT_DEFAULT) -> []byte {
|
||||
arena_alloc :: proc(arena: ^Arena, size: int, alignment: int = DEFAULT_ALIGNMENT, should_zero := true, loc := #caller_location) -> (allocation: []byte, error: AllocatorError) {
|
||||
assert(arena != nil)
|
||||
active := arena.current
|
||||
size_requested := size
|
||||
@@ -46,19 +44,65 @@ arena_alloc :: proc(arena: ^Arena, size: int, alignment: int = MEMORY_ALIGNMENT_
|
||||
reserved := int(active.backing.reserved)
|
||||
should_chain := (.No_Chaining not_in arena.flags) && (reserved < pos_pst)
|
||||
if should_chain {
|
||||
new_arena := arena_make(reserved, active.backing.commit_size, 0, transmute(ArenaFlags) active.backing.flags)
|
||||
new_arena: ^Arena; new_arena, error = arena_make(reserved, active.backing.commit_size, 0, transmute(ArenaFlags) active.backing.flags)
|
||||
if ensure(error == .None) do return
|
||||
new_arena.base_pos = active.base_pos + reserved
|
||||
sll_stack_push_n(& arena.current, & new_arena, & new_arena.prev)
|
||||
new_arena.prev = active
|
||||
active = arena.current
|
||||
}
|
||||
result_ptr := transmute([^]byte) (uintptr(active) + uintptr(pos_pre))
|
||||
vresult, error := varena_alloc(active.backing, size_aligned, alignment)
|
||||
assert(error == .None)
|
||||
slice_assert(vresult)
|
||||
assert(raw_data(vresult) == result_ptr)
|
||||
vresult: []byte; vresult, error = varena_alloc(active.backing, size_aligned, alignment, should_zero)
|
||||
if ensure(error == .None) do return
|
||||
assert(cursor(vresult) == result_ptr)
|
||||
active.pos = pos_pst
|
||||
return slice(result_ptr, size)
|
||||
allocation = slice(result_ptr, size)
|
||||
return
|
||||
}
|
||||
arena_grow :: proc(arena: ^Arena, old_allocation: []byte, requested_size: int, alignment: int = DEFAULT_ALIGNMENT, zero_memory := true, loc := #caller_location
|
||||
) -> (allocation: []byte, error: AllocatorError)
|
||||
{
|
||||
active := arena.current
|
||||
if len(old_allocation) == 0 { allocation = {}; return }
|
||||
alloc_end := end(old_allocation)
|
||||
arena_end := transmute([^]byte) (uintptr(active) + uintptr(active.pos))
|
||||
if alloc_end == arena_end
|
||||
{
|
||||
// Can grow in place
|
||||
grow_amount := requested_size - len(old_allocation)
|
||||
aligned_grow := align_pow2(grow_amount, alignment)
|
||||
if active.pos + aligned_grow <= cast(int) active.backing.reserved
|
||||
{
|
||||
vresult: []byte; vresult, error = varena_alloc(active.backing, aligned_grow, alignment, zero_memory)
|
||||
if ensure(error == .None) do return
|
||||
active.pos += aligned_grow
|
||||
allocation = slice(cursor(old_allocation), requested_size)
|
||||
return
|
||||
}
|
||||
}
|
||||
// Can't grow in place, allocate new
|
||||
allocation, error = arena_alloc(arena, requested_size, alignment, false)
|
||||
if ensure(error == .None) do return
|
||||
copy(allocation, old_allocation)
|
||||
zero(cursor(allocation)[len(old_allocation):], (requested_size - len(old_allocation)) * int(zero_memory))
|
||||
return
|
||||
}
|
||||
arena_shrink :: proc(arena: ^Arena, old_allocation: []byte, requested_size, alignment: int, loc := #caller_location) -> (result: []byte, error: AllocatorError) {
|
||||
active := arena.current
|
||||
if ensure(len(old_allocation) != 0) { return }
|
||||
alloc_end := end(old_allocation)
|
||||
arena_end := transmute([^]byte) (uintptr(active) + uintptr(active.pos))
|
||||
if alloc_end != arena_end {
|
||||
// Not at the end, can't shrink but return adjusted size
|
||||
result = old_allocation[:requested_size]
|
||||
}
|
||||
// Calculate shrinkage
|
||||
aligned_original := align_pow2(len(old_allocation), DEFAULT_ALIGNMENT)
|
||||
aligned_new := align_pow2(requested_size, alignment)
|
||||
pos_reduction := aligned_original - aligned_new
|
||||
active.pos -= pos_reduction
|
||||
result, error = varena_shrink(active.backing, old_allocation, aligned_new)
|
||||
return
|
||||
}
|
||||
arena_release :: proc(arena: ^Arena) {
|
||||
assert(arena != nil)
|
||||
@@ -72,10 +116,10 @@ arena_release :: proc(arena: ^Arena) {
|
||||
arena_reset :: proc(arena: ^Arena) {
|
||||
arena_rewind(arena, AllocatorSP { type_sig = arena_allocator_proc, slot = 0 })
|
||||
}
|
||||
arena_rewind :: proc(arena: ^Arena, save_point: AllocatorSP) {
|
||||
arena_rewind :: proc(arena: ^Arena, save_point: AllocatorSP, loc := #caller_location) {
|
||||
assert(arena != nil)
|
||||
assert(save_point.type_sig == arena_allocator_proc)
|
||||
header_size := align_pow2(size_of(Arena), MEMORY_ALIGNMENT_DEFAULT)
|
||||
header_size := align_pow2(size_of(Arena), DEFAULT_ALIGNMENT)
|
||||
curr := arena.current
|
||||
big_pos := max(header_size, save_point.slot)
|
||||
// Release arenas that are beyond the save point
|
||||
@@ -85,15 +129,43 @@ arena_rewind :: proc(arena: ^Arena, save_point: AllocatorSP) {
|
||||
curr = prev
|
||||
}
|
||||
arena.current = curr
|
||||
new_pos := big_pos - curr.base_pos
|
||||
assert(new_pos <= curr.pos)
|
||||
new_pos := big_pos - curr.base_pos; assert(new_pos <= curr.pos)
|
||||
curr.pos = new_pos
|
||||
varena_rewind(curr.backing, { type_sig = varena_allocator_proc, slot = curr.pos + size_of(VArena) })
|
||||
}
|
||||
arena_save :: #force_inline proc(arena: ^Arena) -> AllocatorSP { return { type_sig = arena_allocator_proc, slot = arena.base_pos + arena.current.pos } }
|
||||
|
||||
arena_allocator_proc :: proc(input: AllocatorProc_In, output: ^AllocatorProc_Out) {
|
||||
panic("not implemented")
|
||||
assert(output != nil)
|
||||
assert(input.data != nil)
|
||||
arena := transmute(^Arena) input.data
|
||||
switch input.op {
|
||||
case .Alloc, .Alloc_NoZero:
|
||||
output.allocation, output.error = arena_alloc(arena, input.requested_size, input.alignment, input.op == .Alloc, input.loc)
|
||||
return
|
||||
case .Free:
|
||||
output.error = .Mode_Not_Implemented
|
||||
case .Reset:
|
||||
arena_reset(arena)
|
||||
case .Grow, .Grow_NoZero:
|
||||
output.allocation, output.error = arena_grow(arena, input.old_allocation, input.requested_size, input.alignment, input.op == .Grow, input.loc)
|
||||
case .Shrink:
|
||||
output.allocation, output.error = arena_shrink(arena, input.old_allocation, input.requested_size, input.alignment, input.loc)
|
||||
case .Rewind:
|
||||
arena_rewind(arena, input.save_point, input.loc)
|
||||
case .SavePoint:
|
||||
output.save_point = arena_save(arena)
|
||||
case .Query:
|
||||
output.features = {.Alloc, .Reset, .Grow, .Shrink, .Rewind, .Actually_Resize, .Is_Owner, .Hint_Fast_Bump }
|
||||
output.max_alloc = int(arena.backing.reserved)
|
||||
output.min_alloc = 0
|
||||
output.left = output.max_alloc
|
||||
output.save_point = arena_save(arena)
|
||||
case .Is_Owner:
|
||||
output.error = .Mode_Not_Implemented
|
||||
case .Startup, .Shutdown, .Thread_Start, .Thread_Stop:
|
||||
output.error = .Mode_Not_Implemented
|
||||
}
|
||||
}
|
||||
arena_odin_allocator_proc :: proc(
|
||||
allocator_data : rawptr,
|
||||
@@ -103,7 +175,7 @@ arena_odin_allocator_proc :: proc(
|
||||
old_memory : rawptr,
|
||||
old_size : int,
|
||||
location : SourceCodeLocation = #caller_location
|
||||
) -> (data: []byte, alloc_error: AllocatorError)
|
||||
) -> (data: []byte, alloc_error: Odin_AllocatorError)
|
||||
{
|
||||
panic("not implemented")
|
||||
}
|
||||
|
||||
@@ -32,7 +32,7 @@ virtual_reserve_remaining :: proc "contextless" ( using vmem : VirtualMemoryRegi
|
||||
@(require_results)
|
||||
virtual_commit :: proc "contextless" ( using vmem : VirtualMemoryRegion, size : uint ) -> ( alloc_error : AllocatorError )
|
||||
{
|
||||
if size < committed {
|
||||
if size < committed {
|
||||
return .None
|
||||
}
|
||||
|
||||
@@ -40,7 +40,7 @@ virtual_commit :: proc "contextless" ( using vmem : VirtualMemoryRegion, size :
|
||||
page_size := uint(virtual_get_page_size())
|
||||
to_commit := memory_align_formula( size, page_size )
|
||||
|
||||
alloc_error = core_virtual.commit( base_address, to_commit )
|
||||
alloc_error = cast(AllocatorError) core_virtual.commit( base_address, to_commit )
|
||||
if alloc_error != .None {
|
||||
return alloc_error
|
||||
}
|
||||
|
||||
@@ -24,5 +24,3 @@ pool_make :: proc() -> (pool: VPool, error: AllocatorError)
|
||||
panic("not implemented")
|
||||
// return
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -14,9 +14,7 @@ load_client_api :: proc(version_id: int) -> (loaded_module: Client_API) {
|
||||
using loaded_module
|
||||
// Make sure we have a dll to work with
|
||||
file_io_err: OS_Error; write_time, file_io_err = file_last_write_time_by_name("sectr.dll")
|
||||
if file_io_err != OS_ERROR_NONE {
|
||||
panic_contextless( "Could not resolve the last write time for sectr")
|
||||
}
|
||||
if file_io_err != OS_ERROR_NONE { panic_contextless( "Could not resolve the last write time for sectr") }
|
||||
//TODO(Ed): Lets try to minimize this...
|
||||
thread_sleep( Millisecond * 25 )
|
||||
// Get the live dll loaded up
|
||||
@@ -84,16 +82,12 @@ main :: proc()
|
||||
startup_time := time_now()
|
||||
year, month, day := time_date( startup_time)
|
||||
hour, min, sec := time_clock_from_time( startup_time)
|
||||
|
||||
if ! os_is_directory( Path_Logs ) {
|
||||
os_make_directory( Path_Logs )
|
||||
}
|
||||
if ! os_is_directory( Path_Logs ) { os_make_directory( Path_Logs ) }
|
||||
timestamp := str_pfmt_tmp("%04d-%02d-%02d_%02d-%02d-%02d", year, month, day, hour, min, sec)
|
||||
host_memory.path_logger_finalized = str_pfmt("%s/sectr_%v.log", Path_Logs, timestamp)
|
||||
}
|
||||
logger_init( & host_memory.host_logger, "Sectr Host", str_pfmt_tmp("%s/sectr.log", Path_Logs))
|
||||
context.logger = to_odin_logger( & host_memory.host_logger )
|
||||
{
|
||||
context.logger = to_odin_logger( & host_memory.host_logger ); {
|
||||
// Log System Context
|
||||
builder := strbuilder_make_len(16 * Kilo, context.temp_allocator)
|
||||
str_pfmt_builder( & builder, "Core Count: %v, ", os_core_count() )
|
||||
@@ -103,8 +97,7 @@ main :: proc()
|
||||
free_all(context.temp_allocator)
|
||||
}
|
||||
context.logger = to_odin_logger( & host_memory.host_logger )
|
||||
// Load the Enviornment API for the first-time
|
||||
{
|
||||
/*Load the Enviornment API for the first-time*/{
|
||||
host_memory.client_api = load_client_api( 1 )
|
||||
verify( host_memory.client_api.lib_version != 0, "Failed to initially load the sectr module" )
|
||||
}
|
||||
@@ -120,7 +113,10 @@ main :: proc()
|
||||
barrier_init(& host_memory.lane_sync, THREAD_TICK_LANES)
|
||||
when THREAD_TICK_LANES > 1 {
|
||||
for id in 1 ..= (THREAD_TICK_LANES - 1) {
|
||||
launch_tick_lane_thread(cast(WorkerID) id)
|
||||
lane_thread := thread_create_ex(host_tick_lane_entrypoint, .High, enum_to_string(cast(WorkerID)id))
|
||||
lane_thread.user_index = id
|
||||
host_memory.threads[lane_thread.user_index] = lane_thread
|
||||
thread_start(lane_thread)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -136,7 +132,7 @@ main :: proc()
|
||||
barrier_init(& host_memory.job_hot_reload_sync, THREAD_JOB_WORKERS + 1)
|
||||
for id in THREAD_JOB_WORKER_ID_START ..< THREAD_JOB_WORKER_ID_END {
|
||||
log_print_fmt("Spawned job worker: %v", cast(WorkerID) id)
|
||||
worker_thread := thread_create(host_job_worker_entrypoint, .Normal)
|
||||
worker_thread := thread_create_ex(host_job_worker_entrypoint, .Normal, enum_to_string(cast(WorkerID) id))
|
||||
worker_thread.user_index = int(id)
|
||||
host_memory.threads[worker_thread.user_index] = worker_thread
|
||||
thread_start(worker_thread)
|
||||
@@ -146,6 +142,7 @@ main :: proc()
|
||||
}
|
||||
free_all(context.temp_allocator)
|
||||
host_tick_lane()
|
||||
host_lane_shutdown()
|
||||
|
||||
profile_begin("Host Shutdown")
|
||||
if thread_memory.id == .Master_Prepper {
|
||||
@@ -165,14 +162,6 @@ main :: proc()
|
||||
spall_buffer_destroy(& host_memory.spall_context, & thread_memory.spall_buffer)
|
||||
spall_context_destroy( & host_memory.spall_context )
|
||||
}
|
||||
launch_tick_lane_thread :: proc(id : WorkerID) {
|
||||
assert_contextless(thread_memory.id == .Master_Prepper)
|
||||
// TODO(Ed): We need to make our own version of this that doesn't allocate memory.
|
||||
lane_thread := thread_create(host_tick_lane_entrypoint, .High)
|
||||
lane_thread.user_index = int(id)
|
||||
host_memory.threads[lane_thread.user_index] = lane_thread
|
||||
thread_start(lane_thread)
|
||||
}
|
||||
|
||||
host_tick_lane_entrypoint :: proc(lane_thread: ^SysThread) {
|
||||
thread_memory.system_ctx = lane_thread
|
||||
@@ -184,13 +173,12 @@ host_tick_lane_entrypoint :: proc(lane_thread: ^SysThread) {
|
||||
grime_set_profiler_thread_buffer(& thread_memory.spall_buffer)
|
||||
}
|
||||
host_tick_lane()
|
||||
host_lane_shutdown()
|
||||
}
|
||||
host_tick_lane :: proc()
|
||||
{
|
||||
profile(#procedure)
|
||||
delta_ns: Duration
|
||||
host_tick := time_tick_now()
|
||||
|
||||
for ; sync_load(& host_memory.tick_running, .Relaxed);
|
||||
{
|
||||
profile("Host Tick")
|
||||
@@ -207,7 +195,6 @@ host_tick_lane :: proc()
|
||||
// Lanes are synced before doing running check..
|
||||
sync_client_api()
|
||||
}
|
||||
host_lane_shutdown()
|
||||
}
|
||||
host_lane_shutdown :: proc()
|
||||
{
|
||||
@@ -218,8 +205,8 @@ host_lane_shutdown :: proc()
|
||||
for ; jobs_enqueued; {
|
||||
jobs_enqueued = false
|
||||
jobs_enqueued |= host_memory.job_system.job_lists[.Normal].head != nil
|
||||
jobs_enqueued |= host_memory.job_system.job_lists[.Low].head != nil
|
||||
jobs_enqueued |= host_memory.job_system.job_lists[.High].head != nil
|
||||
jobs_enqueued |= host_memory.job_system.job_lists[.Low ].head != nil
|
||||
jobs_enqueued |= host_memory.job_system.job_lists[.High ].head != nil
|
||||
// if jobs_enqueued == false do debug_trap()
|
||||
}
|
||||
sync_store(& host_memory.job_system.running, false, .Release)
|
||||
@@ -242,8 +229,8 @@ host_job_worker_entrypoint :: proc(worker_thread: ^SysThread)
|
||||
}
|
||||
jobs_enqueued := false
|
||||
jobs_enqueued |= host_memory.job_system.job_lists[.Normal].head != nil
|
||||
jobs_enqueued |= host_memory.job_system.job_lists[.Low].head != nil
|
||||
jobs_enqueued |= host_memory.job_system.job_lists[.High].head != nil
|
||||
jobs_enqueued |= host_memory.job_system.job_lists[.Low ].head != nil
|
||||
jobs_enqueued |= host_memory.job_system.job_lists[.High ].head != nil
|
||||
delta_ns: Duration
|
||||
host_tick := time_tick_now()
|
||||
for ; jobs_enqueued || sync_load(& host_memory.job_system.running, .Relaxed);
|
||||
@@ -251,15 +238,12 @@ host_job_worker_entrypoint :: proc(worker_thread: ^SysThread)
|
||||
// profile("Host Job Tick")
|
||||
|
||||
host_memory.client_api.jobsys_worker_tick(duration_seconds(delta_ns), delta_ns)
|
||||
|
||||
delta_ns = time_tick_lap_time( & host_tick )
|
||||
host_tick = time_tick_now()
|
||||
|
||||
jobs_enqueued = false
|
||||
jobs_enqueued |= host_memory.job_system.job_lists[.Normal].head != nil
|
||||
jobs_enqueued |= host_memory.job_system.job_lists[.Low].head != nil
|
||||
jobs_enqueued |= host_memory.job_system.job_lists[.High].head != nil
|
||||
|
||||
jobs_enqueued |= host_memory.job_system.job_lists[.Low ].head != nil
|
||||
jobs_enqueued |= host_memory.job_system.job_lists[.High ].head != nil
|
||||
if jobs_enqueued == false && sync_load(& host_memory.client_api_hot_reloaded, .Acquire) {
|
||||
// Signals to main hread when all jobs have drained.
|
||||
leader :=barrier_wait(& host_memory.job_hot_reload_sync)
|
||||
|
||||
@@ -43,6 +43,9 @@ import "core:prof/spall"
|
||||
spall_buffer_create :: spall.buffer_create
|
||||
spall_buffer_destroy :: spall.buffer_destroy
|
||||
|
||||
import "core:reflect"
|
||||
enum_to_string :: reflect.enum_string
|
||||
|
||||
import "core:strings"
|
||||
strbuilder_from_bytes :: strings.builder_from_bytes
|
||||
strbuilder_make_len :: strings.builder_make_len
|
||||
@@ -72,6 +75,7 @@ import "core:time"
|
||||
import "core:thread"
|
||||
SysThread :: thread.Thread
|
||||
thread_create :: thread.create
|
||||
thread_create_ex :: thread.create_ex
|
||||
thread_start :: thread.start
|
||||
thread_destroy :: thread.destroy
|
||||
thread_join_multiple :: thread.join_multiple
|
||||
@@ -93,8 +97,7 @@ import grime "codebase:grime"
|
||||
|
||||
// Need to have it with un-wrapped allocator
|
||||
// file_copy_sync :: grime.file_copy_sync
|
||||
file_copy_sync :: proc( path_src, path_dst: string, allocator := context.allocator ) -> b32
|
||||
{
|
||||
file_copy_sync :: proc( path_src, path_dst: string, allocator := context.allocator ) -> b32 {
|
||||
file_size : i64
|
||||
{
|
||||
path_info, result := file_status( path_src, allocator )
|
||||
@@ -104,14 +107,12 @@ import grime "codebase:grime"
|
||||
}
|
||||
file_size = path_info.size
|
||||
}
|
||||
|
||||
src_content, result := os.read_entire_file_from_filename( path_src, allocator )
|
||||
if ! result {
|
||||
log_print_fmt( "Failed to read file to copy: %v", path_src, LoggerLevel.Error )
|
||||
debug_trap()
|
||||
return false
|
||||
}
|
||||
|
||||
result = os.write_entire_file( path_dst, src_content, false )
|
||||
if ! result {
|
||||
log_print_fmt( "Failed to copy file: %v", path_dst, LoggerLevel.Error )
|
||||
|
||||
@@ -56,7 +56,7 @@ Host_API :: struct {
|
||||
}
|
||||
|
||||
ThreadMemory :: struct {
|
||||
using _: ThreadWorkerContext,
|
||||
using _: ThreadWorkerContext,
|
||||
|
||||
// Per-thread profiling
|
||||
spall_buffer_backing: [SPALL_BUFFER_DEFAULT_SIZE]byte,
|
||||
|
||||
@@ -77,8 +77,8 @@ import "codebase:grime"
|
||||
logger_init :: grime.logger_init
|
||||
// Memory
|
||||
mem_alloc :: grime.mem_alloc
|
||||
mem_copy_overlapping :: grime.mem_copy_overlapping
|
||||
mem_copy :: grime.mem_copy
|
||||
mem_copy_non_overlapping :: grime.mem_copy_non_overlapping
|
||||
mem_zero :: grime.mem_zero
|
||||
slice_zero :: grime.slice_zero
|
||||
// Ring Buffer
|
||||
|
||||
Reference in New Issue
Block a user