got multi-laned hot-reload

This commit is contained in:
2025-10-13 02:13:58 -04:00
parent 8ced7cc71e
commit 5f57cea027
18 changed files with 499 additions and 176 deletions

View File

@@ -1,8 +1,6 @@
package sectr
// import "base:runtime"
// import c "core:c/libc"
import "core:dynlib"
import "core:dynlib"
import "core:sync"
Path_Assets :: "../assets/"
@@ -10,60 +8,70 @@ Path_Shaders :: "../shaders/"
Path_Input_Replay :: "input.sectr_replay"
ModuleAPI :: struct {
lib: dynlib.Library,
// write-time: FileTime,
lib: dynlib.Library,
write_time: FileTime,
lib_version : int,
startup: type_of( startup ),
hot_reload: type_of( hot_reload ),
tick_lane_startup: type_of( tick_lane_startup),
hot_reload: type_of( hot_reload ),
tick_lane: type_of( tick_lane ),
clean_frame: type_of( clean_frame),
}
StartupContext :: struct {}
/*
Called by host.main when it completes its setup.
The goal of startup is to first prapre persistent state,
then prepare for multi-threaded "laned" tick: thread_wide_startup.
*/
@export
startup :: proc(host_mem: ^HostMemory, thread_mem: ^ThreadMemory)
startup :: proc(host_mem: ^ProcessMemory, thread_mem: ^ThreadMemory)
{
dummy : int = 0
dummy += 1
memory = host_mem
thread_wide_startup(thread_mem)
}
thread_wide_startup :: proc(thread_mem: ^ThreadMemory)
/*
Called by 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)
{
if thread_mem.id == .Master_Prepper {
sync.barrier_init(& memory.client_api_sync_lock, THREAD_TICK_LANES)
thread_ctx = thread_mem
if thread_ctx.id == .Master_Prepper {
thread_coherent_store(& memory, host_mem)
}
memory.host_api.launch_tick_lane_thread(.Atomic_Accountant)
tick_lane_startup(thread_mem)
}
/*
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_memory = thread_mem
thread_memory.live_lanes = THREAD_TICK_LANES
tick_lane()
}
tick_lane :: proc()
{
dummy : int = 0
for ;;
{
dummy += 1
if thread_memory.id == .Master_Prepper
{
memory.host_api.sync_client_module()
}
leader := sync.barrier_wait(& memory.client_api_sync_lock)
}
thread_ctx = thread_mem
thread_ctx.live_lanes = THREAD_TICK_LANES
}
@export
hot_reload :: proc(host_mem: ^HostMemory, thread_mem: ^ThreadMemory)
tick_lane :: proc(host_delta_time_ms: f64, host_delta_ns: Duration) -> (should_close: b64)
{
@thread_local dummy: int = 0;
dummy += 2
return true
}
@export
clean_frame :: proc()
{
@thread_local dummy: int = 0;
dummy += 1
return
}

View File

@@ -2,16 +2,35 @@ package sectr
import "core:sync"
HostMemory :: struct {
host_scratch: [256 * Kilo]byte,
/*
Everything defined for the host module within the client module
so that the client module has full awareness of relevant host definitions
*/
ProcessMemory :: struct {
// Host
host_persist_buf: [64 * Mega]byte,
host_scratch_buf: [32 * Mega]byte,
host_persist: Odin_Arena,
host_scratch: Odin_Arena,
host_api: Host_API,
// Textual Logging
logger: Logger,
// Profiling
spall_profiler: SpallProfiler,
// TODO(Ed): Try Superluminal!
// Multi-threading
threads: [MAX_THREADS](SysThread),
client_api_sync_lock: sync.Barrier,
client_api_hot_reloaded: b64,
client_api_sync_lock: sync.Barrier,
// Client Module
client_api: ModuleAPI,
client_memory: State,
host_api: Host_API,
}
Host_API :: struct {