diff options
Diffstat (limited to 'indra/llcommon')
-rw-r--r-- | indra/llcommon/llapr.cpp | 2 | ||||
-rw-r--r-- | indra/llcommon/llapr.h | 2 | ||||
-rw-r--r-- | indra/llcommon/llerror.cpp | 2 | ||||
-rw-r--r-- | indra/llcommon/llmutex.cpp | 195 | ||||
-rw-r--r-- | indra/llcommon/llmutex.h | 79 | ||||
-rw-r--r-- | indra/llcommon/llsys.cpp | 6 | ||||
-rw-r--r-- | indra/llcommon/llsys_objc.mm | 28 | ||||
-rw-r--r-- | indra/llcommon/lluuid.cpp | 2 |
8 files changed, 271 insertions, 45 deletions
diff --git a/indra/llcommon/llapr.cpp b/indra/llcommon/llapr.cpp index 575c524219..834b0e7a3a 100644 --- a/indra/llcommon/llapr.cpp +++ b/indra/llcommon/llapr.cpp @@ -571,7 +571,7 @@ S32 LLAPRFile::readEx(const std::string& filename, void *buf, S32 offset, S32 nb } //static -S32 LLAPRFile::writeEx(const std::string& filename, void *buf, S32 offset, S32 nbytes, LLVolatileAPRPool* pool) +S32 LLAPRFile::writeEx(const std::string& filename, const void *buf, S32 offset, S32 nbytes, LLVolatileAPRPool* pool) { LL_PROFILE_ZONE_SCOPED; apr_int32_t flags = APR_CREATE|APR_WRITE|APR_BINARY; diff --git a/indra/llcommon/llapr.h b/indra/llcommon/llapr.h index 565d7cfb63..f5717ea75e 100644 --- a/indra/llcommon/llapr.h +++ b/indra/llcommon/llapr.h @@ -193,7 +193,7 @@ public: // Returns bytes read/written, 0 if read/write fails: static S32 readEx(const std::string& filename, void *buf, S32 offset, S32 nbytes, LLVolatileAPRPool* pool = NULL); - static S32 writeEx(const std::string& filename, void *buf, S32 offset, S32 nbytes, LLVolatileAPRPool* pool = NULL); // offset<0 means append + static S32 writeEx(const std::string& filename, const void *buf, S32 offset, S32 nbytes, LLVolatileAPRPool* pool = NULL); // offset<0 means append //******************************************************************************************************************************* }; diff --git a/indra/llcommon/llerror.cpp b/indra/llcommon/llerror.cpp index 414515854a..19c285ea5a 100644 --- a/indra/llcommon/llerror.cpp +++ b/indra/llcommon/llerror.cpp @@ -700,7 +700,7 @@ namespace bool shouldLogToStderr() { #if LL_DARWIN - // On Mac OS X, stderr from apps launched from the Finder goes to the + // On macOS, stderr from apps launched from the Finder goes to the // console log. It's generally considered bad form to spam too much // there. That scenario can be detected by noticing that stderr is a // character device (S_IFCHR). diff --git a/indra/llcommon/llmutex.cpp b/indra/llcommon/llmutex.cpp index 0273dd5970..973ecbc87b 100644 --- a/indra/llcommon/llmutex.cpp +++ b/indra/llcommon/llmutex.cpp @@ -29,19 +29,20 @@ #include "llthread.h" #include "lltimer.h" -//============================================================================ +//--------------------------------------------------------------------- +// +// LLMutex +// LLMutex::LLMutex() : mCount(0) { } - LLMutex::~LLMutex() { } - void LLMutex::lock() { LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD @@ -112,7 +113,7 @@ LLThread::id_t LLMutex::lockingThread() const bool LLMutex::trylock() { LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD - if(isSelfLocked()) + if (isSelfLocked()) { //redundant lock mCount++; return true; @@ -135,19 +136,194 @@ bool LLMutex::trylock() 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 @@ -168,7 +344,10 @@ void LLCondition::broadcast() } - +//--------------------------------------------------------------------- +// +// LLMutexTrylock +// LLMutexTrylock::LLMutexTrylock(LLMutex* mutex) : mMutex(mutex), mLocked(false) diff --git a/indra/llcommon/llmutex.h b/indra/llcommon/llmutex.h index 0d70da6178..077f810d61 100644 --- a/indra/llcommon/llmutex.h +++ b/indra/llcommon/llmutex.h @@ -32,6 +32,8 @@ #include <boost/noncopyable.hpp> #include "mutex.h" +#include <shared_mutex> +#include <unordered_map> #include <condition_variable> //============================================================================ @@ -66,6 +68,45 @@ protected: #endif }; +//============================================================================ + +class LL_COMMON_API LLSharedMutex +{ +public: + LLSharedMutex(); + + bool isLocked() const; + bool isThreadLocked() const; + bool isShared() const { return mIsShared; } + + void lockShared(); + void lockExclusive(); + template<bool SHARED> void lock(); + template<> void lock<true>() { lockShared(); } + template<> void lock<false>() { lockExclusive(); } + + bool trylockShared(); + bool trylockExclusive(); + template<bool SHARED> bool trylock(); + template<> bool trylock<true>() { return trylockShared(); } + template<> bool trylock<false>() { return trylockExclusive(); } + + void unlockShared(); + void unlockExclusive(); + template<bool SHARED> void unlock(); + template<> void unlock<true>() { unlockShared(); } + template<> void unlock<false>() { unlockExclusive(); } + +private: + std::shared_mutex mSharedMutex; + mutable std::mutex mLockMutex; + std::unordered_map<LLThread::id_t, U32> mLockingThreads; + bool mIsShared; + + using iterator = std::unordered_map<LLThread::id_t, U32>::iterator; + using const_iterator = std::unordered_map<LLThread::id_t, U32>::const_iterator; +}; + // Actually a condition/mutex pair (since each condition needs to be associated with a mutex). class LL_COMMON_API LLCondition : public LLMutex { @@ -81,27 +122,57 @@ protected: std::condition_variable mCond; }; +//============================================================================ + class LLMutexLock { public: LLMutexLock(LLMutex* mutex) { mMutex = mutex; - - if(mMutex) + + if (mMutex) mMutex->lock(); } + ~LLMutexLock() { - if(mMutex) + if (mMutex) mMutex->unlock(); } + private: LLMutex* mMutex; }; //============================================================================ +template<bool SHARED> +class LLSharedMutexLockTemplate +{ +public: + LLSharedMutexLockTemplate(LLSharedMutex* mutex) + : mSharedMutex(mutex) + { + if (mSharedMutex) + mSharedMutex->lock<SHARED>(); + } + + ~LLSharedMutexLockTemplate() + { + if (mSharedMutex) + mSharedMutex->unlock<SHARED>(); + } + +private: + LLSharedMutex* mSharedMutex; +}; + +using LLSharedMutexLock = LLSharedMutexLockTemplate<true>; +using LLExclusiveMutexLock = LLSharedMutexLockTemplate<false>; + +//============================================================================ + // Scoped locking class similar in function to LLMutexLock but uses // the trylock() method to conditionally acquire lock without // blocking. Caller resolves the resulting condition by calling @@ -127,6 +198,8 @@ private: bool mLocked; }; +//============================================================================ + /** * @class LLScopedLock * @brief Small class to help lock and unlock mutexes. diff --git a/indra/llcommon/llsys.cpp b/indra/llcommon/llsys.cpp index 938685bae6..d3f99a413d 100644 --- a/indra/llcommon/llsys.cpp +++ b/indra/llcommon/llsys.cpp @@ -269,9 +269,9 @@ LLOSInfo::LLOSInfo() : #elif LL_DARWIN // Initialize mOSStringSimple to something like: - // "Mac OS X 10.6.7" + // "macOS 10.13.1" { - const char * DARWIN_PRODUCT_NAME = "Mac OS X"; + const char * DARWIN_PRODUCT_NAME = "macOS"; int64_t major_version, minor_version, bugfix_version = 0; @@ -294,7 +294,7 @@ LLOSInfo::LLOSInfo() : } // Initialize mOSString to something like: - // "Mac OS X 10.6.7 Darwin Kernel Version 10.7.0: Sat Jan 29 15:17:16 PST 2011; root:xnu-1504.9.37~1/RELEASE_I386 i386" + // "macOS 10.13.1 Darwin Kernel Version 10.7.0: Sat Jan 29 15:17:16 PST 2011; root:xnu-1504.9.37~1/RELEASE_I386 i386" struct utsname un; if(uname(&un) != -1) { diff --git a/indra/llcommon/llsys_objc.mm b/indra/llcommon/llsys_objc.mm index 3fd85fb1c9..1393ccea50 100644 --- a/indra/llcommon/llsys_objc.mm +++ b/indra/llcommon/llsys_objc.mm @@ -27,38 +27,12 @@ #import "llsys_objc.h" #import <AppKit/AppKit.h> -static auto intAtStringIndex(NSArray *array, int index) -{ - return [(NSString *)[array objectAtIndex:index] integerValue]; -} - bool LLGetDarwinOSInfo(int64_t &major, int64_t &minor, int64_t &patch) { - if (NSAppKitVersionNumber > NSAppKitVersionNumber10_8) - { NSOperatingSystemVersion osVersion = [[NSProcessInfo processInfo] operatingSystemVersion]; major = osVersion.majorVersion; minor = osVersion.minorVersion; patch = osVersion.patchVersion; - } - else - { - NSString* versionString = [[NSDictionary dictionaryWithContentsOfFile: - @"/System/Library/CoreServices/SystemVersion.plist"] objectForKey:@"ProductVersion"]; - NSArray* versions = [versionString componentsSeparatedByString:@"."]; - NSUInteger count = [versions count]; - if (count > 0) - { - major = intAtStringIndex(versions, 0); - if (count > 1) - { - minor = intAtStringIndex(versions, 1); - if (count > 2) - { - patch = intAtStringIndex(versions, 2); - } - } - } - } + return true; } diff --git a/indra/llcommon/lluuid.cpp b/indra/llcommon/lluuid.cpp index 200add404f..285469f0d4 100644 --- a/indra/llcommon/lluuid.cpp +++ b/indra/llcommon/lluuid.cpp @@ -510,7 +510,7 @@ S32 LLUUID::getNodeID(unsigned char* node_id) } #elif LL_DARWIN -// Mac OS X version of the UUID generation code... +// macOS version of the UUID generation code... /* * Get an ethernet hardware address, if we can find it... */ |