#include "SDL_internal.h"
#ifdef SDL_THREAD_WINDOWS
#include "SDL_sysmutex_c.h"
SDL_mutex_impl_t SDL_mutex_impl_active = { 0 };
typedef VOID (WINAPI *pfnInitializeSRWLock)(PSRWLOCK);
typedef VOID (WINAPI *pfnReleaseSRWLockExclusive)(PSRWLOCK);
typedef VOID (WINAPI *pfnAcquireSRWLockExclusive)(PSRWLOCK);
typedef BOOLEAN (WINAPI *pfnTryAcquireSRWLockExclusive)(PSRWLOCK);
static pfnInitializeSRWLock pInitializeSRWLock = NULL;
static pfnReleaseSRWLockExclusive pReleaseSRWLockExclusive = NULL;
static pfnAcquireSRWLockExclusive pAcquireSRWLockExclusive = NULL;
static pfnTryAcquireSRWLockExclusive pTryAcquireSRWLockExclusive = NULL;
static SDL_Mutex *SDL_CreateMutex_srw(void)
{
SDL_mutex_srw *mutex = (SDL_mutex_srw *)SDL_calloc(1, sizeof(*mutex));
if (mutex) {
pInitializeSRWLock(&mutex->srw);
}
return (SDL_Mutex *)mutex;
}
static void SDL_DestroyMutex_srw(SDL_Mutex *mutex)
{
SDL_free(mutex);
}
static void SDL_LockMutex_srw(SDL_Mutex *_mutex) SDL_NO_THREAD_SAFETY_ANALYSIS {
SDL_mutex_srw *mutex = (SDL_mutex_srw *)_mutex;
const DWORD this_thread = GetCurrentThreadId();
if (mutex->owner == this_thread) {
++mutex->count;
} else {
pAcquireSRWLockExclusive(&mutex->srw);
SDL_assert(mutex->count == 0 && mutex->owner == 0);
mutex->owner = this_thread;
mutex->count = 1;
}
}
static bool SDL_TryLockMutex_srw(SDL_Mutex *_mutex)
{
SDL_mutex_srw *mutex = (SDL_mutex_srw *)_mutex;
const DWORD this_thread = GetCurrentThreadId();
bool retval = true;
if (mutex->owner == this_thread) {
++mutex->count;
} else {
if (pTryAcquireSRWLockExclusive(&mutex->srw) != 0) {
SDL_assert(mutex->count == 0 && mutex->owner == 0);
mutex->owner = this_thread;
mutex->count = 1;
} else {
retval = false;
}
}
return retval;
}
static void SDL_UnlockMutex_srw(SDL_Mutex *_mutex) SDL_NO_THREAD_SAFETY_ANALYSIS {
SDL_mutex_srw *mutex = (SDL_mutex_srw *)_mutex;
if (mutex->owner == GetCurrentThreadId()) {
if (--mutex->count == 0) {
mutex->owner = 0;
pReleaseSRWLockExclusive(&mutex->srw);
}
} else {
SDL_assert(!"mutex not owned by this thread"); }
}
static const SDL_mutex_impl_t SDL_mutex_impl_srw = {
&SDL_CreateMutex_srw,
&SDL_DestroyMutex_srw,
&SDL_LockMutex_srw,
&SDL_TryLockMutex_srw,
&SDL_UnlockMutex_srw,
SDL_MUTEX_SRW,
};
static SDL_Mutex *SDL_CreateMutex_cs(void)
{
SDL_mutex_cs *mutex = (SDL_mutex_cs *)SDL_malloc(sizeof(*mutex));
if (mutex) {
(void)InitializeCriticalSectionAndSpinCount(&mutex->cs, 2000);
}
return (SDL_Mutex *)mutex;
}
static void SDL_DestroyMutex_cs(SDL_Mutex *mutex_)
{
SDL_mutex_cs *mutex = (SDL_mutex_cs *)mutex_;
DeleteCriticalSection(&mutex->cs);
SDL_free(mutex);
}
static void SDL_LockMutex_cs(SDL_Mutex *mutex_) SDL_NO_THREAD_SAFETY_ANALYSIS {
SDL_mutex_cs *mutex = (SDL_mutex_cs *)mutex_;
EnterCriticalSection(&mutex->cs);
}
static bool SDL_TryLockMutex_cs(SDL_Mutex *mutex_)
{
SDL_mutex_cs *mutex = (SDL_mutex_cs *)mutex_;
return (TryEnterCriticalSection(&mutex->cs) == TRUE);
}
static void SDL_UnlockMutex_cs(SDL_Mutex *mutex_) SDL_NO_THREAD_SAFETY_ANALYSIS {
SDL_mutex_cs *mutex = (SDL_mutex_cs *)mutex_;
LeaveCriticalSection(&mutex->cs);
}
static const SDL_mutex_impl_t SDL_mutex_impl_cs = {
&SDL_CreateMutex_cs,
&SDL_DestroyMutex_cs,
&SDL_LockMutex_cs,
&SDL_TryLockMutex_cs,
&SDL_UnlockMutex_cs,
SDL_MUTEX_CS,
};
SDL_Mutex *SDL_CreateMutex(void)
{
if (!SDL_mutex_impl_active.Create) {
const SDL_mutex_impl_t *impl = &SDL_mutex_impl_cs;
HMODULE kernel32 = GetModuleHandle(TEXT("kernel32.dll"));
if (kernel32) {
pInitializeSRWLock = (pfnInitializeSRWLock)GetProcAddress(kernel32, "InitializeSRWLock");
pReleaseSRWLockExclusive = (pfnReleaseSRWLockExclusive)GetProcAddress(kernel32, "ReleaseSRWLockExclusive");
pAcquireSRWLockExclusive = (pfnAcquireSRWLockExclusive)GetProcAddress(kernel32, "AcquireSRWLockExclusive");
pTryAcquireSRWLockExclusive = (pfnTryAcquireSRWLockExclusive)GetProcAddress(kernel32, "TryAcquireSRWLockExclusive");
if (pInitializeSRWLock && pReleaseSRWLockExclusive && pAcquireSRWLockExclusive && pTryAcquireSRWLockExclusive) {
impl = &SDL_mutex_impl_srw;
}
}
SDL_copyp(&SDL_mutex_impl_active, impl);
}
return SDL_mutex_impl_active.Create();
}
void SDL_DestroyMutex(SDL_Mutex *mutex)
{
if (mutex) {
SDL_mutex_impl_active.Destroy(mutex);
}
}
void SDL_LockMutex(SDL_Mutex *mutex)
{
if (mutex) {
SDL_mutex_impl_active.Lock(mutex);
}
}
bool SDL_TryLockMutex(SDL_Mutex *mutex)
{
bool result = true;
if (mutex) {
result = SDL_mutex_impl_active.TryLock(mutex);
}
return result;
}
void SDL_UnlockMutex(SDL_Mutex *mutex)
{
if (mutex) {
SDL_mutex_impl_active.Unlock(mutex);
}
}
#endif