rwlock: Added SDL_rwlock API for shared locks.

This commit is contained in:
Ryan C. Gordon
2023-04-24 01:07:59 -04:00
parent 776820526b
commit e474047ff8
31 changed files with 1244 additions and 20 deletions

View File

@@ -159,3 +159,4 @@ int SDL_UnlockMutex(SDL_mutex *mutex) SDL_NO_THREAD_SAFETY_ANALYSIS /* clang doe
return 0;
#endif /* SDL_THREADS_DISABLED */
}

View File

@@ -0,0 +1,185 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 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"
/* An implementation of rwlocks using mutexes, condition variables, and atomics. */
#include "SDL_systhread_c.h"
#include "../generic/SDL_sysrwlock_c.h"
/* If two implementations are to be compiled into SDL (the active one
* will be chosen at runtime), the function names need to be
* suffixed
*/
/* !!! FIXME: this is quite a tapdance with macros and the build system, maybe we can simplify how we do this. --ryan. */
#ifndef SDL_THREAD_GENERIC_RWLOCK_SUFFIX
#define SDL_CreateRWLock_generic SDL_CreateRWLock
#define SDL_DestroyRWLock_generic SDL_DestroyRWLock
#define SDL_LockRWLockForReading_generic SDL_LockRWLockForReading
#define SDL_LockRWLockForWriting_generic SDL_LockRWLockForWriting
#define SDL_TryLockRWLockForReading_generic SDL_TryLockRWLockForReading
#define SDL_TryLockRWLockForWriting_generic SDL_TryLockRWLockForWriting
#define SDL_UnlockRWLock_generic SDL_UnlockRWLock
#endif
struct SDL_rwlock
{
SDL_mutex *lock;
SDL_cond *condition;
SDL_threadID writer_thread;
SDL_AtomicInt reader_count;
SDL_AtomicInt writer_count;
};
SDL_rwlock *SDL_CreateRWLock_generic(void)
{
SDL_rwlock *rwlock = (SDL_rwlock *) SDL_malloc(sizeof (*rwlock));
if (!rwlock) {
SDL_OutOfMemory();
return NULL;
}
rwlock->lock = SDL_CreateMutex();
if (!rwlock->lock) {
SDL_free(rwlock);
return NULL;
}
rwlock->condition = SDL_CreateCond();
if (!rwlock->condition) {
SDL_DestroyMutex(rwlock->lock);
SDL_free(rwlock);
return NULL;
}
SDL_AtomicSet(&rwlock->reader_count, 0);
SDL_AtomicSet(&rwlock->writer_count, 0);
return rwlock;
}
void SDL_DestroyRWLock_generic(SDL_rwlock *rwlock)
{
if (rwlock) {
SDL_DestroyMutex(rwlock->lock);
SDL_DestroyCond(rwlock->condition);
SDL_free(rwlock);
}
}
int SDL_LockRWLockForReading_generic(SDL_rwlock *rwlock) SDL_NO_THREAD_SAFETY_ANALYSIS /* clang doesn't know about NULL mutexes */
{
if (!rwlock) {
return SDL_InvalidParamError("rwlock");
} else if (SDL_LockMutex(rwlock->lock) == -1) {
return -1;
}
SDL_assert(SDL_AtomicGet(&rwlock->writer_count) == 0); /* shouldn't be able to grab lock if there's a writer! */
SDL_AtomicAdd(&rwlock->reader_count, 1);
SDL_UnlockMutex(rwlock->lock); /* other readers can attempt to share the lock. */
return 0;
}
int SDL_LockRWLockForWriting_generic(SDL_rwlock *rwlock) SDL_NO_THREAD_SAFETY_ANALYSIS /* clang doesn't know about NULL mutexes */
{
if (!rwlock) {
return SDL_InvalidParamError("rwlock");
} else if (SDL_LockMutex(rwlock->lock) == -1) {
return -1;
}
while (SDL_AtomicGet(&rwlock->reader_count) > 0) { /* while something is holding the shared lock, keep waiting. */
SDL_CondWait(rwlock->condition, rwlock->lock); /* release the lock and wait for readers holding the shared lock to release it, regrab the lock. */
}
/* we hold the lock! */
SDL_AtomicAdd(&rwlock->writer_count, 1); /* we let these be recursive, but the API doesn't require this. It _does_ trust you unlock correctly! */
return 0;
}
int SDL_TryLockRWLockForReading_generic(SDL_rwlock *rwlock)
{
int rc;
if (!rwlock) {
return SDL_InvalidParamError("rwlock");
}
rc = SDL_TryLockMutex(rwlock->lock);
if (rc != 0) {
/* !!! FIXME: there is a small window where a reader has to lock the mutex, and if we hit that, we will return SDL_RWLOCK_TIMEDOUT even though we could have shared the lock. */
return rc;
}
SDL_assert(SDL_AtomicGet(&rwlock->writer_count) == 0); /* shouldn't be able to grab lock if there's a writer! */
SDL_AtomicAdd(&rwlock->reader_count, 1);
SDL_UnlockMutex(rwlock->lock); /* other readers can attempt to share the lock. */
return 0;
}
int SDL_TryLockRWLockForWriting_generic(SDL_rwlock *rwlock)
{
int rc;
if (!rwlock) {
return SDL_InvalidParamError("rwlock");
} else if ((rc = SDL_TryLockMutex(rwlock->lock)) != 0) {
return rc;
}
if (SDL_AtomicGet(&rwlock->reader_count) > 0) { /* a reader is using the shared lock, treat it as unavailable. */
SDL_UnlockMutex(rwlock->lock);
return SDL_RWLOCK_TIMEDOUT;
}
/* we hold the lock! */
SDL_AtomicAdd(&rwlock->writer_count, 1); /* we let these be recursive, but the API doesn't require this. It _does_ trust you unlock correctly! */
return 0;
}
int SDL_UnlockRWLock_generic(SDL_rwlock *rwlock) SDL_NO_THREAD_SAFETY_ANALYSIS /* clang doesn't know about NULL mutexes */
{
if (!rwlock) {
return SDL_InvalidParamError("rwlock");
}
SDL_LockMutex(rwlock->lock); /* recursive lock for writers, readers grab lock to make sure things are sane. */
if (SDL_AtomicGet(&rwlock->reader_count) > 0) { /* we're a reader */
SDL_AtomicAdd(&rwlock->reader_count, -1);
SDL_CondBroadcast(rwlock->condition); /* alert any pending writers to attempt to try to grab the lock again. */
} else if (SDL_AtomicGet(&rwlock->writer_count) > 0) { /* we're a writer */
SDL_AtomicAdd(&rwlock->writer_count, -1);
SDL_UnlockMutex(rwlock->lock); /* recursive unlock. */
}
SDL_UnlockMutex(rwlock->lock);
return 0;
}

