/////////////////////////////////////////////////////////////////////////////// // Copyright (c) Electronic Arts Inc. All rights reserved. /////////////////////////////////////////////////////////////////////////////// #include #include #include #include namespace EA { namespace Thread { EA::Thread::Allocator* gpAllocator = NULL; EATHREADLIB_API void SetAllocator(Allocator* pEAThreadAllocator) { gpAllocator = pEAThreadAllocator; } EATHREADLIB_API Allocator* GetAllocator() { return gpAllocator; } // Currently we take advantage of the fact that ICoreAllocator // is a binary mapping to EA::Thread::Allocator. // To do: We need to come up with a better solution that this, // as it is not future-safe and not even guaranteed to // be portable. The problem is that we can't make this // package dependent on the CoreAllocator package without // breaking users who aren't using it. EATHREADLIB_API void SetAllocator(EA::Allocator::ICoreAllocator* pCoreAllocator) { gpAllocator = (EA::Thread::Allocator*)(uintptr_t)pCoreAllocator; } EATHREADLIB_API void SetThreadAffinityMask(ThreadAffinityMask nAffinityMask) { EA::Thread::SetThreadAffinityMask(GetThreadId(), nAffinityMask); } EATHREADLIB_API ThreadAffinityMask GetThreadAffinityMask() { return GetThreadAffinityMask(GetThreadId()); } } } #if !EA_THREADS_AVAILABLE // Do nothing #elif EA_USE_CPP11_CONCURRENCY #include "cpp11/eathread_cpp11.cpp" #elif defined(EA_PLATFORM_SONY) #include "sony/eathread_sony.cpp" #elif defined(EA_PLATFORM_UNIX) || EA_POSIX_THREADS_AVAILABLE #include "unix/eathread_unix.cpp" #if defined(EA_PLATFORM_STADIA) #include "unix/eathread_stadia.cpp" #endif #elif defined(EA_PLATFORM_MICROSOFT) #include "pc/eathread_pc.cpp" #endif EA::Thread::ThreadAffinityMask EA::Thread::GetAvailableCpuAffinityMask() { #if defined(EA_PLATFORM_STADIA) return getValidCpuAffinityMask(); #else // We assume that the available cores are 0...ProcessorCount-1. int processorCount = GetProcessorCount(); EA::Thread::ThreadAffinityMask ret = 0; EA::Thread::ThreadAffinityMask mask = 1; while (processorCount > 0) { ret |= mask; mask <<= 1; --processorCount; } return ret; #endif } namespace EA { namespace Thread { namespace detail { #if !defined(EAThreadIdToString_CUSTOM_IMPLEMENTATION) ThreadIdToStringBuffer::ThreadIdToStringBuffer(EA::Thread::ThreadId threadId) { sprintf(mBuf, "%d", (int)(intptr_t)threadId); } SysThreadIdToStringBuffer::SysThreadIdToStringBuffer(EA::Thread::SysThreadId sysThreadId) { sprintf(mBuf, "%d", (int)(intptr_t)sysThreadId); } #endif } } } #if !defined(EAT_ASSERT_SNPRINTF) #if defined(EA_PLATFORM_MICROSOFT) #define EAT_ASSERT_SNPRINTF _vsnprintf #else #define EAT_ASSERT_SNPRINTF snprintf #endif #endif void EA::Thread::AssertionFailureV(const char* pFormat, ...) { const size_t kBufferSize = 512; char buffer[kBufferSize]; va_list arguments; va_start(arguments, pFormat); const int nReturnValue = EAT_ASSERT_SNPRINTF(buffer, kBufferSize, pFormat, arguments); va_end(arguments); if(nReturnValue > 0) { buffer[kBufferSize - 1] = 0; AssertionFailure(buffer); } } /////////////////////////////////////////////////////////////////////////////// // non-threaded implementation /////////////////////////////////////////////////////////////////////////////// #if !EA_THREADS_AVAILABLE #include #if defined(EA_PLATFORM_UNIX) || EA_POSIX_THREADS_AVAILABLE #include #include #elif defined(EA_PLATFORM_WINDOWS) extern "C" __declspec(dllimport) void __stdcall Sleep(unsigned long dwMilliseconds); #endif namespace EA { namespace Thread { // Assertion variables. EA::Thread::AssertionFailureFunction gpAssertionFailureFunction = NULL; void* gpAssertionFailureContext = NULL; } } EA::Thread::ThreadId EA::Thread::GetThreadId() { return 1; } int EA::Thread::GetThreadPriority() { return kThreadPriorityDefault; } bool EA::Thread::SetThreadPriority(int nPriority) { return true; } void* EA::Thread::GetThreadStackBase() { return NULL; } void EA::Thread::SetThreadProcessor(int /*nProcessor*/) { } int EA::Thread::GetThreadProcessor() { return 0; } int EA::Thread::GetProcessorCount() { return 1; } void EA::Thread::ThreadSleep(const ThreadTime& timeRelative) { #if defined(EA_PLATFORM_WINDOWS) // There is no nanosleep on Windows, but there is Sleep. if(timeRelative == kTimeoutImmediate) Sleep(0); else Sleep((unsigned)((timeRelative.tv_sec * 1000) + (((timeRelative.tv_nsec % 1000) * 1000000)))); #elif defined(EA_PLATFORM_UNIX) || EA_POSIX_THREADS_AVAILABLE if(timeRelative == kTimeoutImmediate) sched_yield(); else nanosleep(&timeRelative, 0); #endif } void EA::Thread::ThreadEnd(intptr_t /*threadReturnValue*/) { // We could possibly call exit here. } EA::Thread::ThreadTime EA::Thread::GetThreadTime() { #if defined(EA_PLATFORM_WINDOWS) return (ThreadTime)GetTickCount(); #elif defined(EA_PLATFORM_UNIX) || EA_POSIX_THREADS_AVAILABLE #if defined(EA_PLATFORM_LINUX) || defined(EA_PLATFORM_CYGWIN) || (_POSIX_TIMERS > 0) ThreadTime threadTime; clock_gettime(CLOCK_REALTIME, &threadTime); // If you get a linker error about clock_getttime, you need to link librt.a (specify -lrt to the linker). return threadTime; #else timeval temp; gettimeofday(&temp, NULL); return ThreadTime(temp.tv_sec, temp.tv_usec * 1000); #endif #endif } void EA::Thread::SetAssertionFailureFunction(EA::Thread::AssertionFailureFunction pAssertionFailureFunction, void* pContext) { gpAssertionFailureFunction = pAssertionFailureFunction; gpAssertionFailureContext = pContext; } void EA::Thread::AssertionFailure(const char* pExpression) { if(gpAssertionFailureFunction) gpAssertionFailureFunction(pExpression, gpAssertionFailureContext); else { #if EAT_ASSERT_ENABLED printf("EA::Thread::AssertionFailure: %s\n", pExpression); #endif } } #endif // EA_THREADS_AVAILABLE