merge base_win32_entry & base_win32

This commit is contained in:
jacob 2025-08-25 16:28:37 -05:00
parent ca9639affb
commit 2989e98d69
15 changed files with 299 additions and 329 deletions

View File

@ -18,7 +18,7 @@
@Dep pp @Dep pp
//- Api //- Api
@IncludeC app_core.h @IncludeC app.h
//- Impl //- Impl
@IncludeC app_core.c @IncludeC app.c

View File

@ -5,7 +5,7 @@ AC_SharedState AC_shared_state = ZI;
//////////////////////////////// ////////////////////////////////
//~ Startup //~ Startup
void AC_StartupCore(void) void AC_Startup(void)
{ {
__prof; __prof;
AC_SharedState *g = &AC_shared_state; AC_SharedState *g = &AC_shared_state;

View File

@ -65,7 +65,7 @@ extern AC_SharedState AC_shared_state;
//////////////////////////////// ////////////////////////////////
//~ Startup //~ Startup
void AC_StartupCore(void); void AC_Startup(void);
//////////////////////////////// ////////////////////////////////
//~ Hash //~ Hash

View File

@ -10,4 +10,4 @@
@IncludeC asset_cache.c @IncludeC asset_cache.c
//- Startup //- Startup
@Startup AC_StartupCore @Startup AC_Startup

View File

@ -640,22 +640,28 @@ Struct(StringList)
# error FiberId not implemented # error FiberId not implemented
#endif #endif
#define MaxFibers 1024
StaticAssert(MaxFibers < I16Max); /* Fiber id type should fit max threads */
////////////////////////////////
//~ Exit callback types
#define ExitFuncDef(name) void name(void)
typedef ExitFuncDef(ExitFunc);
//////////////////////////////// ////////////////////////////////
//~ @hookdecl Core hooks //~ @hookdecl Core hooks
void StartupBase(void);
StringList GetCommandLineArgs(void); StringList GetCommandLineArgs(void);
b32 Panic(String msg); b32 Panic(String msg);
b32 IsRunningInDebugger(void); b32 IsRunningInDebugger(void);
void TrueRand(String buffer); void TrueRand(String buffer);
void OnExit(ExitFunc *func);
#define MaxThreads 1024 void SignalExit(i32 code);
#define MaxFibers 1024 void ExitNow(i32 code);
StaticAssert(MaxThreads < I16Max); /* Thread id type should fit max threads */
StaticAssert(MaxFibers < I16Max); /* Fiber id type should fit max threads */
//////////////////////////////// ////////////////////////////////
//~ @hookdecl Layer startup hook (defined by metaprogram) //~ @hookdecl Layer initialization hook (defined by metaprogram)
void StartupLayers(void); void StartupLayers(void);

View File

@ -1,8 +1,8 @@
//////////////////////////////// ////////////////////////////////
//~ Job queue types //~ Job queue types
/* Work pools contain their own worker threads with their own thread priority /* Work pools contain their own worker threads with their own thread priorities
* affinity based on the intended context of the pool. */ * and affinities based on the intended context of the pool. */
Enum(JobPool) Enum(JobPool)
{ {
JobPool_Inherit = -1, JobPool_Inherit = -1,

View File

@ -3,22 +3,12 @@ W32_SharedState W32_shared_state = ZI;
//////////////////////////////// ////////////////////////////////
//~ @hookdef Core hooks //~ @hookdef Core hooks
//- Startup
void StartupBase(void)
{
W32_SharedState *g = &W32_shared_state;
g->tls_index = TlsAlloc();
TlsSetValue(g->tls_index, 0);
}
//- Command line args
StringList GetCommandLineArgs(void) StringList GetCommandLineArgs(void)
{ {
StringList result = ZI; StringList result = ZI;
return result; return result;
} }
//- Panic
b32 Panic(String msg) b32 Panic(String msg)
{ {
char msg_cstr[4096]; char msg_cstr[4096];
@ -40,14 +30,260 @@ b32 Panic(String msg)
return 0; return 0;
} }
//- Debugger check
b32 IsRunningInDebugger(void) b32 IsRunningInDebugger(void)
{ {
return IsDebuggerPresent(); return IsDebuggerPresent();
} }
//- True randomness
void TrueRand(String buffer) 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);
} }
void OnExit(ExitFunc *func)
{
W32_SharedState *g = &W32_shared_state;
i32 index = Atomic32FetchAdd(&g->num_exit_funcs, 1);
if (index >= W32_MaxOnExitFuncs)
{
Panic(Lit("Maximum on exit functions registered"));
}
g->exit_funcs[index] = func;
}
void SignalExit(i32 code)
{
W32_SharedState *g = &W32_shared_state;
Atomic32FetchSet(&g->exit_code, code);
SetEvent(g->exit_begin_event);
}
void ExitNow(i32 code)
{
ExitProcess(code);
}
////////////////////////////////
//~ Startup / shutdown jobs
JobDef(W32_StartupLayersJob, UNUSED sig, UNUSED id)
{
W32_SharedState *g = &W32_shared_state;
TempArena scratch = BeginScratchNoConflict();
{
StartupLayers();
SetEvent(g->startup_end_event);
}
EndScratch(scratch);
}
JobDef(W32_ShutdownLayersJob, UNUSED sig, UNUSED id)
{
__prof;
W32_SharedState *g = &W32_shared_state;
i32 num_funcs = Atomic32Fetch(&g->num_exit_funcs);
for (i32 i = num_funcs - 1; i >= 0; --i)
{
ExitFunc *func = g->exit_funcs[i];
func();
}
SetEvent(g->exit_end_event);
}
////////////////////////////////
//~ Main
i32 W32_Main(void)
{
__profthread("Main thread", PROF_THREAD_GROUP_MAIN);
W32_SharedState *g = &W32_shared_state;
#if ProfilingIsEnabled
/* Start profiler */
{
__profn("Launch profiler");
STARTUPINFO si = ZI;
si.cb = sizeof(si);
PROCESS_INFORMATION pi = ZI;
wchar_t cmd[sizeof(ProfilingCmdWstr)] = ZI;
CopyBytes(cmd, ProfilingCmdWstr, sizeof(ProfilingCmdWstr));
DeleteFileW(ProfilingOutFileWstr);
b32 success = CreateProcessW(0, cmd, 0, 0, 0, DETACHED_PROCESS, 0, 0, &si, &pi);
if (!success)
{
MessageBoxExW(0, L"Failed to launch profiler using command '" ProfilingCmdWstr L"'.", L"Error", MB_ICONSTOP | MB_SETFOREGROUND | MB_TOPMOST, 0);
}
}
/* Set internal profiler thread affinities */
{
__profn("Set profiler thread affinities");
wchar_t *prefix_name_wstr = ProfilerThreadPrefixWstr;
u64 prefix_name_wstr_len = ((i32)sizeof(ProfilerThreadPrefixWstr) >> 1) - 1;
if (prefix_name_wstr_len > 0 && ProfilerThreadAffinityMask != 0)
{
DWORD proc_id = GetCurrentProcessId();
HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0);
if (snapshot != INVALID_HANDLE_VALUE)
{
THREADENTRY32 te = ZI;
te.dwSize = sizeof(THREADENTRY32);
if (Thread32First(snapshot, &te))
{
do
{
if (te.th32OwnerProcessID == proc_id)
{
i32 thread_id = te.th32ThreadID;
HANDLE thread = OpenThread(THREAD_ALL_ACCESS, FALSE, thread_id);
if (thread)
{
wchar_t *thread_name_wstr = 0;
HRESULT hr = GetThreadDescription(thread, &thread_name_wstr);
if (SUCCEEDED(hr))
{
u64 thread_name_len = WstrLenNoLimit(thread_name_wstr);
if (thread_name_len >= prefix_name_wstr_len && EqBytes(thread_name_wstr, prefix_name_wstr, prefix_name_wstr_len))
{
__profn("Set profiler thread affinity");
b32 success = SetThreadAffinityMask(thread, ProfilerThreadAffinityMask) != 0;
{
/* Retry until external tools can set correct process affinity */
i32 delay_ms = 16;
while (!success && delay_ms <= 1024)
{
__profn("Profiler thread affinity retry");
Sleep(delay_ms);
success = SetThreadAffinityMask(thread, ProfilerThreadAffinityMask) != 0;
delay_ms *= 2;
}
}
Assert(success);
LAX success;
}
}
CloseHandle(thread);
}
}
} while (Thread32Next(snapshot, &te));
}
}
CloseHandle(snapshot);
}
}
#endif
/* Set up exit events */
g->panic_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_end_event = CreateEventW(0, 1, 0, 0);
g->main_thread_id = GetCurrentThreadId();
SetThreadDescription(GetCurrentThread(), L"Main thread");
/* Query system info */
GetSystemInfo(&g->info);
//- Startup jobs
StartupBaseJobs();
/* Startup layers */
if (!Atomic32Fetch(&g->panicking))
{
RunJob(1, W32_StartupLayersJob, JobPool_Floating, JobPriority_High, 0, 0);
}
/* Wait for startup end or panic */
if (!Atomic32Fetch(&g->panicking))
{
HANDLE handles[] = {
g->startup_end_event,
g->panic_event
};
WaitForMultipleObjects(countof(handles), handles, 0, INFINITE);
}
/* Wait for exit start or panic */
if (!Atomic32Fetch(&g->panicking))
{
HANDLE handles[] = {
g->exit_begin_event,
g->panic_event
};
WaitForMultipleObjects(countof(handles), handles, 0, INFINITE);
}
//- App shutdown
/* Run exit callbacks job */
if (!Atomic32Fetch(&g->panicking))
{
RunJob(1, W32_ShutdownLayersJob, JobPool_Floating, JobPriority_High, 0, 0);
}
/* Wait for exit end or panic */
if (!Atomic32Fetch(&g->panicking))
{
HANDLE handles[] = {
g->exit_end_event,
g->panic_event
};
WaitForMultipleObjects(countof(handles), handles, 0, INFINITE);
}
/* Exit */
if (Atomic32Fetch(&g->panicking))
{
WaitForSingleObject(g->panic_event, INFINITE);
MessageBoxExW(0, g->panic_wstr, L"Fatal error", MB_ICONSTOP | MB_SETFOREGROUND | MB_TOPMOST, 0);
Atomic32FetchTestSet(&g->exit_code, 0, 1);
}
return Atomic32Fetch(&g->exit_code);
}
////////////////////////////////
//~ Crt main
#if CrtlibIsEnabled
# if IsConsoleApp
int main(char **argc, int argv)
{
LAX argc;
LAX argv;
return W32_Main();
}
# else
int CALLBACK wWinMain(_In_ HINSTANCE instance, _In_opt_ HINSTANCE prev_instance, _In_ LPWSTR cmdline_wstr, _In_ int show_code)
{
LAX instance;
LAX prev_instance;
LAX cmdline_wstr;
LAX show_code;
return W32_Main();
}
# endif /* IsConsoleApp */
#endif /* CrtlibIsEnabled */
////////////////////////////////
//~ Crt stub
#if !CrtlibIsEnabled
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wmissing-variable-declarations"
#pragma clang diagnostic ignored "-Wmissing-prototypes"
/* Enable floating point */
__attribute((used))
int _fltused;
__attribute((used))
void __stdcall wWinMainCRTStartup(void)
{
i32 result = W32_Main();
ExitProcess(result);
}
#pragma clang diagnostic pop
#endif /* !CrtlibIsEnabled */