View File

@@ -0,0 +1,38 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 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"
#ifndef SDL_sysrwlock_c_h_
#define SDL_sysrwlock_c_h_
#ifdef SDL_THREAD_GENERIC_RWLOCK_SUFFIX
SDL_rwlock *SDL_CreateRWLock_generic(void);
void SDL_DestroyRWLock_generic(SDL_rwlock *rwlock);
int SDL_LockRWLockForReading_generic(SDL_rwlock *rwlock);
int SDL_LockRWLockForWriting_generic(SDL_rwlock *rwlock);
int SDL_TryLockRWLockForReading_generic(SDL_rwlock *rwlock);
int SDL_TryLockRWLockForWriting_generic(SDL_rwlock *rwlock);
int SDL_UnlockRWLock_generic(SDL_rwlock *rwlock);
#endif /* SDL_THREAD_GENERIC_RWLOCK_SUFFIX */
#endif /* SDL_sysrwlock_c_h_ */

View File

@@ -109,3 +109,4 @@ int SDL_UnlockMutex(SDL_mutex *mutex) SDL_NO_THREAD_SAFETY_ANALYSIS /* clang doe
return 0;
}

View File

@@ -24,6 +24,7 @@
#include <e32std.h>
/* !!! FIXME: Should this be SDL_MUTEX_TIMEDOUT? */
#define SDL_MUTEX_TIMEOUT -2
struct SDL_semaphore

