From ff5e6e6039237b1df2ea25f66d4ab699e1934cdd Mon Sep 17 00:00:00 2001 From: Reuben Dunnington Date: Sun, 30 Jul 2023 20:59:00 -0700 Subject: [PATCH] add win32 platform_thread.h implementation --- build.bat | 2 +- src/milepost.c | 5 +- src/platform/win32_thread.c | 230 ++++++++++++++++++++++++++++++++++++ 3 files changed, 234 insertions(+), 3 deletions(-) create mode 100644 src/platform/win32_thread.c diff --git a/build.bat b/build.bat index 35fb163..58984af 100644 --- a/build.bat +++ b/build.bat @@ -11,4 +11,4 @@ call python3 scripts\embed_text.py %glsl_shaders% --prefix=glsl_ --output src\gl set INCLUDES=/I src /I src/util /I src/platform /I ext /I ext/angle_headers set LIBS=user32.lib opengl32.lib gdi32.lib shcore.lib delayimp.lib dwmapi.lib comctl32.lib ole32.lib shell32.lib shlwapi.lib /LIBPATH:./bin libEGL.dll.lib libGLESv2.dll.lib /DELAYLOAD:libEGL.dll /DELAYLOAD:libGLESv2.dll -cl /we4013 /Zi /Zc:preprocessor /DMP_BUILD_DLL /std:c11 %INCLUDES% src/milepost.c /Fo:bin/milepost.o /LD /link /MANIFEST:EMBED /MANIFESTINPUT:src/win32_manifest.xml %LIBS% /OUT:bin/milepost.dll /IMPLIB:bin/milepost.dll.lib +cl /we4013 /Zi /Zc:preprocessor /DMP_BUILD_DLL /std:c11 /experimental:c11atomics %INCLUDES% src/milepost.c /Fo:bin/milepost.o /LD /link /MANIFEST:EMBED /MANIFESTINPUT:src/win32_manifest.xml %LIBS% /OUT:bin/milepost.dll /IMPLIB:bin/milepost.dll.lib diff --git a/src/milepost.c b/src/milepost.c index b0a0080..6f224ae 100644 --- a/src/milepost.c +++ b/src/milepost.c @@ -20,14 +20,15 @@ #include"platform/win32_string_helpers.c" #include"platform/win32_path.c" #include"platform/win32_io.c" + #include"platform/win32_thread.c" //TODO #elif PLATFORM_MACOS #include"platform/unix_memory.c" #include"platform/osx_clock.c" #include"platform/posix_io.c" + #include"platform/posix_thread.c" /* #include"platform/unix_rng.c" - #include"platform/posix_thread.c" #include"platform/posix_socket.c" */ @@ -35,9 +36,9 @@ #include"platform/unix_base_memory.c" #include"platform/linux_clock.c" #include"platform/posix_io.c" + #include"platform/posix_thread.c" /* #include"platform/unix_rng.c" - #include"platform/posix_thread.c" #include"platform/posix_socket.c" */ #else diff --git a/src/platform/win32_thread.c b/src/platform/win32_thread.c new file mode 100644 index 0000000..614298c --- /dev/null +++ b/src/platform/win32_thread.c @@ -0,0 +1,230 @@ +/************************************************************//** +* +* @file: win32_thread.c +* @author: Reuben Dunnington +* @date: 7/30/2023 +* @revision: +* +*****************************************************************/ + +#include +#include +#include //INFINITY + +#include"platform_thread.h" + +struct mp_thread +{ + mp_thread_start_function start; + HANDLE handle; + DWORD threadId; + void* userPointer; + char name[MP_THREAD_NAME_MAX_SIZE]; +}; + +static DWORD WINAPI mp_thread_bootstrap(LPVOID lpParameter) +{ + mp_thread* thread = (mp_thread*)lpParameter; + i32 exitCode = thread->start(thread->userPointer); + return(exitCode); +} + +mp_thread* mp_thread_create_with_name(mp_thread_start_function start, void* userPointer, const char* name) +{ + mp_thread* thread = (mp_thread*)malloc(sizeof(mp_thread)); + thread->start = start; + thread->handle = INVALID_HANDLE_VALUE; + thread->userPointer = userPointer; + if(name) + { + char* end = strncpy(thread->name, name, MP_THREAD_NAME_MAX_SIZE-1); + *end = '\0'; + } + else + { + thread->name[0] = '\0'; + } + + SECURITY_ATTRIBUTES childProcessSecurity = { + .nLength = sizeof(SECURITY_ATTRIBUTES), + .bInheritHandle = false, + }; + SIZE_T stackSize = 0; // uses process default + DWORD flags = 0; + DWORD threadId = 0; + thread->handle = CreateThread(&childProcessSecurity, stackSize, mp_thread_bootstrap, thread, flags, &threadId); + if (thread->handle == NULL) { + free(thread); + return(NULL); + } + + thread->threadId = threadId; + + if (thread->name[0]) { + wchar_t widename[MP_THREAD_NAME_MAX_SIZE]; + size_t length = mbstowcs(widename, thread->name, MP_THREAD_NAME_MAX_SIZE - 1); + widename[length] = '\0'; + + SetThreadDescription(thread->handle, widename); + } + + return(thread); +} + +mp_thread* mp_thread_create(mp_thread_start_function start, void* userPointer) +{ + return(mp_thread_create_with_name(start, userPointer, NULL)); +} + +const char* mp_thread_get_name(mp_thread* thread) +{ + return(thread->name); +} + +u64 mp_thread_unique_id(mp_thread* thread) +{ + return(thread->threadId); +} + +u64 mp_thread_self_id() +{ + return(GetCurrentThreadId()); +} + +int mp_thread_signal(mp_thread* thread, int sig) +{ + BOOL success = TerminateThread(thread->handle, (DWORD)sig); + return(success ? 0 : -1); +} + +int mp_thread_join(mp_thread* thread, i64* exitCode) +{ + DWORD result = WaitForSingleObject(thread->handle, INFINITE); + if (result == WAIT_FAILED) { + return(-1); + } + + if (exitCode) + { + DWORD exitCodeWin32 = 0; + if (GetExitCodeThread(thread->handle, &exitCodeWin32)) + { + *exitCode = exitCodeWin32; + } + } + + free(thread); + return(0); +} + +int mp_thread_detach(mp_thread* thread) +{ + if (CloseHandle(thread->handle)) + { + free(thread); + return(0); + } + return(-1); +} + + +struct mp_mutex +{ + u64 owningThreadId; + SRWLOCK lock; +}; + +mp_mutex* mp_mutex_create() +{ + mp_mutex* mutex = (mp_mutex*)malloc(sizeof(mp_mutex)); + mutex->owningThreadId = 0; + InitializeSRWLock(&mutex->lock); + return mutex; +} + +int mp_mutex_destroy(mp_mutex* mutex) +{ + DEBUG_ASSERT(mutex->owningThreadId == 0); + free(mutex); + return(0); +} + +int mp_mutex_lock(mp_mutex* mutex) +{ + DEBUG_ASSERT(mutex->owningThreadId == 0); + AcquireSRWLockExclusive(&mutex->lock); + return(0); +} + +int mp_mutex_unlock(mp_mutex* mutex) +{ + DEBUG_ASSERT(mp_thread_self_id() == mutex->owningThreadId); + ReleaseSRWLockExclusive(&mutex->lock); + mutex->owningThreadId = 0; + return(0); +} + +// mp_ticket_spin_mutex has a mirrored implementation in posix_thread.c + +void mp_ticket_spin_mutex_init(mp_ticket_spin_mutex* mutex) +{ + mutex->nextTicket = 0; + mutex->serving = 0; +} + +void mp_ticket_spin_mutex_lock(mp_ticket_spin_mutex* mutex) +{ + u64 ticket = atomic_fetch_add(&mutex->nextTicket, 1ULL); + while(ticket != mutex->serving); //spin +} + +void mp_ticket_spin_mutex_unlock(mp_ticket_spin_mutex* mutex) +{ + atomic_fetch_add(&mutex->serving, 1ULL); +} + + +struct mp_condition +{ + CONDITION_VARIABLE cond; +}; + +mp_condition* mp_condition_create() +{ + mp_condition* cond = (mp_condition*)malloc(sizeof(mp_condition)); + InitializeConditionVariable(&cond->cond); + return cond; +} + +int mp_condition_destroy(mp_condition* cond) +{ + free(cond); + return(0); +} + +int mp_condition_wait(mp_condition* cond, mp_mutex* mutex) +{ + return mp_condition_timedwait(cond, mutex, INFINITY); +} + +int mp_condition_timedwait(mp_condition* cond, mp_mutex* mutex, f64 seconds) +{ + const f32 ms = (seconds == INFINITY) ? INFINITE : seconds * 1000; + if (!SleepConditionVariableSRW(&cond->cond, &mutex->lock, ms, 0)) + { + return(GetLastError()); + } + return(0); +} + +int mp_condition_signal(mp_condition* cond) +{ + WakeConditionVariable(&cond->cond); + return(0); +} + +int mp_condition_broadcast(mp_condition* cond) +{ + WakeAllConditionVariable(&cond->cond); + return(0); +}