WIP: fleshing out cod2 for once a bit more
Planning to try out a flavor of Ryan's multi-threaded laned procs with the some extra threads hooked up separately to a job system. Will most likely do 2 threads main/helper on live lanes, then 2 others on job queue loops
This commit is contained in:
7
code2/grime/Readme.md
Normal file
7
code2/grime/Readme.md
Normal file
@@ -0,0 +1,7 @@
|
||||
# Grime
|
||||
|
||||
This is a top-level package to adjust odin to my personalized usage.
|
||||
|
||||
I curate all usage of odin's provided package definitons through here. The client and host packages should never directly import them.
|
||||
|
||||
There are no implicit static allocations in Grime. Ideally there are also none from the base/core packages but some probably leak.
|
1
code2/grime/arenas.odin
Normal file
1
code2/grime/arenas.odin
Normal file
@@ -0,0 +1 @@
|
||||
package grime
|
8
code2/grime/context.odin
Normal file
8
code2/grime/context.odin
Normal file
@@ -0,0 +1,8 @@
|
||||
package grime
|
||||
|
||||
// Context :: struct {
|
||||
// }
|
||||
|
||||
// context_usr :: #force_inline proc( $ Type : typeid ) -> (^Type) {
|
||||
// return cast(^Type) context.user_ptr
|
||||
// }
|
20
code2/grime/linked_list.odin
Normal file
20
code2/grime/linked_list.odin
Normal file
@@ -0,0 +1,20 @@
|
||||
package grime
|
||||
|
||||
sll_stack_push_n :: proc "contextless" (curr, n, n_link: ^^$Type) {
|
||||
(n_link ^) = (curr ^)
|
||||
(curr ^) = (n ^)
|
||||
}
|
||||
sll_queue_push_nz :: proc "contextless" (first: ^$ParentType, last, n: ^^$Type, nil_val: ^Type) {
|
||||
if (first ^) == nil_val {
|
||||
(first ^) = n^
|
||||
(last ^) = n^
|
||||
n^.next = nil_val
|
||||
}
|
||||
else {
|
||||
(last ^).next = n^
|
||||
(last ^) = n^
|
||||
n^.next = nil_val
|
||||
}
|
||||
}
|
||||
sll_queue_push_n :: #force_inline proc "contextless" (first: $ParentType, last, n: ^^$Type) { sll_queue_push_nz(first, last, n, nil) }
|
||||
|
226
code2/grime/memory.odin
Normal file
226
code2/grime/memory.odin
Normal file
@@ -0,0 +1,226 @@
|
||||
package grime
|
||||
|
||||
Kilo :: 1024
|
||||
Mega :: Kilo * 1024
|
||||
Giga :: Mega * 1024
|
||||
Tera :: Giga * 1024
|
||||
|
||||
ptr_cursor :: #force_inline proc "contextless" (ptr: ^$Type) -> [^]Type { return transmute([^]Type) ptr }
|
||||
|
||||
align_pow2 :: proc(x: int, b: int) -> int {
|
||||
assert(b != 0)
|
||||
assert((b & (b - 1)) == 0) // Check power of 2
|
||||
return ((x + b - 1) & ~(b - 1))
|
||||
}
|
||||
memory_zero_explicit :: proc "contextless" (data: rawptr, len: int) -> rawptr {
|
||||
mem_zero_volatile(data, len) // Use the volatile mem_zero
|
||||
atomic_thread_fence(.Seq_Cst) // Prevent reordering
|
||||
return data
|
||||
}
|
||||
memory_copy :: proc "contextless" (dst, src: rawptr, len: int) -> rawptr {
|
||||
mem_copy(dst, src, len)
|
||||
return dst
|
||||
}
|
||||
|
||||
SliceByte :: struct {
|
||||
data: [^]byte,
|
||||
len: int
|
||||
}
|
||||
SliceRaw :: struct ($Type: typeid) {
|
||||
data: [^]Type,
|
||||
len: int,
|
||||
}
|
||||
slice :: #force_inline proc "contextless" (s: [^] $Type, num: $Some_Integer) -> [ ]Type { return transmute([]Type) SliceRaw(Type) { s, cast(int) num } }
|
||||
slice_cursor :: #force_inline proc "contextless" (s: []$Type) -> [^]Type { return transmute([^]Type) raw_data(s) }
|
||||
slice_assert :: #force_inline proc (s: $SliceType / []$Type) {
|
||||
assert(len(s) > 0)
|
||||
assert(s != nil)
|
||||
}
|
||||
slice_end :: #force_inline proc "contextless" (s : $SliceType / []$Type) -> ^Type { return & cursor(s)[len(s)] }
|
||||
|
||||
slice_copy :: proc "contextless" (dst, src: $SliceType / []$Type) -> int {
|
||||
n := max(0, min(len(dst), len(src)))
|
||||
if n > 0 {
|
||||
mem_copy(raw_data(dst), raw_data(src), n * size_of(Type))
|
||||
}
|
||||
return n
|
||||
}
|
||||
|
||||
@(require_results) slice_to_bytes :: proc "contextless" (s: []$Type) -> []byte { return ([^]byte)(raw_data(s))[:len(s) * size_of(Type)] }
|
||||
@(require_results) slice_raw :: proc "contextless" (s: []$Type) -> SliceRaw(Type) { return transmute(SliceRaw(Type)) s }
|
||||
|
||||
//region Allocator Interface
|
||||
AllocatorOp :: enum u32 {
|
||||
Alloc_NoZero = 0, // If Alloc exist, so must No_Zero
|
||||
Alloc,
|
||||
Free,
|
||||
Reset,
|
||||
Grow_NoZero,
|
||||
Grow,
|
||||
Shrink,
|
||||
Rewind,
|
||||
SavePoint,
|
||||
Query, // Must always be implemented
|
||||
}
|
||||
AllocatorQueryFlag :: enum u64 {
|
||||
Alloc,
|
||||
Free,
|
||||
Reset, // Wipe the allocator's state
|
||||
|
||||
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,
|
||||
|
||||
Hint_Fast_Bump,
|
||||
Hint_General_Heap,
|
||||
Hint_Per_Frame_Temporary,
|
||||
Hint_Debug_Support,
|
||||
}
|
||||
AllocatorQueryFlags :: bit_set[AllocatorQueryFlag; u64]
|
||||
AllocatorSP :: struct {
|
||||
type_sig: AllocatorProc,
|
||||
slot: int,
|
||||
}
|
||||
AllocatorProc :: #type proc (input: AllocatorProc_In, out: ^AllocatorProc_Out)
|
||||
AllocatorProc_In :: struct {
|
||||
data: rawptr,
|
||||
requested_size: int,
|
||||
alignment: int,
|
||||
using _ : struct #raw_union {
|
||||
old_allocation: []byte,
|
||||
save_point : AllocatorSP,
|
||||
},
|
||||
op: AllocatorOp,
|
||||
}
|
||||
AllocatorProc_Out :: struct {
|
||||
using _ : struct #raw_union {
|
||||
allocation: []byte,
|
||||
save_point: AllocatorSP,
|
||||
},
|
||||
features: AllocatorQueryFlags,
|
||||
left: int,
|
||||
max_alloc: int,
|
||||
min_alloc: int,
|
||||
continuity_break: b32,
|
||||
}
|
||||
AllocatorQueryInfo :: struct {
|
||||
save_point: AllocatorSP,
|
||||
features: AllocatorQueryFlags,
|
||||
left: int,
|
||||
max_alloc: int,
|
||||
min_alloc: int,
|
||||
continuity_break: b32,
|
||||
}
|
||||
AllocatorInfo :: struct {
|
||||
procedure: AllocatorProc,
|
||||
data: rawptr,
|
||||
}
|
||||
// #assert(size_of(AllocatorQueryInfo) == size_of(AllocatorProc_Out))
|
||||
|
||||
MEMORY_ALIGNMENT_DEFAULT :: 2 * size_of(rawptr)
|
||||
|
||||
allocator_query :: proc(ainfo := context.allocator) -> AllocatorQueryInfo {
|
||||
assert(ainfo.procedure != nil)
|
||||
out: AllocatorQueryInfo; (cast(AllocatorProc)ainfo.procedure)({data = ainfo.data, op = .Query}, transmute(^AllocatorProc_Out) & out)
|
||||
return out
|
||||
}
|
||||
mem_free :: proc(mem: []byte, ainfo := context.allocator) {
|
||||
assert(ainfo.procedure != nil)
|
||||
(cast(AllocatorProc)ainfo.procedure)({data = ainfo.data, op = .Free, old_allocation = mem}, & {})
|
||||
}
|
||||
mem_reset :: proc(ainfo := context.allocator) {
|
||||
assert(ainfo.procedure != nil)
|
||||
(cast(AllocatorProc)ainfo.procedure)({data = ainfo.data, op = .Reset}, &{})
|
||||
}
|
||||
mem_rewind :: proc(ainfo := context.allocator, save_point: AllocatorSP) {
|
||||
assert(ainfo.procedure != nil)
|
||||
(cast(AllocatorProc)ainfo.procedure)({data = ainfo.data, op = .Rewind, save_point = save_point}, & {})
|
||||
}
|
||||
mem_save_point :: proc(ainfo := context.allocator) -> AllocatorSP {
|
||||
assert(ainfo.procedure != nil)
|
||||
out: AllocatorProc_Out
|
||||
(cast(AllocatorProc)ainfo.procedure)({data = ainfo.data, op = .SavePoint}, & out)
|
||||
return out.save_point
|
||||
}
|
||||
mem_alloc :: proc(size: int, alignment: int = MEMORY_ALIGNMENT_DEFAULT, no_zero: b32 = false, ainfo := context.allocator) -> []byte {
|
||||
assert(ainfo.procedure != nil)
|
||||
input := AllocatorProc_In {
|
||||
data = ainfo.data,
|
||||
op = no_zero ? .Alloc_NoZero : .Alloc,
|
||||
requested_size = size,
|
||||
alignment = alignment,
|
||||
}
|
||||
output: AllocatorProc_Out
|
||||
(cast(AllocatorProc)ainfo.procedure)(input, & output)
|
||||
return output.allocation
|
||||
}
|
||||
mem_grow :: proc(mem: []byte, size: int, alignment: int = MEMORY_ALIGNMENT_DEFAULT, no_zero: b32 = false, ainfo := context.allocator) -> []byte {
|
||||
assert(ainfo.procedure != nil)
|
||||
input := AllocatorProc_In {
|
||||
data = ainfo.data,
|
||||
op = no_zero ? .Grow_NoZero : .Grow,
|
||||
requested_size = size,
|
||||
alignment = alignment,
|
||||
old_allocation = mem,
|
||||
}
|
||||
output: AllocatorProc_Out
|
||||
(cast(AllocatorProc)ainfo.procedure)(input, & output)
|
||||
return output.allocation
|
||||
}
|
||||
mem_resize :: proc(mem: []byte, size: int, alignment: int = MEMORY_ALIGNMENT_DEFAULT, no_zero: b32 = false, ainfo := context.allocator) -> []byte {
|
||||
assert(ainfo.procedure != nil)
|
||||
input := AllocatorProc_In {
|
||||
data = ainfo.data,
|
||||
op = len(mem) < size ? .Shrink : no_zero ? .Grow_NoZero : .Grow,
|
||||
requested_size = size,
|
||||
alignment = alignment,
|
||||
old_allocation = mem,
|
||||
}
|
||||
output: AllocatorProc_Out
|
||||
(cast(AllocatorProc)ainfo.procedure)(input, & output)
|
||||
return output.allocation
|
||||
}
|
||||
mem_shrink :: proc(mem: []byte, size: int, alignment: int = MEMORY_ALIGNMENT_DEFAULT, no_zero: b32 = false, ainfo := context.allocator) -> []byte {
|
||||
assert(ainfo.procedure != nil)
|
||||
input := AllocatorProc_In {
|
||||
data = ainfo.data,
|
||||
op = .Shrink,
|
||||
requested_size = size,
|
||||
alignment = alignment,
|
||||
old_allocation = mem,
|
||||
}
|
||||
output: AllocatorProc_Out
|
||||
(cast(AllocatorProc)ainfo.procedure)(input, & output)
|
||||
return output.allocation
|
||||
}
|
||||
|
||||
alloc_type :: proc($Type: typeid, alignment: int = MEMORY_ALIGNMENT_DEFAULT, no_zero: b32 = false, ainfo := context.allocator) -> ^Type {
|
||||
assert(ainfo.procedure != nil)
|
||||
input := AllocatorProc_In {
|
||||
data = ainfo.data,
|
||||
op = no_zero ? .Alloc_NoZero : .Alloc,
|
||||
requested_size = size_of(Type),
|
||||
alignment = alignment,
|
||||
}
|
||||
output: AllocatorProc_Out
|
||||
(cast(AllocatorProc)ainfo.procedure)(input, & output)
|
||||
return transmute(^Type) raw_data(output.allocation)
|
||||
}
|
||||
alloc_slice :: proc($SliceType: typeid / []$Type, num : int, alignment: int = MEMORY_ALIGNMENT_DEFAULT, no_zero: b32 = false, ainfo := context.allocator) -> []Type {
|
||||
assert(ainfo.procedure != nil)
|
||||
input := AllocatorProc_In {
|
||||
data = ainfo.data,
|
||||
op = no_zero ? .Alloc_NoZero : .Alloc,
|
||||
requested_size = size_of(Type) * num,
|
||||
alignment = alignment,
|
||||
}
|
||||
output: AllocatorProc_Out
|
||||
(cast(AllocatorProc)ainfo.procedure)(input, & output)
|
||||
return transmute([]Type) slice(raw_data(output.allocation), num)
|
||||
}
|
||||
//endregion Allocator Interface
|
1
code2/grime/os.odin
Normal file
1
code2/grime/os.odin
Normal file
@@ -0,0 +1 @@
|
||||
package grime
|
@@ -0,0 +1,23 @@
|
||||
package grime
|
||||
|
||||
import "base:builtin"
|
||||
Odin_OS_Type :: type_of(ODIN_OS)
|
||||
|
||||
import "base:intrinsics"
|
||||
atomic_thread_fence :: intrinsics.atomic_thread_fence
|
||||
mem_zero :: intrinsics.mem_zero
|
||||
mem_zero_volatile :: intrinsics.mem_zero_volatile
|
||||
mem_copy :: intrinsics.mem_copy_non_overlapping
|
||||
mem_copy_overlapping :: intrinsics.mem_copy
|
||||
|
||||
import "base:runtime"
|
||||
Assertion_Failure_Proc :: runtime.Assertion_Failure_Proc
|
||||
Logger :: runtime.Logger
|
||||
Random_Generator :: runtime.Random_Generator
|
||||
slice_copy_overlapping :: runtime.copy_slice
|
||||
|
||||
import core_os "core:os"
|
||||
// ODIN_OS :: core_os.ODIN_OS
|
||||
|
||||
import "core:slice"
|
||||
slice_zero :: slice.zero
|
||||
|
Reference in New Issue
Block a user