View File

@@ -23,20 +23,7 @@
#include <errno.h>
#include <pthread.h>
#if !(defined(SDL_THREAD_PTHREAD_RECURSIVE_MUTEX) || \
defined(SDL_THREAD_PTHREAD_RECURSIVE_MUTEX_NP))
#define FAKE_RECURSIVE_MUTEX
#endif
struct SDL_mutex
{
pthread_mutex_t id;
#ifdef FAKE_RECURSIVE_MUTEX
int recursive;
pthread_t owner;
#endif
};
#include "SDL_sysmutex_c.h"
SDL_mutex *
SDL_CreateMutex(void)
@@ -186,3 +173,4 @@ int SDL_UnlockMutex(SDL_mutex *mutex) SDL_NO_THREAD_SAFETY_ANALYSIS /* clang doe
return 0;
}

View File

@@ -23,9 +23,18 @@
#ifndef SDL_mutex_c_h_
#define SDL_mutex_c_h_
#if !(defined(SDL_THREAD_PTHREAD_RECURSIVE_MUTEX) || \
defined(SDL_THREAD_PTHREAD_RECURSIVE_MUTEX_NP))
#define FAKE_RECURSIVE_MUTEX
#endif
struct SDL_mutex
{
pthread_mutex_t id;
#ifdef FAKE_RECURSIVE_MUTEX
int recursive;
pthread_t owner;
#endif
};
#endif /* SDL_mutex_c_h_ */

View File

@@ -0,0 +1,127 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 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 <errno.h>
#include <pthread.h>
struct SDL_rwlock
{
pthread_rwlock_t id;
};
SDL_rwlock *
SDL_CreateRWLock(void)
{
SDL_rwlock *rwlock;
/* Allocate the structure */
rwlock = (SDL_rwlock *)SDL_calloc(1, sizeof(*rwlock));
if (rwlock) {
if (pthread_rwlock_init(&rwlock->id, NULL) != 0) {
SDL_SetError("pthread_rwlock_init() failed");
SDL_free(rwlock);
rwlock = NULL;
}
} else {
SDL_OutOfMemory();
}
return rwlock;
}
void SDL_DestroyRWLock(SDL_rwlock *rwlock)
{
if (rwlock) {
pthread_rwlock_destroy(&rwlock->id);
SDL_free(rwlock);
}
}
int SDL_LockRWLockForReading(SDL_rwlock *rwlock) SDL_NO_THREAD_SAFETY_ANALYSIS /* clang doesn't know about NULL mutexes */
{
if (rwlock == NULL) {
return SDL_InvalidParamError("rwlock");
} else if (pthread_rwlock_rdlock(&rwlock->id) != 0) {
return SDL_SetError("pthread_rwlock_rdlock() failed");
}
return 0;
}
int SDL_LockRWLockForWriting(SDL_rwlock *rwlock) SDL_NO_THREAD_SAFETY_ANALYSIS /* clang doesn't know about NULL mutexes */
{
if (rwlock == NULL) {
return SDL_InvalidParamError("rwlock");
} else if (pthread_rwlock_wrlock(&rwlock->id) != 0) {
return SDL_SetError("pthread_rwlock_wrlock() failed");
}
return 0;
}
int SDL_TryLockRWLockForReading(SDL_rwlock *rwlock)
{
int retval = 0;
if (rwlock == NULL) {
retval = SDL_InvalidParamError("rwlock");
} else {
const int result = pthread_rwlock_tryrdlock(&rwlock->id);
if (result != 0) {
if (result == EBUSY) {
retval = SDL_RWLOCK_TIMEDOUT;
} else {
retval = SDL_SetError("pthread_rwlock_tryrdlock() failed");
}
}
}
return retval;
}
int SDL_TryLockRWLockForWriting(SDL_rwlock *rwlock)
{
int retval = 0;
if (rwlock == NULL) {
retval = SDL_InvalidParamError("rwlock");
} else {
const int result = pthread_rwlock_trywrlock(&rwlock->id);
if (result != 0) {
if (result == EBUSY) {
retval = SDL_RWLOCK_TIMEDOUT;
} else {
retval = SDL_SetError("pthread_rwlock_tryrdlock() failed");
}
}
}
return retval;
}
int SDL_UnlockRWLock(SDL_rwlock *rwlock) SDL_NO_THREAD_SAFETY_ANALYSIS /* clang doesn't know about NULL mutexes */
{
if (rwlock == NULL) {
return SDL_InvalidParamError("rwlock");
} else if (pthread_rwlock_unlock(&rwlock->id) != 0) {
return SDL_SetError("pthread_rwlock_unlock() failed");
}
return 0;
}

