#include "../../SDL_internal.h"
#include "SDL_thread.h"
#include "../generic/SDL_syscond_c.h"
#if !SDL_THREAD_GENERIC_COND_SUFFIX
#define SDL_CreateCond_generic SDL_CreateCond
#define SDL_DestroyCond_generic SDL_DestroyCond
#define SDL_CondSignal_generic SDL_CondSignal
#define SDL_CondBroadcast_generic SDL_CondBroadcast
#define SDL_CondWait_generic SDL_CondWait
#define SDL_CondWaitTimeout_generic SDL_CondWaitTimeout
#endif
typedef struct SDL_cond_generic
{
SDL_mutex *lock;
int waiting;
int signals;
SDL_sem *wait_sem;
SDL_sem *wait_done;
} SDL_cond_generic;
SDL_cond *
SDL_CreateCond_generic(void)
{
SDL_cond_generic *cond;
cond = (SDL_cond_generic *) SDL_malloc(sizeof(SDL_cond_generic));
if (cond) {
cond->lock = SDL_CreateMutex();
cond->wait_sem = SDL_CreateSemaphore(0);
cond->wait_done = SDL_CreateSemaphore(0);
cond->waiting = cond->signals = 0;
if (!cond->lock || !cond->wait_sem || !cond->wait_done) {
SDL_DestroyCond_generic((SDL_cond *)cond);
cond = NULL;
}
} else {
SDL_OutOfMemory();
}
return (SDL_cond *)cond;
}
void
SDL_DestroyCond_generic(SDL_cond * _cond)
{
SDL_cond_generic *cond = (SDL_cond_generic *)_cond;
if (cond) {
if (cond->wait_sem) {
SDL_DestroySemaphore(cond->wait_sem);
}
if (cond->wait_done) {
SDL_DestroySemaphore(cond->wait_done);
}
if (cond->lock) {
SDL_DestroyMutex(cond->lock);
}
SDL_free(cond);
}
}
int
SDL_CondSignal_generic(SDL_cond * _cond)
{
SDL_cond_generic *cond = (SDL_cond_generic *)_cond;
if (!cond) {
return SDL_InvalidParamError("cond");
}
SDL_LockMutex(cond->lock);
if (cond->waiting > cond->signals) {
++cond->signals;
SDL_SemPost(cond->wait_sem);
SDL_UnlockMutex(cond->lock);
SDL_SemWait(cond->wait_done);
} else {
SDL_UnlockMutex(cond->lock);
}
return 0;
}
int
SDL_CondBroadcast_generic(SDL_cond * _cond)
{
SDL_cond_generic *cond = (SDL_cond_generic *)_cond;
if (!cond) {
return SDL_InvalidParamError("cond");
}
SDL_LockMutex(cond->lock);
if (cond->waiting > cond->signals) {
int i, num_waiting;
num_waiting = (cond->waiting - cond->signals);
cond->signals = cond->waiting;
for (i = 0; i < num_waiting; ++i) {
SDL_SemPost(cond->wait_sem);
}
SDL_UnlockMutex(cond->lock);
for (i = 0; i < num_waiting; ++i) {
SDL_SemWait(cond->wait_done);
}
} else {
SDL_UnlockMutex(cond->lock);
}
return 0;
}
int
SDL_CondWaitTimeout_generic(SDL_cond * _cond, SDL_mutex * mutex, Uint32 ms)
{
SDL_cond_generic *cond = (SDL_cond_generic *)_cond;
int retval;
if (!cond) {
return SDL_InvalidParamError("cond");
}
SDL_LockMutex(cond->lock);
++cond->waiting;
SDL_UnlockMutex(cond->lock);
SDL_UnlockMutex(mutex);
if (ms == SDL_MUTEX_MAXWAIT) {
retval = SDL_SemWait(cond->wait_sem);
} else {
retval = SDL_SemWaitTimeout(cond->wait_sem, ms);
}
SDL_LockMutex(cond->lock);
if (cond->signals > 0) {
if (retval > 0) {
SDL_SemWait(cond->wait_sem);
}
SDL_SemPost(cond->wait_done);
--cond->signals;
}
--cond->waiting;
SDL_UnlockMutex(cond->lock);
SDL_LockMutex(mutex);
return retval;
}
int
SDL_CondWait_generic(SDL_cond * cond, SDL_mutex * mutex)
{
return SDL_CondWaitTimeout_generic(cond, mutex, SDL_MUTEX_MAXWAIT);
}