291 lines
7.6 KiB
C
291 lines
7.6 KiB
C
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;
|
|
}
|