View File

@@ -97,3 +97,4 @@ SDL_UnlockMutex(SDL_mutex *mutex) SDL_NO_THREAD_SAFETY_ANALYSIS /* clang doesn't
mutex->cpp_mutex.unlock();
return 0;
}

View File

@@ -26,3 +26,4 @@ struct SDL_mutex
{
std::recursive_mutex cpp_mutex;
};

View File

@@ -0,0 +1,130 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 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 <shared_mutex>
#include <system_error>
#include <Windows.h>
struct SDL_rwlock
{
std::shared_mutex cpp_mutex;
SDL_threadID write_owner;
};
/* Create a rwlock */
extern "C" SDL_rwlock *SDL_CreateRWLock(void)
{
/* Allocate and initialize the rwlock */
try {
SDL_rwlock *rwlock = new SDL_rwlock;
return rwlock;
} catch (std::system_error &ex) {
SDL_SetError("unable to create a C++ rwlock: code=%d; %s", ex.code(), ex.what());
return NULL;
} catch (std::bad_alloc &) {
SDL_OutOfMemory();
return NULL;
}
}
/* Free the rwlock */
extern "C" void SDL_DestroyRWLock(SDL_rwlock *rwlock)
{
if (rwlock != NULL) {
delete rwlock;
}
}
/* Lock the rwlock */
extern "C" int SDL_LockRWLockForReading(SDL_rwlock *rwlock) SDL_NO_THREAD_SAFETY_ANALYSIS /* clang doesn't know about NULL mutexes */
{
if (!rwlock) {
return SDL_InvalidParamError("rwlock");
}
try {
rwlock->cpp_mutex.lock_shared();
return 0;
} catch (std::system_error &ex) {
return SDL_SetError("unable to lock a C++ rwlock: code=%d; %s", ex.code(), ex.what());
}
}
/* Lock the rwlock for writing */
extern "C" int SDL_LockRWLockForWriting(SDL_rwlock *rwlock) SDL_NO_THREAD_SAFETY_ANALYSIS /* clang doesn't know about NULL mutexes */
{
if (!rwlock) {
return SDL_InvalidParamError("rwlock");
}
try {
rwlock->cpp_mutex.lock();
rwlock->write_owner = SDL_ThreadID();
return 0;
} catch (std::system_error &ex) {
return SDL_SetError("unable to lock a C++ rwlock: code=%d; %s", ex.code(), ex.what());
}
}
/* TryLock the rwlock for reading */
int SDL_TryLockRWLockForReading(SDL_rwlock *rwlock)
{
int retval = 0;
if (!rwlock) {
retval = SDL_InvalidParamError("rwlock");
} else if (rwlock->cpp_mutex.try_lock_shared() == false) {
retval = SDL_RWLOCK_TIMEDOUT;
}
return retval;
}
/* TryLock the rwlock for writing */
int SDL_TryLockRWLockForWriting(SDL_rwlock *rwlock)
{
int retval = 0;
if (!rwlock) {
retval = SDL_InvalidParamError("rwlock");
} else if (rwlock->cpp_mutex.try_lock() == false) {
retval = SDL_RWLOCK_TIMEDOUT;
} else {
rwlock->write_owner = SDL_ThreadID();
}
return retval;
}
/* Unlock the rwlock */
extern "C" int
SDL_UnlockRWLock(SDL_rwlock *rwlock) SDL_NO_THREAD_SAFETY_ANALYSIS /* clang doesn't know about NULL mutexes */
{
if (!rwlock) {
return SDL_InvalidParamError("rwlock");
} else if (rwlock->write_owner == SDL_ThreadID()) {
rwlock->write_owner = 0;
rwlock->cpp_mutex.unlock();
} else {
rwlock->cpp_mutex.unlock_shared();
}
return 0;
}

