#include "../../SDL_internal.h"
#if SDL_THREAD_WINDOWS
#include "SDL_hints.h"
#include "SDL_sysmutex_c.h"
SDL_mutex_impl_t SDL_mutex_impl_active = {0};
#if __WINRT__
#define pReleaseSRWLockExclusive ReleaseSRWLockExclusive
#define pAcquireSRWLockExclusive AcquireSRWLockExclusive
#define pTryAcquireSRWLockExclusive TryAcquireSRWLockExclusive
#else
typedef VOID(WINAPI *pfnReleaseSRWLockExclusive)(PSRWLOCK);
typedef VOID(WINAPI *pfnAcquireSRWLockExclusive)(PSRWLOCK);
typedef BOOLEAN(WINAPI *pfnTryAcquireSRWLockExclusive)(PSRWLOCK);
static pfnReleaseSRWLockExclusive pReleaseSRWLockExclusive = NULL;
static pfnAcquireSRWLockExclusive pAcquireSRWLockExclusive = NULL;
static pfnTryAcquireSRWLockExclusive pTryAcquireSRWLockExclusive = NULL;
#endif
static SDL_mutex *
SDL_CreateMutex_srw(void)
{
SDL_mutex_srw *mutex;
mutex = (SDL_mutex_srw *) SDL_calloc(1, sizeof(*mutex));
if (!mutex) {
SDL_OutOfMemory();
}
return (SDL_mutex *)mutex;
}
static void
SDL_DestroyMutex_srw(SDL_mutex * mutex)
{
if (mutex) {
SDL_free(mutex);
}
}
static int
SDL_LockMutex_srw(SDL_mutex * _mutex)
{
SDL_mutex_srw *mutex = (SDL_mutex_srw *)_mutex;
DWORD this_thread;
if (mutex == NULL) {
return SDL_InvalidParamError("mutex");
}
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;
}
return 0;
}
static int
SDL_TryLockMutex_srw(SDL_mutex * _mutex)
{
SDL_mutex_srw *mutex = (SDL_mutex_srw *)_mutex;
DWORD this_thread;
int retval = 0;
if (mutex == NULL) {
return SDL_InvalidParamError("mutex");
}
this_thread = GetCurrentThreadId();
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 = SDL_MUTEX_TIMEDOUT;
}
}
return retval;
}
static int
SDL_UnlockMutex_srw(SDL_mutex * _mutex)
{
SDL_mutex_srw *mutex = (SDL_mutex_srw *)_mutex;
if (mutex == NULL) {
return SDL_InvalidParamError("mutex");
}
if (mutex->owner == GetCurrentThreadId()) {
if (--mutex->count == 0) {
mutex->owner = 0;
pReleaseSRWLockExclusive(&mutex->srw);
}
} else {
return SDL_SetError("mutex not owned by this thread");
}
return 0;
}
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;
mutex = (SDL_mutex_cs *) SDL_malloc(sizeof(*mutex));
if (mutex) {
#if __WINRT__
InitializeCriticalSectionEx(&mutex->cs, 2000, 0);
#else
InitializeCriticalSectionAndSpinCount(&mutex->cs, 2000);
#endif
} else {
SDL_OutOfMemory();
}
return (SDL_mutex *)mutex;
}
static void
SDL_DestroyMutex_cs(SDL_mutex * mutex_)
{
SDL_mutex_cs *mutex = (SDL_mutex_cs *)mutex_;
if (mutex) {
DeleteCriticalSection(&mutex->cs);
SDL_free(mutex);
}
}
static int
SDL_LockMutex_cs(SDL_mutex * mutex_)
{
SDL_mutex_cs *mutex = (SDL_mutex_cs *)mutex_;
if (mutex == NULL) {
return SDL_InvalidParamError("mutex");
}
EnterCriticalSection(&mutex->cs);
return 0;
}
static int
SDL_TryLockMutex_cs(SDL_mutex * mutex_)
{
SDL_mutex_cs *mutex = (SDL_mutex_cs *)mutex_;
int retval = 0;
if (mutex == NULL) {
return SDL_InvalidParamError("mutex");
}
if (TryEnterCriticalSection(&mutex->cs) == 0) {
retval = SDL_MUTEX_TIMEDOUT;
}
return retval;
}
static int
SDL_UnlockMutex_cs(SDL_mutex * mutex_)
{
SDL_mutex_cs *mutex = (SDL_mutex_cs *)mutex_;
if (mutex == NULL) {
return SDL_InvalidParamError("mutex");
}
LeaveCriticalSection(&mutex->cs);
return 0;
}
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 == NULL) {
const SDL_mutex_impl_t * impl = &SDL_mutex_impl_cs;
if (!SDL_GetHintBoolean(SDL_HINT_WINDOWS_FORCE_MUTEX_CRITICAL_SECTIONS, SDL_FALSE)) {
#if __WINRT__
impl = &SDL_mutex_impl_srw;
#else
HMODULE kernel32 = GetModuleHandle(TEXT("kernel32.dll"));
if (kernel32) {
pReleaseSRWLockExclusive = (pfnReleaseSRWLockExclusive) GetProcAddress(kernel32, "ReleaseSRWLockExclusive");
pAcquireSRWLockExclusive = (pfnAcquireSRWLockExclusive) GetProcAddress(kernel32, "AcquireSRWLockExclusive");
pTryAcquireSRWLockExclusive = (pfnTryAcquireSRWLockExclusive) GetProcAddress(kernel32, "TryAcquireSRWLockExclusive");
if (pReleaseSRWLockExclusive && pAcquireSRWLockExclusive && pTryAcquireSRWLockExclusive) {
impl = &SDL_mutex_impl_srw;
}
}
#endif
}
SDL_copyp(&SDL_mutex_impl_active, impl);
}
return SDL_mutex_impl_active.Create();
}
void
SDL_DestroyMutex(SDL_mutex * mutex) {
SDL_mutex_impl_active.Destroy(mutex);
}
int
SDL_LockMutex(SDL_mutex * mutex) {
return SDL_mutex_impl_active.Lock(mutex);
}
int
SDL_TryLockMutex(SDL_mutex * mutex) {
return SDL_mutex_impl_active.TryLock(mutex);
}
int
SDL_UnlockMutex(SDL_mutex * mutex) {
return SDL_mutex_impl_active.Unlock(mutex);
}
#endif