mirror of
https://github.com/openmoh/openmohaa.git
synced 2025-04-28 21:57:57 +03:00
213 lines
5.7 KiB
C
213 lines
5.7 KiB
C
//
|
|
// Mac OSX Threading Support (pthreads)
|
|
// *same as Linux*
|
|
//
|
|
// NOTE: when implementing this make sure the "-lpthread" compiler option is used
|
|
//
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
#include "../gsPlatformUtil.h"
|
|
#include "../gsPlatformThread.h"
|
|
#include "../gsAssert.h"
|
|
#include "../gsDebug.h"
|
|
#include <pthread.h>
|
|
|
|
#define _REENTRANT
|
|
|
|
#define PTHREAD_NO_ERROR 0
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// These functions are unsupported in the current version of the SDK
|
|
|
|
gsi_u32 gsiInterlockedIncrement(gsi_u32 * value)
|
|
{
|
|
GS_ASSERT_STR(gsi_false, "gsiInterlockIncrement is unsupported for Mac OSX in the current version of the SDK\n");
|
|
return 1;
|
|
}
|
|
|
|
gsi_u32 gsiInterlockedDecrement(gsi_u32 * value)
|
|
{
|
|
GS_ASSERT_STR(gsi_false, "gsiInterlockIncrement is unsupported for Mac OSX in the current version of the SDK\n");
|
|
return 1;
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
int gsiStartThread(GSThreadFunc func, gsi_u32 theStackSize, void *arg, GSIThreadID * id)
|
|
{
|
|
pthread_attr_init(&id->attr);
|
|
pthread_attr_setstacksize(&id->attr, theStackSize);
|
|
|
|
if (pthread_create(&id->thread, &id->attr, (void *)func, arg) != PTHREAD_NO_ERROR)
|
|
{
|
|
gsDebugFormat(GSIDebugCat_Common, GSIDebugType_Misc, GSIDebugLevel_WarmError,
|
|
"Failed to create thread\r\n");
|
|
return -1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
void gsiCancelThread(GSIThreadID id)
|
|
{
|
|
//should i destroy the attributes here?
|
|
pthread_attr_destroy(&id.attr);
|
|
|
|
if (pthread_cancel(id.thread) != PTHREAD_NO_ERROR) {
|
|
//there was an error - how should we handle these? or should we?
|
|
gsDebugFormat(GSIDebugCat_Common, GSIDebugType_Misc, GSIDebugLevel_WarmError,
|
|
"Failed to cancel thread\r\n");
|
|
}
|
|
//free up memory and set to NULL
|
|
|
|
gsifree(&id.thread);
|
|
}
|
|
|
|
// This must be called from INSIDE the thread you wish to exit
|
|
void gsiExitThread(GSIThreadID id)
|
|
{
|
|
// detach the thread so that it knows to free resources upon exit
|
|
pthread_detach(id.thread);
|
|
|
|
// exit thread to free up resources
|
|
pthread_exit(NULL);
|
|
}
|
|
|
|
void gsiCleanupThread(GSIThreadID id)
|
|
{
|
|
// destroy any leftover attributes associated with the thread
|
|
pthread_attr_destroy(&id.attr);
|
|
}
|
|
|
|
gsi_u32 gsiHasThreadShutdown(GSIThreadID id)
|
|
{
|
|
// pthreads lacks detection mechanism for this
|
|
GSI_UNUSED(id);
|
|
return 1;
|
|
}
|
|
|
|
void gsiInitializeCriticalSection(GSICriticalSection *theCrit)
|
|
{
|
|
if (pthread_mutex_init(theCrit, NULL) != PTHREAD_NO_ERROR)
|
|
{
|
|
gsDebugFormat(GSIDebugCat_Common, GSIDebugType_Misc, GSIDebugLevel_WarmError,
|
|
"Failed to initialize critical section\r\n");
|
|
}
|
|
}
|
|
|
|
void gsiEnterCriticalSection(GSICriticalSection *theCrit)
|
|
{
|
|
if (pthread_mutex_lock(theCrit) != PTHREAD_NO_ERROR)
|
|
{
|
|
gsDebugFormat(GSIDebugCat_Common, GSIDebugType_Misc, GSIDebugLevel_WarmError,
|
|
"Failed to lock mutex for entering critical section\r\n");
|
|
}
|
|
}
|
|
|
|
void gsiLeaveCriticalSection(GSICriticalSection *theCrit)
|
|
{
|
|
if (pthread_mutex_unlock(theCrit) != PTHREAD_NO_ERROR)
|
|
{
|
|
gsDebugFormat(GSIDebugCat_Common, GSIDebugType_Misc, GSIDebugLevel_WarmError,
|
|
"Failed to unlock mutex for leaving critical section\r\n");
|
|
}
|
|
}
|
|
|
|
void gsiDeleteCriticalSection(GSICriticalSection *theCrit)
|
|
{
|
|
if (pthread_mutex_destroy(theCrit) != PTHREAD_NO_ERROR)
|
|
{
|
|
gsDebugFormat(GSIDebugCat_Common, GSIDebugType_Misc, GSIDebugLevel_WarmError,
|
|
"Failed to destroy mutex\r\n");
|
|
}
|
|
theCrit = NULL;
|
|
}
|
|
|
|
GSISemaphoreID gsiCreateSemaphore(gsi_i32 theInitialCount, gsi_i32 theMaxCount, char* theName)
|
|
{
|
|
int result;
|
|
GSISemaphoreID semaphore;
|
|
|
|
//we can use the default attributes for the mutex by passing NULL
|
|
result = pthread_mutex_init(&semaphore.mLock, NULL);
|
|
|
|
if (result != PTHREAD_NO_ERROR)
|
|
{
|
|
gsDebugFormat(GSIDebugCat_Common, GSIDebugType_Misc, GSIDebugLevel_WarmError,
|
|
"Failed to create semaphore\r\n");
|
|
}
|
|
|
|
semaphore.mValue = theInitialCount;
|
|
semaphore.mMax = theMaxCount;
|
|
|
|
GSI_UNUSED(theName);
|
|
return semaphore;
|
|
}
|
|
|
|
// Waits for -- and signals -- the semaphore
|
|
gsi_u32 gsiWaitForSemaphore(GSISemaphoreID theSemaphore, gsi_u32 theTimeoutMs)
|
|
{
|
|
gsi_time startTime = current_time();
|
|
gsi_bool infinite = (theTimeoutMs == GSI_INFINITE)?gsi_true:gsi_false;
|
|
|
|
do
|
|
{
|
|
//try to lock, if it doesn't then its busy
|
|
if(pthread_mutex_trylock(&theSemaphore.mLock) == PTHREAD_NO_ERROR)
|
|
{
|
|
if(theSemaphore.mValue > 0)
|
|
{
|
|
theSemaphore.mValue--;
|
|
pthread_mutex_unlock(&theSemaphore.mLock);
|
|
return 1;
|
|
}
|
|
|
|
pthread_mutex_unlock(&theSemaphore.mLock);
|
|
}
|
|
|
|
if(theTimeoutMs != 0)
|
|
msleep(2);
|
|
|
|
} while(gsi_is_true(infinite) || ((current_time() - startTime) < theTimeoutMs));
|
|
|
|
return 0;
|
|
}
|
|
|
|
// Allow other objects to access the semaphore
|
|
void gsiReleaseSemaphore(GSISemaphoreID theSemaphore, gsi_i32 theReleaseCount)
|
|
{
|
|
if(pthread_mutex_trylock(&theSemaphore.mLock) != PTHREAD_NO_ERROR)
|
|
{
|
|
gsDebugFormat(GSIDebugCat_Common, GSIDebugType_Misc, GSIDebugLevel_WarmError,
|
|
"Failed to lock semaphore\r\n");
|
|
|
|
GSI_UNUSED(theReleaseCount);
|
|
}
|
|
else
|
|
{
|
|
theSemaphore.mValue += theReleaseCount;
|
|
if(theSemaphore.mValue > theSemaphore.mMax)
|
|
theSemaphore.mValue = theSemaphore.mMax;
|
|
|
|
pthread_mutex_unlock(&theSemaphore.mLock);
|
|
}
|
|
}
|
|
|
|
void gsiCloseSemaphore(GSISemaphoreID theSemaphore)
|
|
{
|
|
if (pthread_mutex_destroy(&theSemaphore.mLock) != PTHREAD_NO_ERROR)
|
|
{
|
|
gsDebugFormat(GSIDebugCat_Common, GSIDebugType_Misc, GSIDebugLevel_WarmError,
|
|
"Failed to destroy semaphore\r\n");
|
|
GSI_UNUSED(theSemaphore);
|
|
}
|
|
|
|
//need to free up memory
|
|
gsifree(&theSemaphore.mValue);
|
|
gsifree(&theSemaphore.mMax);
|
|
gsifree(&theSemaphore);
|
|
}
|
|
|
|
|