#include "../../SDL_internal.h"
#include <errno.h>
#include <pthread.h>
#include <semaphore.h>
#include <sys/time.h>
#include <time.h>
#include "SDL_thread.h"
#include "SDL_timer.h"
#if defined(__MACOSX__) || defined(__IPHONEOS__)
#include "../generic/SDL_syssem.c"
#else
struct SDL_semaphore
{
sem_t sem;
};
SDL_sem *
SDL_CreateSemaphore(Uint32 initial_value)
{
SDL_sem *sem = (SDL_sem *) SDL_malloc(sizeof(SDL_sem));
if (sem) {
if (sem_init(&sem->sem, 0, initial_value) < 0) {
SDL_SetError("sem_init() failed");
SDL_free(sem);
sem = NULL;
}
} else {
SDL_OutOfMemory();
}
return sem;
}
void
SDL_DestroySemaphore(SDL_sem * sem)
{
if (sem) {
sem_destroy(&sem->sem);
SDL_free(sem);
}
}
int
SDL_SemTryWait(SDL_sem * sem)
{
int retval;
if (!sem) {
return SDL_InvalidParamError("sem");
}
retval = SDL_MUTEX_TIMEDOUT;
if (sem_trywait(&sem->sem) == 0) {
retval = 0;
}
return retval;
}
int
SDL_SemWait(SDL_sem * sem)
{
int retval;
if (!sem) {
return SDL_InvalidParamError("sem");
}
do {
retval = sem_wait(&sem->sem);
} while (retval < 0 && errno == EINTR);
if (retval < 0) {
retval = SDL_SetError("sem_wait() failed");
}
return retval;
}
int
SDL_SemWaitTimeout(SDL_sem * sem, Uint32 timeout)
{
int retval;
#ifdef HAVE_SEM_TIMEDWAIT
#ifndef HAVE_CLOCK_GETTIME
struct timeval now;
#endif
struct timespec ts_timeout;
#else
Uint32 end;
#endif
if (!sem) {
return SDL_InvalidParamError("sem");
}
if (timeout == 0) {
return SDL_SemTryWait(sem);
}
if (timeout == SDL_MUTEX_MAXWAIT) {
return SDL_SemWait(sem);
}
#ifdef HAVE_SEM_TIMEDWAIT
#ifdef HAVE_CLOCK_GETTIME
clock_gettime(CLOCK_REALTIME, &ts_timeout);
ts_timeout.tv_nsec += (timeout % 1000) * 1000000;
ts_timeout.tv_sec += timeout / 1000;
#else
gettimeofday(&now, NULL);
ts_timeout.tv_sec = now.tv_sec + (timeout / 1000);
ts_timeout.tv_nsec = (now.tv_usec + (timeout % 1000) * 1000) * 1000;
#endif
if (ts_timeout.tv_nsec > 1000000000) {
ts_timeout.tv_sec += 1;
ts_timeout.tv_nsec -= 1000000000;
}
do {
retval = sem_timedwait(&sem->sem, &ts_timeout);
} while (retval < 0 && errno == EINTR);
if (retval < 0) {
if (errno == ETIMEDOUT) {
retval = SDL_MUTEX_TIMEDOUT;
} else {
SDL_SetError("sem_timedwait returned an error: %s", strerror(errno));
}
}
#else
end = SDL_GetTicks() + timeout;
while ((retval = SDL_SemTryWait(sem)) == SDL_MUTEX_TIMEDOUT) {
if (SDL_TICKS_PASSED(SDL_GetTicks(), end)) {
break;
}
SDL_Delay(1);
}
#endif
return retval;
}
Uint32
SDL_SemValue(SDL_sem * sem)
{
int ret = 0;
if (sem) {
sem_getvalue(&sem->sem, &ret);
if (ret < 0) {
ret = 0;
}
}
return (Uint32) ret;
}
int
SDL_SemPost(SDL_sem * sem)
{
int retval;
if (!sem) {
return SDL_InvalidParamError("sem");
}
retval = sem_post(&sem->sem);
if (retval < 0) {
SDL_SetError("sem_post() failed");
}
return retval;
}
#endif