WIP: Untested more process runtime bootstrapping, some decisions on how grime is setup..

This commit is contained in:
2025-10-13 12:47:16 -04:00
parent 4abd2401f0
commit 0d904fba7c
15 changed files with 257 additions and 203 deletions

View File

@@ -2,6 +2,5 @@
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 is only one definition with static allocations in Grime. Ideally there are also none, but spall profiler needs a context.
There are no implicit static allocations in Grime. Ideally there are also none from the base/core packages but some probably leak.

View File

@@ -1,32 +1,21 @@
package grime
import "core:os"
// Below should be defined per-package
ensure :: #force_inline proc( condition : b32, msg : string, location := #caller_location )
{
if condition {
return
}
ensure :: #force_inline proc( condition : b32, msg : string, location := #caller_location ) {
if condition do return
log_print( msg, LoggerLevel.Warning, location )
debug_trap()
}
// TODO(Ed) : Setup exit codes!
fatal :: #force_inline proc( msg : string, exit_code : int = -1, location := #caller_location )
{
fatal :: #force_inline proc( msg : string, exit_code : int = -1, location := #caller_location ) {
log_print( msg, LoggerLevel.Fatal, location )
debug_trap()
process_exit( exit_code )
}
// TODO(Ed) : Setup exit codes!
verify :: #force_inline proc( condition : b32, msg : string, exit_code : int = -1, location := #caller_location )
{
if condition {
return
}
verify :: #force_inline proc( condition : b32, msg : string, exit_code : int = -1, location := #caller_location ) {
if condition do return
log_print( msg, LoggerLevel.Fatal, location )
debug_trap()
process_exit( exit_code )

View File

@@ -1,6 +1,6 @@
package grime
Context :: struct {
OdinContext :: struct {
allocator: AllocatorInfo,
temp_allocator: AllocatorInfo,
assertion_failure_proc: Assertion_Failure_Proc,
@@ -14,6 +14,6 @@ Context :: struct {
_internal: rawptr,
}
context_usr :: #force_inline proc( $ Type : typeid ) -> (^Type) {
context_user :: #force_inline proc( $ Type : typeid ) -> (^Type) {
return cast(^Type) context.user_ptr
}

View File

@@ -119,7 +119,6 @@ memory_aign_forward :: #force_inline proc( address, alignment : uintptr) -> uint
return aligned_address
}
// align_up :: proc(address: uintptr, alignment: uintptr) -> uintptr {
// return (address + alignment - 1) & ~(alignment - 1)
// }

View File

@@ -78,8 +78,12 @@ import "core:os"
file_truncate :: os.truncate
file_write :: os.write
file_read_entire :: os.read_entire_file
file_write_entire :: os.write_entire_file
file_read_entire_from_filename :: #force_inline proc(name: string, allocator := context.allocator, loc := #caller_location) -> (data: []byte, success: bool) { return os.read_entire_file_from_filename(name, resolve_odin_allocator(allocator), loc) }
file_write_entire :: os.write_entire_file
file_read_entire :: proc {
file_read_entire_from_filename,
}
import "core:strings"
StrBuilder :: strings.Builder

View File

@@ -12,26 +12,21 @@ SpallProfiler :: struct {
buffer : spall.Buffer,
}
// @(private)
// Module_Context : ^SpallProfiler
// set_profiler_module_context :: #force_inline proc "contextless" ( ctx : ^SpallProfiler ) {
// Module_Context = ctx
// }
set_profiler_module_context :: #force_inline proc "contextless" ( profiler : ^SpallProfiler ) {
static_memory.spall_profiler = profiler
}
DISABLE_PROFILING :: true
@(deferred_none = profile_end, disabled = DISABLE_PROFILING)
profile :: #force_inline proc "contextless" ( name : string, loc := #caller_location ) {
// spall._buffer_begin( & Module_Context.ctx, & Module_Context.buffer, name, "", loc )
spall._buffer_begin( & static_memory.spall_profiler.ctx, & static_memory.spall_profiler.buffer, name, "", loc )
}
@(disabled = DISABLE_PROFILING)
profile_begin :: #force_inline proc "contextless" ( name : string, loc := #caller_location ) {
// spall._buffer_begin( & Module_Context.ctx, & Module_Context.buffer, name, "", loc )
spall._buffer_begin( & static_memory.spall_profiler.ctx, & static_memory.spall_profiler.buffer, name, "", loc )
}
@(disabled = DISABLE_PROFILING)
profile_end :: #force_inline proc "contextless" () {
// spall._buffer_end( & Module_Context.ctx, & Module_Context.buffer)
spall._buffer_end( & static_memory.spall_profiler.ctx, & static_memory.spall_profiler.buffer)
}