View File

@ -13,10 +13,37 @@ u32 BCryptGenRandom(void *algorithm, u8 *buffer, u32 buffer_size, u32 flags);
//////////////////////////////// ////////////////////////////////
//~ Shared state //~ Shared state
#define W32_MaxOnExitFuncs 1024
Struct(W32_SharedState) Struct(W32_SharedState)
{ {
DWORD tls_index; SYSTEM_INFO info;
u32 main_thread_id;
Atomic32 shutdown;
Atomic32 exit_code; Atomic32 exit_code;
//- Application control flow
Atomic32 panicking;
wchar_t panic_wstr[4096];
HANDLE panic_event;
HANDLE startup_end_event;
HANDLE exit_begin_event;
HANDLE exit_end_event;
//- Exit funcs
Atomic32 num_exit_funcs;
ExitFunc *exit_funcs[W32_MaxOnExitFuncs];
}; };
extern W32_SharedState W32_shared_state; extern W32_SharedState W32_shared_state;
////////////////////////////////
//~ Startup / shutdown jobs
JobDecl(W32_StartupLayersJob, EmptySig);
JobDecl(W32_ShutdownLayersJob, EmptySig);
////////////////////////////////
//~ Main
i32 W32_Main(void);

View File

@ -1,253 +0,0 @@
W32_SharedEntryCtx W32_shared_entry_ctx = ZI;
////////////////////////////////
//~ Startup / shutdown jobs
JobDef(W32_StartupLayersJob, UNUSED sig, UNUSED id)
{
W32_SharedEntryCtx *g = &W32_shared_entry_ctx;
TempArena scratch = BeginScratchNoConflict();
{
StartupLayers();
SetEvent(g->startup_end_event);
}
EndScratch(scratch);
}
JobDef(W32_ShutdownLayersJob, UNUSED sig, UNUSED id)
{
__prof;
W32_SharedEntryCtx *g = &W32_shared_entry_ctx;
i32 num_funcs = Atomic32Fetch(&g->num_exit_funcs);
for (i32 i = num_funcs - 1; i >= 0; --i)
{
ExitFunc *func = g->exit_funcs[i];
func();
}
SetEvent(g->exit_end_event);
}
////////////////////////////////
//~ @hookdef Exit hooks
void OnExit(ExitFunc *func)
{
W32_SharedEntryCtx *g = &W32_shared_entry_ctx;
i32 index = Atomic32FetchAdd(&g->num_exit_funcs, 1);
if (index >= W32_MaxOnExitFuncs)
{
Panic(Lit("Maximum on exit functions registered"));
}
g->exit_funcs[index] = func;
}
void SignalExit(i32 code)
{
W32_SharedEntryCtx *g = &W32_shared_entry_ctx;
Atomic32FetchSet(&g->exit_code, code);
SetEvent(g->exit_begin_event);
}
void ExitNow(i32 code)
{
ExitProcess(code);
}
////////////////////////////////
//~ Main
i32 W32_Main(void)
{
__profthread("Main thread", PROF_THREAD_GROUP_MAIN);
W32_SharedEntryCtx *g = &W32_shared_entry_ctx;
#if ProfilingIsEnabled
/* Start profiler */
{
__profn("Launch profiler");
STARTUPINFO si = ZI;
si.cb = sizeof(si);
PROCESS_INFORMATION pi = ZI;
wchar_t cmd[sizeof(ProfilingCmdWstr)] = ZI;
CopyBytes(cmd, ProfilingCmdWstr, sizeof(ProfilingCmdWstr));
DeleteFileW(ProfilingOutFileWstr);
b32 success = CreateProcessW(0, cmd, 0, 0, 0, DETACHED_PROCESS, 0, 0, &si, &pi);
if (!success)
{
MessageBoxExW(0, L"Failed to launch profiler using command '" ProfilingCmdWstr L"'.", L"Error", MB_ICONSTOP | MB_SETFOREGROUND | MB_TOPMOST, 0);
}
}
/* Set internal profiler thread affinities */
{
__profn("Set profiler thread affinities");
wchar_t *prefix_name_wstr = ProfilerThreadPrefixWstr;
u64 prefix_name_wstr_len = ((i32)sizeof(ProfilerThreadPrefixWstr) >> 1) - 1;
if (prefix_name_wstr_len > 0 && ProfilerThreadAffinityMask != 0)
{
DWORD proc_id = GetCurrentProcessId();
HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0);
if (snapshot != INVALID_HANDLE_VALUE)
{
THREADENTRY32 te = ZI;
te.dwSize = sizeof(THREADENTRY32);
if (Thread32First(snapshot, &te))
{
do
{
if (te.th32OwnerProcessID == proc_id)
{
i32 thread_id = te.th32ThreadID;
HANDLE thread = OpenThread(THREAD_ALL_ACCESS, FALSE, thread_id);
if (thread)
{
wchar_t *thread_name_wstr = 0;
HRESULT hr = GetThreadDescription(thread, &thread_name_wstr);
if (SUCCEEDED(hr))
{
u64 thread_name_len = WstrLenNoLimit(thread_name_wstr);
if (thread_name_len >= prefix_name_wstr_len && EqBytes(thread_name_wstr, prefix_name_wstr, prefix_name_wstr_len))
{
__profn("Set profiler thread affinity");
b32 success = SetThreadAffinityMask(thread, ProfilerThreadAffinityMask) != 0;
{
/* Retry until external tools can set correct process affinity */
i32 delay_ms = 16;
while (!success && delay_ms <= 1024)
{
__profn("Profiler thread affinity retry");
Sleep(delay_ms);
success = SetThreadAffinityMask(thread, ProfilerThreadAffinityMask) != 0;
delay_ms *= 2;
}
}
Assert(success);
LAX success;
}
}
CloseHandle(thread);
}
}
} while (Thread32Next(snapshot, &te));
}
}
CloseHandle(snapshot);
}
}
#endif
/* Set up exit events */
g->panic_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_end_event = CreateEventW(0, 1, 0, 0);
g->main_thread_id = GetCurrentThreadId();
SetThreadDescription(GetCurrentThread(), L"Main thread");
/* Query system info */
GetSystemInfo(&g->info);
//- Startup jobs
StartupBaseJobs();
/* Startup layers */
if (!Atomic32Fetch(&g->panicking))
{
RunJob(1, W32_StartupLayersJob, JobPool_Floating, JobPriority_High, 0, 0);
}
/* Wait for startup end or panic */
if (!Atomic32Fetch(&g->panicking))
{
HANDLE handles[] = {
g->startup_end_event,
g->panic_event
};
WaitForMultipleObjects(countof(handles), handles, 0, INFINITE);
}
/* Wait for exit start or panic */
if (!Atomic32Fetch(&g->panicking))
{
HANDLE handles[] = {
g->exit_begin_event,
g->panic_event
};
WaitForMultipleObjects(countof(handles), handles, 0, INFINITE);
}
//- App shutdown
/* Run exit callbacks job */
if (!Atomic32Fetch(&g->panicking))
{
RunJob(1, W32_ShutdownLayersJob, JobPool_Floating, JobPriority_High, 0, 0);
}
/* Wait for exit end or panic */
if (!Atomic32Fetch(&g->panicking))
{
HANDLE handles[] = {
g->exit_end_event,
g->panic_event
};
WaitForMultipleObjects(countof(handles), handles, 0, INFINITE);
}
/* Exit */
if (Atomic32Fetch(&g->panicking))
{
WaitForSingleObject(g->panic_event, INFINITE);
MessageBoxExW(0, g->panic_wstr, L"Fatal error", MB_ICONSTOP | MB_SETFOREGROUND | MB_TOPMOST, 0);
Atomic32FetchTestSet(&g->exit_code, 0, 1);
}
return Atomic32Fetch(&g->exit_code);
}
////////////////////////////////
//~ Crt main
#if CrtlibIsEnabled
# if IsConsoleApp
int main(char **argc, int argv)
{
LAX argc;
LAX argv;
return W32_Main();
}
# else
int CALLBACK wWinMain(_In_ HINSTANCE instance, _In_opt_ HINSTANCE prev_instance, _In_ LPWSTR cmdline_wstr, _In_ int show_code)
{
LAX instance;
LAX prev_instance;
LAX cmdline_wstr;
LAX show_code;
return W32_Main();
}
# endif /* IsConsoleApp */
#endif /* CrtlibIsEnabled */
////////////////////////////////
//~ Crt stub
#if !CrtlibIsEnabled
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wmissing-variable-declarations"
#pragma clang diagnostic ignored "-Wmissing-prototypes"
/* Enable floating point */
__attribute((used))
int _fltused;
__attribute((used))
void __stdcall wWinMainCRTStartup(void)
{
i32 result = W32_Main();
ExitProcess(result);
}
#pragma clang diagnostic pop
#endif /* !CrtlibIsEnabled */

