Merge pull request 'mp_thread' (#3) from mp_thread into main

Reviewed-on: MartinFouilleul/milepost#3
This commit is contained in:
MartinFouilleul 2023-07-31 18:06:54 +00:00
commit 6221370aa0
10 changed files with 325 additions and 98 deletions

View File

@ -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 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 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

View File

@ -1,7 +1,4 @@
set pthread_dir=..\..\..\..\vcpkg\packages\pthreads_x64-windows set INCLUDES=/I ..\..\src /I ..\..\src\util /I ..\..\src\platform /I ../../ext /I ../../ext/angle_headers
set INCLUDES=/I ..\..\src /I ..\..\src\util /I ..\..\src\platform /I ../../ext /I ../../ext/angle_headers /I %pthread_dir%\include
cl /we4013 /Zi /Zc:preprocessor /std:c11 %INCLUDES% main.c /link /MANIFEST:EMBED /MANIFESTINPUT:../../src/win32_manifest.xml /LIBPATH:../../bin milepost.dll.lib /LIBPATH:%pthread_dir%\lib pthreadVC3.lib /out:../../bin/example_render_thread.exe cl /we4013 /Zi /Zc:preprocessor /std:c11 /experimental:c11atomics %INCLUDES% main.c /link /MANIFEST:EMBED /MANIFESTINPUT:../../src/win32_manifest.xml /LIBPATH:../../bin milepost.dll.lib /out:../../bin/example_render_thread.exe
copy %pthread_dir%\bin\pthreadVC3.dll ..\..\bin

View File

@ -1,7 +1,6 @@
#include<stdlib.h> #include<stdlib.h>
#include<stdio.h> #include<stdio.h>
#include<pthread.h>
#define MG_INCLUDE_GL_API 1 #define MG_INCLUDE_GL_API 1
#include"milepost.h" #include"milepost.h"
@ -9,7 +8,7 @@
mg_surface surface = {0}; mg_surface surface = {0};
mg_canvas canvas = {0}; mg_canvas canvas = {0};
void* render_thread(void* user) i32 render_thread(void* user)
{ {
while(!mp_should_quit()) while(!mp_should_quit())
{ {
@ -79,16 +78,14 @@ int main()
mp_window_bring_to_front(window); mp_window_bring_to_front(window);
mp_window_focus(window); mp_window_focus(window);
pthread_t renderThread; mp_thread* renderThread = mp_thread_create(render_thread, NULL);
pthread_create(&renderThread, 0, render_thread, 0);
while(!mp_should_quit()) while(!mp_should_quit())
{ {
mp_pump_events(0); mp_pump_events(0);
} }
void* res; mp_thread_join(renderThread, NULL);
pthread_join(renderThread, &res);
mg_canvas_destroy(canvas); mg_canvas_destroy(canvas);
mg_surface_destroy(surface); mg_surface_destroy(surface);

View File

@ -1,4 +1,4 @@
set INCLUDES=/I ..\..\src /I ..\..\src\util /I ..\..\src\platform /I ../../ext /I ../../ext/angle_headers /I ..\..\..\..\vcpkg\packages\pthreads_x64-windows\include set INCLUDES=/I ..\..\src /I ..\..\src\util /I ..\..\src\platform /I ../../ext /I ../../ext/angle_headers
cl /we4013 /Zi /Zc:preprocessor /std:c11 %INCLUDES% main.c /link /LIBPATH:../../bin milepost.dll.lib /LIBPATH:..\..\..\..\vcpkg\packages\pthreads_x64-windows\lib pthreadVC3.lib /out:../../bin/example_smooth_resize.exe cl /we4013 /Zi /Zc:preprocessor /std:c11 /experimental:c11atomics %INCLUDES% main.c /link /LIBPATH:../../bin milepost.dll.lib /out:../../bin/example_smooth_resize.exe

View File

@ -17,8 +17,6 @@
#define MG_INCLUDE_GL_API #define MG_INCLUDE_GL_API
#include"milepost.h" #include"milepost.h"
#include<pthread.h>
unsigned int program; unsigned int program;
const char* vshaderSource = const char* vshaderSource =
@ -124,7 +122,7 @@ void update_and_render(app_data* app)
mem_arena_clear(mem_scratch()); mem_arena_clear(mem_scratch());
} }
void* render(void* user) i32 render(void* user)
{ {
app_data* app = (app_data*)user; app_data* app = (app_data*)user;
@ -210,16 +208,14 @@ int main()
app_data app = {.window = window, app_data app = {.window = window,
.surface = surface}; .surface = surface};
pthread_t renderThread; mp_thread* renderThread = mp_thread_create(render, &app);
pthread_create(&renderThread, 0, render, &app);
while(!mp_should_quit()) while(!mp_should_quit())
{ {
mp_pump_events(0); mp_pump_events(0);
} }
void* res; mp_thread_join(renderThread, NULL);
pthread_join(renderThread, &res);
mg_surface_destroy(surface); mg_surface_destroy(surface);
mp_window_destroy(window); mp_window_destroy(window);

View File

@ -20,14 +20,15 @@
#include"platform/win32_string_helpers.c" #include"platform/win32_string_helpers.c"
#include"platform/win32_path.c" #include"platform/win32_path.c"
#include"platform/win32_io.c" #include"platform/win32_io.c"
#include"platform/win32_thread.c"
//TODO //TODO
#elif PLATFORM_MACOS #elif PLATFORM_MACOS
#include"platform/unix_memory.c" #include"platform/unix_memory.c"
#include"platform/osx_clock.c" #include"platform/osx_clock.c"
#include"platform/posix_io.c" #include"platform/posix_io.c"
#include"platform/posix_thread.c"
/* /*
#include"platform/unix_rng.c" #include"platform/unix_rng.c"
#include"platform/posix_thread.c"
#include"platform/posix_socket.c" #include"platform/posix_socket.c"
*/ */
@ -35,9 +36,9 @@
#include"platform/unix_base_memory.c" #include"platform/unix_base_memory.c"
#include"platform/linux_clock.c" #include"platform/linux_clock.c"
#include"platform/posix_io.c" #include"platform/posix_io.c"
#include"platform/posix_thread.c"
/* /*
#include"platform/unix_rng.c" #include"platform/unix_rng.c"
#include"platform/posix_thread.c"
#include"platform/posix_socket.c" #include"platform/posix_socket.c"
*/ */
#else #else

View File

@ -28,6 +28,7 @@
#include"platform/platform_clock.h" #include"platform/platform_clock.h"
#include"platform/platform_path.h" #include"platform/platform_path.h"
#include"platform/platform_io.h" #include"platform/platform_io.h"
#include"platform/platform_thread.h"
/* /*
#include"platform_rng.h" #include"platform_rng.h"
#include"platform_socket.h" #include"platform_socket.h"

View File

@ -25,61 +25,61 @@ extern "C" {
// Platform Thread API // Platform Thread API
//--------------------------------------------------------------- //---------------------------------------------------------------
typedef struct platform_thread platform_thread; enum
{
MP_THREAD_NAME_MAX_SIZE = 64, // including null terminator
};
typedef void* (*ThreadStartFunction)(void* userPointer); typedef struct mp_thread mp_thread;
platform_thread* ThreadCreate(ThreadStartFunction start, void* userPointer); typedef i32 (*mp_thread_start_function)(void* userPointer);
platform_thread* ThreadCreateWithName(ThreadStartFunction start, void* userPointer, const char* name);
const char* ThreadGetName(platform_thread* thread); MP_API mp_thread* mp_thread_create(mp_thread_start_function start, void* userPointer);
MP_API mp_thread* mp_thread_create_with_name(mp_thread_start_function start, void* userPointer, const char* name);
u64 ThreadSelfID(); MP_API const char* mp_thread_get_name(mp_thread* thread);
u64 ThreadUniqueID(platform_thread* thread); MP_API u64 mp_thread_unique_id(mp_thread* thread);
MP_API u64 mp_thread_self_id();
int ThreadSignal(platform_thread* thread, int sig); MP_API int mp_thread_signal(mp_thread* thread, int sig);
void ThreadCancel(platform_thread* thread); MP_API int mp_thread_join(mp_thread* thread, i64* exitCode);
int ThreadJoin(platform_thread* thread, void** ret); MP_API int mp_thread_detach(mp_thread* thread);
int ThreadDetach(platform_thread* thread);
//--------------------------------------------------------------- //---------------------------------------------------------------
// Platform Mutex API // Platform Mutex API
//--------------------------------------------------------------- //---------------------------------------------------------------
typedef struct platform_mutex platform_mutex; typedef struct mp_mutex mp_mutex;
platform_mutex* MutexCreate();
int MutexDestroy(platform_mutex* mutex);
int MutexLock(platform_mutex* mutex);
int MutexUnlock(platform_mutex* mutex);
MP_API mp_mutex* mp_mutex_create();
MP_API int mp_mutex_destroy(mp_mutex* mutex);
MP_API int mp_mutex_lock(mp_mutex* mutex);
MP_API int mp_mutex_unlock(mp_mutex* mutex);
//--------------------------------------------------------------- //---------------------------------------------------------------
// Lightweight ticket mutex API // Lightweight ticket mutex API
//--------------------------------------------------------------- //---------------------------------------------------------------
typedef struct ticket_spin_mutex typedef struct mp_ticket_spin_mutex
{ {
volatile _Atomic(u64) nextTicket; volatile _Atomic(u64) nextTicket;
volatile _Atomic(u64) serving; volatile _Atomic(u64) serving;
} ticket_spin_mutex; } mp_ticket_spin_mutex;
void TicketSpinMutexInit(ticket_spin_mutex* mutex); MP_API void mp_ticket_spin_mutex_init(mp_ticket_spin_mutex* mutex);
void TicketSpinMutexLock(ticket_spin_mutex* mutex); MP_API void mp_ticket_spin_mutex_lock(mp_ticket_spin_mutex* mutex);
void TicketSpinMutexUnlock(ticket_spin_mutex* mutex); MP_API void mp_ticket_spin_mutex_unlock(mp_ticket_spin_mutex* mutex);
//--------------------------------------------------------------- //---------------------------------------------------------------
// Platform condition variable API // Platform condition variable API
//--------------------------------------------------------------- //---------------------------------------------------------------
typedef struct platform_condition platform_condition; typedef struct mp_condition mp_condition;
platform_condition* ConditionCreate(); MP_API mp_condition* mp_condition_create();
int ConditionDestroy(platform_condition* cond); MP_API int mp_condition_destroy(mp_condition* cond);
int ConditionWait(platform_condition* cond, platform_mutex* mutex); MP_API int mp_condition_wait(mp_condition* cond, mp_mutex* mutex);
int ConditionTimedWait(platform_condition* cond, platform_mutex* mutex, f64 seconds); MP_API int mp_condition_timedwait(mp_condition* cond, mp_mutex* mutex, f64 seconds);
int ConditionSignal(platform_condition* cond); MP_API int mp_condition_signal(mp_condition* cond);
int ConditionBroadcast(platform_condition* cond); MP_API int mp_condition_broadcast(mp_condition* cond);
#ifdef __cplusplus #ifdef __cplusplus
} // extern "C" } // extern "C"

View File

@ -14,30 +14,29 @@
#include"platform_thread.h" #include"platform_thread.h"
const u32 PLATFORM_THREAD_NAME_MAX_SIZE = 64; // including null terminator struct mp_thread
struct platform_thread
{ {
bool valid; bool valid;
pthread_t pthread; pthread_t pthread;
ThreadStartFunction start; mp_thread_start_function start;
void* userPointer; void* userPointer;
char name[PLATFORM_THREAD_NAME_MAX_SIZE]; char name[MP_THREAD_NAME_MAX_SIZE];
}; };
void* platform_thread_bootstrap(void* data) static void* mp_thread_bootstrap(void* data)
{ {
platform_thread* thread = (platform_thread*)data; mp_thread* thread = (mp_thread*)data;
if(strlen(thread->name)) if(strlen(thread->name))
{ {
pthread_setname_np(thread->name); pthread_setname_np(thread->name);
} }
return(thread->start(thread->userPointer)); i32 exitCode = thread->start(thread->userPointer);
return((void*)(ptrdiff_t)exitCode);
} }
platform_thread* ThreadCreateWithName(ThreadStartFunction start, void* userPointer, const char* name) mp_thread* mp_thread_create_with_name(mp_thread_start_function start, void* userPointer, const char* name)
{ {
platform_thread* thread = (platform_thread*)malloc(sizeof(platform_thread)); mp_thread* thread = (mp_thread*)malloc(sizeof(mp_thread));
if(!thread) if(!thread)
{ {
return(0); return(0);
@ -45,7 +44,7 @@ platform_thread* ThreadCreateWithName(ThreadStartFunction start, void* userPoint
if(name) if(name)
{ {
char* end = stpncpy(thread->name, name, PLATFORM_THREAD_NAME_MAX_SIZE-1); char* end = stpncpy(thread->name, name, MP_THREAD_NAME_MAX_SIZE-1);
*end = '\0'; *end = '\0';
} }
else else
@ -55,7 +54,7 @@ platform_thread* ThreadCreateWithName(ThreadStartFunction start, void* userPoint
thread->start = start; thread->start = start;
thread->userPointer = userPointer; thread->userPointer = userPointer;
if(pthread_create(&thread->pthread, 0, platform_thread_bootstrap, thread) != 0) if(pthread_create(&thread->pthread, 0, mp_thread_bootstrap, thread) != 0)
{ {
free(thread); free(thread);
return(0); return(0);
@ -67,30 +66,24 @@ platform_thread* ThreadCreateWithName(ThreadStartFunction start, void* userPoint
} }
} }
platform_thread* ThreadCreate(ThreadStartFunction start, void* userPointer) mp_thread* mp_thread_create(mp_thread_start_function start, void* userPointer)
{ {
return(ThreadCreateWithName(start, userPointer, 0)); return(mp_thread_create_with_name(start, userPointer, 0));
} }
void ThreadCancel(platform_thread* thread) const char* mp_thread_get_name(mp_thread* thread)
{
pthread_cancel(thread->pthread);
}
const char* ThreadGetName(platform_thread* thread)
{ {
return(thread->name); return(thread->name);
} }
u64 mp_thread_unique_id(mp_thread* thread)
u64 ThreadUniqueID(platform_thread* thread)
{ {
u64 id; u64 id;
pthread_threadid_np(thread->pthread, &id); pthread_threadid_np(thread->pthread, &id);
return(id); return(id);
} }
u64 ThreadSelfID() u64 mp_thread_self_id()
{ {
pthread_t thread = pthread_self(); pthread_t thread = pthread_self();
u64 id; u64 id;
@ -98,22 +91,28 @@ u64 ThreadSelfID()
return(id); return(id);
} }
int ThreadSignal(platform_thread* thread, int sig) int mp_thread_signal(mp_thread* thread, int sig)
{ {
return(pthread_kill(thread->pthread, sig)); return(pthread_kill(thread->pthread, sig));
} }
int ThreadJoin(platform_thread* thread, void** ret) int mp_thread_join(mp_thread* thread, i64* exitCode)
{ {
if(pthread_join(thread->pthread, ret)) void* ret;
if(pthread_join(thread->pthread, &ret))
{ {
return(-1); return(-1);
} }
free(thread); free(thread);
if (exitCode)
{
*exitCode = (off_t)ret;
}
return(0); return(0);
} }
int ThreadDetach(platform_thread* thread) int mp_thread_detach(mp_thread* thread)
{ {
if(pthread_detach(thread->pthread)) if(pthread_detach(thread->pthread))
{ {
@ -124,14 +123,14 @@ int ThreadDetach(platform_thread* thread)
} }
struct platform_mutex struct mp_mutex
{ {
pthread_mutex_t pmutex; pthread_mutex_t pmutex;
}; };
platform_mutex* MutexCreate() mp_mutex* mp_mutex_create()
{ {
platform_mutex* mutex = (platform_mutex*)malloc(sizeof(platform_mutex)); mp_mutex* mutex = (mp_mutex*)malloc(sizeof(mp_mutex));
if(!mutex) if(!mutex)
{ {
return(0); return(0);
@ -143,7 +142,8 @@ platform_mutex* MutexCreate()
} }
return(mutex); return(mutex);
} }
int MutexDestroy(platform_mutex* mutex)
int mp_mutex_destroy(mp_mutex* mutex)
{ {
if(pthread_mutex_destroy(&mutex->pmutex) != 0) if(pthread_mutex_destroy(&mutex->pmutex) != 0)
{ {
@ -153,41 +153,44 @@ int MutexDestroy(platform_mutex* mutex)
return(0); return(0);
} }
int MutexLock(platform_mutex* mutex) int mp_mutex_lock(mp_mutex* mutex)
{ {
return(pthread_mutex_lock(&mutex->pmutex)); return(pthread_mutex_lock(&mutex->pmutex));
} }
int MutexUnlock(platform_mutex* mutex) int mp_mutex_unlock(mp_mutex* mutex)
{ {
return(pthread_mutex_unlock(&mutex->pmutex)); return(pthread_mutex_unlock(&mutex->pmutex));
} }
void TicketSpinMutexInit(ticket_spin_mutex* mutex) // mp_ticket_spin_mutex has a mirrored implementation in win32_thread.c
void mp_ticket_spin_mutex_init(mp_ticket_spin_mutex* mutex)
{ {
mutex->nextTicket = 0; mutex->nextTicket = 0;
mutex->serving = 0; mutex->serving = 0;
} }
void TicketSpinMutexLock(ticket_spin_mutex* mutex) void mp_ticket_spin_mutex_lock(mp_ticket_spin_mutex* mutex)
{ {
u64 ticket = atomic_fetch_add(&mutex->nextTicket, 1ULL); u64 ticket = atomic_fetch_add(&mutex->nextTicket, 1ULL);
while(ticket != mutex->serving); //spin while(ticket != mutex->serving); //spin
} }
void TicketSpinMutexUnlock(ticket_spin_mutex* mutex) void mp_ticket_spin_mutex_unlock(mp_ticket_spin_mutex* mutex)
{ {
atomic_fetch_add(&mutex->serving, 1ULL); atomic_fetch_add(&mutex->serving, 1ULL);
} }
struct platform_condition
struct mp_condition
{ {
pthread_cond_t pcond; pthread_cond_t pcond;
}; };
platform_condition* ConditionCreate() mp_condition* mp_condition_create()
{ {
platform_condition* cond = (platform_condition*)malloc(sizeof(platform_condition)); mp_condition* cond = (mp_condition*)malloc(sizeof(mp_condition));
if(!cond) if(!cond)
{ {
return(0); return(0);
@ -199,7 +202,8 @@ platform_condition* ConditionCreate()
} }
return(cond); return(cond);
} }
int ConditionDestroy(platform_condition* cond)
int mp_condition_destroy(mp_condition* cond)
{ {
if(pthread_cond_destroy(&cond->pcond) != 0) if(pthread_cond_destroy(&cond->pcond) != 0)
{ {
@ -208,12 +212,13 @@ int ConditionDestroy(platform_condition* cond)
free(cond); free(cond);
return(0); return(0);
} }
int ConditionWait(platform_condition* cond, platform_mutex* mutex)
int mp_condition_wait(mp_condition* cond, mp_mutex* mutex)
{ {
return(pthread_cond_wait(&cond->pcond, &mutex->pmutex)); return(pthread_cond_wait(&cond->pcond, &mutex->pmutex));
} }
int ConditionTimedWait(platform_condition* cond, platform_mutex* mutex, f64 seconds) int mp_condition_timedwait(mp_condition* cond, mp_mutex* mutex, f64 seconds)
{ {
struct timeval tv; struct timeval tv;
gettimeofday(&tv, 0); gettimeofday(&tv, 0);
@ -230,12 +235,12 @@ int ConditionTimedWait(platform_condition* cond, platform_mutex* mutex, f64 seco
return(pthread_cond_timedwait(&cond->pcond, &mutex->pmutex, &ts)); return(pthread_cond_timedwait(&cond->pcond, &mutex->pmutex, &ts));
} }
int ConditionSignal(platform_condition* cond) int mp_condition_signal(mp_condition* cond)
{ {
return(pthread_cond_signal(&cond->pcond)); return(pthread_cond_signal(&cond->pcond));
} }
int ConditionBroadcast(platform_condition* cond) int mp_condition_broadcast(mp_condition* cond)
{ {
return(pthread_cond_broadcast(&cond->pcond)); return(pthread_cond_broadcast(&cond->pcond));
} }

230
src/platform/win32_thread.c Normal file
View File

@ -0,0 +1,230 @@
/************************************************************//**
*
* @file: win32_thread.c
* @author: Reuben Dunnington
* @date: 7/30/2023
* @revision:
*
*****************************************************************/
#include<processthreadsapi.h>
#include<synchapi.h>
#include<math.h> //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);
}