diff options
author | RunitaiLinden <davep@lindenlab.com> | 2024-05-06 16:48:58 -0500 |
---|---|---|
committer | RunitaiLinden <davep@lindenlab.com> | 2024-05-06 16:48:58 -0500 |
commit | c6d752b880cacca8fb8f10f28790a50161fcb9ab (patch) | |
tree | 14910a69597962134f2e78e864a2f05962a16356 /indra/llcommon/llmutex.cpp | |
parent | 76101843c0d390c25a783f212eb1ea75e508ada4 (diff) | |
parent | 7d87e41bbd5d4761b1eb17e49b7a00b948d84213 (diff) |
Merge remote-tracking branch 'origin/DRTVWR-600-maint-A' into gltf-dev-maint-a-merge
Diffstat (limited to 'indra/llcommon/llmutex.cpp')
-rw-r--r-- | indra/llcommon/llmutex.cpp | 211 |
1 files changed, 195 insertions, 16 deletions
diff --git a/indra/llcommon/llmutex.cpp b/indra/llcommon/llmutex.cpp index 5d93d6e72b..c90c00b5f4 100644 --- a/indra/llcommon/llmutex.cpp +++ b/indra/llcommon/llmutex.cpp @@ -30,19 +30,20 @@ #include "lltimer.h" #include "llcoros.h" -//============================================================================ +//--------------------------------------------------------------------- +// +// LLMutex +// LLMutex::LLMutex() : mCount(0) { } - LLMutex::~LLMutex() { } - void LLMutex::lock() { LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD; @@ -67,9 +68,9 @@ void LLMutex::lock() #if MUTEX_DEBUG // Have to have the lock before we can access the debug info auto id = LLThread::currentID(); - if (mIsLocked[id] != FALSE) + if (mIsLocked[id] != false) LL_ERRS() << "Already locked in Thread: " << id << LL_ENDL; - mIsLocked[id] = TRUE; + mIsLocked[id] = true; #endif mLockingThread = LLThread::currentID(); @@ -88,9 +89,9 @@ void LLMutex::unlock() #if MUTEX_DEBUG // Access the debug info while we have the lock auto id = LLThread::currentID(); - if (mIsLocked[id] != TRUE) - LL_ERRS() << "Not locked in Thread: " << id << LL_ENDL; - mIsLocked[id] = FALSE; + if (mIsLocked[id] != true) + LL_ERRS() << "Not locked in Thread: " << id << LL_ENDL; + mIsLocked[id] = false; #endif mLockingThread = LLThread::id_t(); @@ -123,8 +124,8 @@ LLThread::id_t LLMutex::lockingThread() const bool LLMutex::trylock() { - LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD; - if(isSelfLocked()) + LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD + if (isSelfLocked()) { //redundant lock mCount++; return true; @@ -138,28 +139,203 @@ bool LLMutex::trylock() #if MUTEX_DEBUG // Have to have the lock before we can access the debug info auto id = LLThread::currentID(); - if (mIsLocked[id] != FALSE) + if (mIsLocked[id] != false) LL_ERRS() << "Already locked in Thread: " << id << LL_ENDL; - mIsLocked[id] = TRUE; + mIsLocked[id] = true; #endif mLockingThread = LLThread::currentID(); return true; } -//============================================================================ +//--------------------------------------------------------------------- +// +// LLSharedMutex +// +LLSharedMutex::LLSharedMutex() +: mLockingThreads(2) // Reserve 2 slots in the map hash table +, mIsShared(false) +{ +} + +bool LLSharedMutex::isLocked() const +{ + LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD + std::lock_guard<std::mutex> lock(mLockMutex); + + return !mLockingThreads.empty(); +} + +bool LLSharedMutex::isThreadLocked() const +{ + LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD + LLThread::id_t current_thread = LLThread::currentID(); + std::lock_guard<std::mutex> lock(mLockMutex); + + const_iterator it = mLockingThreads.find(current_thread); + return it != mLockingThreads.end(); +} + +void LLSharedMutex::lockShared() +{ + LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD + LLThread::id_t current_thread = LLThread::currentID(); + + mLockMutex.lock(); + iterator it = mLockingThreads.find(current_thread); + if (it != mLockingThreads.end()) + { + it->second++; + } + else + { + // Acquire the mutex immediately if the mutex is not locked exclusively + // or enter a locking state if the mutex is already locked exclusively + mLockMutex.unlock(); + mSharedMutex.lock_shared(); + mLockMutex.lock(); + // Continue after acquiring the mutex + mLockingThreads.emplace(std::make_pair(current_thread, 1)); + mIsShared = true; + } + mLockMutex.unlock(); +} + +void LLSharedMutex::lockExclusive() +{ + LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD + LLThread::id_t current_thread = LLThread::currentID(); + + mLockMutex.lock(); + iterator it = mLockingThreads.find(current_thread); + if (it != mLockingThreads.end()) + { + if (mIsShared) + { + // The mutex is already locked in the current thread + // but this lock is SHARED (not EXCLISIVE) + // We can't lock it again, the lock stays shared + // This can lead to a collision (theoretically) + llassert_always(!"The current thread is already locked SHARED and can't be locked EXCLUSIVE"); + } + it->second++; + } + else + { + // Acquire the mutex immediately if mLockingThreads is empty + // or enter a locking state if mLockingThreads is not empty + mLockMutex.unlock(); + mSharedMutex.lock(); + mLockMutex.lock(); + // Continue after acquiring the mutex (and possible quitting the locking state) + mLockingThreads.emplace(std::make_pair(current_thread, 1)); + mIsShared = false; + } + mLockMutex.unlock(); +} + +bool LLSharedMutex::trylockShared() +{ + LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD + LLThread::id_t current_thread = LLThread::currentID(); + std::lock_guard<std::mutex> lock(mLockMutex); + + iterator it = mLockingThreads.find(current_thread); + if (it != mLockingThreads.end()) + { + it->second++; + } + else + { + if (!mSharedMutex.try_lock_shared()) + return false; + + mLockingThreads.emplace(std::make_pair(current_thread, 1)); + mIsShared = true; + } + + return true; +} + +bool LLSharedMutex::trylockExclusive() +{ + LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD + LLThread::id_t current_thread = LLThread::currentID(); + std::lock_guard<std::mutex> lock(mLockMutex); + + if (mLockingThreads.size() == 1 && mLockingThreads.begin()->first == current_thread) + { + mLockingThreads.begin()->second++; + } + else + { + if (!mSharedMutex.try_lock()) + return false; + + mLockingThreads.emplace(std::make_pair(current_thread, 1)); + mIsShared = false; + } + + return true; +} + +void LLSharedMutex::unlockShared() +{ + LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD + LLThread::id_t current_thread = LLThread::currentID(); + std::lock_guard<std::mutex> lock(mLockMutex); + + iterator it = mLockingThreads.find(current_thread); + if (it != mLockingThreads.end()) + { + if (it->second > 1) + { + it->second--; + } + else + { + mLockingThreads.erase(it); + mSharedMutex.unlock_shared(); + } + } +} + +void LLSharedMutex::unlockExclusive() +{ + LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD + LLThread::id_t current_thread = LLThread::currentID(); + std::lock_guard<std::mutex> lock(mLockMutex); + + iterator it = mLockingThreads.find(current_thread); + if (it != mLockingThreads.end()) + { + if (it->second > 1) + { + it->second--; + } + else + { + mLockingThreads.erase(it); + mSharedMutex.unlock(); + } + } +} + + +//--------------------------------------------------------------------- +// +// LLCondition +// LLCondition::LLCondition() : LLMutex() { } - LLCondition::~LLCondition() { } - void LLCondition::wait() { LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD @@ -180,7 +356,10 @@ void LLCondition::broadcast() } - +//--------------------------------------------------------------------- +// +// LLMutexTrylock +// LLMutexTrylock::LLMutexTrylock(LLMutex* mutex) : mMutex(mutex), mLocked(false) |