View File

@ -1,37 +0,0 @@
////////////////////////////////
//~ Shared state
#define W32_MaxOnExitFuncs 1024
Struct(W32_SharedEntryCtx)
{
SYSTEM_INFO info;
u32 main_thread_id;
Atomic32 shutdown;
Atomic32 exit_code;
//- Application control flow
Atomic32 panicking;
wchar_t panic_wstr[4096];
HANDLE panic_event;
HANDLE startup_end_event;
HANDLE exit_begin_event;
HANDLE exit_end_event;
//- Exit funcs
Atomic32 num_exit_funcs;
ExitFunc *exit_funcs[W32_MaxOnExitFuncs];
};
extern W32_SharedEntryCtx W32_shared_entry_ctx;
////////////////////////////////
//~ Startup / shutdown jobs
JobDecl(W32_StartupLayersJob, EmptySig);
JobDecl(W32_ShutdownLayersJob, EmptySig);
////////////////////////////////
//~ Main
i32 W32_Main(void);

View File

@ -1,9 +1,7 @@
//- Api //- Api
#include "base_win32.h" #include "base_win32.h"
#include "base_win32_entry.h"
#include "base_win32_job.h" #include "base_win32_job.h"
//- Impl //- Impl
#include "base_win32.c" #include "base_win32.c"
#include "base_win32_entry.c"
#include "base_win32_job.c" #include "base_win32_job.c"

