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

218 lines
6.9 KiB
C++

///////////////////////////////////////////////////////////////////////////////
// Copyright (c) Electronic Arts Inc. All rights reserved.
///////////////////////////////////////////////////////////////////////////////
#include <EABase/eabase.h>
#include "eathread/eathread.h"
#include "eathread/eathread_thread.h"
#include <cstring>
#include <sstream>
#include <type_traits>
namespace EA
{
namespace Thread
{
EA::Thread::AssertionFailureFunction gpAssertionFailureFunction = NULL;
void* gpAssertionFailureContext = NULL;
EATHREADLIB_API ThreadId EA::Thread::GetThreadId()
{
return std::this_thread::get_id();
}
EATHREADLIB_API ThreadId EA::Thread::GetThreadId(EA::Thread::SysThreadId id)
{
EAThreadDynamicData* const pTDD = EA::Thread::FindThreadDynamicData(id);
if(pTDD)
{
return pTDD->mpComp->mThread.get_id();
}
return EA::Thread::kThreadIdInvalid;
}
EATHREADLIB_API SysThreadId EA::Thread::GetSysThreadId(ThreadId threadId)
{
EAThreadDynamicData* tdd = EA::Thread::FindThreadDynamicData(threadId);
if (tdd && tdd->mpComp)
return tdd->mpComp->mThread.native_handle();
ThreadId threadIdCurrent = GetThreadId();
if(threadId == threadIdCurrent)
{
#if defined(EA_PLATFORM_MICROSOFT)
std::thread::id stdId = std::this_thread::get_id();
EAT_COMPILETIME_ASSERT(sizeof(_Thrd_t) == sizeof(std::thread::id));
return ((_Thrd_t&)stdId)._Hnd;
#elif EA_POSIX_THREADS_AVAILABLE && defined(EA_HAVE_DINKUMWARE_CPP_LIBRARY)
std::thread::id stdId = std::this_thread::get_id();
EAT_COMPILETIME_ASSERT(sizeof(_Thrd_t) == sizeof(std::thread::id));
return reinterpret_cast<_Thrd_t>(stdId);
#else
#error Platform not supported yet.
#endif
}
EAT_ASSERT_MSG(false, "Failed to find associated EAThreadDynamicData for this thread.\n");
return SysThreadId();
}
EATHREADLIB_API SysThreadId EA::Thread::GetSysThreadId()
{
// There currently isn't a means to directly get the current SysThreadId, so we do it indirectly:
return GetSysThreadId(std::this_thread::get_id());
}
EATHREADLIB_API ThreadTime EA::Thread::GetThreadTime()
{
using namespace std::chrono;
auto nowMs = duration_cast<milliseconds>(system_clock::now().time_since_epoch());
return nowMs.count();
}
EATHREADLIB_API int GetThreadPriority()
{
// No way to query or set thread priority through standard C++11 thread library.
// On some platforms this could be implemented through platform specific APIs
return kThreadPriorityDefault;
}
EATHREADLIB_API bool SetThreadPriority(int nPriority)
{
// No way to query or set thread priority through standard C++11 thread library.
// On some platforms this could be implemented through platform specific APIs
return false;
}
EATHREADLIB_API void SetThreadProcessor(int nProcessor)
{
// No way to query or set thread processor through standard C++11 thread library.
// On some platforms this could be implemented through platform specific APIs
}
EATHREADLIB_API int GetThreadProcessor()
{
// No way to query or set thread processor through standard C++11 thread library.
// On some platforms this could be implemented through platform specific APIs
return 0;
}
EATHREADLIB_API int GetProcessorCount()
{
return static_cast<int>(std::thread::hardware_concurrency());
}
EATHREADLIB_API void ThreadSleep(const ThreadTime& timeRelative)
{
std::this_thread::sleep_for(std::chrono::milliseconds(timeRelative));
}
void ThreadEnd(intptr_t threadReturnValue)
{
// No way to end a thread through standard C++11 thread library.
// On some platforms this could be implemented through platform specific APIs
EAT_ASSERT_MSG(false, "ThreadEnd is not implemented for C++11 threads.\n");
}
EATHREADLIB_API void EA::Thread::SetThreadAffinityMask(const EA::Thread::ThreadId& id, ThreadAffinityMask nAffinityMask)
{
// Update the affinity mask in the thread dynamic data cache.
EAThreadDynamicData* const pTDD = FindThreadDynamicData(id);
if(pTDD)
{
pTDD->mnThreadAffinityMask = nAffinityMask;
}
#if EATHREAD_THREAD_AFFINITY_MASK_SUPPORTED
// Call the Windows library function.
#endif
}
EATHREADLIB_API EA::Thread::ThreadAffinityMask EA::Thread::GetThreadAffinityMask(const EA::Thread::ThreadId& id)
{
// Update the affinity mask in the thread dynamic data cache.
EAThreadDynamicData* const pTDD = FindThreadDynamicData(id);
if(pTDD)
{
return pTDD->mnThreadAffinityMask;
}
return kThreadAffinityMaskAny;
}
EATHREADLIB_API void SetAssertionFailureFunction(AssertionFailureFunction pAssertionFailureFunction, void* pContext)
{
gpAssertionFailureFunction = pAssertionFailureFunction;
gpAssertionFailureContext = pContext;
}
EATHREADLIB_API void AssertionFailure(const char* pExpression)
{
if(gpAssertionFailureFunction)
gpAssertionFailureFunction(pExpression, gpAssertionFailureContext);
}
void* GetThreadStackBase()
{
return nullptr;
}
// This can be removed once all remaining synchronization primitives are implemented in terms of C++11 APIs
uint32_t EA::Thread::RelativeTimeoutFromAbsoluteTimeout(ThreadTime timeoutAbsolute)
{
EAT_ASSERT((timeoutAbsolute == kTimeoutImmediate) || (timeoutAbsolute > EATHREAD_MIN_ABSOLUTE_TIME)); // Assert that the user didn't make the mistake of treating time as relative instead of absolute.
DWORD timeoutRelative = 0;
if (timeoutAbsolute == kTimeoutNone)
{
timeoutRelative = 0xffffffff;
}
else if (timeoutAbsolute == kTimeoutImmediate)
{
timeoutRelative = 0;
}
else
{
ThreadTime timeCurrent(GetThreadTime());
timeoutRelative = (timeoutAbsolute > timeCurrent) ? static_cast<DWORD>(timeoutAbsolute - timeCurrent) : 0;
}
EAT_ASSERT((timeoutRelative == 0xffffffff) || (timeoutRelative < 100000000)); // Assert that the timeout is a sane value and didn't wrap around.
return timeoutRelative;
}
// Implement native_handle_type comparison as a memcmp() - may need platform specific implementations on some future platforms.
bool Equals(const SysThreadId& a, const SysThreadId& b)
{
static_assert((std::is_fundamental<SysThreadId>::value || std::is_pointer<SysThreadId>::value || std::is_pod<SysThreadId>::value),
"SysThreadId should be comparable using memcmp()");
return memcmp(&a, &b, sizeof(SysThreadId)) == 0;
}
namespace detail
{
// Override the default EAThreadToString implementation
#define EAThreadIdToString_CUSTOM_IMPLEMENTATION
ThreadIdToStringBuffer::ThreadIdToStringBuffer(EA::Thread::ThreadId threadId)
{
std::stringstream formatStream;
formatStream << threadId;
strncpy(mBuf, formatStream.str().c_str(), BufSize - 1);
mBuf[BufSize - 1] = '\0';
}
SysThreadIdToStringBuffer::SysThreadIdToStringBuffer(EA::Thread::SysThreadId sysThreadId)
{
strncpy(mBuf, "Unknown", BufSize - 1);
mBuf[BufSize - 1] = '\0';
}
}
}
}