Kawe Mazidjatari b3a68ed095 Add EABase, EAThread and DirtySDK to R5sdk
DirtySDK (EA's Dirty Sockets library) will be used for the LiveAPI implementation, and depends on: EABase, EAThread.
2024-04-05 18:29:03 +02:00

231 lines
6.9 KiB
C++

/*H********************************************************************************/
/*!
\File dirtylib.cpp
\Description
Platform specific support library for network code. Suppplies
simple time, memory, and semaphore functions.
\Copyright
Copyright (c) Electronic Arts 2002-2018. ALL RIGHTS RESERVED.
\Version 01/02/02 (eesponda) Initial C++ version ported to use EAThread
*/
/********************************************************************************H*/
#include "eathread/eathread_mutex.h"
#include "DirtySDK/platform.h"
#include "DirtySDK/dirtysock/dirtymem.h"
#include "DirtySDK/dirtysock/dirtylib.h"
/*** Type Definitions ************************************************************/
// critical section state
struct NetCritPrivT
{
EA::Thread::Mutex Mutex; //!< mutex state, must come first
uint8_t bEnabled; //!< controls if this lock is enabled
uint8_t _pad[3];
int32_t iMemGroup; //!< memory group identifier
void *pMemGroupUserdata; //!< user data passed along with allocation
};
/*** Variables *******************************************************************/
// global critical section
static NetCritPrivT _NetLib_GlobalCrit;
// sets the functions to no-op in this situation
#if defined(DIRTYCODE_LINUX)
extern uint8_t _NetLib_bSingleThreaded;
#else
static uint8_t _NetLib_bSingleThreaded = FALSE;
#endif
/*** Public Functions *************************************************************/
/*F********************************************************************************/
/*!
\Function NetCritInit
\Description
Initialize a critical section for use. Allocates persistant storage
for the lifetime of the critical section if not using the global crit.
\Input *pCrit - critical section marker
\Input *pCritName - name of the critical section
\Output
int32_t - zero=success, negative=failure
\Version 09/26/2017 (eesponda)
*/
/********************************************************************************F*/
int32_t NetCritInit(NetCritT *pCrit, const char *pCritName)
{
return(NetCritInit2(pCrit, pCritName, NETCRIT_OPTION_NONE));
}
/*F********************************************************************************/
/*!
\Function NetCritInit2
\Description
Initialize a critical section for use. Allocates persistant storage
for the lifetime of the critical section if not using the global crit.
\Input *pCrit - critical section marker
\Input *pCritName - name of the critical section
\Input uFlags - NETCRIT_OPTIONS_* flag options to set on the crit
\Output
int32_t - zero=success, negative=failure
\Version 07/24/2018 (eesponda)
*/
/********************************************************************************F*/
int32_t NetCritInit2(NetCritT *pCrit, const char *pCritName, uint32_t uFlags)
{
NetCritPrivT *pPriv;
EA::Thread::MutexParameters Params;
ds_strnzcpy(Params.mName, pCritName, sizeof(Params.mName));
Params.mbIntraProcess = true;
// allocate memory if necessary
if (pCrit != NULL)
{
int32_t iMemGroup;
void *pMemGroupUserdata;
// query memgroup info
DirtyMemGroupQuery(&iMemGroup, &pMemGroupUserdata);
// allocate the memory needed for mutex state
if ((pCrit->pData = (NetCritPrivT *)DirtyMemAlloc(sizeof(*pCrit->pData), DIRTYTHREAD_MEMID, iMemGroup, pMemGroupUserdata)) == NULL)
{
return(-1);
}
ds_memclr(pCrit->pData, sizeof(*pCrit->pData));
pCrit->pData->iMemGroup = iMemGroup;
pCrit->pData->pMemGroupUserdata = pMemGroupUserdata;
}
/* we always clear the single-thread enable option on the global crit. it would be counter productive if it was
enabled when we are in single-threaded mode */
else
{
uFlags &= ~NETCRIT_OPTION_SINGLETHREADENABLE;
}
pPriv = (pCrit ? pCrit->pData : &_NetLib_GlobalCrit);
pPriv->Mutex.Init(&Params);
pPriv->bEnabled = !_NetLib_bSingleThreaded || ((uFlags & NETCRIT_OPTION_SINGLETHREADENABLE) == NETCRIT_OPTION_SINGLETHREADENABLE);
return(0);
}
/*F********************************************************************************/
/*!
\Function NetCritKill
\Description
Release resources and destroy critical section.
\Input *pCrit - critical section marker
\Version 09/26/2017 (eesponda)
*/
/********************************************************************************F*/
void NetCritKill(NetCritT *pCrit)
{
EA::Thread::Mutex *pMutex = (pCrit ? &pCrit->pData->Mutex : &_NetLib_GlobalCrit.Mutex);
pMutex->~Mutex();
// if we are not using the global crit free the memory
if (pCrit != NULL)
{
NetCritPrivT *pPriv = pCrit->pData;
DirtyMemFree(pPriv, DIRTYTHREAD_MEMID, pPriv->iMemGroup, pPriv->pMemGroupUserdata);
pCrit->pData = NULL;
}
}
/*F********************************************************************************/
/*!
\Function NetCritEnter
\Description
Enter a critical section, blocking if needed.
\Input *pCrit - critical section marker
\Version 09/26/2017 (eesponda)
*/
/********************************************************************************F*/
void NetCritEnter(NetCritT *pCrit)
{
NetCritPrivT *pPriv = (pCrit ? pCrit->pData : &_NetLib_GlobalCrit);
if (pPriv->bEnabled)
{
pPriv->Mutex.Lock();
}
}
/*F********************************************************************************/
/*!
\Function NetCritTry
\Description
Attempt to gain access to critical section. Always returns immediately
regadless of access status. A thread that already has access to a critical
section can always receive repeated access to it.
\Input *pCrit - critical section marker
\Output
int32_t - zero=unable to get access, non-zero=access granted
\Version 09/26/2017 (eesponda)
*/
/********************************************************************************F*/
int32_t NetCritTry(NetCritT *pCrit)
{
NetCritPrivT *pPriv = (pCrit ? pCrit->pData : &_NetLib_GlobalCrit);
if (pPriv->bEnabled)
{
return(pPriv->Mutex.Lock(EA::Thread::kTimeoutImmediate) > 0);
}
else
{
return(1);
}
}
/*F********************************************************************************/
/*!
\Function NetCritLeave
\Description
Leave a critical section. Must be called once for every NetCritEnter (or
successful NetCritTry).
\Input *pCrit - critical section marker
\Version 09/26/2017 (eesponda)
*/
/********************************************************************************F*/
void NetCritLeave(NetCritT *pCrit)
{
NetCritPrivT *pPriv = (pCrit ? pCrit->pData : &_NetLib_GlobalCrit);
if (pPriv->bEnabled)
{
pPriv->Mutex.Unlock();
}
}