2024-01-21 20:38:02 -08:00
|
|
|
package host
|
|
|
|
|
2024-02-27 04:50:57 -08:00
|
|
|
//region Grime & Dependencies
|
|
|
|
import "base:runtime"
|
|
|
|
Byte :: runtime.Byte
|
|
|
|
Kilobyte :: runtime.Kilobyte
|
|
|
|
Megabyte :: runtime.Megabyte
|
|
|
|
Gigabyte :: runtime.Gigabyte
|
|
|
|
Terabyte :: runtime.Terabyte
|
|
|
|
Petabyte :: runtime.Petabyte
|
|
|
|
Exabyte :: runtime.Exabyte
|
|
|
|
import "core:dynlib"
|
|
|
|
os_lib_load :: dynlib.load_library
|
|
|
|
os_lib_unload :: dynlib.unload_library
|
|
|
|
os_lib_get_proc :: dynlib.symbol_address
|
|
|
|
import "core:io"
|
|
|
|
import fmt_io "core:fmt"
|
|
|
|
str_fmt :: fmt_io.printf
|
|
|
|
str_fmt_tmp :: fmt_io.tprintf
|
|
|
|
str_fmt_builder :: fmt_io.sbprintf
|
|
|
|
import "core:log"
|
|
|
|
import "core:mem"
|
|
|
|
Allocator :: mem.Allocator
|
|
|
|
TrackingAllocator :: mem.Tracking_Allocator
|
|
|
|
import "core:mem/virtual"
|
|
|
|
Arena :: virtual.Arena
|
|
|
|
MapFileError :: virtual.Map_File_Error
|
|
|
|
MapFileFlag :: virtual.Map_File_Flag
|
|
|
|
MapFileFlags :: virtual.Map_File_Flags
|
|
|
|
import "core:os"
|
|
|
|
FileFlag_Create :: os.O_CREATE
|
|
|
|
FileFlag_ReadWrite :: os.O_RDWR
|
|
|
|
file_open :: os.open
|
|
|
|
file_close :: os.close
|
|
|
|
file_rename :: os.rename
|
|
|
|
file_remove :: os.remove
|
|
|
|
file_resize :: os.ftruncate
|
|
|
|
file_status_via_handle :: os.fstat
|
|
|
|
file_status_via_path :: os.stat
|
|
|
|
import "core:strings"
|
|
|
|
builder_to_string :: strings.to_string
|
|
|
|
str_clone :: strings.clone
|
|
|
|
str_builder_from_bytes :: strings.builder_from_bytes
|
|
|
|
import "core:time"
|
|
|
|
Millisecond :: time.Millisecond
|
|
|
|
Second :: time.Second
|
|
|
|
Duration :: time.Duration
|
|
|
|
duration_seconds :: time.duration_seconds
|
|
|
|
thread_sleep :: time.sleep
|
2024-01-21 20:38:02 -08:00
|
|
|
import rl "vendor:raylib"
|
|
|
|
import sectr "../."
|
2024-02-27 04:50:57 -08:00
|
|
|
fatal :: sectr.fatal
|
|
|
|
file_is_locked :: sectr.file_is_locked
|
|
|
|
file_copy_sync :: sectr.file_copy_sync
|
|
|
|
Logger :: sectr.Logger
|
|
|
|
logger_init :: sectr.logger_init
|
|
|
|
LogLevel :: sectr.LogLevel
|
|
|
|
log :: sectr.log
|
|
|
|
to_odin_logger :: sectr.to_odin_logger
|
|
|
|
TrackedAllocator :: sectr.TrackedAllocator
|
|
|
|
tracked_allocator :: sectr.tracked_allocator
|
|
|
|
tracked_allocator_init :: sectr.tracked_allocator_init
|
|
|
|
verify :: sectr.verify
|
|
|
|
|
|
|
|
file_status :: proc {
|
|
|
|
file_status_via_handle,
|
|
|
|
file_status_via_path,
|
|
|
|
}
|
2024-01-21 20:38:02 -08:00
|
|
|
|
2024-02-27 04:50:57 -08:00
|
|
|
to_str :: proc {
|
|
|
|
builder_to_string,
|
|
|
|
}
|
|
|
|
//endregion Grime & Dependencies
|
2024-02-08 19:33:53 -08:00
|
|
|
|
2024-02-27 04:50:57 -08:00
|
|
|
Path_Snapshot :: "VMemChunk_1.snapshot"
|
|
|
|
Path_Logs :: "../logs"
|
2024-01-29 22:29:48 -08:00
|
|
|
when ODIN_OS == runtime.Odin_OS_Type.Windows
|
|
|
|
{
|
2024-02-27 04:50:57 -08:00
|
|
|
Path_Sectr_Module :: "sectr.dll"
|
|
|
|
Path_Sectr_Live_Module :: "sectr_live.dll"
|
|
|
|
Path_Sectr_Debug_Symbols :: "sectr.pdb"
|
2024-01-29 22:29:48 -08:00
|
|
|
}
|
2024-01-25 07:49:57 -08:00
|
|
|
|
2024-01-21 20:38:02 -08:00
|
|
|
RuntimeState :: struct {
|
2024-01-22 00:47:53 -08:00
|
|
|
running : b32,
|
|
|
|
memory : VMemChunk,
|
2024-01-21 20:38:02 -08:00
|
|
|
sectr_api : sectr.ModuleAPI,
|
|
|
|
}
|
|
|
|
|
|
|
|
VMemChunk :: struct {
|
2024-02-27 04:50:57 -08:00
|
|
|
og_allocator : Allocator,
|
|
|
|
og_temp_allocator : Allocator,
|
2024-01-29 22:29:48 -08:00
|
|
|
host_persistent : TrackedAllocator,
|
|
|
|
host_transient : TrackedAllocator,
|
2024-02-27 04:50:57 -08:00
|
|
|
sectr_live : Arena,
|
2024-02-08 07:50:36 -08:00
|
|
|
sectr_snapshot : []u8
|
2024-01-21 20:38:02 -08:00
|
|
|
}
|
|
|
|
|
2024-02-23 06:36:23 -08:00
|
|
|
setup_memory :: proc() -> VMemChunk
|
2024-01-21 20:38:02 -08:00
|
|
|
{
|
2024-01-22 00:47:53 -08:00
|
|
|
memory : VMemChunk; using memory
|
2024-01-21 20:38:02 -08:00
|
|
|
|
2024-02-27 04:50:57 -08:00
|
|
|
Host_Persistent_Size :: 32 * Megabyte
|
|
|
|
Host_Transient_Size :: 96 * Megabyte
|
|
|
|
Internals_Size :: 4 * Megabyte
|
2024-01-21 20:38:02 -08:00
|
|
|
|
2024-02-27 04:50:57 -08:00
|
|
|
host_persistent = tracked_allocator_init( Host_Persistent_Size, Internals_Size )
|
|
|
|
host_transient = tracked_allocator_init( Host_Transient_Size, Internals_Size )
|
2024-01-25 07:49:57 -08:00
|
|
|
|
2024-01-21 20:38:02 -08:00
|
|
|
// Setup the static arena for the entire application
|
|
|
|
{
|
2024-02-27 04:50:57 -08:00
|
|
|
base_address : rawptr = transmute( rawptr) u64(sectr.Memory_Base_Address)
|
|
|
|
result := arena_init_static( & sectr_live, base_address, sectr.Memory_Chunk_Size, sectr.Memory_Chunk_Size )
|
2024-02-23 06:36:23 -08:00
|
|
|
verify( result == runtime.Allocator_Error.None, "Failed to allocate live memory for the sectr module" )
|
2024-02-08 07:50:36 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
// Setup memory mapped io for snapshots
|
|
|
|
{
|
2024-02-27 04:50:57 -08:00
|
|
|
snapshot_file, open_error := file_open( Path_Snapshot, FileFlag_ReadWrite | FileFlag_Create )
|
2024-02-23 06:36:23 -08:00
|
|
|
verify( open_error == os.ERROR_NONE, "Failed to open snapshot file for the sectr module" )
|
2024-02-08 19:33:53 -08:00
|
|
|
|
2024-02-27 04:50:57 -08:00
|
|
|
file_info, stat_code := file_status( snapshot_file )
|
2024-02-08 13:05:15 -08:00
|
|
|
{
|
2024-02-27 04:50:57 -08:00
|
|
|
if file_info.size != sectr.Memory_Chunk_Size {
|
|
|
|
file_resize( snapshot_file, sectr.Memory_Chunk_Size )
|
2024-02-08 13:05:15 -08:00
|
|
|
}
|
|
|
|
}
|
2024-02-27 04:50:57 -08:00
|
|
|
map_error : MapFileError
|
|
|
|
map_flags : MapFileFlags = { MapFileFlag.Read, MapFileFlag.Write }
|
2024-02-08 19:33:53 -08:00
|
|
|
sectr_snapshot, map_error = virtual.map_file_from_file_descriptor( uintptr(snapshot_file), map_flags )
|
2024-02-27 04:50:57 -08:00
|
|
|
verify( map_error == MapFileError.None, "Failed to allocate snapshot memory for the sectr module" )
|
|
|
|
file_close(snapshot_file)
|
2024-01-21 20:38:02 -08:00
|
|
|
}
|
|
|
|
|
2024-01-29 22:29:48 -08:00
|
|
|
// Reassign default allocators for host
|
|
|
|
memory.og_allocator = context.allocator
|
|
|
|
memory.og_temp_allocator = context.temp_allocator
|
2024-02-08 19:33:53 -08:00
|
|
|
log("Memory setup")
|
2024-01-21 20:38:02 -08:00
|
|
|
return memory;
|
|
|
|
}
|
|
|
|
|
2024-02-23 06:36:23 -08:00
|
|
|
load_sectr_api :: proc( version_id : i32 ) -> sectr.ModuleAPI
|
2024-01-21 20:38:02 -08:00
|
|
|
{
|
|
|
|
loaded_module : sectr.ModuleAPI
|
|
|
|
|
2024-02-08 19:33:53 -08:00
|
|
|
write_time, result := os.last_write_time_by_name("sectr.dll")
|
2024-01-21 20:38:02 -08:00
|
|
|
if result != os.ERROR_NONE {
|
2024-02-08 19:33:53 -08:00
|
|
|
log( "Could not resolve the last write time for sectr.dll", LogLevel.Warning )
|
2024-01-21 20:38:02 -08:00
|
|
|
runtime.debug_trap()
|
|
|
|
return {}
|
|
|
|
}
|
|
|
|
|
2024-02-27 04:50:57 -08:00
|
|
|
live_file := Path_Sectr_Live_Module
|
|
|
|
file_copy_sync( Path_Sectr_Module, live_file )
|
2024-01-21 20:38:02 -08:00
|
|
|
|
2024-02-27 04:50:57 -08:00
|
|
|
lib, load_result := os_lib_load( live_file )
|
2024-01-21 20:38:02 -08:00
|
|
|
if ! load_result {
|
2024-02-08 19:33:53 -08:00
|
|
|
log( "Failed to load the sectr module.", LogLevel.Warning )
|
2024-01-21 20:38:02 -08:00
|
|
|
runtime.debug_trap()
|
|
|
|
return {}
|
|
|
|
}
|
|
|
|
|
2024-02-27 04:50:57 -08:00
|
|
|
startup := cast( type_of( sectr.startup )) os_lib_get_proc( lib, "startup" )
|
|
|
|
shutdown := cast( type_of( sectr.sectr_shutdown )) os_lib_get_proc( lib, "sectr_shutdown" )
|
|
|
|
reload := cast( type_of( sectr.reload )) os_lib_get_proc( lib, "reload" )
|
|
|
|
tick := cast( type_of( sectr.tick )) os_lib_get_proc( lib, "tick" )
|
|
|
|
clean_temp := cast( type_of( sectr.clean_temp )) os_lib_get_proc( lib, "clean_temp" )
|
2024-01-22 00:47:53 -08:00
|
|
|
|
|
|
|
missing_symbol : b32 = false
|
2024-02-27 04:50:57 -08:00
|
|
|
if startup == nil do log("Failed to load sectr.startup symbol", LogLevel.Warning )
|
|
|
|
if shutdown == nil do log("Failed to load sectr.shutdown symbol", LogLevel.Warning )
|
|
|
|
if reload == nil do log("Failed to load sectr.reload symbol", LogLevel.Warning )
|
|
|
|
if tick == nil do log("Failed to load sectr.tick symbol", LogLevel.Warning )
|
|
|
|
if clean_temp == nil do log("Failed to load sector.clean_temp symbol", LogLevel.Warning )
|
2024-01-22 00:47:53 -08:00
|
|
|
if missing_symbol {
|
|
|
|
runtime.debug_trap()
|
|
|
|
return {}
|
|
|
|
}
|
|
|
|
|
2024-02-08 19:33:53 -08:00
|
|
|
log("Loaded sectr API")
|
2024-01-21 20:38:02 -08:00
|
|
|
loaded_module = {
|
|
|
|
lib = lib,
|
2024-01-22 00:47:53 -08:00
|
|
|
write_time = write_time,
|
2024-01-21 20:38:02 -08:00
|
|
|
lib_version = version_id,
|
|
|
|
|
2024-01-29 22:29:48 -08:00
|
|
|
startup = startup,
|
|
|
|
shutdown = shutdown,
|
|
|
|
reload = reload,
|
2024-02-10 00:40:53 -08:00
|
|
|
tick = tick,
|
2024-01-29 22:29:48 -08:00
|
|
|
clean_temp = clean_temp,
|
2024-01-21 20:38:02 -08:00
|
|
|
}
|
|
|
|
return loaded_module
|
|
|
|
}
|
|
|
|
|
2024-02-23 06:36:23 -08:00
|
|
|
unload_sectr_api :: proc( module : ^ sectr.ModuleAPI )
|
2024-01-22 00:47:53 -08:00
|
|
|
{
|
2024-02-27 04:50:57 -08:00
|
|
|
os_lib_unload( module.lib )
|
|
|
|
file_remove( Path_Sectr_Live_Module )
|
2024-01-22 00:47:53 -08:00
|
|
|
module^ = {}
|
2024-02-08 19:33:53 -08:00
|
|
|
log("Unloaded sectr API")
|
2024-01-22 00:47:53 -08:00
|
|
|
}
|
|
|
|
|
2024-02-27 04:50:57 -08:00
|
|
|
sync_sectr_api :: proc( sectr_api : ^ sectr.ModuleAPI, memory : ^ VMemChunk, logger : ^ Logger )
|
2024-01-29 22:29:48 -08:00
|
|
|
{
|
2024-02-27 04:50:57 -08:00
|
|
|
if write_time, result := os.last_write_time_by_name( Path_Sectr_Module );
|
2024-01-29 22:29:48 -08:00
|
|
|
result == os.ERROR_NONE && sectr_api.write_time != write_time
|
|
|
|
{
|
|
|
|
version_id := sectr_api.lib_version + 1
|
|
|
|
unload_sectr_api( sectr_api )
|
|
|
|
|
|
|
|
// Wait for pdb to unlock (linker may still be writting)
|
2024-02-27 04:50:57 -08:00
|
|
|
for ; file_is_locked( Path_Sectr_Debug_Symbols ) && file_is_locked( Path_Sectr_Live_Module ); {}
|
|
|
|
thread_sleep( Millisecond * 50 )
|
2024-01-29 22:29:48 -08:00
|
|
|
|
|
|
|
sectr_api ^ = load_sectr_api( version_id )
|
2024-02-23 06:36:23 -08:00
|
|
|
verify( sectr_api.lib_version != 0, "Failed to hot-reload the sectr module" )
|
2024-02-08 19:33:53 -08:00
|
|
|
|
|
|
|
sectr_api.reload( memory.sectr_live, memory.sectr_snapshot, logger )
|
2024-01-29 22:29:48 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-01-21 20:38:02 -08:00
|
|
|
main :: proc()
|
|
|
|
{
|
2024-01-22 00:47:53 -08:00
|
|
|
state : RuntimeState
|
|
|
|
using state
|
|
|
|
|
2024-02-27 04:50:57 -08:00
|
|
|
// Generating the logger's name, it will be used when the app is shutting down.
|
2024-02-08 19:33:53 -08:00
|
|
|
path_logger_finalized : string
|
|
|
|
{
|
|
|
|
startup_time := time.now()
|
|
|
|
year, month, day := time.date( startup_time)
|
|
|
|
hour, min, sec := time.clock_from_time( startup_time)
|
|
|
|
|
2024-02-27 04:50:57 -08:00
|
|
|
if ! os.is_dir( Path_Logs ) {
|
|
|
|
os.make_directory( Path_Logs )
|
2024-02-08 19:33:53 -08:00
|
|
|
}
|
|
|
|
|
2024-02-27 04:50:57 -08:00
|
|
|
timestamp := str_fmt_tmp("%04d-%02d-%02d_%02d-%02d-%02d", year, month, day, hour, min, sec)
|
|
|
|
path_logger_finalized = str_clone( str_fmt_tmp( "%s/sectr_%v.log", Path_Logs, timestamp) )
|
2024-02-08 19:33:53 -08:00
|
|
|
}
|
2024-02-27 04:50:57 -08:00
|
|
|
|
2024-02-08 19:33:53 -08:00
|
|
|
logger : sectr.Logger
|
2024-02-27 04:50:57 -08:00
|
|
|
logger_init( & logger, "Sectr Host", str_fmt_tmp( "%s/sectr.log", Path_Logs ) )
|
|
|
|
context.logger = to_odin_logger( & logger )
|
2024-02-08 19:33:53 -08:00
|
|
|
{
|
|
|
|
// Log System Context
|
|
|
|
backing_builder : [16 * Kilobyte] u8
|
2024-02-27 04:50:57 -08:00
|
|
|
builder := str_builder_from_bytes( backing_builder[:] )
|
|
|
|
str_fmt_builder( & builder, "Core Count: %v, ", os.processor_core_count() )
|
|
|
|
str_fmt_builder( & builder, "Page Size: %v", os.get_page_size() )
|
2024-02-08 19:33:53 -08:00
|
|
|
|
2024-02-27 04:50:57 -08:00
|
|
|
log( to_str(builder) )
|
2024-02-08 19:33:53 -08:00
|
|
|
}
|
|
|
|
|
2024-01-21 20:38:02 -08:00
|
|
|
// Basic Giant VMem Block
|
|
|
|
{
|
|
|
|
// By default odin uses a growing arena for the runtime context
|
|
|
|
// We're going to make it static for the prototype and separate it from the 'project' memory.
|
|
|
|
// Then shove the context allocator for the engine to it.
|
|
|
|
// The project's context will use its own subsection arena allocator.
|
2024-01-29 22:29:48 -08:00
|
|
|
memory = setup_memory()
|
2024-01-21 20:38:02 -08:00
|
|
|
}
|
|
|
|
|
2024-02-08 19:33:53 -08:00
|
|
|
// TODO(Ed): Cannot use the manually created allocators for the host. Not sure why
|
|
|
|
// context.allocator = tracked_allocator( & memory.host_persistent )
|
|
|
|
// context.temp_allocator = tracked_allocator( & memory.host_transient )
|
|
|
|
|
2024-01-21 20:38:02 -08:00
|
|
|
// Load the Enviornment API for the first-time
|
|
|
|
{
|
2024-02-08 19:33:53 -08:00
|
|
|
sectr_api = load_sectr_api( 1 )
|
2024-02-23 06:36:23 -08:00
|
|
|
verify( sectr_api.lib_version != 0, "Failed to initially load the sectr module" )
|
2024-01-21 20:38:02 -08:00
|
|
|
}
|
|
|
|
|
2024-02-27 04:50:57 -08:00
|
|
|
running = true;
|
|
|
|
sectr_api = sectr_api
|
2024-02-08 19:33:53 -08:00
|
|
|
sectr_api.startup( memory.sectr_live, memory.sectr_snapshot, & logger )
|
2024-01-21 20:38:02 -08:00
|
|
|
|
2024-02-27 04:50:57 -08:00
|
|
|
delta_ns : Duration
|
2024-02-10 00:40:53 -08:00
|
|
|
|
2024-01-22 00:47:53 -08:00
|
|
|
// TODO(Ed) : This should have an end status so that we know the reason the engine stopped.
|
|
|
|
for ; running ;
|
2024-01-21 20:38:02 -08:00
|
|
|
{
|
2024-02-10 00:40:53 -08:00
|
|
|
start_tick := time.tick_now()
|
|
|
|
|
2024-01-21 20:38:02 -08:00
|
|
|
// Hot-Reload
|
2024-02-08 19:33:53 -08:00
|
|
|
sync_sectr_api( & sectr_api, & memory, & logger )
|
2024-01-21 20:38:02 -08:00
|
|
|
|
2024-02-27 04:50:57 -08:00
|
|
|
running = sectr_api.tick( duration_seconds( delta_ns ) )
|
2024-02-10 00:40:53 -08:00
|
|
|
sectr_api.clean_temp()
|
|
|
|
|
|
|
|
delta_ns = time.tick_lap_time( & start_tick )
|
2024-01-21 20:38:02 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
// Determine how the run_cyle completed, if it failed due to an error,
|
|
|
|
// fallback the env to a failsafe state and reload the run_cycle.
|
|
|
|
{
|
|
|
|
// TODO(Ed): Implement this.
|
|
|
|
}
|
|
|
|
|
2024-01-22 00:47:53 -08:00
|
|
|
sectr_api.shutdown()
|
|
|
|
unload_sectr_api( & sectr_api )
|
2024-02-08 19:33:53 -08:00
|
|
|
|
|
|
|
log("Succesfuly closed")
|
2024-02-27 04:50:57 -08:00
|
|
|
file_close( logger.file )
|
|
|
|
file_rename( logger.file_path, path_logger_finalized )
|
2024-01-21 20:38:02 -08:00
|
|
|
}
|