Atlas - SDL_syscond_cv.c
Home / ext / SDL / src / thread / windows Lines: 1 | Size: 7322 bytes [Download] [Show on GitHub] [Search similar files] [Raw] [Raw (proxy)][FILE BEGIN]1/* 2 Simple DirectMedia Layer 3 Copyright (C) 1997-2025 Sam Lantinga <[email protected]> 4 5 This software is provided 'as-is', without any express or implied 6 warranty. In no event will the authors be held liable for any damages 7 arising from the use of this software. 8 9 Permission is granted to anyone to use this software for any purpose, 10 including commercial applications, and to alter it and redistribute it 11 freely, subject to the following restrictions: 12 13 1. The origin of this software must not be misrepresented; you must not 14 claim that you wrote the original software. If you use this software 15 in a product, an acknowledgment in the product documentation would be 16 appreciated but is not required. 17 2. Altered source versions must be plainly marked as such, and must not be 18 misrepresented as being the original software. 19 3. This notice may not be removed or altered from any source distribution. 20*/ 21#include "SDL_internal.h" 22 23#include "../generic/SDL_syscond_c.h" 24#include "SDL_sysmutex_c.h" 25 26typedef SDL_Condition *(*pfnSDL_CreateCondition)(void); 27typedef void (*pfnSDL_DestroyCondition)(SDL_Condition *); 28typedef void (*pfnSDL_SignalCondition)(SDL_Condition *); 29typedef void (*pfnSDL_BroadcastCondition)(SDL_Condition *); 30typedef bool (*pfnSDL_WaitConditionTimeoutNS)(SDL_Condition *, SDL_Mutex *, Sint64); 31 32typedef struct SDL_cond_impl_t 33{ 34 pfnSDL_CreateCondition Create; 35 pfnSDL_DestroyCondition Destroy; 36 pfnSDL_SignalCondition Signal; 37 pfnSDL_BroadcastCondition Broadcast; 38 pfnSDL_WaitConditionTimeoutNS WaitTimeoutNS; 39} SDL_cond_impl_t; 40 41// Implementation will be chosen at runtime based on available Kernel features 42static SDL_cond_impl_t SDL_cond_impl_active = { 0 }; 43 44/** 45 * Native Windows Condition Variable (SRW Locks) 46 */ 47 48#ifndef CONDITION_VARIABLE_INIT 49#define CONDITION_VARIABLE_INIT \ 50 { \ 51 0 \ 52 } 53typedef struct CONDITION_VARIABLE 54{ 55 PVOID Ptr; 56} CONDITION_VARIABLE, *PCONDITION_VARIABLE; 57#endif 58 59typedef VOID (WINAPI *pfnWakeConditionVariable)(PCONDITION_VARIABLE); 60typedef VOID (WINAPI *pfnWakeAllConditionVariable)(PCONDITION_VARIABLE); 61typedef BOOL (WINAPI *pfnSleepConditionVariableSRW)(PCONDITION_VARIABLE, PSRWLOCK, DWORD, ULONG); 62typedef BOOL (WINAPI *pfnSleepConditionVariableCS)(PCONDITION_VARIABLE, PCRITICAL_SECTION, DWORD); 63 64static pfnWakeConditionVariable pWakeConditionVariable = NULL; 65static pfnWakeAllConditionVariable pWakeAllConditionVariable = NULL; 66static pfnSleepConditionVariableSRW pSleepConditionVariableSRW = NULL; 67static pfnSleepConditionVariableCS pSleepConditionVariableCS = NULL; 68 69typedef struct SDL_cond_cv 70{ 71 CONDITION_VARIABLE cond; 72} SDL_cond_cv; 73 74static SDL_Condition *SDL_CreateCondition_cv(void) 75{ 76 // Relies on CONDITION_VARIABLE_INIT == 0. 77 return (SDL_Condition *)SDL_calloc(1, sizeof(SDL_cond_cv)); 78} 79 80static void SDL_DestroyCondition_cv(SDL_Condition *cond) 81{ 82 // There are no kernel allocated resources 83 SDL_free(cond); 84} 85 86static void SDL_SignalCondition_cv(SDL_Condition *_cond) 87{ 88 SDL_cond_cv *cond = (SDL_cond_cv *)_cond; 89 pWakeConditionVariable(&cond->cond); 90} 91 92static void SDL_BroadcastCondition_cv(SDL_Condition *_cond) 93{ 94 SDL_cond_cv *cond = (SDL_cond_cv *)_cond; 95 pWakeAllConditionVariable(&cond->cond); 96} 97 98static bool SDL_WaitConditionTimeoutNS_cv(SDL_Condition *_cond, SDL_Mutex *_mutex, Sint64 timeoutNS) 99{ 100 SDL_cond_cv *cond = (SDL_cond_cv *)_cond; 101 DWORD timeout; 102 bool result; 103 104 if (timeoutNS < 0) { 105 timeout = INFINITE; 106 } else { 107 timeout = (DWORD)SDL_NS_TO_MS(timeoutNS); 108 } 109 110 if (SDL_mutex_impl_active.Type == SDL_MUTEX_SRW) { 111 SDL_mutex_srw *mutex = (SDL_mutex_srw *)_mutex; 112 113 if (mutex->count != 1 || mutex->owner != GetCurrentThreadId()) { 114 // Passed mutex is not locked or locked recursively" 115 return false; 116 } 117 118 // The mutex must be updated to the released state 119 mutex->count = 0; 120 mutex->owner = 0; 121 122 result = (pSleepConditionVariableSRW(&cond->cond, &mutex->srw, timeout, 0) == TRUE); 123 124 // The mutex is owned by us again, regardless of status of the wait 125 SDL_assert(mutex->count == 0 && mutex->owner == 0); 126 mutex->count = 1; 127 mutex->owner = GetCurrentThreadId(); 128 } else { 129 SDL_mutex_cs *mutex = (SDL_mutex_cs *)_mutex; 130 131 SDL_assert(SDL_mutex_impl_active.Type == SDL_MUTEX_CS); 132 133 result = (pSleepConditionVariableCS(&cond->cond, &mutex->cs, timeout) == TRUE); 134 } 135 136 return result; 137} 138 139static const SDL_cond_impl_t SDL_cond_impl_cv = { 140 &SDL_CreateCondition_cv, 141 &SDL_DestroyCondition_cv, 142 &SDL_SignalCondition_cv, 143 &SDL_BroadcastCondition_cv, 144 &SDL_WaitConditionTimeoutNS_cv, 145}; 146 147 148// Generic Condition Variable implementation using SDL_Mutex and SDL_Semaphore 149static const SDL_cond_impl_t SDL_cond_impl_generic = { 150 &SDL_CreateCondition_generic, 151 &SDL_DestroyCondition_generic, 152 &SDL_SignalCondition_generic, 153 &SDL_BroadcastCondition_generic, 154 &SDL_WaitConditionTimeoutNS_generic, 155}; 156 157SDL_Condition *SDL_CreateCondition(void) 158{ 159 if (!SDL_cond_impl_active.Create) { 160 const SDL_cond_impl_t *impl = NULL; 161 162 if (SDL_mutex_impl_active.Type == SDL_MUTEX_INVALID) { 163 // The mutex implementation isn't decided yet, trigger it 164 SDL_Mutex *mutex = SDL_CreateMutex(); 165 if (!mutex) { 166 return NULL; 167 } 168 SDL_DestroyMutex(mutex); 169 170 SDL_assert(SDL_mutex_impl_active.Type != SDL_MUTEX_INVALID); 171 } 172 173 // Default to generic implementation, works with all mutex implementations 174 impl = &SDL_cond_impl_generic; 175 { 176 HMODULE kernel32 = GetModuleHandle(TEXT("kernel32.dll")); 177 if (kernel32) { 178 pWakeConditionVariable = (pfnWakeConditionVariable)GetProcAddress(kernel32, "WakeConditionVariable"); 179 pWakeAllConditionVariable = (pfnWakeAllConditionVariable)GetProcAddress(kernel32, "WakeAllConditionVariable"); 180 pSleepConditionVariableSRW = (pfnSleepConditionVariableSRW)GetProcAddress(kernel32, "SleepConditionVariableSRW"); 181 pSleepConditionVariableCS = (pfnSleepConditionVariableCS)GetProcAddress(kernel32, "SleepConditionVariableCS"); 182 if (pWakeConditionVariable && pWakeAllConditionVariable && pSleepConditionVariableSRW && pSleepConditionVariableCS) { 183 // Use the Windows provided API 184 impl = &SDL_cond_impl_cv; 185 } 186 } 187 } 188 189 SDL_copyp(&SDL_cond_impl_active, impl); 190 } 191 return SDL_cond_impl_active.Create(); 192} 193 194void SDL_DestroyCondition(SDL_Condition *cond) 195{ 196 if (cond) { 197 SDL_cond_impl_active.Destroy(cond); 198 } 199} 200 201void SDL_SignalCondition(SDL_Condition *cond) 202{ 203 if (!cond) { 204 return; 205 } 206 207 SDL_cond_impl_active.Signal(cond); 208} 209 210void SDL_BroadcastCondition(SDL_Condition *cond) 211{ 212 if (!cond) { 213 return; 214 } 215 216 SDL_cond_impl_active.Broadcast(cond); 217} 218 219bool SDL_WaitConditionTimeoutNS(SDL_Condition *cond, SDL_Mutex *mutex, Sint64 timeoutNS) 220{ 221 if (!cond || !mutex) { 222 return true; 223 } 224 225 return SDL_cond_impl_active.WaitTimeoutNS(cond, mutex, timeoutNS); 226} 227[FILE END](C) 2025 0x4248 (C) 2025 4248 Media and 4248 Systems, All part of 0x4248 See LICENCE files for more information. Not all files are by 0x4248 always check Licencing.