Path: blob/master/thirdparty/sdl/thread/windows/SDL_syscond_cv.c
9905 views
/*1Simple DirectMedia Layer2Copyright (C) 1997-2025 Sam Lantinga <[email protected]>34This software is provided 'as-is', without any express or implied5warranty. In no event will the authors be held liable for any damages6arising from the use of this software.78Permission is granted to anyone to use this software for any purpose,9including commercial applications, and to alter it and redistribute it10freely, subject to the following restrictions:11121. The origin of this software must not be misrepresented; you must not13claim that you wrote the original software. If you use this software14in a product, an acknowledgment in the product documentation would be15appreciated but is not required.162. Altered source versions must be plainly marked as such, and must not be17misrepresented as being the original software.183. This notice may not be removed or altered from any source distribution.19*/20#include "SDL_internal.h"2122#include "../generic/SDL_syscond_c.h"23#include "SDL_sysmutex_c.h"2425typedef SDL_Condition *(*pfnSDL_CreateCondition)(void);26typedef void (*pfnSDL_DestroyCondition)(SDL_Condition *);27typedef void (*pfnSDL_SignalCondition)(SDL_Condition *);28typedef void (*pfnSDL_BroadcastCondition)(SDL_Condition *);29typedef bool (*pfnSDL_WaitConditionTimeoutNS)(SDL_Condition *, SDL_Mutex *, Sint64);3031typedef struct SDL_cond_impl_t32{33pfnSDL_CreateCondition Create;34pfnSDL_DestroyCondition Destroy;35pfnSDL_SignalCondition Signal;36pfnSDL_BroadcastCondition Broadcast;37pfnSDL_WaitConditionTimeoutNS WaitTimeoutNS;38} SDL_cond_impl_t;3940// Implementation will be chosen at runtime based on available Kernel features41static SDL_cond_impl_t SDL_cond_impl_active = { 0 };4243/**44* Native Windows Condition Variable (SRW Locks)45*/4647#ifndef CONDITION_VARIABLE_INIT48#define CONDITION_VARIABLE_INIT \49{ \500 \51}52typedef struct CONDITION_VARIABLE53{54PVOID Ptr;55} CONDITION_VARIABLE, *PCONDITION_VARIABLE;56#endif5758typedef VOID(WINAPI *pfnWakeConditionVariable)(PCONDITION_VARIABLE);59typedef VOID(WINAPI *pfnWakeAllConditionVariable)(PCONDITION_VARIABLE);60typedef BOOL(WINAPI *pfnSleepConditionVariableSRW)(PCONDITION_VARIABLE, PSRWLOCK, DWORD, ULONG);61typedef BOOL(WINAPI *pfnSleepConditionVariableCS)(PCONDITION_VARIABLE, PCRITICAL_SECTION, DWORD);6263static pfnWakeConditionVariable pWakeConditionVariable = NULL;64static pfnWakeAllConditionVariable pWakeAllConditionVariable = NULL;65static pfnSleepConditionVariableSRW pSleepConditionVariableSRW = NULL;66static pfnSleepConditionVariableCS pSleepConditionVariableCS = NULL;6768typedef struct SDL_cond_cv69{70CONDITION_VARIABLE cond;71} SDL_cond_cv;7273static SDL_Condition *SDL_CreateCondition_cv(void)74{75// Relies on CONDITION_VARIABLE_INIT == 0.76return (SDL_Condition *)SDL_calloc(1, sizeof(SDL_cond_cv));77}7879static void SDL_DestroyCondition_cv(SDL_Condition *cond)80{81// There are no kernel allocated resources82SDL_free(cond);83}8485static void SDL_SignalCondition_cv(SDL_Condition *_cond)86{87SDL_cond_cv *cond = (SDL_cond_cv *)_cond;88pWakeConditionVariable(&cond->cond);89}9091static void SDL_BroadcastCondition_cv(SDL_Condition *_cond)92{93SDL_cond_cv *cond = (SDL_cond_cv *)_cond;94pWakeAllConditionVariable(&cond->cond);95}9697static bool SDL_WaitConditionTimeoutNS_cv(SDL_Condition *_cond, SDL_Mutex *_mutex, Sint64 timeoutNS)98{99SDL_cond_cv *cond = (SDL_cond_cv *)_cond;100DWORD timeout;101bool result;102103if (timeoutNS < 0) {104timeout = INFINITE;105} else {106timeout = (DWORD)SDL_NS_TO_MS(timeoutNS);107}108109if (SDL_mutex_impl_active.Type == SDL_MUTEX_SRW) {110SDL_mutex_srw *mutex = (SDL_mutex_srw *)_mutex;111112if (mutex->count != 1 || mutex->owner != GetCurrentThreadId()) {113// Passed mutex is not locked or locked recursively"114return false;115}116117// The mutex must be updated to the released state118mutex->count = 0;119mutex->owner = 0;120121result = (pSleepConditionVariableSRW(&cond->cond, &mutex->srw, timeout, 0) == TRUE);122123// The mutex is owned by us again, regardless of status of the wait124SDL_assert(mutex->count == 0 && mutex->owner == 0);125mutex->count = 1;126mutex->owner = GetCurrentThreadId();127} else {128SDL_mutex_cs *mutex = (SDL_mutex_cs *)_mutex;129130SDL_assert(SDL_mutex_impl_active.Type == SDL_MUTEX_CS);131132result = (pSleepConditionVariableCS(&cond->cond, &mutex->cs, timeout) == TRUE);133}134135return result;136}137138static const SDL_cond_impl_t SDL_cond_impl_cv = {139&SDL_CreateCondition_cv,140&SDL_DestroyCondition_cv,141&SDL_SignalCondition_cv,142&SDL_BroadcastCondition_cv,143&SDL_WaitConditionTimeoutNS_cv,144};145146147// Generic Condition Variable implementation using SDL_Mutex and SDL_Semaphore148static const SDL_cond_impl_t SDL_cond_impl_generic = {149&SDL_CreateCondition_generic,150&SDL_DestroyCondition_generic,151&SDL_SignalCondition_generic,152&SDL_BroadcastCondition_generic,153&SDL_WaitConditionTimeoutNS_generic,154};155156SDL_Condition *SDL_CreateCondition(void)157{158if (!SDL_cond_impl_active.Create) {159const SDL_cond_impl_t *impl = NULL;160161if (SDL_mutex_impl_active.Type == SDL_MUTEX_INVALID) {162// The mutex implementation isn't decided yet, trigger it163SDL_Mutex *mutex = SDL_CreateMutex();164if (!mutex) {165return NULL;166}167SDL_DestroyMutex(mutex);168169SDL_assert(SDL_mutex_impl_active.Type != SDL_MUTEX_INVALID);170}171172// Default to generic implementation, works with all mutex implementations173impl = &SDL_cond_impl_generic;174{175HMODULE kernel32 = GetModuleHandle(TEXT("kernel32.dll"));176if (kernel32) {177pWakeConditionVariable = (pfnWakeConditionVariable)GetProcAddress(kernel32, "WakeConditionVariable");178pWakeAllConditionVariable = (pfnWakeAllConditionVariable)GetProcAddress(kernel32, "WakeAllConditionVariable");179pSleepConditionVariableSRW = (pfnSleepConditionVariableSRW)GetProcAddress(kernel32, "SleepConditionVariableSRW");180pSleepConditionVariableCS = (pfnSleepConditionVariableCS)GetProcAddress(kernel32, "SleepConditionVariableCS");181if (pWakeConditionVariable && pWakeAllConditionVariable && pSleepConditionVariableSRW && pSleepConditionVariableCS) {182// Use the Windows provided API183impl = &SDL_cond_impl_cv;184}185}186}187188SDL_copyp(&SDL_cond_impl_active, impl);189}190return SDL_cond_impl_active.Create();191}192193void SDL_DestroyCondition(SDL_Condition *cond)194{195if (cond) {196SDL_cond_impl_active.Destroy(cond);197}198}199200void SDL_SignalCondition(SDL_Condition *cond)201{202if (!cond) {203return;204}205206SDL_cond_impl_active.Signal(cond);207}208209void SDL_BroadcastCondition(SDL_Condition *cond)210{211if (!cond) {212return;213}214215SDL_cond_impl_active.Broadcast(cond);216}217218bool SDL_WaitConditionTimeoutNS(SDL_Condition *cond, SDL_Mutex *mutex, Sint64 timeoutNS)219{220if (!cond || !mutex) {221return true;222}223224return SDL_cond_impl_active.WaitTimeoutNS(cond, mutex, timeoutNS);225}226227228