| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214 |
- ///////////////////////////////////////////////////////////////////////////////
- // Copyright (c) Electronic Arts Inc. All rights reserved.
- ///////////////////////////////////////////////////////////////////////////////
- #include "EABase/eabase.h"
- #include "eathread/eathread_mutex.h"
- #include "eathread/eathread.h"
- #if defined(EA_PLATFORM_MICROSOFT)
- EA_DISABLE_ALL_VC_WARNINGS()
- #include <Windows.h>
- EA_RESTORE_ALL_VC_WARNINGS()
- #endif
- #ifdef CreateMutex
- #undef CreateMutex // Windows #defines CreateMutex to CreateMutexA or CreateMutexW.
- #endif
- #if defined(EA_PLATFORM_MICROSOFT) && !EA_POSIX_THREADS_AVAILABLE
- #if defined(EA_PLATFORM_WINDOWS)
- extern "C" WINBASEAPI BOOL WINAPI TryEnterCriticalSection(_Inout_ LPCRITICAL_SECTION lpCriticalSection);
- #endif
- EAMutexData::EAMutexData()
- : mnLockCount(0), mbIntraProcess(true)
- {
- #if EAT_ASSERT_ENABLED
- mThreadId = EA::Thread::kThreadIdInvalid;
- mSysThreadId = EA::Thread::kSysThreadIdInvalid;
- #endif
- ::memset(&mData, 0, sizeof(mData));
- }
- EA::Thread::MutexParameters::MutexParameters(bool bIntraProcess, const char* pName)
- : mbIntraProcess(bIntraProcess)
- {
- if(pName)
- {
- strncpy(mName, pName, sizeof(mName)-1);
- mName[sizeof(mName)-1] = 0;
- }
- else
- mName[0] = 0;
- }
- EA::Thread::Mutex::Mutex(const MutexParameters* pMutexParameters, bool bDefaultParameters)
- {
- if(!pMutexParameters && bDefaultParameters)
- {
- MutexParameters parameters;
- Init(¶meters);
- }
- else
- Init(pMutexParameters);
- }
- EA::Thread::Mutex::~Mutex()
- {
- EAT_ASSERT(mMutexData.mnLockCount == 0);
- // Consider doing something to verify the mutex object has been initialized.
- #if defined(EA_PLATFORM_WINDOWS)
- if(mMutexData.mbIntraProcess)
- DeleteCriticalSection((CRITICAL_SECTION*)mMutexData.mData);
- else
- CloseHandle(*(HANDLE*)mMutexData.mData);
- #else
- DeleteCriticalSection((CRITICAL_SECTION*)mMutexData.mData);
- #endif
- }
- bool EA::Thread::Mutex::Init(const MutexParameters* pMutexParameters)
- {
- // Make sure that internal structure is big enough to hold critical section data.
- // If this assert fires, please adjust MUTEX_PLATFORM_DATA_SIZE in eathread_mutex.h accordingly.
- EAT_COMPILETIME_ASSERT(sizeof(CRITICAL_SECTION) <= (MUTEX_PLATFORM_DATA_SIZE / sizeof(uint64_t) * sizeof(uint64_t)));
- EAT_COMPILETIME_ASSERT(sizeof(HANDLE) <= MUTEX_PLATFORM_DATA_SIZE);
- if(pMutexParameters)
- {
- mMutexData.mnLockCount = 0;
- #if defined(EA_PLATFORM_WINDOWS)
- mMutexData.mbIntraProcess = pMutexParameters->mbIntraProcess;
- if(mMutexData.mbIntraProcess)
- {
- // We use InitializeCriticalSectionAndSpinCount, as that has resulted in improved performance in practice on multiprocessors systems.
- int rv = InitializeCriticalSectionAndSpinCount((CRITICAL_SECTION*)mMutexData.mData, 256);
- EAT_ASSERT(rv != 0);
- EA_UNUSED(rv);
- return true;
- }
- else
- {
- EAT_COMPILETIME_ASSERT(sizeof(pMutexParameters->mName) <= MAX_PATH);
- *(HANDLE*)mMutexData.mData = ::CreateMutexA(NULL, false, pMutexParameters->mName[0] ? pMutexParameters->mName : NULL);
- EAT_ASSERT(*(HANDLE*)mMutexData.mData != 0);
- return *(HANDLE*)mMutexData.mData != 0;
- }
- #else
- // We use InitializeCriticalSectionAndSpinCount, as that has resulted in improved performance in practice on multiprocessors systems.
- InitializeCriticalSectionAndSpinCount((CRITICAL_SECTION*)mMutexData.mData, 256);
- return true;
- #endif
- }
- return false;
- }
- EA_DISABLE_VC_WARNING(4706) // disable warning about assignment within a conditional expression
- int EA::Thread::Mutex::Lock(const ThreadTime& timeoutAbsolute)
- {
- EAT_ASSERT(mMutexData.mnLockCount < 100000);
- #if defined(EA_PLATFORM_WINDOWS) // Non-Windows is always assumed to be intra-process.
- if(mMutexData.mbIntraProcess)
- {
- #endif
- if(timeoutAbsolute == kTimeoutNone)
- EnterCriticalSection((CRITICAL_SECTION*)mMutexData.mData);
- else
- {
- // To consider: Have a pathway for kTimeoutImmediate which doesn't check the current time.
- while(!TryEnterCriticalSection((CRITICAL_SECTION*)mMutexData.mData))
- {
- if(GetThreadTime() >= timeoutAbsolute)
- return kResultTimeout;
- Sleep(1);
- }
- }
- #if defined(EA_PLATFORM_WINDOWS)
- }
- else
- {
- EAT_ASSERT(*(HANDLE*)mMutexData.mData != 0);
- const DWORD dw = ::WaitForSingleObject(*(HANDLE*)mMutexData.mData, RelativeTimeoutFromAbsoluteTimeout(timeoutAbsolute));
- if(dw == WAIT_TIMEOUT)
- return kResultTimeout;
- if(dw != WAIT_OBJECT_0)
- {
- EAT_ASSERT(false);
- return kResultError;
- }
- }
- #endif
- EAT_ASSERT((mMutexData.mSysThreadId = EA::Thread::GetSysThreadId()) != kSysThreadIdInvalid);
- EAT_ASSERT(mMutexData.mnLockCount >= 0);
- return ++mMutexData.mnLockCount; // This is safe to do because we have the lock.
- }
- EA_RESTORE_VC_WARNING()
- int EA::Thread::Mutex::Unlock()
- {
- EAT_ASSERT(mMutexData.mSysThreadId == EA::Thread::GetSysThreadId());
- EAT_ASSERT(mMutexData.mnLockCount > 0);
- const int nReturnValue(--mMutexData.mnLockCount); // This is safe to do because we have the lock.
- #if defined(EA_PLATFORM_WINDOWS)
- if(mMutexData.mbIntraProcess)
- LeaveCriticalSection((CRITICAL_SECTION*)mMutexData.mData);
- else
- {
- EAT_ASSERT(*(HANDLE*)mMutexData.mData != 0);
- ReleaseMutex(*(HANDLE*)mMutexData.mData);
- }
- #else
- LeaveCriticalSection((CRITICAL_SECTION*)mMutexData.mData);
- #endif
- return nReturnValue;
- }
- int EA::Thread::Mutex::GetLockCount() const
- {
- return mMutexData.mnLockCount;
- }
- bool EA::Thread::Mutex::HasLock() const
- {
- #if EAT_ASSERT_ENABLED
- return (mMutexData.mnLockCount > 0) && (mMutexData.mSysThreadId == EA::Thread::GetSysThreadId());
- #else
- return (mMutexData.mnLockCount > 0); // This is the best we can do, though it is of limited use, since it doesn't tell you if you are the thread with the lock.
- #endif
- }
- #endif // EA_PLATFORM_XXX
|