W32_SharedState W32_shared_state = ZI; //////////////////////////////// //~ @hookdef Core hooks StringList GetCommandLineArgs(void) { StringList result = ZI; return result; } b32 Panic(String msg) { char msg_cstr[4096]; CstrFromStringToBuff(StringFromArray(msg_cstr), msg); { u32 mb_flags = MB_SETFOREGROUND | MB_ICONERROR; MessageBoxExA(0, msg_cstr, "Fatal error", mb_flags, 0); } HANDLE console_handle = GetStdHandle(STD_ERROR_HANDLE); if (console_handle != INVALID_HANDLE_VALUE) { WriteFile(console_handle, msg.text, msg.len, 0, 0); } if (IsRunningInDebugger()) { Assert(0); } else { ExitProcess(1); } return 0; } b32 IsRunningInDebugger(void) { return IsDebuggerPresent(); } void TrueRand(String buffer) { 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 workers InitJobWorkers(); /* Startup layers */ if (!Atomic32Fetch(&g->panicking)) { RunJob(1, W32_StartupLayersJob, JobPool_Hyper, 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_Hyper, 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 */