#include "../../SDL_internal.h"
#include <errno.h>
#include <pthread.h>
#include "SDL_thread.h"
#if !SDL_THREAD_PTHREAD_RECURSIVE_MUTEX && \
!SDL_THREAD_PTHREAD_RECURSIVE_MUTEX_NP
#define FAKE_RECURSIVE_MUTEX 1
#endif
struct SDL_mutex
{
pthread_mutex_t id;
#if FAKE_RECURSIVE_MUTEX
int recursive;
pthread_t owner;
#endif
};
SDL_mutex *
SDL_CreateMutex(void)
{
SDL_mutex *mutex;
pthread_mutexattr_t attr;
mutex = (SDL_mutex *) SDL_calloc(1, sizeof(*mutex));
if (mutex) {
pthread_mutexattr_init(&attr);
#if SDL_THREAD_PTHREAD_RECURSIVE_MUTEX
pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
#elif SDL_THREAD_PTHREAD_RECURSIVE_MUTEX_NP
pthread_mutexattr_setkind_np(&attr, PTHREAD_MUTEX_RECURSIVE_NP);
#else
#endif
if (pthread_mutex_init(&mutex->id, &attr) != 0) {
SDL_SetError("pthread_mutex_init() failed");
SDL_free(mutex);
mutex = NULL;
}
} else {
SDL_OutOfMemory();
}
return (mutex);
}
void
SDL_DestroyMutex(SDL_mutex * mutex)
{
if (mutex) {
pthread_mutex_destroy(&mutex->id);
SDL_free(mutex);
}
}
int
SDL_LockMutex(SDL_mutex * mutex)
{
#if FAKE_RECURSIVE_MUTEX
pthread_t this_thread;
#endif
if (mutex == NULL) {
return SDL_InvalidParamError("mutex");
}
#if FAKE_RECURSIVE_MUTEX
this_thread = pthread_self();
if (mutex->owner == this_thread) {
++mutex->recursive;
} else {
if (pthread_mutex_lock(&mutex->id) == 0) {
mutex->owner = this_thread;
mutex->recursive = 0;
} else {
return SDL_SetError("pthread_mutex_lock() failed");
}
}
#else
if (pthread_mutex_lock(&mutex->id) != 0) {
return SDL_SetError("pthread_mutex_lock() failed");
}
#endif
return 0;
}
int
SDL_TryLockMutex(SDL_mutex * mutex)
{
int retval;
int result;
#if FAKE_RECURSIVE_MUTEX
pthread_t this_thread;
#endif
if (mutex == NULL) {
return SDL_InvalidParamError("mutex");
}
retval = 0;
#if FAKE_RECURSIVE_MUTEX
this_thread = pthread_self();
if (mutex->owner == this_thread) {
++mutex->recursive;
} else {
result = pthread_mutex_trylock(&mutex->id);
if (result == 0) {
mutex->owner = this_thread;
mutex->recursive = 0;
} else if (result == EBUSY) {
retval = SDL_MUTEX_TIMEDOUT;
} else {
retval = SDL_SetError("pthread_mutex_trylock() failed");
}
}
#else
result = pthread_mutex_trylock(&mutex->id);
if (result != 0) {
if (result == EBUSY) {
retval = SDL_MUTEX_TIMEDOUT;
} else {
retval = SDL_SetError("pthread_mutex_trylock() failed");
}
}
#endif
return retval;
}
int
SDL_UnlockMutex(SDL_mutex * mutex)
{
if (mutex == NULL) {
return SDL_InvalidParamError("mutex");
}
#if FAKE_RECURSIVE_MUTEX
if (pthread_self() == mutex->owner) {
if (mutex->recursive) {
--mutex->recursive;
} else {
mutex->owner = 0;
pthread_mutex_unlock(&mutex->id);
}
} else {
return SDL_SetError("mutex not owned by this thread");
}
#else
if (pthread_mutex_unlock(&mutex->id) != 0) {
return SDL_SetError("pthread_mutex_unlock() failed");
}
#endif
return 0;
}