View File

@@ -0,0 +1,9 @@
package grime
//region STATIC MEMORY
static_memory: StaticMemory
//endregion STATIC MEMORY
StaticMemory :: struct {
spall_profiler: ^SpallProfiler,
}

3
code2/gui_code/Readme.md Normal file
View File

@@ -0,0 +1,3 @@
# gui_code
This is the UI package used by sectr. It's meant to be optimial for composing complex code visualizations in soft real-time.

View File

@@ -1,59 +1,39 @@
package host
import "core:thread"
import "core:sync"
//region STATIC MEMORY
// All program defined process memory here. (There will still be artifacts from the OS CRT and third-party pacakges)
host_memory: ProcessMemory
@(thread_local) thread_memory: ThreadMemory
Path_Logs :: "../logs"
when ODIN_OS == .Windows
{
Path_Sectr_Module :: "sectr.dll"
Path_Sectr_Live_Module :: "sectr_live.dll"
Path_Sectr_Debug_Symbols :: "sectr.pdb"
Path_Sectr_Spall_Record :: "sectr.spall"
}
//endregion STATIC MEMORY
// Only static memory host has.
host_memory: ProcessMemory
//region HOST RUNTIME
@(thread_local)
thread_memory: ThreadMemory
load_client_api :: proc(version_id: int) -> (loaded_module: Client_API)
{
write_time, result := file_last_write_time_by_name("sectr.dll")
if result != OS_ERROR_NONE {
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")
}
//TODO(Ed): Lets try to minimize this...
thread_sleep( Millisecond * 100 )
// Get the live dll loaded up
live_file := Path_Sectr_Live_Module
file_copy_sync( Path_Sectr_Module, live_file, allocator = context.temp_allocator )
lib, load_result := os_lib_load( live_file )
if ! load_result {
panic( "Failed to load the sectr module." )
}
startup := cast( type_of( host_memory.client_api.startup)) os_lib_get_proc(lib, "startup")
tick_lane_startup := cast( type_of( host_memory.client_api.tick_lane_startup)) os_lib_get_proc(lib, "tick_lane_startup")
hot_reload := cast( type_of( host_memory.client_api.hot_reload)) os_lib_get_proc(lib, "hot_reload")
tick_lane := cast( type_of( host_memory.client_api.tick_lane)) os_lib_get_proc(lib, "tick_lane")
clean_frame := cast( type_of( host_memory.client_api.clean_frame)) os_lib_get_proc(lib, "clean_frame")
did_load: bool; lib, did_load = os_lib_load( live_file )
if ! did_load do panic( "Failed to load the sectr module.")
startup = cast( type_of( host_memory.client_api.startup)) os_lib_get_proc(lib, "startup")
tick_lane_startup = cast( type_of( host_memory.client_api.tick_lane_startup)) os_lib_get_proc(lib, "tick_lane_startup")
hot_reload = cast( type_of( host_memory.client_api.hot_reload)) os_lib_get_proc(lib, "hot_reload")
tick_lane = cast( type_of( host_memory.client_api.tick_lane)) os_lib_get_proc(lib, "tick_lane")
clean_frame = cast( type_of( host_memory.client_api.clean_frame)) os_lib_get_proc(lib, "clean_frame")
if startup == nil do panic("Failed to load sectr.startup symbol" )
if tick_lane_startup == nil do panic("Failed to load sectr.tick_lane_startup symbol" )
if hot_reload == nil do panic("Failed to load sectr.hot_reload symbol" )
if tick_lane == nil do panic("Failed to load sectr.tick_lane symbol" )
if clean_frame == nil do panic("Failed to load sectr.clean_frmae symbol" )
loaded_module.lib = lib
loaded_module.write_time = write_time
loaded_module.lib_version = version_id
loaded_module.startup = startup
loaded_module.tick_lane_startup = tick_lane_startup
loaded_module.hot_reload = hot_reload
loaded_module.tick_lane = tick_lane
loaded_module.clean_frame = clean_frame
lib_version = version_id
return
}
@@ -65,8 +45,9 @@ main :: proc()
arena_init(& host_memory.host_scratch, host_memory.host_scratch_buf[:])
context.allocator = arena_allocator(& host_memory.host_persist)
context.temp_allocator = arena_allocator(& host_memory.host_scratch)
// Setup the profiler
when SHOULD_SETUP_PROFILERS
{
// Setup profilers
buffer_backing := make([]u8, SPALL_BUFFER_DEFAULT_SIZE * 4)
host_memory.spall_profiler.ctx = spall_context_create(Path_Sectr_Spall_Record)
host_memory.spall_profiler.buffer = spall_buffer_create(buffer_backing)
@@ -120,43 +101,32 @@ main :: proc()
host_memory.client_api = load_client_api( 1 )
verify( host_memory.client_api.lib_version != 0, "Failed to initially load the sectr module" )
}
// Client API Startup
host_memory.host_api.sync_client_module = sync_client_api
host_memory.host_api.launch_tick_lane_thread = launch_tick_lane_thread
host_memory.client_api.startup(& host_memory, & thread_memory)
// Start the tick lanes
thread_wide_startup()
}
thread_wide_startup :: proc()
{
assert(thread_memory.id == .Master_Prepper)
if THREAD_TICK_LANES > 1 {
launch_tick_lane_thread(.Atomic_Accountant)
sync.barrier_init(& host_memory.client_api_sync_lock, THREAD_TICK_LANES)
/*thread_wide_startup() :: proc()*/ {
assert(thread_memory.id == .Master_Prepper)
if THREAD_TICK_LANES > 1 {
launch_tick_lane_thread(.Atomic_Accountant)
barrier_init(& host_memory.client_api_sync_lock, THREAD_TICK_LANES)
}
host_tick_lane_startup(thread_memory.system_ctx)
}
host_tick_lane_startup(thread_memory.system_ctx)
}
@export
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_startup, .High)
lane_thread := thread_create(host_tick_lane_startup, .High)
lane_thread.user_index = int(id)
thread.start(lane_thread)
thread_start(lane_thread)
}
host_tick_lane_startup :: proc(lane_thread: ^SysThread) {
thread_memory.system_ctx = lane_thread
thread_memory.id = cast(WorkerID) lane_thread.user_index
host_memory.client_api.tick_lane_startup(& thread_memory)
host_tick_lane()
}
host_tick_lane :: proc()
{
delta_ns: Duration
@@ -167,6 +137,7 @@ host_tick_lane :: proc()
for ; running ;
{
profile("Host Tick")
leader := barrier_wait(& host_memory.client_api_sync_lock)
sync_client_api()
running = host_memory.client_api.tick_lane( duration_seconds(delta_ns), delta_ns )
@@ -180,41 +151,40 @@ host_tick_lane :: proc()
@export
sync_client_api :: proc()
{
leader := sync.barrier_wait(& host_memory.client_api_sync_lock)
free_all(context.temp_allocator)
profile(#procedure)
if thread_memory.id == .Master_Prepper
{
write_time, result := file_last_write_time_by_name( Path_Sectr_Module );
if result == OS_ERROR_NONE && host_memory.client_api.write_time != write_time
if thread_memory.id == .Master_Prepper
{
cache_coherent_store(& host_memory.client_api_hot_reloaded, true)
version_id := host_memory.client_api.lib_version + 1
unload_client_api( & host_memory.client_api )
// Wait for pdb to unlock (linker may still be writting)
for ; file_is_locked( Path_Sectr_Debug_Symbols ) && file_is_locked( Path_Sectr_Live_Module ); {}
thread_sleep( Millisecond * 100 )
host_memory.client_api = load_client_api( version_id )
verify( host_memory.client_api.lib_version != 0, "Failed to hot-reload the sectr module" )
profile("Master_Prepper: Reloading client module")
write_time, result := file_last_write_time_by_name( Path_Sectr_Module );
if result == OS_ERROR_NONE && host_memory.client_api.write_time != write_time
{
sync_store(& host_memory.client_api_hot_reloaded, true, .Release)
version_id := host_memory.client_api.lib_version + 1
unload_client_api( & host_memory.client_api )
// Wait for pdb to unlock (linker may still be writting)
for ; file_is_locked( Path_Sectr_Debug_Symbols ) && file_is_locked( Path_Sectr_Live_Module ); {}
thread_sleep( Millisecond * 100 )
host_memory.client_api = load_client_api( version_id )
verify( host_memory.client_api.lib_version != 0, "Failed to hot-reload the sectr module" )
}
}
}
leader = sync.barrier_wait(& host_memory.client_api_sync_lock)
if cache_coherent_load(& host_memory.client_api_hot_reloaded)
leader := barrier_wait(& host_memory.client_api_sync_lock)
if sync_load(& host_memory.client_api_hot_reloaded, .Acquire)
{
host_memory.client_api.hot_reload(& host_memory, & thread_memory)
if thread_memory.id == .Master_Prepper {
cache_coherent_store(& host_memory.client_api_hot_reloaded, false)
sync_store(& host_memory.client_api_hot_reloaded, false, .Release)
}
}
}
unload_client_api :: proc( module : ^Client_API )
{
os_lib_unload( module.lib )
file_remove( Path_Sectr_Live_Module )
module^ = {}
log_print("Unloaded sectr API")
log_print("Unloaded client API")
}
//endregion HOST RUNTIME

View File

@@ -1,15 +1,5 @@
package host
// 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"
debug_trap :: runtime.debug_trap
@@ -31,10 +21,11 @@ import "core:mem"
arena_init :: mem.arena_init
import "core:os"
OS_ERROR_NONE :: os.ERROR_NONE
OS_Error :: os.Error
FileTime :: os.File_Time
file_last_write_time_by_name :: os.last_write_time_by_name
file_remove :: os.remove
OS_ERROR_NONE :: os.ERROR_NONE
os_is_directory :: os.is_dir
os_make_directory :: os.make_directory
os_core_count :: os.processor_core_count
@@ -51,9 +42,12 @@ import "core:strings"
builder_to_str :: strings.to_string
import "core:sync"
Barrier :: sync.Barrier
barrier_init :: sync.barrier_init
barrier_wait :: sync.barrier_wait
thread_current_id :: sync.current_thread_id
cache_coherent_load :: sync.atomic_load
cache_coherent_store :: sync.atomic_store
sync_load :: sync.atomic_load_explicit
sync_store :: sync.atomic_store_explicit
import "core:time"
Millisecond :: time.Millisecond
@@ -68,79 +62,74 @@ import "core:time"
time_tick_lap_time :: time.tick_lap_time
import "core:thread"
SysThread :: thread.Thread
SysThread :: thread.Thread
thread_create :: thread.create
thread_start :: thread.start
import grime "codebase:grime"
DISABLE_PROFILING :: grime.DISABLE_PROFILING
DISABLE_GRIME_PROFILING :: grime.DISABLE_PROFILING
file_copy_sync :: grime.file_copy_sync
file_is_locked :: grime.file_is_locked
logger_init :: grime.logger_init
to_odin_logger :: grime.to_odin_logger
import "codebase:sectr"
MAX_THREADS :: sectr.MAX_THREADS
THREAD_TICK_LANES :: sectr.THREAD_TICK_LANES
DISABLE_HOST_PROFILING :: sectr.DISABLE_HOST_PROFILING
DISABLE_CLIENT_PROFILING :: sectr.DISABLE_CLIENT_PROFILING
Path_Logs :: sectr.Path_Logs
Path_Sectr_Debug_Symbols :: sectr.Path_Debug_Symbols
Path_Sectr_Live_Module :: sectr.Path_Live_Module
Path_Sectr_Module :: sectr.Path_Module
Path_Sectr_Spall_Record :: sectr.Path_Spall_Record
MAX_THREADS :: sectr.MAX_THREADS
THREAD_TICK_LANES :: sectr.THREAD_TICK_LANES
Client_API :: sectr.ModuleAPI
ProcessMemory :: sectr.ProcessMemory
ThreadMemory :: sectr.ThreadMemory
WorkerID :: sectr.WorkerID
SpallProfiler :: sectr.SpallProfiler
ensure :: #force_inline proc( condition : b32, msg : string, location := #caller_location )
{
if condition {
return
}
ensure :: #force_inline proc( condition : b32, msg : string, location := #caller_location ) {
if condition do return
log_print( msg, LoggerLevel.Warning, location )
debug_trap()
}
// TODO(Ed) : Setup exit codes!
fatal :: #force_inline proc( msg : string, exit_code : int = -1, location := #caller_location )
{
fatal :: #force_inline proc( msg : string, exit_code : int = -1, location := #caller_location ) {
log_print( msg, LoggerLevel.Fatal, location )
debug_trap()
process_exit( exit_code )
}
// TODO(Ed) : Setup exit codes!
verify :: #force_inline proc( condition : b32, msg : string, exit_code : int = -1, location := #caller_location )
{
if condition {
return
}
verify :: #force_inline proc( condition : b32, msg : string, exit_code : int = -1, location := #caller_location ) {
if condition do return
log_print( msg, LoggerLevel.Fatal, location )
debug_trap()
process_exit( exit_code )
}
log_print :: proc( msg : string, level := LoggerLevel.Info, loc := #caller_location ) {
context.allocator = arena_allocator(& host_memory.host_scratch)
context.temp_allocator = arena_allocator(& host_memory.host_scratch)
log.log( level, msg, location = loc )
}
log_print_fmt :: proc( fmt : string, args : ..any, level := LoggerLevel.Info, loc := #caller_location ) {
context.allocator = arena_allocator(& host_memory.host_scratch)
context.temp_allocator = arena_allocator(& host_memory.host_scratch)
log.logf( level, fmt, ..args, location = loc )
}
@(deferred_none = profile_end, disabled = DISABLE_PROFILING)
profile :: #force_inline proc "contextless" ( name : string, loc := #caller_location ) {
spall._buffer_begin( & host_memory.spall_profiler.ctx, & host_memory.spall_profiler.buffer, name, "", loc )
}
@(deferred_none = profile_end, disabled = DISABLE_HOST_PROFILING) profile :: #force_inline proc "contextless" ( name : string, loc := #caller_location ) { spall._buffer_begin( & host_memory.spall_profiler.ctx, & host_memory.spall_profiler.buffer, name, "", loc ) }
@( disabled = DISABLE_HOST_PROFILING) profile_begin :: #force_inline proc "contextless" ( name : string, loc := #caller_location ) { spall._buffer_begin( & host_memory.spall_profiler.ctx, & host_memory.spall_profiler.buffer, name, "", loc ) }
@( disabled = DISABLE_HOST_PROFILING) profile_end :: #force_inline proc "contextless" () { spall._buffer_end ( & host_memory.spall_profiler.ctx, & host_memory.spall_profiler.buffer) }
@(disabled = DISABLE_PROFILING)
profile_begin :: #force_inline proc "contextless" ( name : string, loc := #caller_location ) {
spall._buffer_begin( & host_memory.spall_profiler.ctx, & host_memory.spall_profiler.buffer, name, "", loc )
}
@(disabled = DISABLE_PROFILING)
profile_end :: #force_inline proc "contextless" () {
spall._buffer_end( & host_memory.spall_profiler.ctx, & host_memory.spall_profiler.buffer)
}
SHOULD_SETUP_PROFILERS :: \
DISABLE_GRIME_PROFILING == false ||
DISABLE_CLIENT_PROFILING == false ||
DISABLE_HOST_PROFILING == false
Kilo :: 1024
Mega :: Kilo * 1024

