| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287 |
- /*
- Simple DirectMedia Layer
- Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
- This software is provided 'as-is', without any express or implied
- warranty. In no event will the authors be held liable for any damages
- arising from the use of this software.
- Permission is granted to anyone to use this software for any purpose,
- including commercial applications, and to alter it and redistribute it
- freely, subject to the following restrictions:
- 1. The origin of this software must not be misrepresented; you must not
- claim that you wrote the original software. If you use this software
- in a product, an acknowledgment in the product documentation would be
- appreciated but is not required.
- 2. Altered source versions must be plainly marked as such, and must not be
- misrepresented as being the original software.
- 3. This notice may not be removed or altered from any source distribution.
- */
- #include "../../SDL_internal.h"
- #include "SDL_hints.h"
- #include "SDL_thread.h"
- #include "../generic/SDL_syscond_c.h"
- #include "SDL_sysmutex_c.h"
- typedef SDL_cond * (*pfnSDL_CreateCond)(void);
- typedef void (*pfnSDL_DestroyCond)(SDL_cond *);
- typedef int (*pfnSDL_CondSignal)(SDL_cond *);
- typedef int (*pfnSDL_CondBroadcast)(SDL_cond *);
- typedef int (*pfnSDL_CondWait)(SDL_cond *, SDL_mutex *);
- typedef int (*pfnSDL_CondWaitTimeout)(SDL_cond *, SDL_mutex *, Uint32);
- typedef struct SDL_cond_impl_t
- {
- pfnSDL_CreateCond Create;
- pfnSDL_DestroyCond Destroy;
- pfnSDL_CondSignal Signal;
- pfnSDL_CondBroadcast Broadcast;
- pfnSDL_CondWait Wait;
- pfnSDL_CondWaitTimeout WaitTimeout;
- } SDL_cond_impl_t;
- /* Implementation will be chosen at runtime based on available Kernel features */
- static SDL_cond_impl_t SDL_cond_impl_active = {0};
- /**
- * Native Windows Condition Variable (SRW Locks)
- */
- #ifndef CONDITION_VARIABLE_INIT
- #define CONDITION_VARIABLE_INIT {0}
- typedef struct CONDITION_VARIABLE {
- PVOID Ptr;
- } CONDITION_VARIABLE, *PCONDITION_VARIABLE;
- #endif
- typedef VOID(WINAPI *pfnWakeConditionVariable)(PCONDITION_VARIABLE);
- typedef VOID(WINAPI *pfnWakeAllConditionVariable)(PCONDITION_VARIABLE);
- typedef BOOL(WINAPI *pfnSleepConditionVariableSRW)(PCONDITION_VARIABLE, PSRWLOCK, DWORD, ULONG);
- typedef BOOL(WINAPI* pfnSleepConditionVariableCS)(PCONDITION_VARIABLE, PCRITICAL_SECTION, DWORD);
- static pfnWakeConditionVariable pWakeConditionVariable = NULL;
- static pfnWakeAllConditionVariable pWakeAllConditionVariable = NULL;
- static pfnSleepConditionVariableSRW pSleepConditionVariableSRW = NULL;
- static pfnSleepConditionVariableCS pSleepConditionVariableCS = NULL;
- typedef struct SDL_cond_cv
- {
- CONDITION_VARIABLE cond;
- } SDL_cond_cv;
- static SDL_cond *
- SDL_CreateCond_cv(void)
- {
- SDL_cond_cv *cond;
- /* Relies on CONDITION_VARIABLE_INIT == 0. */
- cond = (SDL_cond_cv *) SDL_calloc(1, sizeof(*cond));
- if (!cond) {
- SDL_OutOfMemory();
- }
- return (SDL_cond *)cond;
- }
- static void
- SDL_DestroyCond_cv(SDL_cond * cond)
- {
- if (cond) {
- /* There are no kernel allocated resources */
- SDL_free(cond);
- }
- }
- static int
- SDL_CondSignal_cv(SDL_cond * _cond)
- {
- SDL_cond_cv *cond = (SDL_cond_cv *)_cond;
- if (!cond) {
- return SDL_InvalidParamError("cond");
- }
- pWakeConditionVariable(&cond->cond);
- return 0;
- }
- static int
- SDL_CondBroadcast_cv(SDL_cond * _cond)
- {
- SDL_cond_cv *cond = (SDL_cond_cv *)_cond;
- if (!cond) {
- return SDL_InvalidParamError("cond");
- }
- pWakeAllConditionVariable(&cond->cond);
- return 0;
- }
- static int
- SDL_CondWaitTimeout_cv(SDL_cond * _cond, SDL_mutex * _mutex, Uint32 ms)
- {
- SDL_cond_cv *cond = (SDL_cond_cv *)_cond;
- DWORD timeout;
- int ret;
- if (!cond) {
- return SDL_InvalidParamError("cond");
- }
- if (!_mutex) {
- return SDL_InvalidParamError("mutex");
- }
- if (ms == SDL_MUTEX_MAXWAIT) {
- timeout = INFINITE;
- } else {
- timeout = (DWORD) ms;
- }
- if (SDL_mutex_impl_active.Type == SDL_MUTEX_SRW) {
- SDL_mutex_srw *mutex = (SDL_mutex_srw *)_mutex;
- if (mutex->count != 1 || mutex->owner != GetCurrentThreadId()) {
- return SDL_SetError("Passed mutex is not locked or locked recursively");
- }
- /* The mutex must be updated to the released state */
- mutex->count = 0;
- mutex->owner = 0;
- if (pSleepConditionVariableSRW(&cond->cond, &mutex->srw, timeout, 0) == FALSE) {
- if (GetLastError() == ERROR_TIMEOUT) {
- ret = SDL_MUTEX_TIMEDOUT;
- } else {
- ret = SDL_SetError("SleepConditionVariableSRW() failed");
- }
- } else {
- ret = 0;
- }
- /* The mutex is owned by us again, regardless of status of the wait */
- SDL_assert(mutex->count == 0 && mutex->owner == 0);
- mutex->count = 1;
- mutex->owner = GetCurrentThreadId();
- } else {
- SDL_mutex_cs *mutex = (SDL_mutex_cs *)_mutex;
- SDL_assert(SDL_mutex_impl_active.Type == SDL_MUTEX_CS);
- if (pSleepConditionVariableCS(&cond->cond, &mutex->cs, timeout) == FALSE) {
- if (GetLastError() == ERROR_TIMEOUT) {
- ret = SDL_MUTEX_TIMEDOUT;
- } else {
- ret = SDL_SetError("SleepConditionVariableCS() failed");
- }
- } else {
- ret = 0;
- }
- }
- return ret;
- }
- static int
- SDL_CondWait_cv(SDL_cond * cond, SDL_mutex * mutex) {
- return SDL_CondWaitTimeout_cv(cond, mutex, SDL_MUTEX_MAXWAIT);
- }
- static const SDL_cond_impl_t SDL_cond_impl_cv =
- {
- &SDL_CreateCond_cv,
- &SDL_DestroyCond_cv,
- &SDL_CondSignal_cv,
- &SDL_CondBroadcast_cv,
- &SDL_CondWait_cv,
- &SDL_CondWaitTimeout_cv,
- };
- /**
- * Generic Condition Variable implementation using SDL_mutex and SDL_sem
- */
- static const SDL_cond_impl_t SDL_cond_impl_generic =
- {
- &SDL_CreateCond_generic,
- &SDL_DestroyCond_generic,
- &SDL_CondSignal_generic,
- &SDL_CondBroadcast_generic,
- &SDL_CondWait_generic,
- &SDL_CondWaitTimeout_generic,
- };
- SDL_cond *
- SDL_CreateCond(void)
- {
- if (SDL_cond_impl_active.Create == NULL) {
- /* Default to generic implementation, works with all mutex implementations */
- const SDL_cond_impl_t * impl = &SDL_cond_impl_generic;
- if (SDL_mutex_impl_active.Type == SDL_MUTEX_INVALID) {
- /* The mutex implementation isn't decided yet, trigger it */
- SDL_mutex *mutex = SDL_CreateMutex();
- if (!mutex) {
- return NULL;
- }
- SDL_DestroyMutex(mutex);
- SDL_assert(SDL_mutex_impl_active.Type != SDL_MUTEX_INVALID);
- }
- {
- HMODULE kernel32 = GetModuleHandle(TEXT("kernel32.dll"));
- if (kernel32) {
- pWakeConditionVariable = (pfnWakeConditionVariable) GetProcAddress(kernel32, "WakeConditionVariable");
- pWakeAllConditionVariable = (pfnWakeAllConditionVariable) GetProcAddress(kernel32, "WakeAllConditionVariable");
- pSleepConditionVariableSRW = (pfnSleepConditionVariableSRW) GetProcAddress(kernel32, "SleepConditionVariableSRW");
- pSleepConditionVariableCS = (pfnSleepConditionVariableCS) GetProcAddress(kernel32, "SleepConditionVariableCS");
- if (pWakeConditionVariable && pWakeAllConditionVariable && pSleepConditionVariableSRW && pSleepConditionVariableCS) {
- /* Use the Windows provided API */
- impl = &SDL_cond_impl_cv;
- }
- }
- }
- SDL_copyp(&SDL_cond_impl_active, impl);
- }
- return SDL_cond_impl_active.Create();
- }
- void
- SDL_DestroyCond(SDL_cond * cond)
- {
- SDL_cond_impl_active.Destroy(cond);
- }
- int
- SDL_CondSignal(SDL_cond * cond)
- {
- return SDL_cond_impl_active.Signal(cond);
- }
- int
- SDL_CondBroadcast(SDL_cond * cond)
- {
- return SDL_cond_impl_active.Broadcast(cond);
- }
- int
- SDL_CondWaitTimeout(SDL_cond * cond, SDL_mutex * mutex, Uint32 ms)
- {
- return SDL_cond_impl_active.WaitTimeout(cond, mutex, ms);
- }
- int
- SDL_CondWait(SDL_cond * cond, SDL_mutex * mutex)
- {
- return SDL_cond_impl_active.Wait(cond, mutex);
- }
- /* vi: set ts=4 sw=4 expandtab: */
|