View File

@ -125,6 +125,7 @@ void StartupBaseJobs(void)
//////////////////////////////// ////////////////////////////////
//~ Shutdown //~ Shutdown
#if 0 #if 0
void ShutdownJobs(void) void ShutdownJobs(void)
{ {

View File

@ -8,10 +8,10 @@
@Dep collider @Dep collider
//- Api //- Api
@IncludeC draw_core.h @IncludeC draw.h
//- Impl //- Impl
@IncludeC draw_core.c @IncludeC draw.c
//- Init //- Init
@Startup D_StartupCore @Startup D_StartupCore

View File

@ -854,10 +854,6 @@ void StartupMeta(void)
PushStringToList(arena, &c_out_lines, Lit("//- Startup")); PushStringToList(arena, &c_out_lines, Lit("//- Startup"));
PushStringToList(arena, &c_out_lines, Lit("void StartupLayers(void)")); PushStringToList(arena, &c_out_lines, Lit("void StartupLayers(void)"));
PushStringToList(arena, &c_out_lines, Lit("{")); PushStringToList(arena, &c_out_lines, Lit("{"));
{
String line = Lit(" StartupBase();");
PushStringToList(arena, &c_out_lines, line);
}
for (L_TopoItem *item = topo.startup_functions.first; item; item = item->next) for (L_TopoItem *item = topo.startup_functions.first; item; item = item->next)
{ {
String line = StringF(arena, " %F();", FmtString(item->s)); String line = StringF(arena, " %F();", FmtString(item->s));
@ -987,7 +983,6 @@ void StartupMeta(void)
void StartupLayers(void) void StartupLayers(void)
{ {
StartupBase();
OS_Startup(); OS_Startup();
StartupMeta(); StartupMeta();
} }

View File

@ -3,9 +3,6 @@
void OS_Startup(void) void OS_Startup(void)
{ {
W32_SharedState *g = &W32_shared_state;
g->tls_index = TlsAlloc();
TlsSetValue(g->tls_index, 0);
} }
//////////////////////////////// ////////////////////////////////