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/examples/render_thread/build.bat b/examples/render_thread/build.bat index e2187a8..67d593c 100644 --- a/examples/render_thread/build.bat +++ b/examples/render_thread/build.bat @@ -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 /I %pthread_dir%\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 /MANIFEST:EMBED /MANIFESTINPUT:../../src/win32_manifest.xml /LIBPATH:../../bin milepost.dll.lib /LIBPATH:%pthread_dir%\lib pthreadVC3.lib /out:../../bin/example_render_thread.exe - -copy %pthread_dir%\bin\pthreadVC3.dll ..\..\bin +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 diff --git a/examples/render_thread/main.c b/examples/render_thread/main.c index 9264c4b..ef7af1b 100644 --- a/examples/render_thread/main.c +++ b/examples/render_thread/main.c @@ -1,7 +1,6 @@ #include #include -#include #define MG_INCLUDE_GL_API 1 #include"milepost.h" @@ -9,7 +8,7 @@ mg_surface surface = {0}; mg_canvas canvas = {0}; -void* render_thread(void* user) +i32 render_thread(void* user) { while(!mp_should_quit()) { @@ -79,16 +78,14 @@ int main() mp_window_bring_to_front(window); mp_window_focus(window); - pthread_t renderThread; - pthread_create(&renderThread, 0, render_thread, 0); + mp_thread* renderThread = mp_thread_create(render_thread, NULL); while(!mp_should_quit()) { mp_pump_events(0); } - void* res; - pthread_join(renderThread, &res); + mp_thread_join(renderThread, NULL); mg_canvas_destroy(canvas); mg_surface_destroy(surface); diff --git a/examples/smooth_resize/build.bat b/examples/smooth_resize/build.bat index 4f2c691..fe06030 100644 --- a/examples/smooth_resize/build.bat +++ b/examples/smooth_resize/build.bat @@ -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 diff --git a/examples/smooth_resize/main.c b/examples/smooth_resize/main.c index 276c0e4..a5c8c4d 100644 --- a/examples/smooth_resize/main.c +++ b/examples/smooth_resize/main.c @@ -17,8 +17,6 @@ #define MG_INCLUDE_GL_API #include"milepost.h" -#include - unsigned int program; const char* vshaderSource = @@ -124,7 +122,7 @@ void update_and_render(app_data* app) mem_arena_clear(mem_scratch()); } -void* render(void* user) +i32 render(void* user) { app_data* app = (app_data*)user; @@ -210,16 +208,14 @@ int main() app_data app = {.window = window, .surface = surface}; - pthread_t renderThread; - pthread_create(&renderThread, 0, render, &app); + mp_thread* renderThread = mp_thread_create(render, &app); while(!mp_should_quit()) { mp_pump_events(0); } - void* res; - pthread_join(renderThread, &res); + mp_thread_join(renderThread, NULL); mg_surface_destroy(surface); mp_window_destroy(window); 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/milepost.h b/src/milepost.h index 5cfa699..19b385b 100644 --- a/src/milepost.h +++ b/src/milepost.h @@ -28,6 +28,7 @@ #include"platform/platform_clock.h" #include"platform/platform_path.h" #include"platform/platform_io.h" +#include"platform/platform_thread.h" /* #include"platform_rng.h" #include"platform_socket.h" diff --git a/src/platform/platform_thread.h b/src/platform/platform_thread.h index 0740748..f54ec0f 100644 --- a/src/platform/platform_thread.h +++ b/src/platform/platform_thread.h @@ -25,61 +25,61 @@ extern "C" { // 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); -platform_thread* ThreadCreateWithName(ThreadStartFunction start, void* userPointer, const char* name); +typedef i32 (*mp_thread_start_function)(void* userPointer); -const char* ThreadGetName(platform_thread* thread); - -u64 ThreadSelfID(); -u64 ThreadUniqueID(platform_thread* thread); - -int ThreadSignal(platform_thread* thread, int sig); -void ThreadCancel(platform_thread* thread); -int ThreadJoin(platform_thread* thread, void** ret); -int ThreadDetach(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); +MP_API const char* mp_thread_get_name(mp_thread* thread); +MP_API u64 mp_thread_unique_id(mp_thread* thread); +MP_API u64 mp_thread_self_id(); +MP_API int mp_thread_signal(mp_thread* thread, int sig); +MP_API int mp_thread_join(mp_thread* thread, i64* exitCode); +MP_API int mp_thread_detach(mp_thread* thread); //--------------------------------------------------------------- // Platform Mutex API //--------------------------------------------------------------- -typedef struct platform_mutex platform_mutex; - -platform_mutex* MutexCreate(); -int MutexDestroy(platform_mutex* mutex); -int MutexLock(platform_mutex* mutex); -int MutexUnlock(platform_mutex* mutex); +typedef struct mp_mutex mp_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 //--------------------------------------------------------------- -typedef struct ticket_spin_mutex +typedef struct mp_ticket_spin_mutex { volatile _Atomic(u64) nextTicket; volatile _Atomic(u64) serving; -} ticket_spin_mutex; +} mp_ticket_spin_mutex; -void TicketSpinMutexInit(ticket_spin_mutex* mutex); -void TicketSpinMutexLock(ticket_spin_mutex* mutex); -void TicketSpinMutexUnlock(ticket_spin_mutex* mutex); +MP_API void mp_ticket_spin_mutex_init(mp_ticket_spin_mutex* mutex); +MP_API void mp_ticket_spin_mutex_lock(mp_ticket_spin_mutex* mutex); +MP_API void mp_ticket_spin_mutex_unlock(mp_ticket_spin_mutex* mutex); //--------------------------------------------------------------- // Platform condition variable API //--------------------------------------------------------------- -typedef struct platform_condition platform_condition; +typedef struct mp_condition mp_condition; -platform_condition* ConditionCreate(); -int ConditionDestroy(platform_condition* cond); -int ConditionWait(platform_condition* cond, platform_mutex* mutex); -int ConditionTimedWait(platform_condition* cond, platform_mutex* mutex, f64 seconds); -int ConditionSignal(platform_condition* cond); -int ConditionBroadcast(platform_condition* cond); +MP_API mp_condition* mp_condition_create(); +MP_API int mp_condition_destroy(mp_condition* cond); +MP_API int mp_condition_wait(mp_condition* cond, mp_mutex* mutex); +MP_API int mp_condition_timedwait(mp_condition* cond, mp_mutex* mutex, f64 seconds); +MP_API int mp_condition_signal(mp_condition* cond); +MP_API int mp_condition_broadcast(mp_condition* cond); #ifdef __cplusplus } // extern "C" diff --git a/src/platform/posix_thread.c b/src/platform/posix_thread.c index 166f514..0727a43 100644 --- a/src/platform/posix_thread.c +++ b/src/platform/posix_thread.c @@ -14,30 +14,29 @@ #include"platform_thread.h" -const u32 PLATFORM_THREAD_NAME_MAX_SIZE = 64; // including null terminator - -struct platform_thread +struct mp_thread { bool valid; pthread_t pthread; - ThreadStartFunction start; + mp_thread_start_function start; 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)) { 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) { return(0); @@ -45,7 +44,7 @@ platform_thread* ThreadCreateWithName(ThreadStartFunction start, void* userPoint 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'; } else @@ -55,7 +54,7 @@ platform_thread* ThreadCreateWithName(ThreadStartFunction start, void* userPoint thread->start = start; 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); 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) -{ - pthread_cancel(thread->pthread); -} - -const char* ThreadGetName(platform_thread* thread) +const char* mp_thread_get_name(mp_thread* thread) { return(thread->name); } - -u64 ThreadUniqueID(platform_thread* thread) +u64 mp_thread_unique_id(mp_thread* thread) { u64 id; pthread_threadid_np(thread->pthread, &id); return(id); } -u64 ThreadSelfID() +u64 mp_thread_self_id() { pthread_t thread = pthread_self(); u64 id; @@ -98,22 +91,28 @@ u64 ThreadSelfID() return(id); } -int ThreadSignal(platform_thread* thread, int sig) +int mp_thread_signal(mp_thread* thread, int 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); } free(thread); + + if (exitCode) + { + *exitCode = (off_t)ret; + } return(0); } -int ThreadDetach(platform_thread* thread) +int mp_thread_detach(mp_thread* thread) { if(pthread_detach(thread->pthread)) { @@ -124,14 +123,14 @@ int ThreadDetach(platform_thread* thread) } -struct platform_mutex +struct mp_mutex { 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) { return(0); @@ -143,7 +142,8 @@ platform_mutex* MutexCreate() } return(mutex); } -int MutexDestroy(platform_mutex* mutex) + +int mp_mutex_destroy(mp_mutex* mutex) { if(pthread_mutex_destroy(&mutex->pmutex) != 0) { @@ -153,41 +153,44 @@ int MutexDestroy(platform_mutex* mutex) return(0); } -int MutexLock(platform_mutex* mutex) +int mp_mutex_lock(mp_mutex* mutex) { return(pthread_mutex_lock(&mutex->pmutex)); } -int MutexUnlock(platform_mutex* mutex) +int mp_mutex_unlock(mp_mutex* mutex) { 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->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); 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); } -struct platform_condition + +struct mp_condition { 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) { return(0); @@ -199,7 +202,8 @@ platform_condition* ConditionCreate() } return(cond); } -int ConditionDestroy(platform_condition* cond) + +int mp_condition_destroy(mp_condition* cond) { if(pthread_cond_destroy(&cond->pcond) != 0) { @@ -208,12 +212,13 @@ int ConditionDestroy(platform_condition* cond) free(cond); 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)); } -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; 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)); } -int ConditionSignal(platform_condition* cond) +int mp_condition_signal(mp_condition* cond) { return(pthread_cond_signal(&cond->pcond)); } -int ConditionBroadcast(platform_condition* cond) +int mp_condition_broadcast(mp_condition* cond) { return(pthread_cond_broadcast(&cond->pcond)); } 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); +}