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,3 +1,15 @@
# Sectr Package
This is the monolithic package representing the prototype itself. Relative to the host package this represents what define's the client module API, process memory, and thread memory.
Many definitions that are considered independent of the prototype have been lifted to the grime package, vefontcache, or in the future other packages within this codebase collection.
All allocators and containers within Sectr are derived from Grime.
The memory heurstics for sectr are categorized for now into:
* Persistent Static: Never released for process lifetime.
* Persistent Conservative: Can be wiped
* Frame
* File Mappings
* Codebase DB

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 {

View File

@@ -1,11 +1,25 @@
package sectr
import "core:mem"
Odin_Arena :: mem.Arena
import "core:os"
FileTime :: os.File_Time
import "core:sync"
AtomicMutex :: sync.Atomic_Mutex
thread_coherent_store :: sync.atomic_store
import "core:thread"
SysThread :: thread.Thread
import "core:time"
Duration :: time.Duration
import "codebase:grime"
Logger :: grime.Logger
SpallProfiler :: grime.SpallProfiler
Kilo :: 1024
Mega :: Kilo * 1024
Giga :: Mega * 1024

View File

@@ -1,10 +1,10 @@
package sectr
// This should be the only global on client module side.
memory: ^HostMemory
memory: ^ProcessMemory
@(thread_local)
thread_memory: ^ThreadMemory
thread_ctx: ^ThreadMemory
THREAD_TICK_LANES :: 2