swap testing

This commit is contained in:
jacob 2025-10-24 05:40:13 -05:00
parent 0f31e27d96
commit 05f6c937cb
7 changed files with 189 additions and 8 deletions

View File

@ -37,6 +37,10 @@
# error Missing compile time definition for 'TestsAreEnabled' # error Missing compile time definition for 'TestsAreEnabled'
#endif #endif
#ifndef HotSwappingIsEnabled
# error Missing compile time definition for 'HotSwappingIsEnabled'
#endif
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
//~ Machine context //~ Machine context

View File

@ -5,7 +5,16 @@
typedef ExitFuncDef(ExitFunc); typedef ExitFuncDef(ExitFunc);
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
//~ @hookdecl Exit operations //~ @hookdecl Swap hooks
b32 IsSwappingIn(void);
b32 IsSwappingOut(void);
String SwappedStateFromName(Arena *arena, String name);
void WriteSwappedState(String name, String data);
////////////////////////////////////////////////////////////
//~ @hookdecl Exit hooks
void OnExit(ExitFunc *func); void OnExit(ExitFunc *func);
void SignalExit(i32 code); void SignalExit(i32 code);

View File

@ -109,6 +109,68 @@ void TrueRand(String buffer)
BCryptGenRandom(BCRYPT_RNG_ALG_HANDLE, (u8 *)buffer.text, buffer.len, 0); BCryptGenRandom(BCRYPT_RNG_ALG_HANDLE, (u8 *)buffer.text, buffer.len, 0);
} }
////////////////////////////////////////////////////////////
//~ Swap hooks
b32 IsSwappingIn(void)
{
return HotSwappingIsEnabled;
}
b32 IsSwappingOut(void)
{
return HotSwappingIsEnabled;
}
String SwappedStateFromName(Arena *arena, String name)
{
TempArena scratch = BeginScratch(arena);
String result = ZI;
String path = StringF(scratch.arena, "swap/%F.swp", FmtString(name));
wchar_t *path_wstr = WstrFromString(scratch.arena, path);
HANDLE handle = CreateFileW(path_wstr, GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
if (handle != INVALID_HANDLE_VALUE)
{
u32 chunk_size = Kibi(64);
result.text = PushDry(arena, u8);
for (;;)
{
u8 *chunk = PushStructsNoZero(arena, u8, chunk_size);
u32 chunk_bytes_read = 0;
ReadFile(handle, chunk, chunk_size, (LPDWORD)&chunk_bytes_read, 0);
result.len += chunk_bytes_read;
if (chunk_bytes_read < chunk_size)
{
PopStructsNoCopy(arena, u8, chunk_size - chunk_bytes_read);
break;
}
}
}
CloseHandle(handle);
EndScratch(scratch);
return result;
}
void WriteSwappedState(String name, String data)
{
TempArena scratch = BeginScratchNoConflict();
String result = ZI;
String path = StringF(scratch.arena, "swap/%F.swp", FmtString(name));
wchar_t *path_wstr = WstrFromString(scratch.arena, path);
HANDLE handle = CreateFileW(path_wstr, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ, 0, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
if (handle != INVALID_HANDLE_VALUE)
{
SetFilePointer(handle, 0, 0, FILE_BEGIN);
SetEndOfFile(handle);
WriteFile(handle, data.text, data.len, 0, 0);
}
CloseHandle(handle);
EndScratch(scratch);
}
////////////////////////////////////////////////////////////
//~ @hookdef Exit hooks
void OnExit(ExitFunc *func) void OnExit(ExitFunc *func)
{ {
W32_SharedState *g = &W32_shared_state; W32_SharedState *g = &W32_shared_state;
@ -254,6 +316,11 @@ i32 W32_Main(void)
} }
/* Set up exit events */ /* Set up exit events */
#if HotSwappingIsEnabled
g->swap_event = CreateEventW(0, 1, 0, L"Local\\pp_swap_start");
#else
g->swap_event = CreateEventW(0, 1, 0, 0);
#endif
g->panic_event = CreateEventW(0, 1, 0, 0); g->panic_event = CreateEventW(0, 1, 0, 0);
g->startup_end_event = CreateEventW(0, 1, 0, 0); g->startup_end_event = CreateEventW(0, 1, 0, 0);
g->exit_begin_event = CreateEventW(0, 1, 0, 0); g->exit_begin_event = CreateEventW(0, 1, 0, 0);
@ -291,7 +358,7 @@ i32 W32_Main(void)
{ {
HANDLE handles[] = { HANDLE handles[] = {
g->startup_end_event, g->startup_end_event,
g->panic_event g->panic_event,
}; };
WaitForMultipleObjects(countof(handles), handles, 0, INFINITE); WaitForMultipleObjects(countof(handles), handles, 0, INFINITE);
} }
@ -301,9 +368,10 @@ i32 W32_Main(void)
{ {
HANDLE handles[] = { HANDLE handles[] = {
g->exit_begin_event, g->exit_begin_event,
g->panic_event g->panic_event,
g->swap_event,
}; };
WaitForMultipleObjects(countof(handles), handles, 0, INFINITE); DWORD wake = WaitForMultipleObjects(countof(handles), handles, 0, INFINITE);
} }
//- App shutdown //- App shutdown
@ -324,6 +392,16 @@ i32 W32_Main(void)
WaitForMultipleObjects(countof(handles), handles, 0, INFINITE); WaitForMultipleObjects(countof(handles), handles, 0, INFINITE);
} }
/* Signal swap finish */
if (!Atomic32Fetch(&g->panicking) && IsSwappingOut())
{
HANDLE swap_end_event = OpenEventW(EVENT_MODIFY_STATE, 0, L"Local\\pp_swap_end");
if (swap_end_event != 0)
{
SetEvent(swap_end_event);
}
}
/* Exit */ /* Exit */
if (Atomic32Fetch(&g->panicking)) if (Atomic32Fetch(&g->panicking))
{ {

View File

@ -38,6 +38,7 @@ Struct(W32_SharedState)
Atomic32 panicking; Atomic32 panicking;
wchar_t panic_wstr[4096]; wchar_t panic_wstr[4096];
HANDLE panic_event; HANDLE panic_event;
HANDLE swap_event;
HANDLE startup_end_event; HANDLE startup_end_event;
HANDLE exit_begin_event; HANDLE exit_begin_event;
HANDLE exit_end_event; HANDLE exit_end_event;

View File

@ -45,6 +45,10 @@
# define TestsAreEnabled 0 # define TestsAreEnabled 0
#endif #endif
#ifndef HotSwappingIsEnabled
# define HotSwappingIsEnabled 0
#endif
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
//~ Includes //~ Includes
@ -96,6 +100,36 @@ LineCol LineColFromPos(String data, i64 pos)
return result; return result;
} }
////////////////////////////////////////////////////////////
//~ Swap
#if PlatformIsWindows
u64 SignalSwapStart(void)
{
OS_Mkdir(Lit("swap"));
HANDLE swap_end_event = CreateEventW(0, 1, 0, L"Local\\pp_swap_end");
HANDLE swap_start_event = OpenEventW(EVENT_MODIFY_STATE, 0, L"Local\\pp_swap_start");
if (swap_start_event != 0)
{
SetEvent(swap_start_event);
CloseHandle(swap_start_event);
}
return (u64)swap_end_event;
}
void WaitForSwapEnd(u64 swap_start, i64 timeout_ns)
{
HANDLE swap_start_event = (HANDLE)swap_start;
if (swap_start_event != 0)
{
DWORD timeout_ms = timeout_ns / 1000000;
WaitForSingleObject(swap_start_event, timeout_ms);
}
}
#else
# error Swap signaling not implemented
#endif
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
//~ OS command job //~ OS command job
@ -138,7 +172,6 @@ Struct(CompilerParams)
StringList linker_only_flags_clang; StringList linker_only_flags_clang;
}; };
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
//~ Build step job //~ Build step job
@ -872,6 +905,8 @@ JobDef(Build, _, __)
} }
} }
u64 swap_start = SignalSwapStart();
////////////////////////////// //////////////////////////////
//- Args //- Args
@ -895,6 +930,7 @@ JobDef(Build, _, __)
PushStringToList(arena, &cp.defs, Lit("-DProfilingIsEnabled=0")); PushStringToList(arena, &cp.defs, Lit("-DProfilingIsEnabled=0"));
PushStringToList(arena, &cp.defs, Lit("-DUnoptimizedIsEnabled=1")); PushStringToList(arena, &cp.defs, Lit("-DUnoptimizedIsEnabled=1"));
PushStringToList(arena, &cp.defs, Lit("-DTestsAreEnabled=0")); PushStringToList(arena, &cp.defs, Lit("-DTestsAreEnabled=0"));
PushStringToList(arena, &cp.defs, Lit("-DHotSwappingIsEnabled=1"));
//- Msvc //- Msvc
{ {
@ -1049,6 +1085,8 @@ JobDef(Build, _, __)
//- Link //- Link
WaitForSwapEnd(swap_start, NsFromSeconds(0.5f / 1000.f));
String exe_file = Lit("pp.exe"); String exe_file = Lit("pp.exe");
i64 link_elapsed_ns = 0; i64 link_elapsed_ns = 0;
if (ret == 0) if (ret == 0)

View File

@ -30,8 +30,36 @@ void StartupUser(void)
g->local_to_user_client_store = AcquireClientStore(); g->local_to_user_client_store = AcquireClientStore();
g->local_to_user_client = AcquireClient(g->local_to_user_client_store); g->local_to_user_client = AcquireClient(g->local_to_user_client_store);
/* Init from swap */
g->world_to_ui_xf = XformIdentity; g->world_to_ui_xf = XformIdentity;
g->world_to_render_xf = XformIdentity; g->world_to_render_xf = XformIdentity;
if (IsSwappingIn());
{
TempArena scratch = BeginScratchNoConflict();
String swap_str = SwappedStateFromName(scratch.arena, Lit("pp_user"));
if (swap_str.len == sizeof(SwappedUserState))
{
SwappedUserState *swap = (SwappedUserState *)swap_str.text;
SharedUserState *old = &swap->s;
g->debug_following = old->debug_following;
g->debug_camera = old->debug_camera;
g->debug_camera_panning = old->debug_camera_panning;
g->debug_camera_pan_start = old->debug_camera_pan_start;
g->debug_draw = old->debug_draw;
g->screen_size = old->screen_size;
g->screen_cursor = old->screen_cursor;
g->ui_to_screen_xf = old->ui_to_screen_xf;
g->ui_size = old->ui_size;
g->ui_cursor = old->ui_cursor;
g->render_to_ui_xf = old->render_to_ui_xf;
g->render_size = old->render_size;
g->world_to_render_xf = old->world_to_render_xf;
g->world_to_ui_xf = old->world_to_ui_xf;
g->world_cursor = old->world_cursor;
g->focus_send = old->focus_send;
}
EndScratch(scratch);
}
g->console_logs_arena = AcquireArena(Gibi(64)); g->console_logs_arena = AcquireArena(Gibi(64));
//P_RegisterLogCallback(ConsoleLogCallback, P_LogLevel_Success); //P_RegisterLogCallback(ConsoleLogCallback, P_LogLevel_Success);
@ -55,6 +83,19 @@ ExitFuncDef(ShutdownUser)
SharedUserState *g = &shared_user_state; SharedUserState *g = &shared_user_state;
Atomic32Set(&g->shutdown, 1); Atomic32Set(&g->shutdown, 1);
YieldOnFence(&g->shutdown_jobs_fence, g->shutdown_jobs_count); YieldOnFence(&g->shutdown_jobs_fence, g->shutdown_jobs_count);
/* Swap out */
if (IsSwappingOut())
{
TempArena scratch = BeginScratchNoConflict();
SwappedUserState *swap = PushStruct(scratch.arena, SwappedUserState);
swap->s = *g;
WriteSwappedState(Lit("pp_user"), StringFromStruct(swap));
EndScratch(scratch);
}
P_ReleaseWindow(g->window); P_ReleaseWindow(g->window);
} }
@ -3215,9 +3256,11 @@ JobDef(UpdateSim, UNUSED sig, UNUSED id)
} }
} }
#if 0
ReleaseClientStore(store); ReleaseClientStore(store);
ReleaseSimAccel(&accel); ReleaseSimAccel(&accel);
BB_ReleaseBuff(&snapshot_writer_bb); BB_ReleaseBuff(&snapshot_writer_bb);
BB_ReleaseBuff(&msg_writer_bb); BB_ReleaseBuff(&msg_writer_bb);
N_ReleaseHost(host); N_ReleaseHost(host);
#endif
} }

View File

@ -264,6 +264,14 @@ Struct(SharedUserState)
Vec2 focus_send; Vec2 focus_send;
} extern shared_user_state; } extern shared_user_state;
////////////////////////////////////////////////////////////
//~ Swap types
Struct(SwappedUserState)
{
SharedUserState s;
};
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
//~ Startup //~ Startup