View File

@@ -0,0 +1,21 @@
package sectr
Path_Assets :: "../assets/"
Path_Shaders :: "../shaders/"
Path_Input_Replay :: "input.sectr_replay"
Path_Logs :: "../logs"
when ODIN_OS == .Windows
{
Path_Module :: "sectr.dll"
Path_Live_Module :: "sectr_live.dll"
Path_Debug_Symbols :: "sectr.pdb"
Path_Spall_Record :: "sectr.spall"
}
DISABLE_CLIENT_PROFILING :: false
DISABLE_HOST_PROFILING :: false
// TODO(Ed): We can technically hot-reload this (spin up or down lanes on reloads)
THREAD_TICK_LANES :: 2

View File

@@ -1,14 +1,18 @@
package sectr
import "core:dynlib"
import "core:sync"
// Sokol should only be used here and in the client_api_sokol_callbacks.odin
Path_Assets :: "../assets/"
Path_Shaders :: "../shaders/"
Path_Input_Replay :: "input.sectr_replay"
import sokol_app "thirdparty:sokol/app"
import sokol_gfx "thirdparty:sokol/gfx"
import sokol_glue "thirdparty:sokol/glue"
import sokol_gp "thirdparty:sokol/gp"
/*
This definies the client interface for the host process to call into
*/
ModuleAPI :: struct {
lib: dynlib.Library,
lib: DynLibrary,
write_time: FileTime,
lib_version : int,
@@ -19,8 +23,6 @@ ModuleAPI :: struct {
clean_frame: type_of( clean_frame),
}
StartupContext :: struct {}
/*
Called by host.main when it completes its setup.
@@ -34,44 +36,63 @@ startup :: proc(host_mem: ^ProcessMemory, thread_mem: ^ThreadMemory)
}
/*
Called by sync_client_api when the client module has be reloaded.
Called by host.sync_client_api when the client module has be reloaded.
Threads will eventually return to their tick_lane upon completion.
*/
@export
hot_reload :: proc(host_mem: ^ProcessMemory, thread_mem: ^ThreadMemory)
{
thread_ctx = thread_mem
if thread_ctx.id == .Master_Prepper {
cache_coherent_store(& memory, host_mem, .Release)
thread = thread_mem
if thread.id == .Master_Prepper {
sync_store(& memory, host_mem, .Release)
}
}
/*
Called by host_tick_lane_startup
Used for lane specific startup operations
The lane tick cannot be handled it, its call must be done by the host module.
(We need threads to not be within a client callstack in the even of a hot-reload)
Called by host_tick_lane_startup
Used for lane specific startup operations
The lane tick cannot be handled it, its call must be done by the host module.
(We need threads to not be within a client callstack in the even of a hot-reload)
*/
@export
tick_lane_startup :: proc(thread_mem: ^ThreadMemory)
{
thread_ctx = thread_mem
thread_ctx.live_lanes = THREAD_TICK_LANES
thread = thread_mem
thread.live_lanes = THREAD_TICK_LANES
}
/*
*/
@export
tick_lane :: proc(host_delta_time_ms: f64, host_delta_ns: Duration) -> (should_close: b64)
{
@thread_local dummy: int = 0;
dummy += 2
profile_begin("sokol_app: pre_client_tick")
// should_close |= cast(b64) sokol_app.pre_client_frame()
profile_end()
profile_begin("Client Tick")
profile_end()
profile_begin("sokol_app: post_client_tick")
profile_end()
tick_lane_frametime()
return true
}
tick_lane_frametime :: proc()
{
}
@export
clean_frame :: proc()
{
@thread_local dummy: int = 0;
dummy += 1
if thread.id == .Master_Prepper
{
}
return
}

View File

@@ -5,6 +5,12 @@ import "core:sync"
/*
Everything defined for the host module within the client module
so that the client module has full awareness of relevant host definitions
Client interaction with host is very minimal,
host will only provide the base runtime for client's tick lanes and job system workers.
Host is has all statically (data/bss) defined memory for the application, it will not mess with
client_memory however.
*/
ProcessMemory :: struct {
@@ -19,8 +25,7 @@ ProcessMemory :: struct {
logger: Logger,
// Profiling
spall_profiler: SpallProfiler,
// TODO(Ed): Try Superluminal!
spall_profiler: ^SpallProfiler,
// Multi-threading
threads: [MAX_THREADS](SysThread),
@@ -34,12 +39,8 @@ ProcessMemory :: struct {
}
Host_API :: struct {
launch_tick_lane_thread: #type proc(WorkerID),
request_virtual_memory: #type proc(),
request_virtual_mapped_io: #type proc(),
sync_client_module : #type proc(),
}
ThreadMemory :: struct {

View File

@@ -1,14 +1,36 @@
package sectr
/*
All direct non-codebase package symbols should do zero allocations.
Any symbol that does must be mapped from the Grime package to properly tirage its allocator to odin's ideomatic interface.
*/
import "base:intrinsics"
debug_trap :: intrinsics.debug_trap
import "core:dynlib"
// Only referenced in ModuleAPI
DynLibrary :: dynlib.Library
import "core:log"
LoggerLevel :: log.Level
import "core:mem"
Odin_Arena :: mem.Arena
// Used strickly for the logger
Odin_Arena :: mem.Arena
odin_arena_allocator :: mem.arena_allocator
import "core:os"
FileTime :: os.File_Time
FileTime :: os.File_Time
process_exit :: os.exit
import "core:prof/spall"
import "core:sync"
AtomicMutex :: sync.Atomic_Mutex
cache_coherent_store :: sync.atomic_store_explicit
sync_store :: sync.atomic_store_explicit
import "core:thread"
SysThread :: thread.Thread
@@ -17,10 +39,44 @@ import "core:time"
Duration :: time.Duration
import "codebase:grime"
Logger :: grime.Logger
SpallProfiler :: grime.SpallProfiler
Logger :: grime.Logger
SpallProfiler :: grime.SpallProfiler
Kilo :: 1024
Mega :: Kilo * 1024
Giga :: Mega * 1024
Tera :: Giga * 1024
ensure :: #force_inline proc( condition : b32, msg : string, location := #caller_location ) {
if condition do return
log_print( msg, LoggerLevel.Warning, location )
debug_trap()
}
// TODO(Ed) : Setup exit codes!
fatal :: #force_inline proc( msg : string, exit_code : int = -1, location := #caller_location ) {
log_print( msg, LoggerLevel.Fatal, location )
debug_trap()
process_exit( exit_code )
}
// TODO(Ed) : Setup exit codes!
verify :: #force_inline proc( condition : b32, msg : string, exit_code : int = -1, location := #caller_location ) {
if condition do return
log_print( msg, LoggerLevel.Fatal, location )
debug_trap()
process_exit( exit_code )
}
log_print :: proc( msg : string, level := LoggerLevel.Info, loc := #caller_location ) {
context.allocator = odin_arena_allocator(& memory.host_scratch)
context.temp_allocator = odin_arena_allocator(& memory.host_scratch)
log.log( level, msg, location = loc )
}
log_print_fmt :: proc( fmt : string, args : ..any, level := LoggerLevel.Info, loc := #caller_location ) {
context.allocator = odin_arena_allocator(& memory.host_scratch)
context.temp_allocator = odin_arena_allocator(& memory.host_scratch)
log.logf( level, fmt, ..args, location = loc )
}
@(deferred_none = profile_end, disabled = DISABLE_CLIENT_PROFILING) profile :: #force_inline proc "contextless" ( name : string, loc := #caller_location ) { spall._buffer_begin( & memory.spall_profiler.ctx, & memory.spall_profiler.buffer, name, "", loc ) }
@( disabled = DISABLE_CLIENT_PROFILING) profile_begin :: #force_inline proc "contextless" ( name : string, loc := #caller_location ) { spall._buffer_begin( & memory.spall_profiler.ctx, & memory.spall_profiler.buffer, name, "", loc ) }
@( disabled = DISABLE_CLIENT_PROFILING) profile_end :: #force_inline proc "contextless" () { spall._buffer_end ( & memory.spall_profiler.ctx, & memory.spall_profiler.buffer) }

View File

@@ -1,12 +1,10 @@
package sectr
//region STATIC MEMORY
// This should be the only global on client module side.
memory: ^ProcessMemory
@(thread_local)
thread_ctx: ^ThreadMemory
THREAD_TICK_LANES :: 2
memory: ^ProcessMemory
@(thread_local) thread: ^ThreadMemory
//endregion STATIC MEMORy
State :: struct {
job_system: JobSystemContext,