View File

@@ -0,0 +1,258 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 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"
/**
* Implementation based on Slim Reader/Writer (SRW) Locks for Win 7 and newer.
*/
/* This header makes sure SRWLOCK is actually declared, even on ancient WinSDKs. */
#include "SDL_sysmutex_c.h"
typedef VOID(WINAPI *pfnInitializeSRWLock)(PSRWLOCK);
typedef VOID(WINAPI *pfnReleaseSRWLockShared)(PSRWLOCK);
typedef VOID(WINAPI *pfnAcquireSRWLockShared)(PSRWLOCK);
typedef BOOLEAN(WINAPI *pfnTryAcquireSRWLockShared)(PSRWLOCK);
typedef VOID(WINAPI *pfnReleaseSRWLockExclusive)(PSRWLOCK);
typedef VOID(WINAPI *pfnAcquireSRWLockExclusive)(PSRWLOCK);
typedef BOOLEAN(WINAPI *pfnTryAcquireSRWLockExclusive)(PSRWLOCK);
#ifdef __WINRT__
/* Functions are guaranteed to be available */
#define pTryAcquireSRWLockExclusive TryAcquireSRWLockExclusive
#define pInitializeSRWLock InitializeSRWLock
#define pReleaseSRWLockShared ReleaseSRWLockShared
#define pAcquireSRWLockShared AcquireSRWLockShared
#define pTryAcquireSRWLockShared TryAcquireSRWLockShared
#define pReleaseSRWLockExclusive ReleaseSRWLockExclusive
#define pAcquireSRWLockExclusive AcquireSRWLockExclusive
#define pTryAcquireSRWLockExclusive TryAcquireSRWLockExclusive
#else
static pfnInitializeSRWLock pInitializeSRWLock = NULL;
static pfnReleaseSRWLockShared pReleaseSRWLockShared = NULL;
static pfnAcquireSRWLockShared pAcquireSRWLockShared = NULL;
static pfnTryAcquireSRWLockShared pTryAcquireSRWLockShared = NULL;
static pfnReleaseSRWLockExclusive pReleaseSRWLockExclusive = NULL;
static pfnAcquireSRWLockExclusive pAcquireSRWLockExclusive = NULL;
static pfnTryAcquireSRWLockExclusive pTryAcquireSRWLockExclusive = NULL;
#endif
typedef SDL_rwlock *(*pfnSDL_CreateRWLock)(void);
typedef void (*pfnSDL_DestroyRWLock)(SDL_rwlock *);
typedef int (*pfnSDL_LockRWLockForReading)(SDL_rwlock *);
typedef int (*pfnSDL_LockRWLockForWriting)(SDL_rwlock *);
typedef int (*pfnSDL_TryLockRWLockForReading)(SDL_rwlock *);
typedef int (*pfnSDL_TryLockRWLockForWriting)(SDL_rwlock *);
typedef int (*pfnSDL_UnlockRWLock)(SDL_rwlock *);
typedef struct SDL_rwlock_impl_t
{
pfnSDL_CreateRWLock Create;
pfnSDL_DestroyRWLock Destroy;
pfnSDL_LockRWLockForReading LockForReading;
pfnSDL_LockRWLockForWriting LockForWriting;
pfnSDL_TryLockRWLockForReading TryLockForReading;
pfnSDL_TryLockRWLockForWriting TryLockForWriting;
pfnSDL_UnlockRWLock Unlock;
} SDL_rwlock_impl_t;
/* Implementation will be chosen at runtime based on available Kernel features */
static SDL_rwlock_impl_t SDL_rwlock_impl_active = { 0 };
/* rwlock implementation using Win7+ slim read/write locks (SRWLOCK) */
typedef struct SDL_rwlock_srw
{
SRWLOCK srw;
SDL_threadID write_owner;
} SDL_rwlock_srw;
static SDL_rwlock *SDL_CreateRWLock_srw(void)
{
SDL_rwlock_srw *rwlock = (SDL_rwlock_srw *)SDL_calloc(1, sizeof(*rwlock));
if (rwlock == NULL) {
SDL_OutOfMemory();
}
pInitializeSRWLock(&rwlock->srw);
return (SDL_rwlock *)rwlock;
}
static void SDL_DestroyRWLock_srw(SDL_rwlock *_rwlock)
{
SDL_rwlock_srw *rwlock = (SDL_rwlock_srw *) _rwlock;
if (rwlock) {
/* There are no kernel allocated resources */
SDL_free(rwlock);
}
}
static int SDL_LockRWLockForReading_srw(SDL_rwlock *_rwlock) SDL_NO_THREAD_SAFETY_ANALYSIS /* clang doesn't know about NULL mutexes */
{
SDL_rwlock_srw *rwlock = (SDL_rwlock_srw *) _rwlock;
if (rwlock == NULL) {
return SDL_InvalidParamError("rwlock");
}
pAcquireSRWLockShared(&rwlock->srw);
return 0;
}
static int SDL_LockRWLockForWriting_srw(SDL_rwlock *_rwlock) SDL_NO_THREAD_SAFETY_ANALYSIS /* clang doesn't know about NULL mutexes */
{
SDL_rwlock_srw *rwlock = (SDL_rwlock_srw *) _rwlock;
if (rwlock == NULL) {
return SDL_InvalidParamError("rwlock");
}
pAcquireSRWLockExclusive(&rwlock->srw);
rwlock->write_owner = SDL_ThreadID();
return 0;
}
static int SDL_TryLockRWLockForReading_srw(SDL_rwlock *_rwlock)
{
SDL_rwlock_srw *rwlock = (SDL_rwlock_srw *) _rwlock;
int retval = 0;
if (rwlock == NULL) {
retval = SDL_InvalidParamError("rwlock");
} else {
retval = pTryAcquireSRWLockShared(&rwlock->srw) ? 0 : SDL_RWLOCK_TIMEDOUT;
}
return retval;
}
static int SDL_TryLockRWLockForWriting_srw(SDL_rwlock *_rwlock)
{
SDL_rwlock_srw *rwlock = (SDL_rwlock_srw *) _rwlock;
int retval = 0;
if (rwlock == NULL) {
retval = SDL_InvalidParamError("rwlock");
} else {
retval = pTryAcquireSRWLockExclusive(&rwlock->srw) ? 0 : SDL_RWLOCK_TIMEDOUT;
}
return retval;
}
static int SDL_UnlockRWLock_srw(SDL_rwlock *_rwlock) SDL_NO_THREAD_SAFETY_ANALYSIS /* clang doesn't know about NULL mutexes */
{
SDL_rwlock_srw *rwlock = (SDL_rwlock_srw *) _rwlock;
if (rwlock == NULL) {
return SDL_InvalidParamError("rwlock");
} else if (rwlock->write_owner == SDL_ThreadID()) {
rwlock->write_owner = 0;
pReleaseSRWLockExclusive(&rwlock->srw);
} else {
pReleaseSRWLockShared(&rwlock->srw);
}
return 0;
}
static const SDL_rwlock_impl_t SDL_rwlock_impl_srw = {
&SDL_CreateRWLock_srw,
&SDL_DestroyRWLock_srw,
&SDL_LockRWLockForReading_srw,
&SDL_LockRWLockForWriting_srw,
&SDL_TryLockRWLockForReading_srw,
&SDL_TryLockRWLockForWriting_srw,
&SDL_UnlockRWLock_srw
};
#ifndef __WINRT__
#include "../generic/SDL_sysrwlock_c.h"
/* Generic rwlock implementation using SDL_mutex, SDL_cond, and SDL_AtomicInt */
static const SDL_rwlock_impl_t SDL_rwlock_impl_generic = {
&SDL_CreateRWLock_generic,
&SDL_DestroyRWLock_generic,
&SDL_LockRWLockForReading_generic,
&SDL_LockRWLockForWriting_generic,
&SDL_TryLockRWLockForReading_generic,
&SDL_TryLockRWLockForWriting_generic,
&SDL_UnlockRWLock_generic
};
#endif
SDL_rwlock *SDL_CreateRWLock(void)
{
if (SDL_rwlock_impl_active.Create == NULL) {
const SDL_rwlock_impl_t *impl;
#ifdef __WINRT__
/* Link statically on this platform */
impl = &SDL_rwlock_impl_srw;
#else
/* Default to generic implementation, works with all mutex implementations */
impl = &SDL_rwlock_impl_generic;
{
HMODULE kernel32 = GetModuleHandle(TEXT("kernel32.dll"));
if (kernel32) {
SDL_bool okay = SDL_TRUE;
#define LOOKUP_SRW_SYM(sym) if (okay) { if ((p##sym = (pfn##sym)GetProcAddress(kernel32, #sym)) == NULL) { okay = SDL_FALSE; } }
LOOKUP_SRW_SYM(InitializeSRWLock);
LOOKUP_SRW_SYM(ReleaseSRWLockShared);
LOOKUP_SRW_SYM(AcquireSRWLockShared);
LOOKUP_SRW_SYM(TryAcquireSRWLockShared);
LOOKUP_SRW_SYM(ReleaseSRWLockExclusive);
LOOKUP_SRW_SYM(AcquireSRWLockExclusive);
LOOKUP_SRW_SYM(TryAcquireSRWLockExclusive);
#undef LOOKUP_SRW_SYM
if (okay) {
impl = &SDL_rwlock_impl_srw; /* Use the Windows provided API instead of generic fallback */
}
}
}
#endif
SDL_copyp(&SDL_rwlock_impl_active, impl);
}
return SDL_rwlock_impl_active.Create();
}
void SDL_DestroyRWLock(SDL_rwlock *rwlock)
{
SDL_rwlock_impl_active.Destroy(rwlock);
}
int SDL_LockRWLockForReading(SDL_rwlock *rwlock) SDL_NO_THREAD_SAFETY_ANALYSIS /* clang doesn't know about NULL mutexes */
{
return SDL_rwlock_impl_active.LockForReading(rwlock);
}
int SDL_LockRWLockForWriting(SDL_rwlock *rwlock) SDL_NO_THREAD_SAFETY_ANALYSIS /* clang doesn't know about NULL mutexes */
{
return SDL_rwlock_impl_active.LockForWriting(rwlock);
}
int SDL_TryLockRWLockForReading(SDL_rwlock *rwlock)
{
return SDL_rwlock_impl_active.TryLockForReading(rwlock);
}
int SDL_TryLockRWLockForWriting(SDL_rwlock *rwlock)
{
return SDL_rwlock_impl_active.TryLockForWriting(rwlock);
}
int SDL_UnlockRWLock(SDL_rwlock *rwlock) SDL_NO_THREAD_SAFETY_ANALYSIS /* clang doesn't know about NULL mutexes */
{
return SDL_rwlock_impl_active.Unlock(rwlock);
}