mirror of
https://github.com/openmoh/openmohaa.git
synced 2025-04-28 21:57:57 +03:00
204 lines
No EOL
4.6 KiB
C
204 lines
No EOL
4.6 KiB
C
///////////////////////////////////////////////////////////////////////////////
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
#include "../gscommon.h"
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
gsi_u32 gsiInterlockedIncrement(gsi_u32 * value)
|
|
{
|
|
int interrupt = DI();
|
|
int ret = ++(*value);
|
|
if (interrupt)
|
|
EI();
|
|
|
|
// return "ret" rather than "value" here b/c
|
|
// value may be modified by another thread
|
|
// before we can return it
|
|
return ret;
|
|
}
|
|
|
|
gsi_u32 gsiInterlockedDecrement(gsi_u32 * value)
|
|
{
|
|
int interrupt = DI();
|
|
int ret = --(*value);
|
|
if (interrupt)
|
|
EI();
|
|
|
|
// return "ret" rather than "value" here b/c
|
|
// value may be modified by another thread
|
|
// before we can return it
|
|
return ret;
|
|
}
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
void gsiInitializeCriticalSection(GSICriticalSection *theCrit)
|
|
{
|
|
theCrit->mSemaphore = gsiCreateSemaphore(1, 1, NULL);
|
|
theCrit->mOwnerThread = 0;
|
|
theCrit->mEntryCount = 0;
|
|
}
|
|
void gsiEnterCriticalSection(GSICriticalSection *theCrit)
|
|
{
|
|
// If we're not already in it, wait for it
|
|
if (GetThreadId() != theCrit->mOwnerThread)
|
|
{
|
|
gsiWaitForSemaphore(theCrit->mSemaphore, 0);
|
|
theCrit->mOwnerThread = GetThreadId();
|
|
}
|
|
|
|
// Increment entry count
|
|
theCrit->mEntryCount++;
|
|
}
|
|
void gsiLeaveCriticalSection(GSICriticalSection *theCrit)
|
|
{
|
|
// We must be the owner? (assert?)
|
|
if (GetThreadId() != theCrit->mOwnerThread)
|
|
{
|
|
assert(GetThreadId() == theCrit->mOwnerThread);
|
|
return;
|
|
}
|
|
|
|
// Release semaphore
|
|
theCrit->mEntryCount--;
|
|
if (theCrit->mEntryCount == 0)
|
|
{
|
|
theCrit->mOwnerThread = 0;
|
|
gsiReleaseSemaphore(theCrit->mSemaphore, 1);
|
|
}
|
|
}
|
|
|
|
void gsiDeleteCriticalSection(GSICriticalSection *theCrit)
|
|
{
|
|
gsiCloseSemaphore(theCrit->mSemaphore);
|
|
}
|
|
|
|
gsi_u32 gsiHasThreadShutdown(GSIThreadID theThreadID)
|
|
{
|
|
struct ThreadParam aStatus;
|
|
ReferThreadStatus(theThreadID, &aStatus);
|
|
if (aStatus.status == THS_DORMANT)
|
|
return 1; // dead
|
|
else
|
|
return 0; // still kicking;
|
|
}
|
|
|
|
GSISemaphoreID gsiCreateSemaphore(gsi_i32 theInitialCount, gsi_i32 theMaxCount, char* theName)
|
|
{
|
|
struct SemaParam aParam;
|
|
int aSemaphore = 0;
|
|
|
|
aParam.initCount = theInitialCount;
|
|
aParam.maxCount = theMaxCount;
|
|
|
|
aSemaphore = CreateSema(&aParam);
|
|
if (aSemaphore < 0)
|
|
{
|
|
gsDebugFormat(GSIDebugCat_Common, GSIDebugType_Misc, GSIDebugLevel_WarmError,
|
|
"Failed to create semaphore\r\n");
|
|
}
|
|
|
|
GSI_UNUSED(theName);
|
|
|
|
return aSemaphore;
|
|
}
|
|
|
|
gsi_u32 gsiWaitForSemaphore(GSISemaphoreID theSemaphore, gsi_u32 theTimeoutMs)
|
|
{
|
|
int result = WaitSema(theSemaphore);
|
|
return (gsi_u32)result;
|
|
|
|
GSI_UNUSED(theTimeoutMs);
|
|
}
|
|
|
|
void gsiReleaseSemaphore(GSISemaphoreID theSemaphore, gsi_i32 theReleaseCount)
|
|
{
|
|
while (theReleaseCount-- > 0)
|
|
SignalSema(theSemaphore);
|
|
//ReleaseSemaphore(theSemaphore, theReleaseCount, NULL);
|
|
}
|
|
|
|
void gsiCloseSemaphore(GSISemaphoreID theSemaphore)
|
|
{
|
|
DeleteSema(theSemaphore);
|
|
}
|
|
|
|
int gsiStartThread(GSThreadFunc func, gsi_u32 theStackSize, void *arg, GSIThreadID *id)
|
|
{
|
|
const unsigned int stackSize = theStackSize;
|
|
const int threadPriority = 3;
|
|
struct ThreadParam param;
|
|
void * stack;
|
|
int threadID;
|
|
|
|
// allocate a stack
|
|
stack = gsimemalign(16, stackSize);
|
|
if(!stack)
|
|
return -1;
|
|
|
|
// setup the thread parameters
|
|
param.entry = func;
|
|
param.stack = stack;
|
|
param.stackSize = (int)stackSize;
|
|
param.gpReg = &_gp;
|
|
param.initPriority = threadPriority;
|
|
|
|
// create the thread
|
|
threadID = CreateThread(¶m);
|
|
if(threadID == -1)
|
|
{
|
|
gsifree(stack);
|
|
return -1;
|
|
}
|
|
|
|
// start the thread
|
|
if(StartThread(threadID, arg) == -1)
|
|
{
|
|
DeleteThread(threadID);
|
|
gsifree(stack);
|
|
return -1;
|
|
}
|
|
|
|
// store the id
|
|
*id = threadID;
|
|
|
|
// Note: This was added to prevent PS2 lockups when starting multiple threads
|
|
// The PS2 would block for approx 5 seconds
|
|
msleep(1);
|
|
|
|
return 0;
|
|
}
|
|
|
|
void gsiCancelThread(GSIThreadID id)
|
|
{
|
|
void* aStack = NULL;
|
|
|
|
// get the stack ptr
|
|
struct ThreadParam aThreadParam;
|
|
ReferThreadStatus(id, &aThreadParam);
|
|
aStack = (void*)aThreadParam.stack;
|
|
|
|
// terminate the thread
|
|
TerminateThread(id);
|
|
|
|
// delete the thread
|
|
DeleteThread(id);
|
|
|
|
//free the stack
|
|
gsifree(aStack);
|
|
}
|
|
|
|
// This must be called from INSIDE the thread you wish to exit
|
|
void gsiExitThread(GSIThreadID id)
|
|
{
|
|
// TODO: does PS2 need to explicitly EXIT a thread like win32/linux?
|
|
GSI_UNUSED(id);
|
|
}
|
|
|
|
void gsiCleanupThread(GSIThreadID id)
|
|
{
|
|
// same as cancel (terminates just to be sure)
|
|
gsiCancelThread(id);
|
|
} |