#include "SDL_internal.h"
#include "SDL_systhread_c.h"
#include "../generic/SDL_sysrwlock_c.h"
#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_UnlockRWLock_generic SDL_UnlockRWLock
#endif
struct SDL_RWLock
{
#ifdef SDL_THREADS_DISABLED
int unused;
#else
SDL_Mutex *lock;
SDL_Condition *condition;
SDL_ThreadID writer_thread;
SDL_AtomicInt reader_count;
SDL_AtomicInt writer_count;
#endif
};
SDL_RWLock *SDL_CreateRWLock_generic(void)
{
SDL_RWLock *rwlock = (SDL_RWLock *) SDL_calloc(1, sizeof (*rwlock));
if (!rwlock) {
return NULL;
}
#ifndef SDL_THREADS_DISABLED
rwlock->lock = SDL_CreateMutex();
if (!rwlock->lock) {
SDL_free(rwlock);
return NULL;
}
rwlock->condition = SDL_CreateCondition();
if (!rwlock->condition) {
SDL_DestroyMutex(rwlock->lock);
SDL_free(rwlock);
return NULL;
}
SDL_SetAtomicInt(&rwlock->reader_count, 0);
SDL_SetAtomicInt(&rwlock->writer_count, 0);
#endif
return rwlock;
}
void SDL_DestroyRWLock_generic(SDL_RWLock *rwlock)
{
if (rwlock) {
#ifndef SDL_THREADS_DISABLED
SDL_DestroyMutex(rwlock->lock);
SDL_DestroyCondition(rwlock->condition);
#endif
SDL_free(rwlock);
}
}
void SDL_LockRWLockForReading_generic(SDL_RWLock *rwlock) SDL_NO_THREAD_SAFETY_ANALYSIS {
#ifndef SDL_THREADS_DISABLED
if (rwlock) {
SDL_LockMutex(rwlock->lock);
SDL_assert(SDL_GetAtomicInt(&rwlock->writer_count) == 0); SDL_AddAtomicInt(&rwlock->reader_count, 1);
SDL_UnlockMutex(rwlock->lock); }
#endif
}
void SDL_LockRWLockForWriting_generic(SDL_RWLock *rwlock) SDL_NO_THREAD_SAFETY_ANALYSIS {
#ifndef SDL_THREADS_DISABLED
if (rwlock) {
SDL_LockMutex(rwlock->lock);
while (SDL_GetAtomicInt(&rwlock->reader_count) > 0) { SDL_WaitCondition(rwlock->condition, rwlock->lock); }
SDL_AddAtomicInt(&rwlock->writer_count, 1); }
#endif
}
bool SDL_TryLockRWLockForReading_generic(SDL_RWLock *rwlock)
{
#ifndef SDL_THREADS_DISABLED
if (rwlock) {
if (!SDL_TryLockMutex(rwlock->lock)) {
return false;
}
SDL_assert(SDL_GetAtomicInt(&rwlock->writer_count) == 0); SDL_AddAtomicInt(&rwlock->reader_count, 1);
SDL_UnlockMutex(rwlock->lock); }
#endif
return true;
}
#ifndef SDL_THREAD_GENERIC_RWLOCK_SUFFIX
bool SDL_TryLockRWLockForReading(SDL_RWLock *rwlock)
{
return SDL_TryLockRWLockForReading_generic(rwlock);
}
#endif
bool SDL_TryLockRWLockForWriting_generic(SDL_RWLock *rwlock)
{
#ifndef SDL_THREADS_DISABLED
if (rwlock) {
if (!SDL_TryLockMutex(rwlock->lock)) {
return false;
}
if (SDL_GetAtomicInt(&rwlock->reader_count) > 0) { SDL_UnlockMutex(rwlock->lock);
return false;
}
SDL_AddAtomicInt(&rwlock->writer_count, 1); }
#endif
return true;
}
#ifndef SDL_THREAD_GENERIC_RWLOCK_SUFFIX
bool SDL_TryLockRWLockForWriting(SDL_RWLock *rwlock)
{
return SDL_TryLockRWLockForWriting_generic(rwlock);
}
#endif
void SDL_UnlockRWLock_generic(SDL_RWLock *rwlock) SDL_NO_THREAD_SAFETY_ANALYSIS {
#ifndef SDL_THREADS_DISABLED
if (rwlock) {
SDL_LockMutex(rwlock->lock);
if (SDL_GetAtomicInt(&rwlock->reader_count) > 0) { SDL_AddAtomicInt(&rwlock->reader_count, -1);
SDL_BroadcastCondition(rwlock->condition); } else if (SDL_GetAtomicInt(&rwlock->writer_count) > 0) { SDL_AddAtomicInt(&rwlock->writer_count, -1);
SDL_UnlockMutex(rwlock->lock); }
SDL_UnlockMutex(rwlock->lock);
}
#endif
}