| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258 |
- ///////////////////////////////////////////////////////////////////////////////
- // Copyright (c) Electronic Arts Inc. All rights reserved.
- ///////////////////////////////////////////////////////////////////////////////
- #include <EABase/eabase.h>
- EA_DISABLE_VC_WARNING(4985) // 'ceil': attributes not present on previous declaration.1> C:\Program Files (x86)\Microsoft Visual Studio 9.0\VC\INCLUDE\intrin.h(142) : see declaration of 'ceil'
- #include <eathread/internal/config.h>
- #include <eathread/eathread_rwmutex.h>
- #include <eathread/eathread.h>
- #include <new> // include new for placement new operator
- #include <string.h>
- EA_DISABLE_VC_WARNING(4996) // This function or variable may be unsafe / deprecated.
- EARWMutexData::EARWMutexData()
- : mnReadWaiters(0),
- mnWriteWaiters(0),
- mnReaders(0),
- mThreadIdWriter(EA::Thread::kThreadIdInvalid),
- mMutex(NULL, false),
- mReadCondition(NULL, false),
- mWriteCondition(NULL, false)
- {
- // Empty
- }
-
-
- EA::Thread::RWMutexParameters::RWMutexParameters(bool bIntraProcess, const char* pName)
- : mbIntraProcess(bIntraProcess)
- {
- (void)pName; // Suppress possible warnings.
- #ifdef EA_PLATFORM_WINDOWS
- if(pName)
- {
- strncpy(mName, pName, sizeof(mName)-1);
- mName[sizeof(mName)-1] = 0;
- }
- else
- mName[0] = 0;
- #endif
- }
-
-
- EA::Thread::RWMutex::RWMutex(const RWMutexParameters* pRWMutexParameters, bool bDefaultParameters)
- {
- if(!pRWMutexParameters && bDefaultParameters)
- {
- RWMutexParameters parameters;
- Init(¶meters);
- }
- else
- Init(pRWMutexParameters);
- }
-
-
- EA::Thread::RWMutex::~RWMutex()
- {
- // Possibly do asserts here.
- }
-
-
- bool EA::Thread::RWMutex::Init(const RWMutexParameters* pRWMutexParameters)
- {
- if(pRWMutexParameters)
- {
- #if EATHREAD_MULTIPROCESSING_OS
- EAT_ASSERT(pRWMutexParameters->mbIntraProcess); // We don't currently have support for intra-process RWMutex on these platforms (and any multi-process platform).
- #endif
- MutexParameters mup(pRWMutexParameters->mbIntraProcess);
- mRWMutexData.mMutex.Init(&mup);
- ConditionParameters mop(pRWMutexParameters->mbIntraProcess);
- mRWMutexData.mReadCondition.Init(&mop);
- mRWMutexData.mWriteCondition.Init(&mop);
- return true;
- }
- return false;
- }
-
-
- int EA::Thread::RWMutex::Lock(LockType lockType, const ThreadTime& timeoutAbsolute)
- {
- int result = 0;
-
- mRWMutexData.mMutex.Lock(); // This lock should always be fast, as it belongs to us and we only hold onto it very temporarily.
- EAT_ASSERT(mRWMutexData.mMutex.GetLockCount() == 1);
-
- // We cannot obtain a write lock recursively, else we will deadlock.
- // Alternatively, we can build a bunch of extra logic to deal with this.
- EAT_ASSERT(mRWMutexData.mThreadIdWriter != GetThreadId());
-
- // Assert that there aren't both readers and writers at the same time.
- EAT_ASSERT(!((mRWMutexData.mThreadIdWriter != kThreadIdInvalid) && mRWMutexData.mnReaders));
-
- if(lockType == kLockTypeRead)
- {
- while(mRWMutexData.mThreadIdWriter != kThreadIdInvalid)
- {
- EAT_ASSERT(mRWMutexData.mMutex.GetLockCount() == 1);
-
- mRWMutexData.mnReadWaiters++;
- const Condition::Result mresult = mRWMutexData.mReadCondition.Wait(&mRWMutexData.mMutex, timeoutAbsolute);
- mRWMutexData.mnReadWaiters--;
-
- EAT_ASSERT(mresult != EA::Thread::Condition::kResultError);
- EAT_ASSERT(mRWMutexData.mMutex.GetLockCount() == 1);
-
- if(mresult == Condition::kResultTimeout)
- {
- mRWMutexData.mMutex.Unlock();
- return kResultTimeout;
- }
- }
-
- result = ++mRWMutexData.mnReaders; // This is not an atomic operation. We are within a mutex lock.
- }
- else if(lockType == kLockTypeWrite)
- {
- while((mRWMutexData.mnReaders > 0) || (mRWMutexData.mThreadIdWriter != kThreadIdInvalid))
- {
- EAT_ASSERT(mRWMutexData.mMutex.GetLockCount() == 1);
-
- mRWMutexData.mnWriteWaiters++;
- const Condition::Result mresult = mRWMutexData.mWriteCondition.Wait(&mRWMutexData.mMutex, timeoutAbsolute);
- mRWMutexData.mnWriteWaiters--;
-
- EAT_ASSERT(mresult != EA::Thread::Condition::kResultError);
- EAT_ASSERT(mRWMutexData.mMutex.GetLockCount() == 1);
-
- if(mresult == Condition::kResultTimeout)
- {
- mRWMutexData.mMutex.Unlock();
- return kResultTimeout;
- }
- }
-
- result = 1;
- mRWMutexData.mThreadIdWriter = GetThreadId();
- }
-
- EAT_ASSERT(mRWMutexData.mMutex.GetLockCount() == 1);
- mRWMutexData.mMutex.Unlock();
-
- return result;
- }
-
-
- int EA::Thread::RWMutex::Unlock()
- {
- mRWMutexData.mMutex.Lock(); // This lock should always be fast, as it belongs to us and we only hold onto it very temporarily.
- EAT_ASSERT(mRWMutexData.mMutex.GetLockCount() == 1);
-
- if(mRWMutexData.mThreadIdWriter != kThreadIdInvalid)
- {
- EAT_ASSERT(mRWMutexData.mThreadIdWriter == GetThreadId());
-
- //Possibly enable this if we want some runtime error checking at some cost.
- //if(mRWMutexData.mThreadIdWriter == GetThreadId()){
- // mRWMutexData.mMutex.Unlock();
- // return kResultError;
- //}
-
- mRWMutexData.mThreadIdWriter = kThreadIdInvalid;
- }
- else
- {
- EAT_ASSERT(mRWMutexData.mnReaders >= 1);
-
- //Possibly enable this if we want some runtime error checking at some cost.
- //if(mRWMutexData.mnReaders < 1){
- // mRWMutexData.mMutex.Unlock();
- // return kResultError;
- //}
-
- const int nNewReaders = --mRWMutexData.mnReaders; // This is not an atomic operation. We are within a mutex lock.
- if(nNewReaders > 0)
- {
- EAT_ASSERT(mRWMutexData.mMutex.GetLockCount() == 1);
- mRWMutexData.mMutex.Unlock();
- return nNewReaders;
- }
- }
-
- if(mRWMutexData.mnWriteWaiters > 0)
- mRWMutexData.mWriteCondition.Signal(false);
- else if(mRWMutexData.mnReadWaiters > 0)
- mRWMutexData.mReadCondition.Signal(true);
-
- EAT_ASSERT(mRWMutexData.mMutex.GetLockCount() == 1);
- mRWMutexData.mMutex.Unlock();
-
- return 0;
- }
-
-
- int EA::Thread::RWMutex::GetLockCount(LockType lockType)
- {
- if(lockType == kLockTypeRead)
- return mRWMutexData.mnReaders;
- else if((lockType == kLockTypeWrite) && (mRWMutexData.mThreadIdWriter != kThreadIdInvalid))
- return 1;
- return 0;
- }
- namespace EA
- {
- namespace Thread
- {
- extern Allocator* gpAllocator;
- }
- }
- EA::Thread::RWMutex* EA::Thread::RWMutexFactory::CreateRWMutex()
- {
- if(gpAllocator)
- return new(gpAllocator->Alloc(sizeof(EA::Thread::RWMutex))) EA::Thread::RWMutex;
- else
- return new EA::Thread::RWMutex;
- }
- void EA::Thread::RWMutexFactory::DestroyRWMutex(EA::Thread::RWMutex* pRWMutex)
- {
- if(gpAllocator)
- {
- pRWMutex->~RWMutex();
- gpAllocator->Free(pRWMutex);
- }
- else
- delete pRWMutex;
- }
- size_t EA::Thread::RWMutexFactory::GetRWMutexSize()
- {
- return sizeof(EA::Thread::RWMutex);
- }
- EA::Thread::RWMutex* EA::Thread::RWMutexFactory::ConstructRWMutex(void* pMemory)
- {
- return new(pMemory) EA::Thread::RWMutex;
- }
- void EA::Thread::RWMutexFactory::DestructRWMutex(EA::Thread::RWMutex* pRWMutex)
- {
- pRWMutex->~RWMutex();
- }
- EA_RESTORE_VC_WARNING() // 4996
- EA_RESTORE_VC_WARNING() // 4985
|