typedef HRESULT W32_SetThreadDescription_Type(HANDLE hThread, PCWSTR lpThreadDescription); #define W32_KERNEL32_EXT_X_LIST X(SetThreadDescription) #define X(x) global W32_##x##_Type* w32_##x##_func; W32_KERNEL32_EXT_X_LIST #undef X // ============================================================================= // Entity Functions internal W32_Entity* w32_entity_alloc(W32_EntityKind kind) { W32_Entity* result = 0; EnterCriticalSection(&w32_state.entity_mutex); { result = w32_state.entity_free; if (result) { SLL_stack_pop(w32_state.entity_free); } else { result = push_array_no_zero(w32_state.entity_arena, W32_Entity, 1); } MemoryZeroStruct(result); } LeaveCriticalSection(&w32_state.entity_mutex); result->kind = kind; return result; } internal void w32_entity_release(W32_Entity* entity) { entity->kind = W32_EntityKind_Null; EnterCriticalSection(&w32_state.entity_mutex); SLL_stack_push(w32_state.entity_free, entity); LeaveCriticalSection(&w32_state.entity_mutex); } // ============================================================================= // Time functions internal uint64 now_time_us() { uint64 result = 0; LARGE_INTEGER large_int_counter; if (QueryPerformanceCounter(&large_int_counter)) { result = (large_int_counter.QuadPart * Million(1)) / w32_state.microsecond_resolution; } return result; } internal void sleep_ms(uint32 ms) { Sleep(ms); } // ============================================================================= // System internal SystemInfo* get_system_info() { return &w32_state.system_info; } // ============================================================================= // Thread Info internal uint32 tid() { DWORD id = GetCurrentThreadId(); return (uint32)id; } internal void set_platform_thread_name(String8 name) { TempArena scratch = scratch_begin(0, 0); // Win10 and + if (w32_SetThreadDescription_func) { String16 name16 = str16_from_8(scratch.arena, name); HRESULT hr = w32_SetThreadDescription_func(GetCurrentThread(), (WCHAR*)name16.str); } // Old way by raising exception { String8 name_copy = str8_copy(scratch.arena, name); #pragma pack(push, 8) typedef struct THREADNAME_INFO THREADNAME_INFO; struct THREADNAME_INFO { uint32 dwType; // Must be 0x1000. char* szName; // Pointer to name (in user addr space). uint32 dwThreadID; // Thread ID (-1=caller thread). uint32 dwFlags; // Reserved for future use, must be zero. }; #pragma pack(pop) THREADNAME_INFO info; info.dwType = 0x1000; info.szName = (char*)name_copy.str; info.dwThreadID = tid(); info.dwFlags = 0; #pragma warning(push) #pragma warning(disable : 6320 6322) __try { RaiseException(0x406D1388, 0, sizeof(info) / sizeof(void*), (const ULONG_PTR*)&info); } __except (EXCEPTION_EXECUTE_HANDLER) { } #pragma warning(pop) } scratch_end(scratch); } // ============================================================================= // Synchronization primitive functions // read write mutexes internal RWMutex rw_mutex_alloc() { W32_Entity* entity = w32_entity_alloc(W32_EntityKind_RWMutex); InitializeSRWLock(&entity->rw_mutex); RWMutex result = { IntFromPtr(entity) }; return result; } internal void rw_mutex_release(RWMutex rw_mutex) { W32_Entity* entity = (W32_Entity*)PtrFromInt(rw_mutex.handle[0]); w32_entity_release(entity); } internal void rw_mutex_take(RWMutex rw_mutex, bool32 write_mode) { W32_Entity* entity = (W32_Entity*)PtrFromInt(rw_mutex.handle[0]); if (write_mode) { AcquireSRWLockExclusive(&entity->rw_mutex); } else { AcquireSRWLockShared(&entity->rw_mutex); } } internal void rw_mutex_drop(RWMutex rw_mutex, bool32 write_mode) { W32_Entity* entity = (W32_Entity*)PtrFromInt(rw_mutex.handle[0]); if (write_mode) { ReleaseSRWLockExclusive(&entity->rw_mutex); } else { ReleaseSRWLockShared(&entity->rw_mutex); } } // ============================================================================= // Memory internal void* reserve_memory(uint64 size) { void* result = VirtualAlloc(0, size, MEM_RESERVE, PAGE_READWRITE); return result; } internal bool32 commit_memory(void* ptr, uint64 size) { bool32 result = (VirtualAlloc(ptr, size, MEM_COMMIT, PAGE_READWRITE) != 0); return result; } internal void* reserve_memory_large(uint64 size) { // Windows do not allow commiting large pages void* result = VirtualAlloc(0, size, MEM_RESERVE | MEM_COMMIT | MEM_LARGE_PAGES, PAGE_READWRITE); return result; } internal bool32 commit_memory_large(void* ptr, uint64 size) { (void)ptr; (void)size; return 1; } internal void decommit_memory(void* ptr, uint64 size) { VirtualFree(ptr, size, MEM_DECOMMIT); } internal void release_memory(void* ptr, uint64 size) { (void)size; // Unused on windows VirtualFree(ptr, 0, MEM_RELEASE); } // ============================================================================= // Aborting internal void abort_self(uint64 exit_code) { ExitProcess((int)exit_code); } // ============================================================================= // Entry points internal void w32_entry_point(int argc, WCHAR** wargv) { // Dynamically load some windows function that are not guaranteed in all sdk { #define X(x) w32_##x##_func = (void*)GetProcAddress(module, Stringify(x)); HMODULE module; module = LoadLibraryA("kernek32.dll"); W32_KERNEL32_EXT_X_LIST FreeLibrary(module); #undef X } SYSTEM_INFO sys_info = { 0 }; GetSystemInfo(&sys_info); { w32_state.microsecond_resolution = 1; LARGE_INTEGER large_int_resolution; if (QueryPerformanceCounter(&large_int_resolution)) { w32_state.microsecond_resolution = large_int_resolution.QuadPart; } } SystemInfo* info = &w32_state.system_info; info->page_size = sys_info.dwPageSize; info->large_page_size = GetLargePageMinimum(); Arena* args_arena = arena_alloc(.reserve_size = MB(1), .commit_size = KB(32)); char** argv = push_array(args_arena, char*, argc); for (int i = 0; i < argc; ++i) { String16 arg16 = str16_cstring((uint16*)wargv[i]); String8 arg8 = str8_from_16(args_arena, arg16); argv[i] = (char*)arg8.str; } // Thread context TCTX* tctx = tctx_alloc(); tctx_select(tctx); // setup w32 state Arena* arena = arena_alloc(); { w32_state.arena = arena; { SystemInfo* info = &w32_state.system_info; DWORD size = MAX_COMPUTERNAME_LENGTH + 1; uint8 buffer[MAX_COMPUTERNAME_LENGTH + 1] = { 0 }; if (GetComputerNameA((char*)buffer, &size)) { info->machine_name = str8_copy(arena, str8(buffer, size)); } } } // setup entity storage InitializeCriticalSection(&w32_state.entity_mutex); w32_state.entity_arena = arena_alloc(); main_thread_core_entry_point(argc, argv); tctx_release(tctx); } int wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR lpCmdLine, int nShowCmd) { (void)hInstance; (void)hPrevInstance; (void)lpCmdLine; (void)nShowCmd; w32_entry_point(__argc, __wargv); return 0; }