#include "SDL_internal.h"
#include "../generic/SDL_syscond_c.h"
#ifndef SDL_THREAD_GENERIC_COND_SUFFIX
#define SDL_CreateCondition_generic SDL_CreateCondition
#define SDL_DestroyCondition_generic SDL_DestroyCondition
#define SDL_SignalCondition_generic SDL_SignalCondition
#define SDL_BroadcastCondition_generic SDL_BroadcastCondition
#endif
typedef struct SDL_cond_generic
{
SDL_Semaphore *sem;
SDL_Semaphore *handshake_sem;
SDL_Semaphore *signal_sem;
int num_waiting;
int num_signals;
} SDL_cond_generic;
SDL_Condition *SDL_CreateCondition_generic(void)
{
SDL_cond_generic *cond = (SDL_cond_generic *)SDL_calloc(1, sizeof(*cond));
#ifndef SDL_THREADS_DISABLED
if (cond) {
cond->sem = SDL_CreateSemaphore(0);
cond->handshake_sem = SDL_CreateSemaphore(0);
cond->signal_sem = SDL_CreateSemaphore(1);
if (!cond->sem || !cond->handshake_sem || !cond->signal_sem) {
SDL_DestroyCondition_generic((SDL_Condition *)cond);
cond = NULL;
}
}
#endif
return (SDL_Condition *)cond;
}
void SDL_DestroyCondition_generic(SDL_Condition *_cond)
{
SDL_cond_generic *cond = (SDL_cond_generic *)_cond;
if (cond) {
if (cond->sem) {
SDL_DestroySemaphore(cond->sem);
}
if (cond->handshake_sem) {
SDL_DestroySemaphore(cond->handshake_sem);
}
if (cond->signal_sem) {
SDL_DestroySemaphore(cond->signal_sem);
}
SDL_free(cond);
}
}
void SDL_SignalCondition_generic(SDL_Condition *_cond)
{
SDL_cond_generic *cond = (SDL_cond_generic *)_cond;
if (!cond) {
return;
}
#ifndef SDL_THREADS_DISABLED
SDL_WaitSemaphore(cond->signal_sem);
if (cond->num_waiting > cond->num_signals) {
cond->num_signals++;
SDL_SignalSemaphore(cond->sem);
SDL_SignalSemaphore(cond->signal_sem);
SDL_WaitSemaphore(cond->handshake_sem);
} else {
SDL_SignalSemaphore(cond->signal_sem);
}
#endif
}
void SDL_BroadcastCondition_generic(SDL_Condition *_cond)
{
SDL_cond_generic *cond = (SDL_cond_generic *)_cond;
if (!cond) {
return;
}
#ifndef SDL_THREADS_DISABLED
SDL_WaitSemaphore(cond->signal_sem);
if (cond->num_waiting > cond->num_signals) {
const int num_waiting = (cond->num_waiting - cond->num_signals);
cond->num_signals = cond->num_waiting;
for (int i = 0; i < num_waiting; i++) {
SDL_SignalSemaphore(cond->sem);
}
SDL_SignalSemaphore(cond->signal_sem);
for (int i = 0; i < num_waiting; i++) {
SDL_WaitSemaphore(cond->handshake_sem);
}
} else {
SDL_SignalSemaphore(cond->signal_sem);
}
#endif
}
bool SDL_WaitConditionTimeoutNS_generic(SDL_Condition *_cond, SDL_Mutex *mutex, Sint64 timeoutNS)
{
SDL_cond_generic *cond = (SDL_cond_generic *)_cond;
bool result = true;
if (!cond || !mutex) {
return true;
}
#ifndef SDL_THREADS_DISABLED
SDL_WaitSemaphore(cond->signal_sem);
cond->num_waiting++;
SDL_SignalSemaphore(cond->signal_sem);
SDL_UnlockMutex(mutex);
result = SDL_WaitSemaphoreTimeoutNS(cond->sem, timeoutNS);
SDL_WaitSemaphore(cond->signal_sem);
if (cond->num_signals > 0) {
SDL_SignalSemaphore(cond->handshake_sem);
cond->num_signals--;
}
cond->num_waiting--;
SDL_SignalSemaphore(cond->signal_sem);
SDL_LockMutex(mutex);
#endif
return result;
}
#ifndef SDL_THREAD_GENERIC_COND_SUFFIX
bool SDL_WaitConditionTimeoutNS(SDL_Condition *cond, SDL_Mutex *mutex, Sint64 timeoutNS)
{
return SDL_WaitConditionTimeoutNS_generic(cond, mutex, timeoutNS);
}
#endif