From 802b52f3044dfaaec3406d654c091d626955f569 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Tue, 22 Sep 2020 23:38:23 +0300 Subject: SL-13979 Crash of logging system at LLError::Settings::getInstance() LLSingleton depends onto logging system, having logging system be based on LLSingleton causes crashes and deadlocks --- indra/llcommon/llerror.cpp | 84 +++++++++++++++++++---------------------- indra/llcommon/llerrorcontrol.h | 5 --- indra/llcommon/llsingleton.cpp | 31 +-------------- 3 files changed, 40 insertions(+), 80 deletions(-) (limited to 'indra/llcommon') diff --git a/indra/llcommon/llerror.cpp b/indra/llcommon/llerror.cpp index 411412c883..f876b8ee4a 100644 --- a/indra/llcommon/llerror.cpp +++ b/indra/llcommon/llerror.cpp @@ -332,12 +332,9 @@ namespace LLError } // huh, that's odd, we should see one or the other prefix -- but don't // try to log unless logging is already initialized - if (is_available()) - { - // in Python, " or ".join(vector) -- but in C++, a PITB - LL_DEBUGS() << "Did not see 'class' or 'struct' prefix on '" - << name << "'" << LL_ENDL; - } + // in Python, " or ".join(vector) -- but in C++, a PITB + LL_DEBUGS() << "Did not see 'class' or 'struct' prefix on '" + << name << "'" << LL_ENDL; return name; #else // neither GCC nor Visual Studio @@ -438,9 +435,12 @@ namespace typedef std::vector Recorders; typedef std::vector CallSiteVector; - class Globals : public LLSingleton + class Globals { - LLSINGLETON(Globals); + public: + static Globals* getInstance(); + protected: + Globals(); public: std::ostringstream messageStream; bool messageStreamInUse; @@ -460,6 +460,16 @@ namespace { } + Globals* Globals::getInstance() + { + // According to C++11 Function-Local Initialization + // of static variables is supposed to be thread safe + // without risk of deadlocks. + static Globals inst; + + return &inst; + } + void Globals::addCallSite(LLError::CallSite& site) { callSites.push_back(&site); @@ -512,14 +522,17 @@ namespace LLError typedef LLPointer SettingsConfigPtr; - class Settings : public LLSingleton + class Settings { - LLSINGLETON(Settings); + public: + static Settings* getInstance(); + protected: + Settings(); public: SettingsConfigPtr getSettingsConfig(); void reset(); - SettingsStoragePtr saveAndReset(); + SettingsStoragePtr saveAndReset(); void restore(SettingsStoragePtr pSettingsStorage); private: @@ -553,6 +566,16 @@ namespace LLError { } + Settings* Settings::getInstance() + { + // According to C++11 Function-Local Initialization + // of static variables is supposed to be thread safe + // without risk of deadlocks. + static Settings inst; + + return &inst; + } + SettingsConfigPtr Settings::getSettingsConfig() { return mSettingsConfig; @@ -577,11 +600,6 @@ namespace LLError SettingsConfigPtr newSettingsConfig(dynamic_cast(pSettingsStorage.get())); mSettingsConfig = newSettingsConfig; } - - bool is_available() - { - return Settings::instanceExists() && Globals::instanceExists(); - } } namespace LLError @@ -1028,7 +1046,7 @@ namespace LLError std::pair, Recorders::iterator> findRecorderPos() { - SettingsConfigPtr s = Settings::instance().getSettingsConfig(); + SettingsConfigPtr s = Settings::getInstance()->getSettingsConfig(); // Since we promise to return an iterator, use a classic iterator // loop. auto end{s->mRecorders.end()}; @@ -1071,7 +1089,7 @@ namespace LLError auto found = findRecorderPos(); if (found.first) { - SettingsConfigPtr s = Settings::instance().getSettingsConfig(); + SettingsConfigPtr s = Settings::getInstance()->getSettingsConfig(); s->mRecorders.erase(found.second); } return bool(found.first); @@ -1307,14 +1325,6 @@ namespace LLError return false; } - // If we hit a logging request very late during shutdown processing, - // when either of the relevant LLSingletons has already been deleted, - // DO NOT resurrect them. - if (Settings::wasDeleted() || Globals::wasDeleted()) - { - return false; - } - SettingsConfigPtr s = Settings::getInstance()->getSettingsConfig(); s->mShouldLogCallCounter++; @@ -1353,10 +1363,8 @@ namespace LLError std::ostringstream* Log::out() { LLMutexTrylock lock(getMutex(),5); - // If we hit a logging request very late during shutdown processing, - // when either of the relevant LLSingletons has already been deleted, - // DO NOT resurrect them. - if (lock.isLocked() && ! (Settings::wasDeleted() || Globals::wasDeleted())) + + if (lock.isLocked()) { Globals* g = Globals::getInstance(); @@ -1378,14 +1386,6 @@ namespace LLError return; } - // If we hit a logging request very late during shutdown processing, - // when either of the relevant LLSingletons has already been deleted, - // DO NOT resurrect them. - if (Settings::wasDeleted() || Globals::wasDeleted()) - { - return; - } - if(strlen(out->str().c_str()) < 128) { strcpy(message, out->str().c_str()); @@ -1418,14 +1418,6 @@ namespace LLError return; } - // If we hit a logging request very late during shutdown processing, - // when either of the relevant LLSingletons has already been deleted, - // DO NOT resurrect them. - if (Settings::wasDeleted() || Globals::wasDeleted()) - { - return; - } - Globals* g = Globals::getInstance(); SettingsConfigPtr s = Settings::getInstance()->getSettingsConfig(); diff --git a/indra/llcommon/llerrorcontrol.h b/indra/llcommon/llerrorcontrol.h index bfa2269025..25786d5457 100644 --- a/indra/llcommon/llerrorcontrol.h +++ b/indra/llcommon/llerrorcontrol.h @@ -203,11 +203,6 @@ namespace LLError LL_COMMON_API std::string abbreviateFile(const std::string& filePath); LL_COMMON_API int shouldLogCallCount(); - - // Check whether Globals exists. This should only be used by LLSingleton - // infrastructure to avoid trying to log when our internal LLSingleton is - // unavailable -- circularity ensues. - LL_COMMON_API bool is_available(); }; #endif // LL_LLERRORCONTROL_H diff --git a/indra/llcommon/llsingleton.cpp b/indra/llcommon/llsingleton.cpp index d3d25201b2..83a4b64e8f 100644 --- a/indra/llcommon/llsingleton.cpp +++ b/indra/llcommon/llsingleton.cpp @@ -28,7 +28,7 @@ #include "llsingleton.h" #include "llerror.h" -#include "llerrorcontrol.h" // LLError::is_available() +#include "llerrorcontrol.h" #include "lldependencies.h" #include "llexception.h" #include "llcoros.h" @@ -41,8 +41,6 @@ namespace { void log(LLError::ELevel level, const char* p1, const char* p2, const char* p3, const char* p4); - -bool oktolog(); } // anonymous namespace // Our master list of all LLSingletons is itself an LLSingleton. We used to @@ -279,8 +277,6 @@ void LLSingletonBase::reset_initializing(list_t::size_type size) void LLSingletonBase::MasterList::LockedInitializing::log(const char* verb, const char* name) { - if (oktolog()) - { LL_DEBUGS("LLSingleton") << verb << ' ' << demangle(name) << ';'; if (mList) { @@ -292,7 +288,6 @@ void LLSingletonBase::MasterList::LockedInitializing::log(const char* verb, cons } } LL_ENDL; - } } void LLSingletonBase::capture_dependency() @@ -455,33 +450,11 @@ void LLSingletonBase::deleteAll() /*---------------------------- Logging helpers -----------------------------*/ namespace { -bool oktolog() -{ - // See comments in log() below. - return LLError::is_available(); -} void log(LLError::ELevel level, const char* p1, const char* p2, const char* p3, const char* p4) { - // The is_available() test below ensures that we'll stop logging once - // LLError has been cleaned up. If we had a similar portable test for - // std::cerr, this would be a good place to use it. - - // Check LLError::is_available() because some of LLError's infrastructure - // is itself an LLSingleton. If that LLSingleton has not yet been - // initialized, trying to log will engage LLSingleton machinery... and - // around and around we go. - if (LLError::is_available()) - { - LL_VLOGS(level, "LLSingleton") << p1 << p2 << p3 << p4 << LL_ENDL; - } - else - { - // Caller may be a test program, or something else whose stderr is - // visible to the user. - std::cerr << p1 << p2 << p3 << p4 << std::endl; - } + LL_VLOGS(level, "LLSingleton") << p1 << p2 << p3 << p4 << LL_ENDL; } } // anonymous namespace -- cgit v1.3 From 95e724f3deb856b0b69a3850ceb938c81d1f0321 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Mon, 26 Oct 2020 21:04:10 +0200 Subject: SL-14004 Coalesce viewer's LLError::Settings and Globals --- indra/llcommon/llerror.cpp | 265 +++++++++++++++++++++------------------------ 1 file changed, 122 insertions(+), 143 deletions(-) (limited to 'indra/llcommon') diff --git a/indra/llcommon/llerror.cpp b/indra/llcommon/llerror.cpp index f876b8ee4a..781c41f3de 100644 --- a/indra/llcommon/llerror.cpp +++ b/indra/llcommon/llerror.cpp @@ -435,6 +435,60 @@ namespace typedef std::vector Recorders; typedef std::vector CallSiteVector; + class SettingsConfig : public LLRefCount + { + friend class Globals; + + public: + virtual ~SettingsConfig(); + + LLError::ELevel mDefaultLevel; + + bool mLogAlwaysFlush; + + U32 mEnabledLogTypesMask; + + LevelMap mFunctionLevelMap; + LevelMap mClassLevelMap; + LevelMap mFileLevelMap; + LevelMap mTagLevelMap; + std::map mUniqueLogMessages; + + LLError::FatalFunction mCrashFunction; + LLError::TimeFunction mTimeFunction; + + Recorders mRecorders; + + int mShouldLogCallCounter; + + private: + SettingsConfig(); + }; + + typedef LLPointer SettingsConfigPtr; + + SettingsConfig::SettingsConfig() + : LLRefCount(), + mDefaultLevel(LLError::LEVEL_DEBUG), + mLogAlwaysFlush(true), + mEnabledLogTypesMask(255), + mFunctionLevelMap(), + mClassLevelMap(), + mFileLevelMap(), + mTagLevelMap(), + mUniqueLogMessages(), + mCrashFunction(NULL), + mTimeFunction(NULL), + mRecorders(), + mShouldLogCallCounter(0) + { + } + + SettingsConfig::~SettingsConfig() + { + mRecorders.clear(); + } + class Globals { public: @@ -449,14 +503,21 @@ namespace void addCallSite(LLError::CallSite&); void invalidateCallSites(); + SettingsConfigPtr getSettingsConfig(); + + void resetSettingsConfig(); + LLError::SettingsStoragePtr saveAndResetSettingsConfig(); + void restore(LLError::SettingsStoragePtr pSettingsStorage); private: CallSiteVector callSites; + SettingsConfigPtr mSettingsConfig; }; Globals::Globals() : messageStream(), messageStreamInUse(false), - callSites() + callSites(), + mSettingsConfig(new SettingsConfig()) { } @@ -486,120 +547,31 @@ namespace callSites.clear(); } -} - -namespace LLError -{ - class SettingsConfig : public LLRefCount - { - friend class Settings; - - public: - virtual ~SettingsConfig(); - - LLError::ELevel mDefaultLevel; - - bool mLogAlwaysFlush; - - U32 mEnabledLogTypesMask; - - LevelMap mFunctionLevelMap; - LevelMap mClassLevelMap; - LevelMap mFileLevelMap; - LevelMap mTagLevelMap; - std::map mUniqueLogMessages; - - LLError::FatalFunction mCrashFunction; - LLError::TimeFunction mTimeFunction; - - Recorders mRecorders; - - int mShouldLogCallCounter; - - private: - SettingsConfig(); - }; - - typedef LLPointer SettingsConfigPtr; - - class Settings - { - public: - static Settings* getInstance(); - protected: - Settings(); - public: - SettingsConfigPtr getSettingsConfig(); - - void reset(); - SettingsStoragePtr saveAndReset(); - void restore(SettingsStoragePtr pSettingsStorage); - - private: - SettingsConfigPtr mSettingsConfig; - }; - - SettingsConfig::SettingsConfig() - : LLRefCount(), - mDefaultLevel(LLError::LEVEL_DEBUG), - mLogAlwaysFlush(true), - mEnabledLogTypesMask(255), - mFunctionLevelMap(), - mClassLevelMap(), - mFileLevelMap(), - mTagLevelMap(), - mUniqueLogMessages(), - mCrashFunction(NULL), - mTimeFunction(NULL), - mRecorders(), - mShouldLogCallCounter(0) - { - } - SettingsConfig::~SettingsConfig() - { - mRecorders.clear(); - } - - Settings::Settings(): - mSettingsConfig(new SettingsConfig()) - { - } - - Settings* Settings::getInstance() + SettingsConfigPtr Globals::getSettingsConfig() { - // According to C++11 Function-Local Initialization - // of static variables is supposed to be thread safe - // without risk of deadlocks. - static Settings inst; - - return &inst; + return mSettingsConfig; } - SettingsConfigPtr Settings::getSettingsConfig() - { - return mSettingsConfig; - } - - void Settings::reset() - { - Globals::getInstance()->invalidateCallSites(); - mSettingsConfig = new SettingsConfig(); - } + void Globals::resetSettingsConfig() + { + invalidateCallSites(); + mSettingsConfig = new SettingsConfig(); + } - SettingsStoragePtr Settings::saveAndReset() - { - SettingsStoragePtr oldSettingsConfig(mSettingsConfig.get()); - reset(); - return oldSettingsConfig; - } + LLError::SettingsStoragePtr Globals::saveAndResetSettingsConfig() + { + LLError::SettingsStoragePtr oldSettingsConfig(mSettingsConfig.get()); + resetSettingsConfig(); + return oldSettingsConfig; + } - void Settings::restore(SettingsStoragePtr pSettingsStorage) - { - Globals::getInstance()->invalidateCallSites(); - SettingsConfigPtr newSettingsConfig(dynamic_cast(pSettingsStorage.get())); - mSettingsConfig = newSettingsConfig; - } + void Globals::restore(LLError::SettingsStoragePtr pSettingsStorage) + { + invalidateCallSites(); + SettingsConfigPtr newSettingsConfig(dynamic_cast(pSettingsStorage.get())); + mSettingsConfig = newSettingsConfig; + } } namespace LLError @@ -723,7 +695,7 @@ namespace void commonInit(const std::string& user_dir, const std::string& app_dir, bool log_to_stderr = true) { - LLError::Settings::getInstance()->reset(); + Globals::getInstance()->resetSettingsConfig(); LLError::setDefaultLevel(LLError::LEVEL_INFO); LLError::setAlwaysFlush(true); @@ -765,13 +737,13 @@ namespace LLError void setFatalFunction(const FatalFunction& f) { - SettingsConfigPtr s = Settings::getInstance()->getSettingsConfig(); + SettingsConfigPtr s = Globals::getInstance()->getSettingsConfig(); s->mCrashFunction = f; } FatalFunction getFatalFunction() { - SettingsConfigPtr s = Settings::getInstance()->getSettingsConfig(); + SettingsConfigPtr s = Globals::getInstance()->getSettingsConfig(); return s->mCrashFunction; } @@ -782,72 +754,77 @@ namespace LLError void setTimeFunction(TimeFunction f) { - SettingsConfigPtr s = Settings::getInstance()->getSettingsConfig(); + SettingsConfigPtr s = Globals::getInstance()->getSettingsConfig(); s->mTimeFunction = f; } void setDefaultLevel(ELevel level) { - Globals::getInstance()->invalidateCallSites(); - SettingsConfigPtr s = Settings::getInstance()->getSettingsConfig(); + Globals *g = Globals::getInstance(); + g->invalidateCallSites(); + SettingsConfigPtr s = g->getSettingsConfig(); s->mDefaultLevel = level; } ELevel getDefaultLevel() { - SettingsConfigPtr s = Settings::getInstance()->getSettingsConfig(); + SettingsConfigPtr s = Globals::getInstance()->getSettingsConfig(); return s->mDefaultLevel; } void setAlwaysFlush(bool flush) { - SettingsConfigPtr s = Settings::getInstance()->getSettingsConfig(); + SettingsConfigPtr s = Globals::getInstance()->getSettingsConfig(); s->mLogAlwaysFlush = flush; } bool getAlwaysFlush() { - SettingsConfigPtr s = Settings::getInstance()->getSettingsConfig(); + SettingsConfigPtr s = Globals::getInstance()->getSettingsConfig(); return s->mLogAlwaysFlush; } void setEnabledLogTypesMask(U32 mask) { - SettingsConfigPtr s = Settings::getInstance()->getSettingsConfig(); + SettingsConfigPtr s = Globals::getInstance()->getSettingsConfig(); s->mEnabledLogTypesMask = mask; } U32 getEnabledLogTypesMask() { - SettingsConfigPtr s = Settings::getInstance()->getSettingsConfig(); + SettingsConfigPtr s = Globals::getInstance()->getSettingsConfig(); return s->mEnabledLogTypesMask; } void setFunctionLevel(const std::string& function_name, ELevel level) { - Globals::getInstance()->invalidateCallSites(); - SettingsConfigPtr s = Settings::getInstance()->getSettingsConfig(); + Globals *g = Globals::getInstance(); + g->invalidateCallSites(); + SettingsConfigPtr s = g->getSettingsConfig(); s->mFunctionLevelMap[function_name] = level; } void setClassLevel(const std::string& class_name, ELevel level) { - Globals::getInstance()->invalidateCallSites(); - SettingsConfigPtr s = Settings::getInstance()->getSettingsConfig(); + Globals *g = Globals::getInstance(); + g->invalidateCallSites(); + SettingsConfigPtr s = g->getSettingsConfig(); s->mClassLevelMap[class_name] = level; } void setFileLevel(const std::string& file_name, ELevel level) { - Globals::getInstance()->invalidateCallSites(); - SettingsConfigPtr s = Settings::getInstance()->getSettingsConfig(); + Globals *g = Globals::getInstance(); + g->invalidateCallSites(); + SettingsConfigPtr s = g->getSettingsConfig(); s->mFileLevelMap[file_name] = level; } void setTagLevel(const std::string& tag_name, ELevel level) { - Globals::getInstance()->invalidateCallSites(); - SettingsConfigPtr s = Settings::getInstance()->getSettingsConfig(); + Globals *g = Globals::getInstance(); + g->invalidateCallSites(); + SettingsConfigPtr s = g->getSettingsConfig(); s->mTagLevelMap[tag_name] = level; } @@ -892,8 +869,9 @@ namespace LLError { void configure(const LLSD& config) { - Globals::getInstance()->invalidateCallSites(); - SettingsConfigPtr s = Settings::getInstance()->getSettingsConfig(); + Globals *g = Globals::getInstance(); + g->invalidateCallSites(); + SettingsConfigPtr s = g->getSettingsConfig(); s->mFunctionLevelMap.clear(); s->mClassLevelMap.clear(); @@ -1020,7 +998,7 @@ namespace LLError { return; } - SettingsConfigPtr s = Settings::getInstance()->getSettingsConfig(); + SettingsConfigPtr s = Globals::getInstance()->getSettingsConfig(); s->mRecorders.push_back(recorder); } @@ -1030,7 +1008,7 @@ namespace LLError { return; } - SettingsConfigPtr s = Settings::getInstance()->getSettingsConfig(); + SettingsConfigPtr s = Globals::getInstance()->getSettingsConfig(); s->mRecorders.erase(std::remove(s->mRecorders.begin(), s->mRecorders.end(), recorder), s->mRecorders.end()); } @@ -1046,7 +1024,7 @@ namespace LLError std::pair, Recorders::iterator> findRecorderPos() { - SettingsConfigPtr s = Settings::getInstance()->getSettingsConfig(); + SettingsConfigPtr s = Globals::getInstance()->getSettingsConfig(); // Since we promise to return an iterator, use a classic iterator // loop. auto end{s->mRecorders.end()}; @@ -1089,7 +1067,7 @@ namespace LLError auto found = findRecorderPos(); if (found.first) { - SettingsConfigPtr s = Settings::getInstance()->getSettingsConfig(); + SettingsConfigPtr s = Globals::getInstance()->getSettingsConfig(); s->mRecorders.erase(found.second); } return bool(found.first); @@ -1187,7 +1165,7 @@ namespace void writeToRecorders(const LLError::CallSite& site, const std::string& message) { LLError::ELevel level = site.mLevel; - LLError::SettingsConfigPtr s = LLError::Settings::getInstance()->getSettingsConfig(); + SettingsConfigPtr s = Globals::getInstance()->getSettingsConfig(); std::string escaped_message; @@ -1325,7 +1303,8 @@ namespace LLError return false; } - SettingsConfigPtr s = Settings::getInstance()->getSettingsConfig(); + Globals *g = Globals::getInstance(); + SettingsConfigPtr s = g->getSettingsConfig(); s->mShouldLogCallCounter++; @@ -1355,7 +1334,7 @@ namespace LLError : false); site.mCached = true; - Globals::getInstance()->addCallSite(site); + g->addCallSite(site); return site.mShouldLog = site.mLevel >= compareLevel; } @@ -1419,7 +1398,7 @@ namespace LLError } Globals* g = Globals::getInstance(); - SettingsConfigPtr s = Settings::getInstance()->getSettingsConfig(); + SettingsConfigPtr s = g->getSettingsConfig(); std::string message = out->str(); if (out == &g->messageStream) @@ -1478,12 +1457,12 @@ namespace LLError { SettingsStoragePtr saveAndResetSettings() { - return Settings::getInstance()->saveAndReset(); + return Globals::getInstance()->saveAndResetSettingsConfig(); } void restoreSettings(SettingsStoragePtr pSettingsStorage) { - return Settings::getInstance()->restore(pSettingsStorage); + return Globals::getInstance()->restore(pSettingsStorage); } std::string removePrefix(std::string& s, const std::string& p) @@ -1529,7 +1508,7 @@ namespace LLError int shouldLogCallCount() { - SettingsConfigPtr s = Settings::getInstance()->getSettingsConfig(); + SettingsConfigPtr s = Globals::getInstance()->getSettingsConfig(); return s->mShouldLogCallCounter; } @@ -1707,8 +1686,8 @@ bool debugLoggingEnabled(const std::string& tag) { return false; } - - LLError::SettingsConfigPtr s = LLError::Settings::getInstance()->getSettingsConfig(); + + SettingsConfigPtr s = Globals::getInstance()->getSettingsConfig(); LLError::ELevel level = LLError::LEVEL_DEBUG; bool res = checkLevelMap(s->mTagLevelMap, tag, level); return res; -- cgit v1.3 From 52c0776afdcd75ba8ebadc6b45d8611564e3b833 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Mon, 16 Nov 2020 22:11:19 +0200 Subject: SL-14340 Fix crash on llerror's recorders --- indra/llcommon/llerror.cpp | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) (limited to 'indra/llcommon') diff --git a/indra/llcommon/llerror.cpp b/indra/llcommon/llerror.cpp index 781c41f3de..012ec08f07 100644 --- a/indra/llcommon/llerror.cpp +++ b/indra/llcommon/llerror.cpp @@ -458,6 +458,7 @@ namespace LLError::TimeFunction mTimeFunction; Recorders mRecorders; + LLMutex mRecorderMutex; int mShouldLogCallCounter; @@ -480,6 +481,7 @@ namespace mCrashFunction(NULL), mTimeFunction(NULL), mRecorders(), + mRecorderMutex(), mShouldLogCallCounter(0) { } @@ -999,6 +1001,7 @@ namespace LLError return; } SettingsConfigPtr s = Globals::getInstance()->getSettingsConfig(); + LLMutexLock lock(&s->mRecorderMutex); s->mRecorders.push_back(recorder); } @@ -1009,6 +1012,7 @@ namespace LLError return; } SettingsConfigPtr s = Globals::getInstance()->getSettingsConfig(); + LLMutexLock lock(&s->mRecorderMutex); s->mRecorders.erase(std::remove(s->mRecorders.begin(), s->mRecorders.end(), recorder), s->mRecorders.end()); } @@ -1020,11 +1024,12 @@ namespace LLError // with a Recorders::iterator indicating the position of that entry in // mRecorders. The shared_ptr might be empty (operator!() returns true) if // there was no such RECORDER subclass instance in mRecorders. + // + // NOTE!!! Requires external mutex lock!!! template std::pair, Recorders::iterator> - findRecorderPos() + findRecorderPos(SettingsConfigPtr &s) { - SettingsConfigPtr s = Globals::getInstance()->getSettingsConfig(); // Since we promise to return an iterator, use a classic iterator // loop. auto end{s->mRecorders.end()}; @@ -1055,7 +1060,9 @@ namespace LLError template boost::shared_ptr findRecorder() { - return findRecorderPos().first; + SettingsConfigPtr s = Globals::getInstance()->getSettingsConfig(); + LLMutexLock lock(&s->mRecorderMutex); + return findRecorderPos(s).first; } // Remove an entry from SettingsConfig::mRecorders whose RecorderPtr @@ -1064,10 +1071,11 @@ namespace LLError template bool removeRecorder() { - auto found = findRecorderPos(); + SettingsConfigPtr s = Globals::getInstance()->getSettingsConfig(); + LLMutexLock lock(&s->mRecorderMutex); + auto found = findRecorderPos(s); if (found.first) { - SettingsConfigPtr s = Globals::getInstance()->getSettingsConfig(); s->mRecorders.erase(found.second); } return bool(found.first); @@ -1168,7 +1176,8 @@ namespace SettingsConfigPtr s = Globals::getInstance()->getSettingsConfig(); std::string escaped_message; - + + LLMutexLock lock(&s->mRecorderMutex); for (Recorders::const_iterator i = s->mRecorders.begin(); i != s->mRecorders.end(); ++i) -- cgit v1.3 From 03921adb1211c6def0ce5c791e2455643142a92a Mon Sep 17 00:00:00 2001 From: Mnikolenko Productengine Date: Mon, 11 Jan 2021 17:07:03 +0200 Subject: SL-2202 Add exception handling around boost::regex_match() calls in the viewer --- indra/llcommon/CMakeLists.txt | 2 +- indra/llcommon/llregex.h | 89 +++++++++++++++++++++++++++++++ indra/llcommon/llsys.cpp | 39 ++------------ indra/llprimitive/llmediaentry.cpp | 5 +- indra/llui/llurlentry.cpp | 3 +- indra/llui/llurlregistry.cpp | 12 +---- indra/llvfs/lldiriterator.cpp | 4 +- indra/newview/llfloaterwindowsize.cpp | 6 +-- indra/newview/llimprocessing.cpp | 4 +- indra/newview/llinventoryfilter.cpp | 5 +- indra/newview/lllogchat.cpp | 12 ++--- indra/newview/llpanelexperiencepicker.cpp | 4 +- indra/newview/llpanelsnapshotpostcard.cpp | 3 +- indra/newview/llversioninfo.cpp | 10 ++-- indra/newview/llweb.cpp | 7 ++- 15 files changed, 126 insertions(+), 79 deletions(-) create mode 100644 indra/llcommon/llregex.h (limited to 'indra/llcommon') diff --git a/indra/llcommon/CMakeLists.txt b/indra/llcommon/CMakeLists.txt index eeb315ead6..0a22942dfd 100644 --- a/indra/llcommon/CMakeLists.txt +++ b/indra/llcommon/CMakeLists.txt @@ -207,9 +207,9 @@ set(llcommon_HEADER_FILES llqueuedthread.h llrand.h llrefcount.h + llregex.h llregistry.h llrun.h - llrefcount.h llsafehandle.h llsd.h llsdjson.h diff --git a/indra/llcommon/llregex.h b/indra/llcommon/llregex.h new file mode 100644 index 0000000000..2b7f5e47c2 --- /dev/null +++ b/indra/llcommon/llregex.h @@ -0,0 +1,89 @@ +/** + * @file llregex.h + * + * $LicenseInfo:firstyear=2021&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2021, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#ifndef LLREGEX_H +#define LLREGEX_H +#include + +template +LL_COMMON_API bool ll_regex_match(const S& string, M& match, const R& regex) +{ + try + { + return boost::regex_match(string, match, regex); + } + catch (const std::runtime_error& e) + { + LL_WARNS() << "error matching with '" << regex.str() << "': " + << e.what() << ":\n'" << string << "'" << LL_ENDL; + return false; + } +} + +template +LL_COMMON_API bool ll_regex_match(const S& string, const R& regex) +{ + try + { + return boost::regex_match(string, regex); + } + catch (const std::runtime_error& e) + { + LL_WARNS() << "error matching with '" << regex.str() << "': " + << e.what() << ":\n'" << string << "'" << LL_ENDL; + return false; + } +} + +template +bool ll_regex_search(const S& string, M& match, const R& regex) +{ + try + { + return boost::regex_search(string, match, regex); + } + catch (const std::runtime_error& e) + { + LL_WARNS() << "error searching with '" << regex.str() << "': " + << e.what() << ":\n'" << string << "'" << LL_ENDL; + return false; + } +} + +template +bool ll_regex_search(const S& string, const R& regex) +{ + try + { + return boost::regex_search(string, regex); + } + catch (const std::runtime_error& e) + { + LL_WARNS() << "error searching with '" << regex.str() << "': " + << e.what() << ":\n'" << string << "'" << LL_ENDL; + return false; + } +} +#endif // LLREGEX_H diff --git a/indra/llcommon/llsys.cpp b/indra/llcommon/llsys.cpp index 1f8d558fbe..f7461422f7 100644 --- a/indra/llcommon/llsys.cpp +++ b/indra/llcommon/llsys.cpp @@ -43,12 +43,12 @@ #include "llerrorcontrol.h" #include "llevents.h" #include "llformat.h" +#include "llregex.h" #include "lltimer.h" #include "llsdserialize.h" #include "llsdutil.h" #include #include -#include #include #include #include @@ -111,39 +111,6 @@ static const F32 MEM_INFO_THROTTLE = 20; // dropped below the login framerate, we'd have very little additional data. static const F32 MEM_INFO_WINDOW = 10*60; -// Wrap boost::regex_match() with a function that doesn't throw. -template -static bool regex_match_no_exc(const S& string, M& match, const R& regex) -{ - try - { - return boost::regex_match(string, match, regex); - } - catch (const std::runtime_error& e) - { - LL_WARNS("LLMemoryInfo") << "error matching with '" << regex.str() << "': " - << e.what() << ":\n'" << string << "'" << LL_ENDL; - return false; - } -} - -// Wrap boost::regex_search() with a function that doesn't throw. -template -static bool regex_search_no_exc(const S& string, M& match, const R& regex) -{ - try - { - return boost::regex_search(string, match, regex); - } - catch (const std::runtime_error& e) - { - LL_WARNS("LLMemoryInfo") << "error searching with '" << regex.str() << "': " - << e.what() << ":\n'" << string << "'" << LL_ENDL; - return false; - } -} - - LLOSInfo::LLOSInfo() : mMajorVer(0), mMinorVer(0), mBuild(0), mOSVersionString("") { @@ -387,7 +354,7 @@ LLOSInfo::LLOSInfo() : boost::smatch matched; std::string glibc_version(gnu_get_libc_version()); - if ( regex_match_no_exc(glibc_version, matched, os_version_parse) ) + if ( ll_regex_match(glibc_version, matched, os_version_parse) ) { LL_INFOS("AppInit") << "Using glibc version '" << glibc_version << "' as OS version" << LL_ENDL; @@ -1116,7 +1083,7 @@ LLSD LLMemoryInfo::loadStatsMap() while (std::getline(meminfo, line)) { LL_DEBUGS("LLMemoryInfo") << line << LL_ENDL; - if (regex_match_no_exc(line, matched, stat_rx)) + if (ll_regex_match(line, matched, stat_rx)) { // e.g. "MemTotal: 4108424 kB" LLSD::String key(matched[1].first, matched[1].second); diff --git a/indra/llprimitive/llmediaentry.cpp b/indra/llprimitive/llmediaentry.cpp index 02aba2bd83..53e9555c6a 100644 --- a/indra/llprimitive/llmediaentry.cpp +++ b/indra/llprimitive/llmediaentry.cpp @@ -27,8 +27,7 @@ #include "linden_common.h" #include "llmediaentry.h" #include "lllslconstants.h" - -#include +#include "llregex.h" // LLSD key defines // DO NOT REORDER OR REMOVE THESE! @@ -456,7 +455,7 @@ static bool pattern_match(const std::string &candidate_str, const std::string &p // case-insensitive matching: boost::regex regexp(expression, boost::regex::perl|boost::regex::icase); - return boost::regex_match(candidate_str, regexp); + return ll_regex_match(candidate_str, regexp); } bool LLMediaEntry::checkCandidateUrl(const std::string& url) const diff --git a/indra/llui/llurlentry.cpp b/indra/llui/llurlentry.cpp index e6835f73fb..ff742a9530 100644 --- a/indra/llui/llurlentry.cpp +++ b/indra/llui/llurlentry.cpp @@ -35,6 +35,7 @@ #include "llavatarnamecache.h" #include "llcachename.h" +#include "llregex.h" #include "lltrans.h" #include "lluicolortable.h" #include "message.h" @@ -1388,7 +1389,7 @@ std::string LLUrlEntryIcon::getIcon(const std::string &url) // Grep icon info between ... tags // matches[1] contains the icon name/path boost::match_results matches; - mIcon = (boost::regex_match(url, matches, mPattern) && matches[1].matched) + mIcon = (ll_regex_match(url, matches, mPattern) && matches[1].matched) ? matches[1] : LLStringUtil::null; LLStringUtil::trim(mIcon); diff --git a/indra/llui/llurlregistry.cpp b/indra/llui/llurlregistry.cpp index ba6fa1e2e9..5f44475bd7 100644 --- a/indra/llui/llurlregistry.cpp +++ b/indra/llui/llurlregistry.cpp @@ -26,10 +26,10 @@ */ #include "linden_common.h" +#include "llregex.h" #include "llurlregistry.h" #include "lluriparser.h" -#include // default dummy callback that ignores any label updates from the server void LLUrlRegistryNullCallback(const std::string &url, const std::string &label, const std::string& icon) @@ -107,15 +107,7 @@ static bool matchRegex(const char *text, boost::regex regex, U32 &start, U32 &en boost::cmatch result; bool found; - // regex_search can potentially throw an exception, so check for it - try - { - found = boost::regex_search(text, result, regex); - } - catch (std::runtime_error &) - { - return false; - } + found = ll_regex_search(text, result, regex); if (! found) { diff --git a/indra/llvfs/lldiriterator.cpp b/indra/llvfs/lldiriterator.cpp index 3eb64e69d9..f57bf4ebc6 100644 --- a/indra/llvfs/lldiriterator.cpp +++ b/indra/llvfs/lldiriterator.cpp @@ -27,8 +27,8 @@ #include "lldiriterator.h" #include "fix_macros.h" +#include "llregex.h" #include -#include namespace fs = boost::filesystem; @@ -131,7 +131,7 @@ bool LLDirIterator::Impl::next(std::string &fname) { boost::smatch match; std::string name = mIter->path().filename().string(); - found = boost::regex_match(name, match, mFilterExp); + found = ll_regex_match(name, match, mFilterExp); if (found) { fname = name; diff --git a/indra/newview/llfloaterwindowsize.cpp b/indra/newview/llfloaterwindowsize.cpp index ec161018b8..863b7cbb12 100644 --- a/indra/newview/llfloaterwindowsize.cpp +++ b/indra/newview/llfloaterwindowsize.cpp @@ -34,18 +34,16 @@ #include "llcombobox.h" #include "llfloater.h" #include "llfloaterreg.h" +#include "llregex.h" #include "lluictrl.h" -// System libraries -#include - // Extract from strings of the form " x ", e.g. "640 x 480". bool extractWindowSizeFromString(const std::string& instr, U32 *width, U32 *height) { boost::cmatch what; // matches (any number)(any non-number)(any number) const boost::regex expression("([0-9]+)[^0-9]+([0-9]+)"); - if (boost::regex_match(instr.c_str(), what, expression)) + if (ll_regex_match(instr.c_str(), what, expression)) { *width = atoi(what[1].first); *height = atoi(what[2].first); diff --git a/indra/newview/llimprocessing.cpp b/indra/newview/llimprocessing.cpp index 1e43e4ea3a..0524313a5c 100644 --- a/indra/newview/llimprocessing.cpp +++ b/indra/newview/llimprocessing.cpp @@ -42,6 +42,7 @@ #include "llnotificationsutil.h" #include "llnotificationmanager.h" #include "llpanelgroup.h" +#include "llregex.h" #include "llregionhandle.h" #include "llsdserialize.h" #include "llslurl.h" @@ -55,7 +56,6 @@ #include "llviewerregion.h" #include "llvoavatarself.h" -#include #include "boost/lexical_cast.hpp" #if LL_MSVC // disable boost::lexical_cast warning @@ -122,7 +122,7 @@ static std::string clean_name_from_task_im(const std::string& msg, boost::smatch match; static const boost::regex returned_exp( "(.*been returned to your inventory lost and found folder by )(.+)( (from|near).*)"); - if (boost::regex_match(msg, match, returned_exp)) + if (ll_regex_match(msg, match, returned_exp)) { // match objects are 1-based for groups std::string final = match[1].str(); diff --git a/indra/newview/llinventoryfilter.cpp b/indra/newview/llinventoryfilter.cpp index 72013f7396..c972b1dab7 100644 --- a/indra/newview/llinventoryfilter.cpp +++ b/indra/newview/llinventoryfilter.cpp @@ -36,13 +36,14 @@ #include "llinventorymodelbackgroundfetch.h" #include "llinventoryfunctions.h" #include "llmarketplacefunctions.h" +#include "llregex.h" #include "llviewercontrol.h" #include "llfolderview.h" #include "llinventorybridge.h" #include "llviewerfoldertype.h" #include "llradiogroup.h" #include "llstartup.h" -#include + // linden library includes #include "llclipboard.h" #include "lltrans.h" @@ -800,7 +801,7 @@ void LLInventoryFilter::setFilterSubString(const std::string& string) boost::regex mPattern = boost::regex("\"\\s*([^<]*)?\\s*\"", boost::regex::perl | boost::regex::icase); boost::match_results matches; - mExactToken = (boost::regex_match(filter_sub_string_new, matches, mPattern) && matches[1].matched) + mExactToken = (ll_regex_match(filter_sub_string_new, matches, mPattern) && matches[1].matched) ? matches[1] : LLStringUtil::null; if ((old_token.empty() && !mExactToken.empty()) diff --git a/indra/newview/lllogchat.cpp b/indra/newview/lllogchat.cpp index 415781bc27..0ddcac44c9 100644 --- a/indra/newview/lllogchat.cpp +++ b/indra/newview/lllogchat.cpp @@ -30,6 +30,7 @@ #include "llagentui.h" #include "llavatarnamecache.h" #include "lllogchat.h" +#include "llregex.h" #include "lltrans.h" #include "llviewercontrol.h" @@ -40,7 +41,6 @@ #include #include -#include #include #include @@ -250,8 +250,8 @@ std::string LLLogChat::makeLogFileName(std::string filename) **/ boost::match_results matches; - bool inboundConf = boost::regex_match(filename, matches, INBOUND_CONFERENCE); - bool outboundConf = boost::regex_match(filename, matches, OUTBOUND_CONFERENCE); + bool inboundConf = ll_regex_match(filename, matches, INBOUND_CONFERENCE); + bool outboundConf = ll_regex_match(filename, matches, OUTBOUND_CONFERENCE); if (!(inboundConf || outboundConf)) { if( gSavedPerAccountSettings.getBOOL("LogFileNamewithDate") ) @@ -815,7 +815,7 @@ bool LLLogChat::isTranscriptFileFound(std::string fullname) { //matching a timestamp boost::match_results matches; - if (boost::regex_match(remove_utf8_bom(buffer), matches, TIMESTAMP)) + if (ll_regex_match(remove_utf8_bom(buffer), matches, TIMESTAMP)) { result = true; } @@ -895,7 +895,7 @@ bool LLChatLogParser::parse(std::string& raw, LLSD& im, const LLSD& parse_params //matching a timestamp boost::match_results matches; - if (!boost::regex_match(raw, matches, TIMESTAMP_AND_STUFF)) return false; + if (!ll_regex_match(raw, matches, TIMESTAMP_AND_STUFF)) return false; bool has_timestamp = matches[IDX_TIMESTAMP].matched; if (has_timestamp) @@ -928,7 +928,7 @@ bool LLChatLogParser::parse(std::string& raw, LLSD& im, const LLSD& parse_params //matching a name and a text std::string stuff = matches[IDX_STUFF]; boost::match_results name_and_text; - if (!boost::regex_match(stuff, name_and_text, NAME_AND_TEXT)) return false; + if (!ll_regex_match(stuff, name_and_text, NAME_AND_TEXT)) return false; bool has_name = name_and_text[IDX_NAME].matched; std::string name = LLURI::unescape(name_and_text[IDX_NAME]); diff --git a/indra/newview/llpanelexperiencepicker.cpp b/indra/newview/llpanelexperiencepicker.cpp index 80aeee6da1..6dfdbaf63f 100644 --- a/indra/newview/llpanelexperiencepicker.cpp +++ b/indra/newview/llpanelexperiencepicker.cpp @@ -41,8 +41,8 @@ #include "llcombobox.h" #include "llviewercontrol.h" #include "llfloater.h" +#include "llregex.h" #include "lltrans.h" -#include #define BTN_FIND "find" #define BTN_OK "ok_btn" @@ -116,7 +116,7 @@ void LLPanelExperiencePicker::onBtnFind() boost::cmatch what; std::string text = getChild(TEXT_EDIT)->getValue().asString(); const boost::regex expression("secondlife:///app/experience/[\\da-f-]+/profile"); - if (boost::regex_match(text.c_str(), what, expression)) + if (ll_regex_match(text.c_str(), what, expression)) { LLURI uri(text); LLSD path_array = uri.pathArray(); diff --git a/indra/newview/llpanelsnapshotpostcard.cpp b/indra/newview/llpanelsnapshotpostcard.cpp index b8aa976657..05fa2b58b1 100644 --- a/indra/newview/llpanelsnapshotpostcard.cpp +++ b/indra/newview/llpanelsnapshotpostcard.cpp @@ -38,6 +38,7 @@ #include "llfloatersnapshot.h" // FIXME: replace with a snapshot storage model #include "llpanelsnapshot.h" #include "llpostcard.h" +#include "llregex.h" #include "llsnapshotlivepreview.h" #include "llviewercontrol.h" // gSavedSettings #include "llviewerwindow.h" @@ -229,7 +230,7 @@ void LLPanelSnapshotPostcard::onSend() boost::regex email_format("[A-Za-z0-9.%+-_]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,}(,[ \t]*[A-Za-z0-9.%+-_]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,})*"); - if (to.empty() || !boost::regex_match(to, email_format)) + if (to.empty() || !ll_regex_match(to, email_format)) { LLNotificationsUtil::add("PromptRecipientEmail"); return; diff --git a/indra/newview/llversioninfo.cpp b/indra/newview/llversioninfo.cpp index 4720a989b0..376a7fce76 100644 --- a/indra/newview/llversioninfo.cpp +++ b/indra/newview/llversioninfo.cpp @@ -28,9 +28,9 @@ #include "llviewerprecompiledheaders.h" #include "llevents.h" #include "lleventfilter.h" +#include "llregex.h" #include "llversioninfo.h" #include "stringize.h" -#include #if ! defined(LL_VIEWER_CHANNEL) \ || ! defined(LL_VIEWER_VERSION_MAJOR) \ @@ -139,19 +139,19 @@ LLVersionInfo::ViewerMaturity LLVersionInfo::getViewerMaturity() static const boost::regex is_project_channel("\\bProject\\b"); static const boost::regex is_release_channel("\\bRelease\\b"); - if (boost::regex_search(channel, is_release_channel)) + if (ll_regex_search(channel, is_release_channel)) { maturity = RELEASE_VIEWER; } - else if (boost::regex_search(channel, is_beta_channel)) + else if (ll_regex_search(channel, is_beta_channel)) { maturity = BETA_VIEWER; } - else if (boost::regex_search(channel, is_project_channel)) + else if (ll_regex_search(channel, is_project_channel)) { maturity = PROJECT_VIEWER; } - else if (boost::regex_search(channel, is_test_channel)) + else if (ll_regex_search(channel, is_test_channel)) { maturity = TEST_VIEWER; } diff --git a/indra/newview/llweb.cpp b/indra/newview/llweb.cpp index 63257d6543..2618f9c719 100644 --- a/indra/newview/llweb.cpp +++ b/indra/newview/llweb.cpp @@ -38,6 +38,7 @@ #include "llfloaterreg.h" #include "lllogininstance.h" #include "llparcel.h" +#include "llregex.h" #include "llsd.h" #include "llui.h" #include "lluri.h" @@ -51,8 +52,6 @@ #include "lluriparser.h" #include "uriparser/Uri.h" -#include - bool on_load_url_external_response(const LLSD& notification, const LLSD& response, bool async ); @@ -239,13 +238,13 @@ bool LLWeb::useExternalBrowser(const std::string &url) boost::regex pattern = boost::regex("\\b(lindenlab.com|secondlife.com)$", boost::regex::perl|boost::regex::icase); boost::match_results matches; - return !(boost::regex_search(uri_string, matches, pattern)); + return !(ll_regex_search(uri_string, matches, pattern)); } else { boost::regex pattern = boost::regex("^mailto:", boost::regex::perl | boost::regex::icase); boost::match_results matches; - return boost::regex_search(url, matches, pattern); + return ll_regex_search(url, matches, pattern); } #endif } -- cgit v1.3 From d3d8203be4aec8ad90c0044e3a0ade1d91df64ea Mon Sep 17 00:00:00 2001 From: Nat Goodspeed Date: Thu, 13 May 2021 22:10:43 -0400 Subject: SL-15258: Remove additional std library features dropped with C++17. --- indra/llcommon/llsd.h | 43 ------ indra/llcommon/llstl.h | 237 +--------------------------------- indra/llcommon/tests/llleap_test.cpp | 2 +- indra/llmessage/llcircuit.cpp | 11 +- indra/llmessage/lldispatcher.cpp | 2 +- indra/llmessage/llmessagethrottle.cpp | 22 ---- indra/newview/llexperiencelog.cpp | 4 - indra/newview/llgesturemgr.cpp | 2 +- 8 files changed, 10 insertions(+), 313 deletions(-) (limited to 'indra/llcommon') diff --git a/indra/llcommon/llsd.h b/indra/llcommon/llsd.h index 5b6d5545af..6638b25feb 100644 --- a/indra/llcommon/llsd.h +++ b/indra/llcommon/llsd.h @@ -413,49 +413,6 @@ public: static std::string typeString(Type type); // Return human-readable type as a string }; -struct llsd_select_bool : public std::unary_function -{ - LLSD::Boolean operator()(const LLSD& sd) const - { - return sd.asBoolean(); - } -}; -struct llsd_select_integer : public std::unary_function -{ - LLSD::Integer operator()(const LLSD& sd) const - { - return sd.asInteger(); - } -}; -struct llsd_select_real : public std::unary_function -{ - LLSD::Real operator()(const LLSD& sd) const - { - return sd.asReal(); - } -}; -struct llsd_select_float : public std::unary_function -{ - F32 operator()(const LLSD& sd) const - { - return (F32)sd.asReal(); - } -}; -struct llsd_select_uuid : public std::unary_function -{ - LLSD::UUID operator()(const LLSD& sd) const - { - return sd.asUUID(); - } -}; -struct llsd_select_string : public std::unary_function -{ - LLSD::String operator()(const LLSD& sd) const - { - return sd.asString(); - } -}; - LL_COMMON_API std::ostream& operator<<(std::ostream& s, const LLSD& llsd); namespace llsd diff --git a/indra/llcommon/llstl.h b/indra/llcommon/llstl.h index a90c2c7e08..d28260b9f8 100644 --- a/indra/llcommon/llstl.h +++ b/indra/llcommon/llstl.h @@ -40,30 +40,6 @@ // For strcmp #include #endif -// Use to compare the first element only of a pair -// e.g. typedef std::set, compare_pair > some_pair_set_t; -template -struct compare_pair_first -{ - bool operator()(const std::pair& a, const std::pair& b) const - { - return a.first < b.first; - } -}; - -template -struct compare_pair_greater -{ - bool operator()(const std::pair& a, const std::pair& b) const - { - if (!(a.first < b.first)) - return true; - else if (!(b.first < a.first)) - return false; - else - return !(a.second < b.second); - } -}; // Use to compare the contents of two pointers (e.g. std::string*) template @@ -123,58 +99,6 @@ struct DeletePairedPointerArray }; -// Alternate version of the above so that has a more cumbersome -// syntax, but it can be used with compositional functors. -// NOTE: The functor retuns a bool because msdev bombs during the -// composition if you return void. Once we upgrade to a newer -// compiler, the second unary_function template parameter can be set -// to void. -// -// Here's a snippet showing how you use this object: -// -// typedef std::map map_type; -// map_type widget_map; -// ... // add elements -// // delete them all -// for_each(widget_map.begin(), -// widget_map.end(), -// llcompose1(DeletePointerFunctor(), -// llselect2nd())); - -template -struct DeletePointerFunctor : public std::unary_function -{ - bool operator()(T* ptr) const - { - delete ptr; - return true; - } -}; - -// See notes about DeleteArray for why you should consider avoiding this. -template -struct DeleteArrayFunctor : public std::unary_function -{ - bool operator()(T* ptr) const - { - delete[] ptr; - return true; - } -}; - -// CopyNewPointer is a simple helper which accepts a pointer, and -// returns a new pointer built with the copy constructor. Example: -// -// transform(in.begin(), in.end(), out.end(), CopyNewPointer()); - -struct CopyNewPointer -{ - template T* operator()(const T* ptr) const - { - return new T(*ptr); - } -}; - template void delete_and_clear(std::list& list) { @@ -363,161 +287,6 @@ OutputIter ll_transform_n( } - -/* - * - * Copyright (c) 1994 - * Hewlett-Packard Company - * - * Permission to use, copy, modify, distribute and sell this software - * and its documentation for any purpose is hereby granted without fee, - * provided that the above copyright notice appear in all copies and - * that both that copyright notice and this permission notice appear - * in supporting documentation. Hewlett-Packard Company makes no - * representations about the suitability of this software for any - * purpose. It is provided "as is" without express or implied warranty. - * - * - * Copyright (c) 1996-1998 - * Silicon Graphics Computer Systems, Inc. - * - * Permission to use, copy, modify, distribute and sell this software - * and its documentation for any purpose is hereby granted without fee, - * provided that the above copyright notice appear in all copies and - * that both that copyright notice and this permission notice appear - * in supporting documentation. Silicon Graphics makes no - * representations about the suitability of this software for any - * purpose. It is provided "as is" without express or implied warranty. - */ - - -// helper to deal with the fact that MSDev does not package -// select... with the stl. Look up usage on the sgi website. - -template -struct _LLSelect1st : public std::unary_function<_Pair, typename _Pair::first_type> { - const typename _Pair::first_type& operator()(const _Pair& __x) const { - return __x.first; - } -}; - -template -struct _LLSelect2nd : public std::unary_function<_Pair, typename _Pair::second_type> -{ - const typename _Pair::second_type& operator()(const _Pair& __x) const { - return __x.second; - } -}; - -template struct llselect1st : public _LLSelect1st<_Pair> {}; -template struct llselect2nd : public _LLSelect2nd<_Pair> {}; - -// helper to deal with the fact that MSDev does not package -// compose... with the stl. Look up usage on the sgi website. - -template -class ll_unary_compose : - public std::unary_function -{ -protected: - _Operation1 __op1; - _Operation2 __op2; -public: - ll_unary_compose(const _Operation1& __x, const _Operation2& __y) - : __op1(__x), __op2(__y) {} - typename _Operation1::result_type - operator()(const typename _Operation2::argument_type& __x) const { - return __op1(__op2(__x)); - } -}; - -template -inline ll_unary_compose<_Operation1,_Operation2> -llcompose1(const _Operation1& __op1, const _Operation2& __op2) -{ - return ll_unary_compose<_Operation1,_Operation2>(__op1, __op2); -} - -template -class ll_binary_compose - : public std::unary_function { -protected: - _Operation1 _M_op1; - _Operation2 _M_op2; - _Operation3 _M_op3; -public: - ll_binary_compose(const _Operation1& __x, const _Operation2& __y, - const _Operation3& __z) - : _M_op1(__x), _M_op2(__y), _M_op3(__z) { } - typename _Operation1::result_type - operator()(const typename _Operation2::argument_type& __x) const { - return _M_op1(_M_op2(__x), _M_op3(__x)); - } -}; - -template -inline ll_binary_compose<_Operation1, _Operation2, _Operation3> -llcompose2(const _Operation1& __op1, const _Operation2& __op2, - const _Operation3& __op3) -{ - return ll_binary_compose<_Operation1,_Operation2,_Operation3> - (__op1, __op2, __op3); -} - -// helpers to deal with the fact that MSDev does not package -// bind... with the stl. Again, this is from sgi. -template -class llbinder1st : - public std::unary_function { -protected: - _Operation op; - typename _Operation::first_argument_type value; -public: - llbinder1st(const _Operation& __x, - const typename _Operation::first_argument_type& __y) - : op(__x), value(__y) {} - typename _Operation::result_type - operator()(const typename _Operation::second_argument_type& __x) const { - return op(value, __x); - } -}; - -template -inline llbinder1st<_Operation> -llbind1st(const _Operation& __oper, const _Tp& __x) -{ - typedef typename _Operation::first_argument_type _Arg1_type; - return llbinder1st<_Operation>(__oper, _Arg1_type(__x)); -} - -template -class llbinder2nd - : public std::unary_function { -protected: - _Operation op; - typename _Operation::second_argument_type value; -public: - llbinder2nd(const _Operation& __x, - const typename _Operation::second_argument_type& __y) - : op(__x), value(__y) {} - typename _Operation::result_type - operator()(const typename _Operation::first_argument_type& __x) const { - return op(__x, value); - } -}; - -template -inline llbinder2nd<_Operation> -llbind2nd(const _Operation& __oper, const _Tp& __x) -{ - typedef typename _Operation::second_argument_type _Arg2_type; - return llbinder2nd<_Operation>(__oper, _Arg2_type(__x)); -} - /** * Compare std::type_info* pointers a la std::less. We break this out as a * separate function for use in two different std::less specializations. @@ -548,8 +317,7 @@ bool before(const std::type_info* lhs, const std::type_info* rhs) namespace std { template <> - struct less: - public std::binary_function + struct less { bool operator()(const std::type_info* lhs, const std::type_info* rhs) const { @@ -558,8 +326,7 @@ namespace std }; template <> - struct less: - public std::binary_function + struct less { bool operator()(std::type_info* lhs, std::type_info* rhs) const { diff --git a/indra/llcommon/tests/llleap_test.cpp b/indra/llcommon/tests/llleap_test.cpp index 9d71e327d8..fd96aa01d5 100644 --- a/indra/llcommon/tests/llleap_test.cpp +++ b/indra/llcommon/tests/llleap_test.cpp @@ -530,7 +530,7 @@ namespace tut result.ensure(); } - struct TestLargeMessage: public std::binary_function + struct TestLargeMessage { TestLargeMessage(const std::string& PYTHON_, const std::string& reader_module_, const std::string& test_name_): diff --git a/indra/llmessage/llcircuit.cpp b/indra/llmessage/llcircuit.cpp index 8baa2e328b..a39989515e 100644 --- a/indra/llmessage/llcircuit.cpp +++ b/indra/llmessage/llcircuit.cpp @@ -436,12 +436,11 @@ LLCircuit::LLCircuit(const F32Seconds circuit_heartbeat_interval, const F32Secon LLCircuit::~LLCircuit() { - // delete pointers in the map. - std::for_each(mCircuitData.begin(), - mCircuitData.end(), - llcompose1( - DeletePointerFunctor(), - llselect2nd())); + // delete pointers in the map. + for (auto circ_pair : mCircuitData) + { + delete circ_pair.second; + } } LLCircuitData *LLCircuit::addCircuitData(const LLHost &host, TPACKETID in_id) diff --git a/indra/llmessage/lldispatcher.cpp b/indra/llmessage/lldispatcher.cpp index 717ef10f70..8dfd924f31 100644 --- a/indra/llmessage/lldispatcher.cpp +++ b/indra/llmessage/lldispatcher.cpp @@ -62,7 +62,7 @@ void LLDispatcher::copyAllHandlerNames(keys_t& names) const mHandlers.begin(), mHandlers.end(), std::back_insert_iterator(names), - llselect1st()); + [](const dispatch_map_t::value_type& pair){ return pair.first; }); } bool LLDispatcher::dispatch( diff --git a/indra/llmessage/llmessagethrottle.cpp b/indra/llmessage/llmessagethrottle.cpp index 579d6d7187..c5ae8b4547 100644 --- a/indra/llmessage/llmessagethrottle.cpp +++ b/indra/llmessage/llmessagethrottle.cpp @@ -32,18 +32,8 @@ #include "llframetimer.h" // This is used for the stl search_n function. -#if _MSC_VER >= 1500 // VC9 has a bug in search_n -struct eq_message_throttle_entry : public std::binary_function< LLMessageThrottleEntry, LLMessageThrottleEntry, bool > -{ - bool operator()(const LLMessageThrottleEntry& a, const LLMessageThrottleEntry& b) const - { - return a.getHash() == b.getHash(); - } -}; -#else bool eq_message_throttle_entry(LLMessageThrottleEntry a, LLMessageThrottleEntry b) { return a.getHash() == b.getHash(); } -#endif const U64 SEC_TO_USEC = 1000000; @@ -118,14 +108,8 @@ BOOL LLMessageThrottle::addViewerAlert(const LLUUID& to, const std::string& mesg LLMessageThrottleEntry entry(hash, LLFrameTimer::getTotalTime()); // Check if this message is already in the list. -#if _MSC_VER >= 1500 // VC9 has a bug in search_n - // SJB: This *should* work but has not been tested yet *TODO: Test! - message_list_iterator_t found = std::find_if(message_list->begin(), message_list->end(), - std::bind2nd(eq_message_throttle_entry(), entry)); -#else message_list_iterator_t found = std::search_n(message_list->begin(), message_list->end(), 1, entry, eq_message_throttle_entry); -#endif if (found == message_list->end()) { // This message was not found. Add it to the list. @@ -152,14 +136,8 @@ BOOL LLMessageThrottle::addAgentAlert(const LLUUID& agent, const LLUUID& task, c LLMessageThrottleEntry entry(hash, LLFrameTimer::getTotalTime()); // Check if this message is already in the list. -#if _MSC_VER >= 1500 // VC9 has a bug in search_n - // SJB: This *should* work but has not been tested yet *TODO: Test! - message_list_iterator_t found = std::find_if(message_list->begin(), message_list->end(), - std::bind2nd(eq_message_throttle_entry(), entry)); -#else message_list_iterator_t found = std::search_n(message_list->begin(), message_list->end(), 1, entry, eq_message_throttle_entry); -#endif if (found == message_list->end()) { diff --git a/indra/newview/llexperiencelog.cpp b/indra/newview/llexperiencelog.cpp index ee5d561927..c441fbc09f 100644 --- a/indra/newview/llexperiencelog.cpp +++ b/indra/newview/llexperiencelog.cpp @@ -149,10 +149,6 @@ std::string LLExperienceLog::getPermissionString( const LLSD& message, const std { buf.str(entry); } - else - { - buf.str(); - } } if(buf.str().empty()) diff --git a/indra/newview/llgesturemgr.cpp b/indra/newview/llgesturemgr.cpp index 950a6cfaef..eb0e77311b 100644 --- a/indra/newview/llgesturemgr.cpp +++ b/indra/newview/llgesturemgr.cpp @@ -752,7 +752,7 @@ S32 LLGestureMgr::getPlayingCount() const } -struct IsGesturePlaying : public std::unary_function +struct IsGesturePlaying { bool operator()(const LLMultiGesture* gesture) const { -- cgit v1.3 From 96cbe528030b16dfb0c17b9668fb441a2cbc22c4 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Fri, 21 May 2021 20:06:41 +0300 Subject: SL-15272 Bugsplat crashes at condition wait() Made sure all waits will be triggered, won't loop back and that in case of http queue it had some time to trigger --- indra/llcommon/llthread.cpp | 3 ++- indra/llcorehttp/_httpreplyqueue.cpp | 1 - indra/llcorehttp/_httpreplyqueue.h | 1 - indra/llcorehttp/_httprequestqueue.cpp | 12 +++++++++--- indra/llcorehttp/_httprequestqueue.h | 2 +- indra/llcorehttp/_httpservice.cpp | 6 +++++- indra/newview/llappearancemgr.cpp | 6 +++--- indra/newview/llcompilequeue.cpp | 2 +- indra/newview/lldelayedgestureerror.cpp | 2 +- indra/newview/llmeshrepository.cpp | 19 ++++++++++--------- indra/newview/lloutfitgallery.cpp | 2 +- indra/newview/lltoolmgr.cpp | 2 +- indra/newview/llviewerassetstorage.cpp | 2 +- indra/win_crash_logger/llcrashloggerwindows.cpp | 2 +- 14 files changed, 36 insertions(+), 26 deletions(-) (limited to 'indra/llcommon') diff --git a/indra/llcommon/llthread.cpp b/indra/llcommon/llthread.cpp index 0b9dec969c..e9e6b5e73c 100644 --- a/indra/llcommon/llthread.cpp +++ b/indra/llcommon/llthread.cpp @@ -354,8 +354,9 @@ void LLThread::setQuitting() { mStatus = QUITTING; } + // It's only safe to remove mRunCondition if all locked threads were notified + mRunCondition->broadcast(); mDataLock->unlock(); - wake(); } // static diff --git a/indra/llcorehttp/_httpreplyqueue.cpp b/indra/llcorehttp/_httpreplyqueue.cpp index 2b138f3ad5..229bfdbe07 100644 --- a/indra/llcorehttp/_httpreplyqueue.cpp +++ b/indra/llcorehttp/_httpreplyqueue.cpp @@ -56,7 +56,6 @@ void HttpReplyQueue::addOp(const HttpReplyQueue::opPtr_t &op) mQueue.push_back(op); } - mQueueCV.notify_all(); } diff --git a/indra/llcorehttp/_httpreplyqueue.h b/indra/llcorehttp/_httpreplyqueue.h index 928ee10a83..33e205c1c9 100644 --- a/indra/llcorehttp/_httpreplyqueue.h +++ b/indra/llcorehttp/_httpreplyqueue.h @@ -98,7 +98,6 @@ protected: OpContainer mQueue; LLCoreInt::HttpMutex mQueueMutex; - LLCoreInt::HttpConditionVariable mQueueCV; }; // end class HttpReplyQueue diff --git a/indra/llcorehttp/_httprequestqueue.cpp b/indra/llcorehttp/_httprequestqueue.cpp index c6f4ad789f..ad72bdcce6 100644 --- a/indra/llcorehttp/_httprequestqueue.cpp +++ b/indra/llcorehttp/_httprequestqueue.cpp @@ -142,13 +142,19 @@ void HttpRequestQueue::wakeAll() } -void HttpRequestQueue::stopQueue() +bool HttpRequestQueue::stopQueue() { { HttpScopedLock lock(mQueueMutex); - mQueueStopped = true; - wakeAll(); + if (!mQueueStopped) + { + mQueueStopped = true; + wakeAll(); + return true; + } + wakeAll(); + return false; } } diff --git a/indra/llcorehttp/_httprequestqueue.h b/indra/llcorehttp/_httprequestqueue.h index 3c3d134b07..f0296f30e3 100644 --- a/indra/llcorehttp/_httprequestqueue.h +++ b/indra/llcorehttp/_httprequestqueue.h @@ -124,7 +124,7 @@ public: /// them on their way. /// /// Threading: callable by any thread. - void stopQueue(); + bool stopQueue(); protected: static HttpRequestQueue * sInstance; diff --git a/indra/llcorehttp/_httpservice.cpp b/indra/llcorehttp/_httpservice.cpp index 34268d94f6..56f52f1b09 100644 --- a/indra/llcorehttp/_httpservice.cpp +++ b/indra/llcorehttp/_httpservice.cpp @@ -87,7 +87,11 @@ HttpService::~HttpService() // is a bit tricky. if (mRequestQueue) { - mRequestQueue->stopQueue(); + if (mRequestQueue->stopQueue()) + { + // Give mRequestQueue a chance to finish + ms_sleep(10); + } } if (mThread) diff --git a/indra/newview/llappearancemgr.cpp b/indra/newview/llappearancemgr.cpp index 268999bd2a..31b5cf9aaa 100644 --- a/indra/newview/llappearancemgr.cpp +++ b/indra/newview/llappearancemgr.cpp @@ -3626,7 +3626,7 @@ void LLAppearanceMgr::serverAppearanceUpdateCoro(LLCoreHttpUtil::HttpCoroutineAd } llcoro::suspend(); - if (LLApp::isQuitting()) + if (LLApp::isExiting()) { return; } @@ -3693,7 +3693,7 @@ void LLAppearanceMgr::serverAppearanceUpdateCoro(LLCoreHttpUtil::HttpCoroutineAd LLSD result = httpAdapter->postAndSuspend(httpRequest, url, postData); - if (LLApp::isQuitting()) + if (LLApp::isExiting()) { return; } @@ -3733,7 +3733,7 @@ void LLAppearanceMgr::serverAppearanceUpdateCoro(LLCoreHttpUtil::HttpCoroutineAd LL_WARNS("Avatar") << "Bake retry #" << retryCount << " in " << timeout << " seconds." << LL_ENDL; llcoro::suspendUntilTimeout(timeout); - if (LLApp::isQuitting()) + if (LLApp::isExiting()) { return; } diff --git a/indra/newview/llcompilequeue.cpp b/indra/newview/llcompilequeue.cpp index 3aaaaf52f5..bf10a9f2b4 100644 --- a/indra/newview/llcompilequeue.cpp +++ b/indra/newview/llcompilequeue.cpp @@ -347,7 +347,7 @@ void LLFloaterCompileQueue::processExperienceIdResults(LLSD result, LLUUID paren bool LLFloaterCompileQueue::processScript(LLHandle hfloater, const LLPointer &object, LLInventoryObject* inventory, LLEventPump &pump) { - if (LLApp::isQuitting()) + if (LLApp::isExiting()) { // Reply from coroutine came on shutdown // We are quiting, don't start any more coroutines! diff --git a/indra/newview/lldelayedgestureerror.cpp b/indra/newview/lldelayedgestureerror.cpp index ef1b644ad4..934a38bb8e 100644 --- a/indra/newview/lldelayedgestureerror.cpp +++ b/indra/newview/lldelayedgestureerror.cpp @@ -113,7 +113,7 @@ bool LLDelayedGestureError::doDialog(const LLErrorEntry &ent, bool uuid_ok) } } - if(!LLApp::isQuitting()) + if(!LLApp::isExiting()) { LLNotificationsUtil::add(ent.mNotifyName, args); } diff --git a/indra/newview/llmeshrepository.cpp b/indra/newview/llmeshrepository.cpp index 3e8731dfe6..2c1c1191da 100644 --- a/indra/newview/llmeshrepository.cpp +++ b/indra/newview/llmeshrepository.cpp @@ -881,7 +881,7 @@ void LLMeshRepoThread::run() LL_WARNS(LOG_MESH) << "Convex decomposition unable to be loaded. Expect severe problems." << LL_ENDL; } - while (!LLApp::isQuitting()) + while (!LLApp::isExiting()) { // *TODO: Revise sleep/wake strategy and try to move away // from polling operations in this thread. We can sleep @@ -898,7 +898,7 @@ void LLMeshRepoThread::run() mSignal->wait(); - if (LLApp::isQuitting()) + if (LLApp::isExiting()) { break; } @@ -1168,7 +1168,7 @@ void LLMeshRepoThread::loadMeshPhysicsShape(const LLUUID& mesh_id) void LLMeshRepoThread::lockAndLoadMeshLOD(const LLVolumeParams& mesh_params, S32 lod) { - if (!LLAppViewer::isQuitting()) + if (!LLAppViewer::isExiting()) { loadMeshLOD(mesh_params, lod); } @@ -2654,7 +2654,7 @@ void LLMeshUploadThread::doWholeModelUpload() LL_DEBUGS(LOG_MESH) << "POST request issued." << LL_ENDL; mHttpRequest->update(0); - while (! LLApp::isQuitting() && ! finished() && ! isDiscarded()) + while (! LLApp::isExiting() && ! finished() && ! isDiscarded()) { ms_sleep(sleep_time); sleep_time = llmin(250U, sleep_time + sleep_time); @@ -2703,7 +2703,7 @@ void LLMeshUploadThread::requestWholeModelFee() U32 sleep_time(10); mHttpRequest->update(0); - while (! LLApp::isQuitting() && ! finished() && ! isDiscarded()) + while (! LLApp::isExiting() && ! finished() && ! isDiscarded()) { ms_sleep(sleep_time); sleep_time = llmin(250U, sleep_time + sleep_time); @@ -3149,7 +3149,7 @@ common_exit: LLMeshHeaderHandler::~LLMeshHeaderHandler() { - if (!LLApp::isQuitting()) + if (!LLApp::isExiting()) { if (! mProcessed) { @@ -3292,7 +3292,7 @@ void LLMeshHeaderHandler::processData(LLCore::BufferArray * /* body */, S32 /* b LLMeshLODHandler::~LLMeshLODHandler() { - if (! LLApp::isQuitting()) + if (! LLApp::isExiting()) { if (! mProcessed) { @@ -3553,7 +3553,7 @@ void LLMeshRepository::shutdown() mUploads[i]->discard() ; //discard the uploading requests. } - mThread->mSignal->signal(); + mThread->mSignal->broadcast(); while (!mThread->isStopped()) { @@ -4682,7 +4682,8 @@ void LLPhysicsDecomp::shutdown() if (mSignal) { mQuitting = true; - mSignal->signal(); + // There is only one wait(), but just in case 'broadcast' + mSignal->broadcast(); while (!isStopped()) { diff --git a/indra/newview/lloutfitgallery.cpp b/indra/newview/lloutfitgallery.cpp index ca7bd8cb2c..593b27f839 100644 --- a/indra/newview/lloutfitgallery.cpp +++ b/indra/newview/lloutfitgallery.cpp @@ -1111,7 +1111,7 @@ void LLOutfitGallery::refreshOutfit(const LLUUID& category_id) } } - if (mGalleryCreated && !LLApp::isQuitting()) + if (mGalleryCreated && !LLApp::isExiting()) { reArrangeRows(); } diff --git a/indra/newview/lltoolmgr.cpp b/indra/newview/lltoolmgr.cpp index 3fcf193dec..fa2dd60ee0 100644 --- a/indra/newview/lltoolmgr.cpp +++ b/indra/newview/lltoolmgr.cpp @@ -405,7 +405,7 @@ void LLToolMgr::clearTransientTool() void LLToolMgr::onAppFocusLost() { - if (LLApp::isQuitting()) + if (LLApp::isExiting()) return; if (mSelectedTool) diff --git a/indra/newview/llviewerassetstorage.cpp b/indra/newview/llviewerassetstorage.cpp index 7842d24279..9ac84b0635 100644 --- a/indra/newview/llviewerassetstorage.cpp +++ b/indra/newview/llviewerassetstorage.cpp @@ -544,7 +544,7 @@ void LLViewerAssetStorage::assetRequestCoro( LLSD result = httpAdapter->getRawAndSuspend(httpRequest, url, httpOpts); - if (LLApp::isQuitting() || !gAssetStorage) + if (LLApp::isExiting() || !gAssetStorage) { // Bail out if result arrives after shutdown has been started. return; diff --git a/indra/win_crash_logger/llcrashloggerwindows.cpp b/indra/win_crash_logger/llcrashloggerwindows.cpp index 267224a79b..0cbe0b0d17 100644 --- a/indra/win_crash_logger/llcrashloggerwindows.cpp +++ b/indra/win_crash_logger/llcrashloggerwindows.cpp @@ -498,7 +498,7 @@ bool LLCrashLoggerWindows::frame() MSG msg; memset(&msg, 0, sizeof(msg)); - while (!LLApp::isQuitting() && GetMessage(&msg, NULL, 0, 0)) + while (!LLApp::isExiting() && GetMessage(&msg, NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); -- cgit v1.3 From efdbaa50be7ec7ccb3359203acef30f4d15c5c19 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Fri, 28 May 2021 19:52:07 +0300 Subject: SL-15093 Crash nanov2_free_to_block Superficially crash happens in disconnect() inside signal's deconstructor. Manual cleanup should help figuring out if crash happens due to named or anonymous listeners --- indra/llcommon/llevents.cpp | 19 ++++++++++++++----- indra/llcommon/llevents.h | 13 +------------ 2 files changed, 15 insertions(+), 17 deletions(-) (limited to 'indra/llcommon') diff --git a/indra/llcommon/llevents.cpp b/indra/llcommon/llevents.cpp index 64fb985951..0a213bddef 100644 --- a/indra/llcommon/llevents.cpp +++ b/indra/llcommon/llevents.cpp @@ -45,7 +45,6 @@ #include // external library headers #include -#include #if LL_WINDOWS #pragma warning (push) #pragma warning (disable : 4701) // compiler thinks might use uninitialized var, but no @@ -285,7 +284,7 @@ LLEventPump::LLEventPump(const std::string& name, bool tweak): // Register every new instance with LLEventPumps mRegistry(LLEventPumps::instance().getHandle()), mName(mRegistry.get()->registerNew(*this, name, tweak)), - mSignal(boost::make_shared()), + mSignal(std::make_shared()), mEnabled(true) {} @@ -317,14 +316,24 @@ void LLEventPump::clear() { // Destroy the original LLStandardSignal instance, replacing it with a // whole new one. - mSignal = boost::make_shared(); + mSignal = std::make_shared(); mConnections.clear(); } void LLEventPump::reset() { - mSignal.reset(); + // Resetting mSignal is supposed to disconnect everything on its own + // But due to crash on 'reset' added explicit cleanup to get more data + ConnectionMap::const_iterator iter = mConnections.begin(); + ConnectionMap::const_iterator end = mConnections.end(); + while (iter!=end) + { + iter->second.disconnect(); + iter++; + } mConnections.clear(); + + mSignal.reset(); //mDeps.clear(); } @@ -543,7 +552,7 @@ bool LLEventStream::post(const LLSD& event) // *stack* instance of the shared_ptr, ensuring that our heap // LLStandardSignal object will live at least until post() returns, even // if 'this' gets destroyed during the call. - boost::shared_ptr signal(mSignal); + std::shared_ptr signal(mSignal); // Let caller know if any one listener handled the event. This is mostly // useful when using LLEventStream as a listener for an upstream // LLEventPump. diff --git a/indra/llcommon/llevents.h b/indra/llcommon/llevents.h index e380c108f4..6ac90cb3a3 100644 --- a/indra/llcommon/llevents.h +++ b/indra/llcommon/llevents.h @@ -49,7 +49,6 @@ #endif #include -#include #include #include // noncopyable #include @@ -571,7 +570,7 @@ protected: const NameList& before); /// implement the dispatching - boost::shared_ptr mSignal; + std::shared_ptr mSignal; /// valve open? bool mEnabled; @@ -745,14 +744,4 @@ private: LL_COMMON_API bool sendReply(const LLSD& reply, const LLSD& request, const std::string& replyKey="reply"); -// Somewhat to my surprise, passing boost::bind(...boost::weak_ptr...) to -// listen() fails in Boost code trying to instantiate LLEventListener (i.e. -// LLStandardSignal::slot_type) because the boost::get_pointer() utility function isn't -// specialized for boost::weak_ptr. This remedies that omission. -namespace boost -{ - template - T* get_pointer(const weak_ptr& ptr) { return shared_ptr(ptr).get(); } -} - #endif /* ! defined(LL_LLEVENTS_H) */ -- cgit v1.3 From e75519ef0e0a3b3aebf7761830b1e93163e3c673 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Mon, 31 May 2021 17:19:37 +0300 Subject: SL-15093 Crash nanov2_free_to_block #2 Mostly converted some boost pointers to std ones Made ~LLNotificationChannelBase() more explicit to get a bit more data on location of another crash that likely happens when cleaning mItems --- indra/llcommon/llevents.h | 1 - indra/llui/llnotificationptr.h | 3 +-- indra/llui/llnotifications.h | 21 +++++++++++++-------- indra/llui/llnotificationslistener.h | 3 +-- indra/llui/llnotificationtemplate.h | 2 +- indra/newview/lleventpoll.cpp | 4 ++-- indra/newview/lleventpoll.h | 2 +- indra/newview/llmediactrl.h | 3 ++- indra/newview/llnotificationmanager.cpp | 2 +- indra/newview/llnotificationmanager.h | 4 +--- 10 files changed, 23 insertions(+), 22 deletions(-) (limited to 'indra/llcommon') diff --git a/indra/llcommon/llevents.h b/indra/llcommon/llevents.h index 6ac90cb3a3..ae6e5aabc9 100644 --- a/indra/llcommon/llevents.h +++ b/indra/llcommon/llevents.h @@ -49,7 +49,6 @@ #endif #include -#include #include // noncopyable #include #include diff --git a/indra/llui/llnotificationptr.h b/indra/llui/llnotificationptr.h index acc047527f..580f353c7d 100644 --- a/indra/llui/llnotificationptr.h +++ b/indra/llui/llnotificationptr.h @@ -27,9 +27,8 @@ // Many classes just store a single LLNotificationPtr // and llnotifications.h is very large, so define this ligher header. -#include class LLNotification; -typedef boost::shared_ptr LLNotificationPtr; +typedef std::shared_ptr LLNotificationPtr; #endif diff --git a/indra/llui/llnotifications.h b/indra/llui/llnotifications.h index 2f4578da17..4287bff059 100644 --- a/indra/llui/llnotifications.h +++ b/indra/llui/llnotifications.h @@ -84,8 +84,6 @@ #include #include -#include -#include #include #include #include @@ -132,7 +130,7 @@ public: typedef boost::function LLNotificationResponder; -typedef boost::shared_ptr LLNotificationResponderPtr; +typedef std::shared_ptr LLNotificationResponderPtr; typedef LLFunctorRegistry LLNotificationFunctorRegistry; typedef LLFunctorRegistration LLNotificationFunctorRegistration; @@ -276,19 +274,19 @@ private: bool mInvertSetting; }; -typedef boost::shared_ptr LLNotificationFormPtr; +typedef std::shared_ptr LLNotificationFormPtr; struct LLNotificationTemplate; // we want to keep a map of these by name, and it's best to manage them // with smart pointers -typedef boost::shared_ptr LLNotificationTemplatePtr; +typedef std::shared_ptr LLNotificationTemplatePtr; struct LLNotificationVisibilityRule; -typedef boost::shared_ptr LLNotificationVisibilityRulePtr; +typedef std::shared_ptr LLNotificationVisibilityRulePtr; /** * @class LLNotification @@ -304,7 +302,7 @@ typedef boost::shared_ptr LLNotificationVisibility */ class LLNotification : boost::noncopyable, - public boost::enable_shared_from_this + public std::enable_shared_from_this { LOG_CLASS(LLNotification); friend class LLNotifications; @@ -743,7 +741,14 @@ public: : mFilter(filter), mItems() {} - virtual ~LLNotificationChannelBase() {} + virtual ~LLNotificationChannelBase() + { + // explicit cleanup for easier issue detection + mChanged.disconnect_all_slots(); + mPassedFilter.disconnect_all_slots(); + mFailedFilter.disconnect_all_slots(); + mItems.clear(); + } // you can also connect to a Channel, so you can be notified of // changes to this channel LLBoundListener connectChanged(const LLEventListener& slot) diff --git a/indra/llui/llnotificationslistener.h b/indra/llui/llnotificationslistener.h index f9f7641de6..4bab377626 100644 --- a/indra/llui/llnotificationslistener.h +++ b/indra/llui/llnotificationslistener.h @@ -31,7 +31,6 @@ #include "lleventapi.h" #include "llnotificationptr.h" -#include #include #include @@ -61,7 +60,7 @@ private: static LLSD asLLSD(LLNotificationPtr); class Forwarder; - typedef std::map > ForwarderMap; + typedef std::map > ForwarderMap; ForwarderMap mForwarders; LLNotifications & mNotifications; }; diff --git a/indra/llui/llnotificationtemplate.h b/indra/llui/llnotificationtemplate.h index 20cbc89ede..a8902486e4 100644 --- a/indra/llui/llnotificationtemplate.h +++ b/indra/llui/llnotificationtemplate.h @@ -31,7 +31,7 @@ #include "llinitparam.h" #include "llnotifications.h" -typedef boost::shared_ptr LLNotificationFormPtr; +typedef std::shared_ptr LLNotificationFormPtr; // This is the class of object read from the XML file (notifications.xml, // from the appropriate local language directory). diff --git a/indra/newview/lleventpoll.cpp b/indra/newview/lleventpoll.cpp index 4b5fd8a758..6f3f6e9166 100644 --- a/indra/newview/lleventpoll.cpp +++ b/indra/newview/lleventpoll.cpp @@ -47,7 +47,7 @@ namespace LLEventPolling namespace Details { - class LLEventPollImpl: public boost::enable_shared_from_this + class LLEventPollImpl: public std::enable_shared_from_this { public: LLEventPollImpl(const LLHost &sender); @@ -284,7 +284,7 @@ namespace Details LLEventPoll::LLEventPoll(const std::string& poll_url, const LLHost& sender): mImpl() { - mImpl = boost::make_shared(sender); + mImpl = std::make_shared(sender); mImpl->start(poll_url); } diff --git a/indra/newview/lleventpoll.h b/indra/newview/lleventpoll.h index 65766dbb2a..d6da04b281 100644 --- a/indra/newview/lleventpoll.h +++ b/indra/newview/lleventpoll.h @@ -51,7 +51,7 @@ public: private: - boost::shared_ptr mImpl; + std::shared_ptr mImpl; }; diff --git a/indra/newview/llmediactrl.h b/indra/newview/llmediactrl.h index 958c76f261..bd24c47a4f 100644 --- a/indra/newview/llmediactrl.h +++ b/indra/newview/llmediactrl.h @@ -31,6 +31,7 @@ #include "lluictrl.h" #include "llframetimer.h" +#include "llnotificationptr.h" class LLViewBorder; class LLUICtrlFactory; @@ -145,7 +146,7 @@ public: void setTextureSize(S32 width, S32 height); - void showNotification(boost::shared_ptr notify); + void showNotification(LLNotificationPtr notify); void hideNotification(); void setTrustedContent(bool trusted); diff --git a/indra/newview/llnotificationmanager.cpp b/indra/newview/llnotificationmanager.cpp index a6f20a9f27..b06131cf38 100644 --- a/indra/newview/llnotificationmanager.cpp +++ b/indra/newview/llnotificationmanager.cpp @@ -63,7 +63,7 @@ void LLNotificationManager::init() mChannels.push_back(new LLBrowserNotification()); mChannels.push_back(new LLIMHandler()); - mChatHandler = boost::shared_ptr(new LLFloaterIMNearbyChatHandler()); + mChatHandler = std::shared_ptr(new LLFloaterIMNearbyChatHandler()); } //-------------------------------------------------------------------------- diff --git a/indra/newview/llnotificationmanager.h b/indra/newview/llnotificationmanager.h index 52c79cc689..cf987ff4e9 100644 --- a/indra/newview/llnotificationmanager.h +++ b/indra/newview/llnotificationmanager.h @@ -35,8 +35,6 @@ #include #include -#include - namespace LLNotificationsUI { class LLToast; @@ -60,7 +58,7 @@ public: void onChat(const LLChat& msg, const LLSD &args); private: - boost::shared_ptr mChatHandler; + std::shared_ptr mChatHandler; std::vector mChannels; }; -- cgit v1.3 From a6ea2dbedcf54b6a847d894b77777cc88698a28d Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Mon, 19 Jul 2021 23:27:00 +0300 Subject: SL-15292 Voice's singleton shutdown before voice's coroutine --- indra/llcommon/llcoros.cpp | 9 +++++++++ indra/llcommon/llcoros.h | 2 ++ 2 files changed, 11 insertions(+) (limited to 'indra/llcommon') diff --git a/indra/llcommon/llcoros.cpp b/indra/llcommon/llcoros.cpp index 23419a52a7..7ad10f206e 100644 --- a/indra/llcommon/llcoros.cpp +++ b/indra/llcommon/llcoros.cpp @@ -131,6 +131,13 @@ LLCoros::LLCoros(): LLCoros::~LLCoros() { +} + +void LLCoros::cleanupSingleton() +{ + // Some of the coroutines (like voice) will depend onto + // origin singletons, so clean coros before deleting those + printActiveCoroutines("at entry to ~LLCoros()"); // Other LLApp status-change listeners do things like close // work queues and inject the Stop exception into pending @@ -146,6 +153,8 @@ LLCoros::~LLCoros() { // don't use llcoro::suspend() because that module depends // on this one + // This will yield current(main) thread and will let active + // corutines run once boost::this_fiber::yield(); } printActiveCoroutines("after pumping"); diff --git a/indra/llcommon/llcoros.h b/indra/llcommon/llcoros.h index 38c2356c99..51f7380def 100644 --- a/indra/llcommon/llcoros.h +++ b/indra/llcommon/llcoros.h @@ -89,6 +89,8 @@ class LL_COMMON_API LLCoros: public LLSingleton { LLSINGLETON(LLCoros); ~LLCoros(); + + void cleanupSingleton(); public: /// The viewer's use of the term "coroutine" became deeply embedded before /// the industry term "fiber" emerged to distinguish userland threads from -- cgit v1.3 From adcd08fbf4d96f8f52cef81895bda202c9e45896 Mon Sep 17 00:00:00 2001 From: Andrey Lihatskiy Date: Tue, 28 Sep 2021 19:07:48 +0300 Subject: Revert "Merge branch 'c++17' into DRTVWR-522-maint" This reverts commit 203ea3a70a775a09cbbffb1740ab7c58f1780baa, reversing changes made to 8e3f0778863a5aa337d1148a243ea91d238a8ac5. # Conflicts: # indra/newview/llmachineid.cpp --- autobuild.xml | 14 +- indra/cmake/00-Common.cmake | 5 +- indra/edit-me-to-trigger-new-build.txt | 2 +- indra/llcommon/llsd.h | 43 ++++++ indra/llcommon/llstl.h | 237 ++++++++++++++++++++++++++++++++- indra/llcommon/tests/llleap_test.cpp | 2 +- indra/llinventory/llparcel.cpp | 2 +- indra/llmessage/llcircuit.cpp | 11 +- indra/llmessage/lldispatcher.cpp | 2 +- indra/llmessage/llmessagethrottle.cpp | 22 +++ indra/llui/lldockablefloater.h | 4 +- indra/newview/llappearancemgr.h | 2 +- indra/newview/llexperiencelog.cpp | 4 + indra/newview/llfavoritesbar.cpp | 2 +- indra/newview/llfloaterregioninfo.cpp | 4 +- indra/newview/llgesturemgr.cpp | 2 +- indra/newview/lltoast.h | 2 +- indra/newview/llwatchdog.cpp | 4 +- indra/test/lldoubledispatch_tut.cpp | 8 +- 19 files changed, 338 insertions(+), 34 deletions(-) (limited to 'indra/llcommon') diff --git a/autobuild.xml b/autobuild.xml index e1e5c19871..5ad6f6293c 100644 --- a/autobuild.xml +++ b/autobuild.xml @@ -308,9 +308,9 @@ archive hash - f5a81594374c8a7f0825e2177510e079 + 02e6a8207dcdaf243dcb6da19b8c3534 url - https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/82030/770590/colladadom-2.3.559710-darwin64-559710.tar.bz2 + http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/64099/601302/colladadom-2.3.545362-darwin64-545362.tar.bz2 name darwin64 @@ -344,9 +344,9 @@ archive hash - 5d0729b835d63b7fe69acdc6b7c60188 + 8a02a10fc69c8f504dc5335644db184a url - https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/82050/770692/colladadom-2.3.559710-windows-559710.tar.bz2 + http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/64104/601313/colladadom-2.3.545362-windows-545362.tar.bz2 name windows @@ -356,16 +356,16 @@ archive hash - 985e3081e41c76b6176d39e44d7fb4b8 + 742180324fca7ab92b6a61a36aab4f9d url - https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/82049/770686/colladadom-2.3.559710-windows64-559710.tar.bz2 + http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/64103/601314/colladadom-2.3.545362-windows64-545362.tar.bz2 name windows64 version - 2.3.559710 + 2.3.545362 curl diff --git a/indra/cmake/00-Common.cmake b/indra/cmake/00-Common.cmake index 0da530c6a2..8aea50e02b 100644 --- a/indra/cmake/00-Common.cmake +++ b/indra/cmake/00-Common.cmake @@ -66,8 +66,7 @@ if (WINDOWS) # CP changed to only append the flag for 32bit builds - on 64bit builds, # locally at least, the build output is spammed with 1000s of 'D9002' # warnings about this switch being ignored. - # We need std::string_view, but that's not available without /std:c++17. - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /MP /std:c++17") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /MP") if( ADDRESS_SIZE EQUAL 32 ) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /p:PreferredToolArchitecture=x64") endif() @@ -176,7 +175,7 @@ if (DARWIN) # Until we decide to set -std=c++14 in viewer-build-variables/variables, set # it locally here: we want to at least prevent inadvertently reintroducing # viewer code that would fail with C++14. - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${DARWIN_extra_cstar_flags} -std=c++17") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${DARWIN_extra_cstar_flags} -std=c++14") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${DARWIN_extra_cstar_flags}") # NOTE: it's critical that the optimization flag is put in front. # NOTE: it's critical to have both CXX_FLAGS and C_FLAGS covered. diff --git a/indra/edit-me-to-trigger-new-build.txt b/indra/edit-me-to-trigger-new-build.txt index ade83202cf..5366987cff 100644 --- a/indra/edit-me-to-trigger-new-build.txt +++ b/indra/edit-me-to-trigger-new-build.txt @@ -1,3 +1,3 @@ euclid 5/29/2020 euclid 7/23/2020 -euclid 4/29/2021 +euclid 4/29/2021 \ No newline at end of file diff --git a/indra/llcommon/llsd.h b/indra/llcommon/llsd.h index 6638b25feb..5b6d5545af 100644 --- a/indra/llcommon/llsd.h +++ b/indra/llcommon/llsd.h @@ -413,6 +413,49 @@ public: static std::string typeString(Type type); // Return human-readable type as a string }; +struct llsd_select_bool : public std::unary_function +{ + LLSD::Boolean operator()(const LLSD& sd) const + { + return sd.asBoolean(); + } +}; +struct llsd_select_integer : public std::unary_function +{ + LLSD::Integer operator()(const LLSD& sd) const + { + return sd.asInteger(); + } +}; +struct llsd_select_real : public std::unary_function +{ + LLSD::Real operator()(const LLSD& sd) const + { + return sd.asReal(); + } +}; +struct llsd_select_float : public std::unary_function +{ + F32 operator()(const LLSD& sd) const + { + return (F32)sd.asReal(); + } +}; +struct llsd_select_uuid : public std::unary_function +{ + LLSD::UUID operator()(const LLSD& sd) const + { + return sd.asUUID(); + } +}; +struct llsd_select_string : public std::unary_function +{ + LLSD::String operator()(const LLSD& sd) const + { + return sd.asString(); + } +}; + LL_COMMON_API std::ostream& operator<<(std::ostream& s, const LLSD& llsd); namespace llsd diff --git a/indra/llcommon/llstl.h b/indra/llcommon/llstl.h index d28260b9f8..a90c2c7e08 100644 --- a/indra/llcommon/llstl.h +++ b/indra/llcommon/llstl.h @@ -40,6 +40,30 @@ // For strcmp #include #endif +// Use to compare the first element only of a pair +// e.g. typedef std::set, compare_pair > some_pair_set_t; +template +struct compare_pair_first +{ + bool operator()(const std::pair& a, const std::pair& b) const + { + return a.first < b.first; + } +}; + +template +struct compare_pair_greater +{ + bool operator()(const std::pair& a, const std::pair& b) const + { + if (!(a.first < b.first)) + return true; + else if (!(b.first < a.first)) + return false; + else + return !(a.second < b.second); + } +}; // Use to compare the contents of two pointers (e.g. std::string*) template @@ -99,6 +123,58 @@ struct DeletePairedPointerArray }; +// Alternate version of the above so that has a more cumbersome +// syntax, but it can be used with compositional functors. +// NOTE: The functor retuns a bool because msdev bombs during the +// composition if you return void. Once we upgrade to a newer +// compiler, the second unary_function template parameter can be set +// to void. +// +// Here's a snippet showing how you use this object: +// +// typedef std::map map_type; +// map_type widget_map; +// ... // add elements +// // delete them all +// for_each(widget_map.begin(), +// widget_map.end(), +// llcompose1(DeletePointerFunctor(), +// llselect2nd())); + +template +struct DeletePointerFunctor : public std::unary_function +{ + bool operator()(T* ptr) const + { + delete ptr; + return true; + } +}; + +// See notes about DeleteArray for why you should consider avoiding this. +template +struct DeleteArrayFunctor : public std::unary_function +{ + bool operator()(T* ptr) const + { + delete[] ptr; + return true; + } +}; + +// CopyNewPointer is a simple helper which accepts a pointer, and +// returns a new pointer built with the copy constructor. Example: +// +// transform(in.begin(), in.end(), out.end(), CopyNewPointer()); + +struct CopyNewPointer +{ + template T* operator()(const T* ptr) const + { + return new T(*ptr); + } +}; + template void delete_and_clear(std::list& list) { @@ -287,6 +363,161 @@ OutputIter ll_transform_n( } + +/* + * + * Copyright (c) 1994 + * Hewlett-Packard Company + * + * Permission to use, copy, modify, distribute and sell this software + * and its documentation for any purpose is hereby granted without fee, + * provided that the above copyright notice appear in all copies and + * that both that copyright notice and this permission notice appear + * in supporting documentation. Hewlett-Packard Company makes no + * representations about the suitability of this software for any + * purpose. It is provided "as is" without express or implied warranty. + * + * + * Copyright (c) 1996-1998 + * Silicon Graphics Computer Systems, Inc. + * + * Permission to use, copy, modify, distribute and sell this software + * and its documentation for any purpose is hereby granted without fee, + * provided that the above copyright notice appear in all copies and + * that both that copyright notice and this permission notice appear + * in supporting documentation. Silicon Graphics makes no + * representations about the suitability of this software for any + * purpose. It is provided "as is" without express or implied warranty. + */ + + +// helper to deal with the fact that MSDev does not package +// select... with the stl. Look up usage on the sgi website. + +template +struct _LLSelect1st : public std::unary_function<_Pair, typename _Pair::first_type> { + const typename _Pair::first_type& operator()(const _Pair& __x) const { + return __x.first; + } +}; + +template +struct _LLSelect2nd : public std::unary_function<_Pair, typename _Pair::second_type> +{ + const typename _Pair::second_type& operator()(const _Pair& __x) const { + return __x.second; + } +}; + +template struct llselect1st : public _LLSelect1st<_Pair> {}; +template struct llselect2nd : public _LLSelect2nd<_Pair> {}; + +// helper to deal with the fact that MSDev does not package +// compose... with the stl. Look up usage on the sgi website. + +template +class ll_unary_compose : + public std::unary_function +{ +protected: + _Operation1 __op1; + _Operation2 __op2; +public: + ll_unary_compose(const _Operation1& __x, const _Operation2& __y) + : __op1(__x), __op2(__y) {} + typename _Operation1::result_type + operator()(const typename _Operation2::argument_type& __x) const { + return __op1(__op2(__x)); + } +}; + +template +inline ll_unary_compose<_Operation1,_Operation2> +llcompose1(const _Operation1& __op1, const _Operation2& __op2) +{ + return ll_unary_compose<_Operation1,_Operation2>(__op1, __op2); +} + +template +class ll_binary_compose + : public std::unary_function { +protected: + _Operation1 _M_op1; + _Operation2 _M_op2; + _Operation3 _M_op3; +public: + ll_binary_compose(const _Operation1& __x, const _Operation2& __y, + const _Operation3& __z) + : _M_op1(__x), _M_op2(__y), _M_op3(__z) { } + typename _Operation1::result_type + operator()(const typename _Operation2::argument_type& __x) const { + return _M_op1(_M_op2(__x), _M_op3(__x)); + } +}; + +template +inline ll_binary_compose<_Operation1, _Operation2, _Operation3> +llcompose2(const _Operation1& __op1, const _Operation2& __op2, + const _Operation3& __op3) +{ + return ll_binary_compose<_Operation1,_Operation2,_Operation3> + (__op1, __op2, __op3); +} + +// helpers to deal with the fact that MSDev does not package +// bind... with the stl. Again, this is from sgi. +template +class llbinder1st : + public std::unary_function { +protected: + _Operation op; + typename _Operation::first_argument_type value; +public: + llbinder1st(const _Operation& __x, + const typename _Operation::first_argument_type& __y) + : op(__x), value(__y) {} + typename _Operation::result_type + operator()(const typename _Operation::second_argument_type& __x) const { + return op(value, __x); + } +}; + +template +inline llbinder1st<_Operation> +llbind1st(const _Operation& __oper, const _Tp& __x) +{ + typedef typename _Operation::first_argument_type _Arg1_type; + return llbinder1st<_Operation>(__oper, _Arg1_type(__x)); +} + +template +class llbinder2nd + : public std::unary_function { +protected: + _Operation op; + typename _Operation::second_argument_type value; +public: + llbinder2nd(const _Operation& __x, + const typename _Operation::second_argument_type& __y) + : op(__x), value(__y) {} + typename _Operation::result_type + operator()(const typename _Operation::first_argument_type& __x) const { + return op(__x, value); + } +}; + +template +inline llbinder2nd<_Operation> +llbind2nd(const _Operation& __oper, const _Tp& __x) +{ + typedef typename _Operation::second_argument_type _Arg2_type; + return llbinder2nd<_Operation>(__oper, _Arg2_type(__x)); +} + /** * Compare std::type_info* pointers a la std::less. We break this out as a * separate function for use in two different std::less specializations. @@ -317,7 +548,8 @@ bool before(const std::type_info* lhs, const std::type_info* rhs) namespace std { template <> - struct less + struct less: + public std::binary_function { bool operator()(const std::type_info* lhs, const std::type_info* rhs) const { @@ -326,7 +558,8 @@ namespace std }; template <> - struct less + struct less: + public std::binary_function { bool operator()(std::type_info* lhs, std::type_info* rhs) const { diff --git a/indra/llcommon/tests/llleap_test.cpp b/indra/llcommon/tests/llleap_test.cpp index fd96aa01d5..9d71e327d8 100644 --- a/indra/llcommon/tests/llleap_test.cpp +++ b/indra/llcommon/tests/llleap_test.cpp @@ -530,7 +530,7 @@ namespace tut result.ensure(); } - struct TestLargeMessage + struct TestLargeMessage: public std::binary_function { TestLargeMessage(const std::string& PYTHON_, const std::string& reader_module_, const std::string& test_name_): diff --git a/indra/llinventory/llparcel.cpp b/indra/llinventory/llparcel.cpp index 2f577bfb07..e2469f3c7e 100644 --- a/indra/llinventory/llparcel.cpp +++ b/indra/llinventory/llparcel.cpp @@ -1268,5 +1268,5 @@ U32 LLParcel::countExperienceKeyType( U32 type ) return std::count_if( boost::begin(mExperienceKeys | boost::adaptors::map_values), boost::end(mExperienceKeys | boost::adaptors::map_values), - [type](U32 key){ return key == type; }); + std::bind2nd(std::equal_to(), type)); } diff --git a/indra/llmessage/llcircuit.cpp b/indra/llmessage/llcircuit.cpp index a39989515e..8baa2e328b 100644 --- a/indra/llmessage/llcircuit.cpp +++ b/indra/llmessage/llcircuit.cpp @@ -436,11 +436,12 @@ LLCircuit::LLCircuit(const F32Seconds circuit_heartbeat_interval, const F32Secon LLCircuit::~LLCircuit() { - // delete pointers in the map. - for (auto circ_pair : mCircuitData) - { - delete circ_pair.second; - } + // delete pointers in the map. + std::for_each(mCircuitData.begin(), + mCircuitData.end(), + llcompose1( + DeletePointerFunctor(), + llselect2nd())); } LLCircuitData *LLCircuit::addCircuitData(const LLHost &host, TPACKETID in_id) diff --git a/indra/llmessage/lldispatcher.cpp b/indra/llmessage/lldispatcher.cpp index 8dfd924f31..717ef10f70 100644 --- a/indra/llmessage/lldispatcher.cpp +++ b/indra/llmessage/lldispatcher.cpp @@ -62,7 +62,7 @@ void LLDispatcher::copyAllHandlerNames(keys_t& names) const mHandlers.begin(), mHandlers.end(), std::back_insert_iterator(names), - [](const dispatch_map_t::value_type& pair){ return pair.first; }); + llselect1st()); } bool LLDispatcher::dispatch( diff --git a/indra/llmessage/llmessagethrottle.cpp b/indra/llmessage/llmessagethrottle.cpp index c5ae8b4547..579d6d7187 100644 --- a/indra/llmessage/llmessagethrottle.cpp +++ b/indra/llmessage/llmessagethrottle.cpp @@ -32,8 +32,18 @@ #include "llframetimer.h" // This is used for the stl search_n function. +#if _MSC_VER >= 1500 // VC9 has a bug in search_n +struct eq_message_throttle_entry : public std::binary_function< LLMessageThrottleEntry, LLMessageThrottleEntry, bool > +{ + bool operator()(const LLMessageThrottleEntry& a, const LLMessageThrottleEntry& b) const + { + return a.getHash() == b.getHash(); + } +}; +#else bool eq_message_throttle_entry(LLMessageThrottleEntry a, LLMessageThrottleEntry b) { return a.getHash() == b.getHash(); } +#endif const U64 SEC_TO_USEC = 1000000; @@ -108,8 +118,14 @@ BOOL LLMessageThrottle::addViewerAlert(const LLUUID& to, const std::string& mesg LLMessageThrottleEntry entry(hash, LLFrameTimer::getTotalTime()); // Check if this message is already in the list. +#if _MSC_VER >= 1500 // VC9 has a bug in search_n + // SJB: This *should* work but has not been tested yet *TODO: Test! + message_list_iterator_t found = std::find_if(message_list->begin(), message_list->end(), + std::bind2nd(eq_message_throttle_entry(), entry)); +#else message_list_iterator_t found = std::search_n(message_list->begin(), message_list->end(), 1, entry, eq_message_throttle_entry); +#endif if (found == message_list->end()) { // This message was not found. Add it to the list. @@ -136,8 +152,14 @@ BOOL LLMessageThrottle::addAgentAlert(const LLUUID& agent, const LLUUID& task, c LLMessageThrottleEntry entry(hash, LLFrameTimer::getTotalTime()); // Check if this message is already in the list. +#if _MSC_VER >= 1500 // VC9 has a bug in search_n + // SJB: This *should* work but has not been tested yet *TODO: Test! + message_list_iterator_t found = std::find_if(message_list->begin(), message_list->end(), + std::bind2nd(eq_message_throttle_entry(), entry)); +#else message_list_iterator_t found = std::search_n(message_list->begin(), message_list->end(), 1, entry, eq_message_throttle_entry); +#endif if (found == message_list->end()) { diff --git a/indra/llui/lldockablefloater.h b/indra/llui/lldockablefloater.h index 1110342f08..89c9852f4a 100644 --- a/indra/llui/lldockablefloater.h +++ b/indra/llui/lldockablefloater.h @@ -108,7 +108,7 @@ public: * * By default returns false. */ - virtual bool overlapsScreenChannel() const { return mOverlapsScreenChannel && getVisible() && isDocked(); } + virtual bool overlapsScreenChannel() { return mOverlapsScreenChannel && getVisible() && isDocked(); } virtual void setOverlapsScreenChannel(bool overlaps) { mOverlapsScreenChannel = overlaps; } bool getUniqueDocking() { return mUniqueDocking; } @@ -131,7 +131,7 @@ protected: boost::function mIsDockedStateForcedCallback; private: - std::unique_ptr mDockControl; + std::auto_ptr mDockControl; LLUIImagePtr mDockTongue; static LLHandle sInstanceHandle; /** diff --git a/indra/newview/llappearancemgr.h b/indra/newview/llappearancemgr.h index a5265a392f..8a55a848db 100644 --- a/indra/newview/llappearancemgr.h +++ b/indra/newview/llappearancemgr.h @@ -276,7 +276,7 @@ private: LLUUID mCOFImageID; - std::unique_ptr mUnlockOutfitTimer; + std::auto_ptr mUnlockOutfitTimer; // Set of temp attachment UUIDs that should be removed typedef std::set doomed_temp_attachments_t; diff --git a/indra/newview/llexperiencelog.cpp b/indra/newview/llexperiencelog.cpp index c441fbc09f..ee5d561927 100644 --- a/indra/newview/llexperiencelog.cpp +++ b/indra/newview/llexperiencelog.cpp @@ -149,6 +149,10 @@ std::string LLExperienceLog::getPermissionString( const LLSD& message, const std { buf.str(entry); } + else + { + buf.str(); + } } if(buf.str().empty()) diff --git a/indra/newview/llfavoritesbar.cpp b/indra/newview/llfavoritesbar.cpp index a7147c3f04..cca6b9ce32 100644 --- a/indra/newview/llfavoritesbar.cpp +++ b/indra/newview/llfavoritesbar.cpp @@ -841,7 +841,7 @@ void LLFavoritesBarCtrl::updateButtons(bool force_update) { //find last visible child to get the rightest button offset child_list_const_reverse_iter_t last_visible_it = std::find_if(childs->rbegin(), childs->rend(), - [](child_list_t::value_type child){ return child->getVisible(); }); + std::mem_fun(&LLView::getVisible)); if(last_visible_it != childs->rend()) { last_right_edge = (*last_visible_it)->getRect().mRight; diff --git a/indra/newview/llfloaterregioninfo.cpp b/indra/newview/llfloaterregioninfo.cpp index a10ba7a39d..17e55b5f2c 100644 --- a/indra/newview/llfloaterregioninfo.cpp +++ b/indra/newview/llfloaterregioninfo.cpp @@ -659,7 +659,9 @@ void LLFloaterRegionInfo::refreshFromRegion(LLViewerRegion* region) std::for_each( mInfoPanels.begin(), mInfoPanels.end(), - [region](info_panels_t::value_type panel){ panel->refreshFromRegion(region); }); + llbind2nd( + std::mem_fun(&LLPanelRegionInfo::refreshFromRegion), + region)); mEnvironmentPanel->refreshFromRegion(region); } diff --git a/indra/newview/llgesturemgr.cpp b/indra/newview/llgesturemgr.cpp index eb0e77311b..950a6cfaef 100644 --- a/indra/newview/llgesturemgr.cpp +++ b/indra/newview/llgesturemgr.cpp @@ -752,7 +752,7 @@ S32 LLGestureMgr::getPlayingCount() const } -struct IsGesturePlaying +struct IsGesturePlaying : public std::unary_function { bool operator()(const LLMultiGesture* gesture) const { diff --git a/indra/newview/lltoast.h b/indra/newview/lltoast.h index 2b1fedf74d..69074b1670 100644 --- a/indra/newview/lltoast.h +++ b/indra/newview/lltoast.h @@ -222,7 +222,7 @@ private: LLPanel* mWrapperPanel; // timer counts a lifetime of a toast - std::unique_ptr mTimer; + std::auto_ptr mTimer; F32 mToastLifetime; // in seconds F32 mToastFadingTime; // in seconds diff --git a/indra/newview/llwatchdog.cpp b/indra/newview/llwatchdog.cpp index a3036ff6d0..0aa0280b25 100644 --- a/indra/newview/llwatchdog.cpp +++ b/indra/newview/llwatchdog.cpp @@ -224,7 +224,7 @@ void LLWatchdog::run() LL_INFOS() << "Watchdog thread delayed: resetting entries." << LL_ENDL; std::for_each(mSuspects.begin(), mSuspects.end(), - [](SuspectsRegistry::value_type suspect){ suspect->reset(); } + std::mem_fun(&LLWatchdogEntry::reset) ); } else @@ -232,7 +232,7 @@ void LLWatchdog::run() SuspectsRegistry::iterator result = std::find_if(mSuspects.begin(), mSuspects.end(), - [](SuspectsRegistry::value_type suspect){ return ! suspect->isAlive(); } + std::not1(std::mem_fun(&LLWatchdogEntry::isAlive)) ); if(result != mSuspects.end()) { diff --git a/indra/test/lldoubledispatch_tut.cpp b/indra/test/lldoubledispatch_tut.cpp index e38d0e92a3..ad8f6454d4 100644 --- a/indra/test/lldoubledispatch_tut.cpp +++ b/indra/test/lldoubledispatch_tut.cpp @@ -135,10 +135,10 @@ namespace tut // Instantiate a few GameObjects. Make sure we refer to them // polymorphically, and don't let them leak. - std::unique_ptr home; - std::unique_ptr obstacle; - std::unique_ptr tug; - std::unique_ptr patrol; + std::auto_ptr home; + std::auto_ptr obstacle; + std::auto_ptr tug; + std::auto_ptr patrol; // prototype objects Asteroid dummyAsteroid; -- cgit v1.3 From ca0b9a3753fa3b42d4ac8183adcf30d957f55016 Mon Sep 17 00:00:00 2001 From: "Brad Payne (Vir Linden)" Date: Tue, 9 Nov 2021 20:25:25 +0000 Subject: SL-16329 - track frame time and jitter (as average deviation frame to frame) in stats window --- indra/llcommon/lltracerecording.cpp | 27 +++++++++++++++++++- indra/llcommon/lltracerecording.h | 29 ++++++++++++++++++++++ indra/llui/llstatbar.cpp | 17 +++++++++++-- indra/llui/llstatbar.h | 6 +++-- indra/newview/llviewerstats.cpp | 11 +++++--- indra/newview/llviewerstats.h | 4 +-- .../newview/skins/default/xui/en/floater_stats.xml | 19 ++++++++++++++ 7 files changed, 103 insertions(+), 10 deletions(-) (limited to 'indra/llcommon') diff --git a/indra/llcommon/lltracerecording.cpp b/indra/llcommon/lltracerecording.cpp index c72a64d086..5ce1b337fe 100644 --- a/indra/llcommon/lltracerecording.cpp +++ b/indra/llcommon/lltracerecording.cpp @@ -858,7 +858,6 @@ F64 PeriodicRecording::getPeriodMean( const StatType& stat, S3 : NaN; } - F64 PeriodicRecording::getPeriodStandardDeviation( const StatType& stat, S32 num_periods /*= S32_MAX*/ ) { LL_PROFILE_ZONE_SCOPED; @@ -952,6 +951,32 @@ F64 PeriodicRecording::getPeriodMean( const StatType& stat, S : NaN; } +F64 PeriodicRecording::getPeriodMedian( const StatType& stat, S32 num_periods /*= S32_MAX*/ ) +{ + LL_PROFILE_ZONE_SCOPED; + num_periods = llmin(num_periods, getNumRecordedPeriods()); + + std::vector buf; + for (S32 i = 1; i <= num_periods; i++) + { + Recording& recording = getPrevRecording(i); + if (recording.getDuration() > (F32Seconds)0.f) + { + if (recording.hasValue(stat)) + { + buf.push_back(recording.getMean(stat)); + } + } + } + if (buf.size()==0) + { + return 0.0f; + } + std::sort(buf.begin(), buf.end()); + + return F64((buf.size() % 2 == 0) ? (buf[buf.size() / 2 - 1] + buf[buf.size() / 2]) / 2 : buf[buf.size() / 2]); +} + F64 PeriodicRecording::getPeriodStandardDeviation( const StatType& stat, S32 num_periods /*= S32_MAX*/ ) { LL_PROFILE_ZONE_SCOPED; diff --git a/indra/llcommon/lltracerecording.h b/indra/llcommon/lltracerecording.h index 6715104613..1f3d37336a 100644 --- a/indra/llcommon/lltracerecording.h +++ b/indra/llcommon/lltracerecording.h @@ -599,6 +599,35 @@ namespace LLTrace return typename RelatedTypes::fractional_t(getPeriodMeanPerSec(static_cast&>(stat), num_periods)); } + F64 getPeriodMedian( const StatType& stat, S32 num_periods = S32_MAX); + + template + typename RelatedTypes::fractional_t getPeriodMedianPerSec(const StatType& stat, S32 num_periods = S32_MAX) + { + LL_PROFILE_ZONE_SCOPED; + num_periods = llmin(num_periods, getNumRecordedPeriods()); + + std::vector ::fractional_t> buf; + for (S32 i = 1; i <= num_periods; i++) + { + Recording& recording = getPrevRecording(i); + if (recording.getDuration() > (F32Seconds)0.f) + { + buf.push_back(recording.getPerSec(stat)); + } + } + std::sort(buf.begin(), buf.end()); + + return typename RelatedTypes::fractional_t((buf.size() % 2 == 0) ? (buf[buf.size() / 2 - 1] + buf[buf.size() / 2]) / 2 : buf[buf.size() / 2]); + } + + template + typename RelatedTypes::fractional_t getPeriodMedianPerSec(const CountStatHandle& stat, S32 num_periods = S32_MAX) + { + LL_PROFILE_ZONE_SCOPED; + return typename RelatedTypes::fractional_t(getPeriodMedianPerSec(static_cast&>(stat), num_periods)); + } + // // PERIODIC STANDARD DEVIATION // diff --git a/indra/llui/llstatbar.cpp b/indra/llui/llstatbar.cpp index 8adcd664df..2449100952 100644 --- a/indra/llui/llstatbar.cpp +++ b/indra/llui/llstatbar.cpp @@ -160,6 +160,7 @@ LLStatBar::Params::Params() tick_spacing("tick_spacing", 0.f), decimal_digits("decimal_digits", 3), show_bar("show_bar", false), + show_median("show_median", false), show_history("show_history", false), scale_range("scale_range", true), num_frames("num_frames", 200), @@ -186,6 +187,7 @@ LLStatBar::LLStatBar(const Params& p) mNumShortHistoryFrames(p.num_frames_short), mMaxHeight(p.max_height), mDisplayBar(p.show_bar), + mShowMedian(p.show_median), mDisplayHistory(p.show_history), mOrientation(p.orientation), mAutoScaleMax(!p.bar_max.isProvided()), @@ -318,7 +320,14 @@ void LLStatBar::draw() min = frame_recording.getPeriodMinPerSec(count_stat, num_frames); max = frame_recording.getPeriodMaxPerSec(count_stat, num_frames); mean = frame_recording.getPeriodMeanPerSec(count_stat, num_frames); - display_value = mean; + if (mShowMedian) + { + display_value = frame_recording.getPeriodMedianPerSec(count_stat, num_frames); + } + else + { + display_value = mean; + } } break; case STAT_EVENT: @@ -344,7 +353,11 @@ void LLStatBar::draw() mean = frame_recording.getPeriodMean(sample_stat, num_frames); num_rapid_changes = calc_num_rapid_changes(frame_recording, sample_stat, RAPID_CHANGE_WINDOW); - if (num_rapid_changes / RAPID_CHANGE_WINDOW.value() > MAX_RAPID_CHANGES_PER_SEC) + if (mShowMedian) + { + display_value = frame_recording.getPeriodMedian(sample_stat, num_frames); + } + else if (num_rapid_changes / RAPID_CHANGE_WINDOW.value() > MAX_RAPID_CHANGES_PER_SEC) { display_value = mean; } diff --git a/indra/llui/llstatbar.h b/indra/llui/llstatbar.h index 1ff4c67fc5..6b481ca68f 100644 --- a/indra/llui/llstatbar.h +++ b/indra/llui/llstatbar.h @@ -44,9 +44,10 @@ public: bar_max, tick_spacing; - Optional show_bar, + Optional show_bar, show_history, - scale_range; + scale_range, + show_median; // default is mean Optional decimal_digits, num_frames, @@ -112,6 +113,7 @@ private: bool mDisplayBar, // Display the bar graph. mDisplayHistory, + mShowMedian, mAutoScaleMax, mAutoScaleMin; }; diff --git a/indra/newview/llviewerstats.cpp b/indra/newview/llviewerstats.cpp index 314c1a1f1e..ac8a657fb2 100644 --- a/indra/newview/llviewerstats.cpp +++ b/indra/newview/llviewerstats.cpp @@ -183,8 +183,9 @@ SimMeasurement SIM_UNACKED_BYTES("simtotalunackedbytes", "", LL_S SimMeasurement SIM_PHYSICS_MEM("physicsmemoryallocated", "", LL_SIM_STAT_SIMPHYSICSMEMORY); LLTrace::SampleStatHandle FRAMETIME_JITTER("frametimejitter", "Average delta between successive frame times"), - FRAMETIME_SLEW("frametimeslew", "Average delta between frame time and mean"), - SIM_PING("simpingstat"); + FRAMETIME_SLEW("frametimeslew", "Average delta between frame time and mean"), + FRAMETIME("frametime", "Measured frame time"), + SIM_PING("simpingstat"); LLTrace::EventStatHandle > AGENT_POSITION_SNAP("agentpositionsnap", "agent position corrections"); @@ -261,8 +262,12 @@ void LLViewerStats::updateFrameStats(const F64Seconds time_diff) // new "stutter" meter add(LLStatViewer::FRAMETIME_DOUBLED, time_diff >= 2.0 * mLastTimeDiff ? 1 : 0); + sample(LLStatViewer::FRAMETIME, time_diff); + // old stats that were never really used - sample(LLStatViewer::FRAMETIME_JITTER, F64Milliseconds (mLastTimeDiff - time_diff)); + F64Seconds jit = (F64Seconds) std::fabs((mLastTimeDiff - time_diff)); + LL_INFOS() << "times " << mLastTimeDiff << ", " << time_diff << " jit " << jit << LL_ENDL; + sample(LLStatViewer::FRAMETIME_JITTER, jit); F32Seconds average_frametime = gRenderStartTime.getElapsedTimeF32() / (F32)gFrameCount; sample(LLStatViewer::FRAMETIME_SLEW, F64Milliseconds (average_frametime - time_diff)); diff --git a/indra/newview/llviewerstats.h b/indra/newview/llviewerstats.h index 04870e0c26..ac8eccc0ca 100644 --- a/indra/newview/llviewerstats.h +++ b/indra/newview/llviewerstats.h @@ -218,8 +218,8 @@ extern SimMeasurement SIM_PHYSICS_MEM; extern LLTrace::SampleStatHandle FRAMETIME_JITTER, - FRAMETIME_SLEW, - SIM_PING; + FRAMETIME_SLEW, + SIM_PING; extern LLTrace::EventStatHandle > AGENT_POSITION_SNAP; diff --git a/indra/newview/skins/default/xui/en/floater_stats.xml b/indra/newview/skins/default/xui/en/floater_stats.xml index e4f735740b..6f84930c75 100644 --- a/indra/newview/skins/default/xui/en/floater_stats.xml +++ b/indra/newview/skins/default/xui/en/floater_stats.xml @@ -35,6 +35,25 @@ decimal_digits="1" show_bar="true" show_history="true"/> + + + Date: Thu, 11 Nov 2021 10:23:16 -0500 Subject: SL-16094: Stylish braces! --- indra/llcommon/llsingleton.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'indra/llcommon') diff --git a/indra/llcommon/llsingleton.h b/indra/llcommon/llsingleton.h index fdd5bdfea9..6042c0906c 100644 --- a/indra/llcommon/llsingleton.h +++ b/indra/llcommon/llsingleton.h @@ -858,7 +858,8 @@ public: static inline T& instance() { return *getInstance(); } static inline bool instanceExists() { return sInstance != nullptr; } - static void deleteSingleton() { + static void deleteSingleton() + { delete sInstance; sInstance = nullptr; } -- cgit v1.3 From 029b41c0419e975bbb28454538b46dc69ce5d2ba Mon Sep 17 00:00:00 2001 From: Dave Houlton Date: Mon, 15 Nov 2021 09:25:35 -0700 Subject: Revert "SL-16220: Merge branch 'origin/DRTVWR-546' into glthread" This reverts commit 5188a26a8521251dda07ac0140bb129f28417e49, reversing changes made to 819088563e13f1d75e048311fbaf0df4a79b7e19. --- indra/llcommon/CMakeLists.txt | 3 +- indra/llcommon/llsingleton.h | 24 +- indra/llcommon/llthreadsafequeue.h | 30 +- indra/llcommon/tests/threadsafeschedule_test.cpp | 4 +- indra/llcommon/tests/workqueue_test.cpp | 72 +--- indra/llcommon/threadpool.cpp | 80 ----- indra/llcommon/threadpool.h | 62 ---- indra/llcommon/timing.cpp | 25 ++ indra/llcommon/workqueue.cpp | 30 +- indra/llcommon/workqueue.h | 378 ++++---------------- indra/llrender/llimagegl.cpp | 91 ++++- indra/llrender/llimagegl.h | 27 +- indra/llui/CMakeLists.txt | 6 +- indra/llui/llviewereventrecorder.cpp | 2 + indra/llwindow/llwindowwin32.cpp | 426 ++++++++++++++++------- indra/llwindow/llwindowwin32.h | 48 ++- indra/newview/CMakeLists.txt | 3 +- indra/newview/app_settings/settings.xml | 25 -- indra/newview/llappviewer.cpp | 66 ++-- indra/newview/llenvironment.cpp | 1 + indra/newview/llmainlooprepeater.cpp | 88 +++++ indra/newview/llmainlooprepeater.h | 64 ++++ indra/newview/llselectmgr.cpp | 2 + indra/newview/llstartup.cpp | 20 -- indra/newview/llviewercamera.cpp | 2 + indra/newview/llviewertexture.cpp | 34 +- indra/newview/llviewertexture.h | 4 - indra/newview/llworld.cpp | 2 + 28 files changed, 770 insertions(+), 849 deletions(-) delete mode 100644 indra/llcommon/threadpool.cpp delete mode 100644 indra/llcommon/threadpool.h create mode 100644 indra/llcommon/timing.cpp create mode 100644 indra/newview/llmainlooprepeater.cpp create mode 100644 indra/newview/llmainlooprepeater.h (limited to 'indra/llcommon') diff --git a/indra/llcommon/CMakeLists.txt b/indra/llcommon/CMakeLists.txt index 78d6ea3090..ad6d3a5049 100644 --- a/indra/llcommon/CMakeLists.txt +++ b/indra/llcommon/CMakeLists.txt @@ -119,8 +119,8 @@ set(llcommon_SOURCE_FILES lluriparser.cpp lluuid.cpp llworkerthread.cpp + timing.cpp u64.cpp - threadpool.cpp workqueue.cpp StackWalker.cpp ) @@ -256,7 +256,6 @@ set(llcommon_HEADER_FILES lockstatic.h stdtypes.h stringize.h - threadpool.h threadsafeschedule.h timer.h tuple.h diff --git a/indra/llcommon/llsingleton.h b/indra/llcommon/llsingleton.h index 6042c0906c..10a8ecfedb 100644 --- a/indra/llcommon/llsingleton.h +++ b/indra/llcommon/llsingleton.h @@ -847,28 +847,22 @@ template class LLSimpleton { public: - template - static void createInstance(ARGS&&... args) - { + static T* sInstance; + + static void createInstance() + { llassert(sInstance == nullptr); - sInstance = new T(std::forward(args)...); + sInstance = new T(); } - + static inline T* getInstance() { return sInstance; } static inline T& instance() { return *getInstance(); } static inline bool instanceExists() { return sInstance != nullptr; } - static void deleteSingleton() - { - delete sInstance; - sInstance = nullptr; + static void deleteSingleton() { + delete sInstance; + sInstance = nullptr; } - -private: - static T* sInstance; }; -template -T* LLSimpleton::sInstance{ nullptr }; - #endif diff --git a/indra/llcommon/llthreadsafequeue.h b/indra/llcommon/llthreadsafequeue.h index 5c934791fe..06e8d8f609 100644 --- a/indra/llcommon/llthreadsafequeue.h +++ b/indra/llcommon/llthreadsafequeue.h @@ -85,8 +85,8 @@ public: LLThreadSafeQueue(U32 capacity = 1024); virtual ~LLThreadSafeQueue() {} - // Add an element to the queue (will block if the queue has reached - // capacity). + // Add an element to the queue (will block if the queue has + // reached capacity). // // This call will raise an interrupt error if the queue is closed while // the caller is blocked. @@ -95,11 +95,6 @@ public: // legacy name void pushFront(ElementT const & element) { return push(element); } - // Add an element to the queue (will block if the queue has reached - // capacity). Return false if the queue is closed before push is possible. - template - bool pushIfOpen(T&& element); - // Try to add an element to the queue without blocking. Returns // true only if the element was actually added. template @@ -316,8 +311,8 @@ bool LLThreadSafeQueue::push_(lock_t& lock, T&& element) template -template -bool LLThreadSafeQueue::pushIfOpen(T&& element) +template +void LLThreadSafeQueue::push(T&& element) { lock_t lock1(mLock); while (true) @@ -326,10 +321,12 @@ bool LLThreadSafeQueue::pushIfOpen(T&& element) // drained or not: the moment either end calls close(), further push() // operations will fail. if (mClosed) - return false; + { + LLTHROW(LLThreadSafeQueueInterrupt()); + } if (push_(lock1, std::forward(element))) - return true; + return; // Storage Full. Wait for signal. mCapacityCond.wait(lock1); @@ -337,17 +334,6 @@ bool LLThreadSafeQueue::pushIfOpen(T&& element) } -template -template -void LLThreadSafeQueue::push(T&& element) -{ - if (! pushIfOpen(std::forward(element))) - { - LLTHROW(LLThreadSafeQueueInterrupt()); - } -} - - template template bool LLThreadSafeQueue::tryPush(T&& element) diff --git a/indra/llcommon/tests/threadsafeschedule_test.cpp b/indra/llcommon/tests/threadsafeschedule_test.cpp index c421cc7b1c..af67b9f492 100644 --- a/indra/llcommon/tests/threadsafeschedule_test.cpp +++ b/indra/llcommon/tests/threadsafeschedule_test.cpp @@ -46,11 +46,11 @@ namespace tut // the real time required for each push() call. Explicitly increment // the timestamp for each one -- but since we're passing explicit // timestamps, make the queue reorder them. - queue.push(Queue::TimeTuple(Queue::Clock::now() + 200ms, "ghi")); + queue.push(Queue::TimeTuple(Queue::Clock::now() + 20ms, "ghi")); // Given the various push() overloads, you have to match the type // exactly: conversions are ambiguous. queue.push("abc"s); - queue.push(Queue::Clock::now() + 100ms, "def"); + queue.push(Queue::Clock::now() + 10ms, "def"); queue.close(); auto entry = queue.pop(); ensure_equals("failed to pop first", std::get<0>(entry), "abc"s); diff --git a/indra/llcommon/tests/workqueue_test.cpp b/indra/llcommon/tests/workqueue_test.cpp index bea3ad911b..d5405400fd 100644 --- a/indra/llcommon/tests/workqueue_test.cpp +++ b/indra/llcommon/tests/workqueue_test.cpp @@ -20,10 +20,7 @@ // external library headers // other Linden headers #include "../test/lltut.h" -#include "../test/catch_and_store_what_in.h" #include "llcond.h" -#include "llcoros.h" -#include "lleventcoro.h" #include "llstring.h" #include "stringize.h" @@ -141,8 +138,7 @@ namespace tut [](){ return 17; }, // Note that a postTo() *callback* can safely bind a reference to // a variable on the invoking thread, because the callback is run - // on the invoking thread. (Of course the bound variable must - // survive until the callback is called.) + // on the invoking thread. [&result](int i){ result = i; }); // this should post the callback to main qptr->runOne(); @@ -160,70 +156,4 @@ namespace tut main.runPending(); ensure_equals("failed to run string callback", alpha, "abc"); } - - template<> template<> - void object::test<5>() - { - set_test_name("postTo with void return"); - WorkQueue main("main"); - auto qptr = WorkQueue::getInstance("queue"); - std::string observe; - main.postTo( - qptr, - // The ONLY reason we can get away with binding a reference to - // 'observe' in our work callable is because we're directly - // calling qptr->runOne() on this same thread. It would be a - // mistake to do that if some other thread were servicing 'queue'. - [&observe](){ observe = "queue"; }, - [&observe](){ observe.append(";main"); }); - qptr->runOne(); - main.runOne(); - ensure_equals("failed to run both lambdas", observe, "queue;main"); - } - - template<> template<> - void object::test<6>() - { - set_test_name("waitForResult"); - std::string stored; - // Try to call waitForResult() on this thread's main coroutine. It - // should throw because the main coroutine must service the queue. - auto what{ catch_what( - [this, &stored](){ stored = queue.waitForResult( - [](){ return "should throw"; }); }) }; - ensure("lambda should not have run", stored.empty()); - ensure_not("waitForResult() should have thrown", what.empty()); - ensure(STRINGIZE("should mention waitForResult: " << what), - what.find("waitForResult") != std::string::npos); - - // Call waitForResult() on a coroutine, with a string result. - LLCoros::instance().launch( - "waitForResult string", - [this, &stored]() - { stored = queue.waitForResult( - [](){ return "string result"; }); }); - llcoro::suspend(); - // Nothing will have happened yet because, even if the coroutine did - // run immediately, all it did was to queue the inner lambda on - // 'queue'. Service it. - queue.runOne(); - llcoro::suspend(); - ensure_equals("bad waitForResult return", stored, "string result"); - - // Call waitForResult() on a coroutine, with a void callable. - stored.clear(); - bool done = false; - LLCoros::instance().launch( - "waitForResult void", - [this, &stored, &done]() - { - queue.waitForResult([&stored](){ stored = "ran"; }); - done = true; - }); - llcoro::suspend(); - queue.runOne(); - llcoro::suspend(); - ensure_equals("didn't run coroutine", stored, "ran"); - ensure("void waitForResult() didn't return", done); - } } // namespace tut diff --git a/indra/llcommon/threadpool.cpp b/indra/llcommon/threadpool.cpp deleted file mode 100644 index cf25cc838e..0000000000 --- a/indra/llcommon/threadpool.cpp +++ /dev/null @@ -1,80 +0,0 @@ -/** - * @file threadpool.cpp - * @author Nat Goodspeed - * @date 2021-10-21 - * @brief Implementation for threadpool. - * - * $LicenseInfo:firstyear=2021&license=viewerlgpl$ - * Copyright (c) 2021, Linden Research, Inc. - * $/LicenseInfo$ - */ - -// Precompiled header -#include "linden_common.h" -// associated header -#include "threadpool.h" -// STL headers -// std headers -// external library headers -// other Linden headers -#include "llerror.h" -#include "llevents.h" -#include "stringize.h" - -LL::ThreadPool::ThreadPool(const std::string& name, size_t threads, size_t capacity): - mQueue(name, capacity), - mName("ThreadPool:" + name) -{ - for (size_t i = 0; i < threads; ++i) - { - std::string tname{ STRINGIZE(mName << ':' << (i+1) << '/' << threads) }; - mThreads.emplace_back(tname, [this, tname](){ run(tname); }); - } - // Listen on "LLApp", and when the app is shutting down, close the queue - // and join the workers. - LLEventPumps::instance().obtain("LLApp").listen( - mName, - [this](const LLSD& stat) - { - std::string status(stat["status"]); - if (status != "running") - { - // viewer is starting shutdown -- proclaim the end is nigh! - LL_DEBUGS("ThreadPool") << mName << " saw " << status << LL_ENDL; - close(); - } - return false; - }); -} - -LL::ThreadPool::~ThreadPool() -{ - close(); -} - -void LL::ThreadPool::close() -{ - if (! mQueue.isClosed()) - { - LL_DEBUGS("ThreadPool") << mName << " closing queue and joining threads" << LL_ENDL; - mQueue.close(); - for (auto& pair: mThreads) - { - LL_DEBUGS("ThreadPool") << mName << " waiting on thread " << pair.first << LL_ENDL; - pair.second.join(); - } - LL_DEBUGS("ThreadPool") << mName << " shutdown complete" << LL_ENDL; - } -} - -void LL::ThreadPool::run(const std::string& name) -{ - LL_DEBUGS("ThreadPool") << name << " starting" << LL_ENDL; - run(); - LL_DEBUGS("ThreadPool") << name << " stopping" << LL_ENDL; -} - -void LL::ThreadPool::run() -{ - mQueue.runUntilClose(); -} diff --git a/indra/llcommon/threadpool.h b/indra/llcommon/threadpool.h deleted file mode 100644 index 1ca24aec58..0000000000 --- a/indra/llcommon/threadpool.h +++ /dev/null @@ -1,62 +0,0 @@ -/** - * @file threadpool.h - * @author Nat Goodspeed - * @date 2021-10-21 - * @brief ThreadPool configures a WorkQueue along with a pool of threads to - * service it. - * - * $LicenseInfo:firstyear=2021&license=viewerlgpl$ - * Copyright (c) 2021, Linden Research, Inc. - * $/LicenseInfo$ - */ - -#if ! defined(LL_THREADPOOL_H) -#define LL_THREADPOOL_H - -#include "workqueue.h" -#include -#include -#include // std::pair -#include - -namespace LL -{ - - class ThreadPool - { - public: - /** - * Pass ThreadPool a string name. This can be used to look up the - * relevant WorkQueue. - */ - ThreadPool(const std::string& name, size_t threads=1, size_t capacity=1024); - virtual ~ThreadPool(); - - /** - * ThreadPool listens for application shutdown messages on the "LLApp" - * LLEventPump. Call close() to shut down this ThreadPool early. - */ - void close(); - - std::string getName() const { return mName; } - size_t getWidth() const { return mThreads.size(); } - /// obtain a non-const reference to the WorkQueue to post work to it - WorkQueue& getQueue() { return mQueue; } - - /** - * Override run() if you need special processing. The default run() - * implementation simply calls WorkQueue::runUntilClose(). - */ - virtual void run(); - - private: - void run(const std::string& name); - - WorkQueue mQueue; - std::string mName; - std::vector> mThreads; - }; - -} // namespace LL - -#endif /* ! defined(LL_THREADPOOL_H) */ diff --git a/indra/llcommon/timing.cpp b/indra/llcommon/timing.cpp new file mode 100644 index 0000000000..c2dc695ef3 --- /dev/null +++ b/indra/llcommon/timing.cpp @@ -0,0 +1,25 @@ +/** + * @file timing.cpp + * @brief This file will be deprecated in the future. + * + * $LicenseInfo:firstyear=2000&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ diff --git a/indra/llcommon/workqueue.cpp b/indra/llcommon/workqueue.cpp index 633594ceea..b32357e832 100644 --- a/indra/llcommon/workqueue.cpp +++ b/indra/llcommon/workqueue.cpp @@ -26,9 +26,8 @@ using Mutex = LLCoros::Mutex; using Lock = LLCoros::LockType; -LL::WorkQueue::WorkQueue(const std::string& name, size_t capacity): - super(makeName(name)), - mQueue(capacity) +LL::WorkQueue::WorkQueue(const std::string& name): + super(makeName(name)) { // TODO: register for "LLApp" events so we can implicitly close() on // viewer shutdown. @@ -39,21 +38,6 @@ void LL::WorkQueue::close() mQueue.close(); } -size_t LL::WorkQueue::size() -{ - return mQueue.size(); -} - -bool LL::WorkQueue::isClosed() -{ - return mQueue.isClosed(); -} - -bool LL::WorkQueue::done() -{ - return mQueue.done(); -} - void LL::WorkQueue::runUntilClose() { try @@ -144,13 +128,3 @@ void LL::WorkQueue::error(const std::string& msg) { LL_ERRS("WorkQueue") << msg << LL_ENDL; } - -void LL::WorkQueue::checkCoroutine(const std::string& method) -{ - // By convention, the default coroutine on each thread has an empty name - // string. See also LLCoros::logname(). - if (LLCoros::getName().empty()) - { - LLTHROW(Error("Do not call " + method + " from a thread's default coroutine")); - } -} diff --git a/indra/llcommon/workqueue.h b/indra/llcommon/workqueue.h index c25d787425..5ec790da79 100644 --- a/indra/llcommon/workqueue.h +++ b/indra/llcommon/workqueue.h @@ -12,14 +12,14 @@ #if ! defined(LL_WORKQUEUE_H) #define LL_WORKQUEUE_H -#include "llcoros.h" -#include "llexception.h" #include "llinstancetracker.h" #include "threadsafeschedule.h" #include -#include // std::current_exception #include // std::function +#include #include +#include // std::pair +#include namespace LL { @@ -45,16 +45,11 @@ namespace LL using TimedWork = Queue::TimeTuple; using Closed = Queue::Closed; - struct Error: public LLException - { - Error(const std::string& what): LLException(what) {} - }; - /** * You may omit the WorkQueue name, in which case a unique name is * synthesized; for practical purposes that makes it anonymous. */ - WorkQueue(const std::string& name = std::string(), size_t capacity=1024); + WorkQueue(const std::string& name = std::string()); /** * Since the point of WorkQueue is to pass work to some other worker @@ -64,36 +59,15 @@ namespace LL */ void close(); - /** - * WorkQueue supports multiple producers and multiple consumers. In - * the general case it's misleading to test size(), since any other - * thread might change it the nanosecond the lock is released. On that - * basis, some might argue against publishing a size() method at all. - * - * But there are two specific cases in which a test based on size() - * might be reasonable: - * - * * If you're the only producer, noticing that size() == 0 is - * meaningful. - * * If you're the only consumer, noticing that size() > 0 is - * meaningful. - */ - size_t size(); - /// producer end: are we prevented from pushing any additional items? - bool isClosed(); - /// consumer end: are we done, is the queue entirely drained? - bool done(); - /*---------------------- fire and forget API -----------------------*/ /// fire-and-forget, but at a particular (future?) time template void post(const TimePoint& time, CALLABLE&& callable) { - // Defer reifying an arbitrary CALLABLE until we hit this or - // postIfOpen(). All other methods should accept CALLABLEs of - // arbitrary type to avoid multiple levels of std::function - // indirection. + // Defer reifying an arbitrary CALLABLE until we hit this method. + // All other methods should accept CALLABLEs of arbitrary type to + // avoid multiple levels of std::function indirection. mQueue.push(TimedWork(time, std::move(callable))); } @@ -108,47 +82,6 @@ namespace LL post(TimePoint::clock::now(), std::move(callable)); } - /** - * post work for a particular time, unless the queue is closed before - * we can post - */ - template - bool postIfOpen(const TimePoint& time, CALLABLE&& callable) - { - // Defer reifying an arbitrary CALLABLE until we hit this or - // post(). All other methods should accept CALLABLEs of arbitrary - // type to avoid multiple levels of std::function indirection. - return mQueue.pushIfOpen(TimedWork(time, std::move(callable))); - } - - /** - * post work, unless the queue is closed before we can post - */ - template - bool postIfOpen(CALLABLE&& callable) - { - return postIfOpen(TimePoint::clock::now(), std::move(callable)); - } - - /** - * Post work to be run at a specified time to another WorkQueue, which - * may or may not still exist and be open. Return true if we were able - * to post. - */ - template - static bool postMaybe(weak_t target, const TimePoint& time, CALLABLE&& callable); - - /** - * Post work to another WorkQueue, which may or may not still exist - * and be open. Return true if we were able to post. - */ - template - static bool postMaybe(weak_t target, CALLABLE&& callable) - { - return postMaybe(target, TimePoint::clock::now(), - std::forward(callable)); - } - /** * Launch a callable returning bool that will trigger repeatedly at * specified interval, until the callable returns false. @@ -182,8 +115,63 @@ namespace LL // Studio compile errors that seem utterly unrelated to this source // code. template - bool postTo(weak_t target, - const TimePoint& time, CALLABLE&& callable, FOLLOWUP&& callback); + bool postTo(WorkQueue::weak_t target, + const TimePoint& time, CALLABLE&& callable, FOLLOWUP&& callback) + { + // We're being asked to post to the WorkQueue at target. + // target is a weak_ptr: have to lock it to check it. + auto tptr = target.lock(); + if (! tptr) + // can't post() if the target WorkQueue has been destroyed + return false; + + // Here we believe target WorkQueue still exists. Post to it a + // lambda that packages our callable, our callback and a weak_ptr + // to this originating WorkQueue. + tptr->post( + time, + [reply = super::getWeak(), + callable = std::move(callable), + callback = std::move(callback)] + () + { + // Call the callable in any case -- but to minimize + // copying the result, immediately bind it into a reply + // lambda. The reply lambda also binds the original + // callback, so that when we, the originating WorkQueue, + // finally receive and process the reply lambda, we'll + // call the bound callback with the bound result -- on the + // same thread that originally called postTo(). + auto rlambda = + [result = callable(), + callback = std::move(callback)] + () + { callback(std::move(result)); }; + // Check if this originating WorkQueue still exists. + // Remember, the outer lambda is now running on a thread + // servicing the target WorkQueue, and real time has + // elapsed since postTo()'s tptr->post() call. + // reply is a weak_ptr: have to lock it to check it. + auto rptr = reply.lock(); + if (rptr) + { + // Only post reply lambda if the originating WorkQueue + // still exists. If not -- who would we tell? Log it? + try + { + rptr->post(std::move(rlambda)); + } + catch (const Closed&) + { + // Originating WorkQueue might still exist, but + // might be Closed. Same thing: just discard the + // callback. + } + } + }); + // looks like we were able to post() + return true; + } /** * Post work to another WorkQueue, requesting a specific callback to @@ -193,36 +181,10 @@ namespace LL * inaccessible. */ template - bool postTo(weak_t target, CALLABLE&& callable, FOLLOWUP&& callback) + bool postTo(WorkQueue::weak_t target, + CALLABLE&& callable, FOLLOWUP&& callback) { - return postTo(target, TimePoint::clock::now(), - std::move(callable), std::move(callback)); - } - - /** - * Post work to another WorkQueue to be run at a specified time, - * blocking the calling coroutine until then, returning the result to - * caller on completion. - * - * In general, we assume that each thread's default coroutine is busy - * servicing its WorkQueue or whatever. To try to prevent mistakes, we - * forbid calling waitForResult() from a thread's default coroutine. - */ - template - auto waitForResult(const TimePoint& time, CALLABLE&& callable); - - /** - * Post work to another WorkQueue, blocking the calling coroutine - * until then, returning the result to caller on completion. - * - * In general, we assume that each thread's default coroutine is busy - * servicing its WorkQueue or whatever. To try to prevent mistakes, we - * forbid calling waitForResult() from a thread's default coroutine. - */ - template - auto waitForResult(CALLABLE&& callable) - { - return waitForResult(TimePoint::clock::now(), std::move(callable)); + return postTo(target, TimePoint::clock::now(), std::move(callable), std::move(callback)); } /*--------------------------- worker API ---------------------------*/ @@ -270,23 +232,6 @@ namespace LL bool runUntil(const TimePoint& until); private: - template - static auto makeReplyLambda(CALLABLE&& callable, FOLLOWUP&& callback); - /// general case: arbitrary C++ return type - template - struct MakeReplyLambda; - /// specialize for CALLABLE returning void - template - struct MakeReplyLambda; - - /// general case: arbitrary C++ return type - template - struct WaitForResult; - /// specialize for CALLABLE returning void - template - struct WaitForResult; - - static void checkCoroutine(const std::string& method); static void error(const std::string& msg); static std::string makeName(const std::string& name); void callWork(const Queue::DataTuple& work); @@ -308,8 +253,8 @@ namespace LL { public: // bind the desired data - BackJack(weak_t target, - const TimePoint& start, + BackJack(WorkQueue::weak_t target, + const WorkQueue::TimePoint& start, const std::chrono::duration& interval, CALLABLE&& callable): mTarget(target), @@ -356,8 +301,8 @@ namespace LL } private: - weak_t mTarget; - TimePoint mStart; + WorkQueue::weak_t mTarget; + WorkQueue::TimePoint mStart; std::chrono::duration mInterval; CALLABLE mCallable; }; @@ -385,187 +330,6 @@ namespace LL getWeak(), TimePoint::clock::now(), interval, std::move(callable))); } - /// general case: arbitrary C++ return type - template - struct WorkQueue::MakeReplyLambda - { - auto operator()(CALLABLE&& callable, FOLLOWUP&& callback) - { - // Call the callable in any case -- but to minimize - // copying the result, immediately bind it into the reply - // lambda. The reply lambda also binds the original - // callback, so that when we, the originating WorkQueue, - // finally receive and process the reply lambda, we'll - // call the bound callback with the bound result -- on the - // same thread that originally called postTo(). - return - [result = std::forward(callable)(), - callback = std::move(callback)] - () - { callback(std::move(result)); }; - } - }; - - /// specialize for CALLABLE returning void - template - struct WorkQueue::MakeReplyLambda - { - auto operator()(CALLABLE&& callable, FOLLOWUP&& callback) - { - // Call the callable, which produces no result. - std::forward(callable)(); - // Our completion callback is simply the caller's callback. - return std::move(callback); - } - }; - - template - auto WorkQueue::makeReplyLambda(CALLABLE&& callable, FOLLOWUP&& callback) - { - return MakeReplyLambda(callable)())>() - (std::move(callable), std::move(callback)); - } - - template - bool WorkQueue::postTo(weak_t target, - const TimePoint& time, CALLABLE&& callable, FOLLOWUP&& callback) - { - // We're being asked to post to the WorkQueue at target. - // target is a weak_ptr: have to lock it to check it. - auto tptr = target.lock(); - if (! tptr) - // can't post() if the target WorkQueue has been destroyed - return false; - - // Here we believe target WorkQueue still exists. Post to it a - // lambda that packages our callable, our callback and a weak_ptr - // to this originating WorkQueue. - tptr->post( - time, - [reply = super::getWeak(), - callable = std::move(callable), - callback = std::move(callback)] - () - { - // Use postMaybe() below in case this originating WorkQueue - // has been closed or destroyed. Remember, the outer lambda is - // now running on a thread servicing the target WorkQueue, and - // real time has elapsed since postTo()'s tptr->post() call. - try - { - // Make a reply lambda to repost to THIS WorkQueue. - // Delegate to makeReplyLambda() so we can partially - // specialize on void return. - postMaybe(reply, makeReplyLambda(std::move(callable), std::move(callback))); - } - catch (...) - { - // Either variant of makeReplyLambda() is responsible for - // calling the caller's callable. If that throws, return - // the exception to the originating thread. - postMaybe( - reply, - // Bind the current exception to transport back to the - // originating WorkQueue. Once there, rethrow it. - [exc = std::current_exception()](){ std::rethrow_exception(exc); }); - } - }); - - // looks like we were able to post() - return true; - } - - template - bool WorkQueue::postMaybe(weak_t target, const TimePoint& time, CALLABLE&& callable) - { - // target is a weak_ptr: have to lock it to check it - auto tptr = target.lock(); - if (tptr) - { - try - { - tptr->post(time, std::forward(callable)); - // we were able to post() - return true; - } - catch (const Closed&) - { - // target WorkQueue still exists, but is Closed - } - } - // either target no longer exists, or its WorkQueue is Closed - return false; - } - - /// general case: arbitrary C++ return type - template - struct WorkQueue::WaitForResult - { - auto operator()(WorkQueue* self, const TimePoint& time, CALLABLE&& callable) - { - LLCoros::Promise promise; - self->post( - time, - // We dare to bind a reference to Promise because it's - // specifically designed for cross-thread communication. - [&promise, callable = std::move(callable)]() - { - try - { - // call the caller's callable and trigger promise with result - promise.set_value(callable()); - } - catch (...) - { - promise.set_exception(std::current_exception()); - } - }); - auto future{ LLCoros::getFuture(promise) }; - // now, on the calling thread, wait for that result - LLCoros::TempStatus st("waiting for WorkQueue::waitForResult()"); - return future.get(); - } - }; - - /// specialize for CALLABLE returning void - template - struct WorkQueue::WaitForResult - { - void operator()(WorkQueue* self, const TimePoint& time, CALLABLE&& callable) - { - LLCoros::Promise promise; - self->post( - time, - // &promise is designed for cross-thread access - [&promise, callable = std::move(callable)]() - { - try - { - callable(); - promise.set_value(); - } - catch (...) - { - promise.set_exception(std::current_exception()); - } - }); - auto future{ LLCoros::getFuture(promise) }; - // block until set_value() - LLCoros::TempStatus st("waiting for void WorkQueue::waitForResult()"); - future.get(); - } - }; - - template - auto WorkQueue::waitForResult(const TimePoint& time, CALLABLE&& callable) - { - checkCoroutine("waitForResult()"); - // derive callable's return type so we can specialize for void - return WaitForResult(callable)())>() - (this, time, std::forward(callable)); - } - } // namespace LL #endif /* ! defined(LL_WORKQUEUE_H) */ diff --git a/indra/llrender/llimagegl.cpp b/indra/llrender/llimagegl.cpp index 1b6920fe3b..cbc5392882 100644 --- a/indra/llrender/llimagegl.cpp +++ b/indra/llrender/llimagegl.cpp @@ -172,19 +172,31 @@ BOOL is_little_endian() return (*c == 0x78) ; } +LLImageGLThread* LLImageGLThread::sInstance = nullptr; + //static void LLImageGL::initClass(LLWindow* window, S32 num_catagories, BOOL skip_analyze_alpha /* = false */) { LL_PROFILE_ZONE_SCOPED; sSkipAnalyzeAlpha = skip_analyze_alpha; - LLImageGLThread::createInstance(window); + LLImageGLThread::sInstance = new LLImageGLThread(window); + LLImageGLThread::sInstance->start(); +} + +//static +void LLImageGL::updateClass() +{ + LL_PROFILE_ZONE_SCOPED; + LLImageGLThread::sInstance->executeCallbacks(); } //static void LLImageGL::cleanupClass() { LL_PROFILE_ZONE_SCOPED; - LLImageGLThread::deleteSingleton(); + LLImageGLThread::sInstance->mFunctionQueue.close(); + delete LLImageGLThread::sInstance; + LLImageGLThread::sInstance = nullptr; } //static @@ -492,9 +504,6 @@ void LLImageGL::init(BOOL usemipmaps) #endif mCategory = -1; - - // Sometimes we have to post work for the main thread. - mMainQueue = LL::WorkQueue::getInstance("mainloop"); } void LLImageGL::cleanup() @@ -1527,7 +1536,8 @@ BOOL LLImageGL::createGLTexture(S32 discard_level, const U8* data_in, BOOL data_ } //if we're on the image loading thread, be sure to delete old_texname and update mTexName on the main thread - if (! on_main_thread()) + if (LLImageGLThread::sInstance != nullptr && + LLThread::currentID() == LLImageGLThread::sInstance->getID()) { { LL_PROFILE_ZONE_NAMED("cglt - sync"); @@ -1544,9 +1554,7 @@ BOOL LLImageGL::createGLTexture(S32 discard_level, const U8* data_in, BOOL data_ } ref(); - LL::WorkQueue::postMaybe( - mMainQueue, - [=]() + LLImageGLThread::sInstance->postCallback([=]() { LL_PROFILE_ZONE_NAMED("cglt - delete callback"); if (old_texname != 0) @@ -2251,24 +2259,73 @@ void LLImageGL::resetCurTexSizebar() */ LLImageGLThread::LLImageGLThread(LLWindow* window) - // We want exactly one thread, but a very large capacity: we never want - // anyone, especially inner-loop render code, to have to block on post() - // because we're full. - : ThreadPool("LLImageGL", 1, 1024*1024) - , mWindow(window) + : LLThread("LLImageGL"), mWindow(window) { mFinished = false; mContext = mWindow->createSharedContext(); } +// post a function to be executed on the LLImageGL background thread + +bool LLImageGLThread::post(const std::function& func) +{ + try + { + mFunctionQueue.post(func); + } + catch (LLThreadSafeQueueInterrupt e) + { + return false; + } + + return true; +} + +//post a callback to be executed on the main thread + +bool LLImageGLThread::postCallback(const std::function& callback) +{ + try + { + if (!mCallbackQueue.tryPost(callback)) + { + mPendingCallbackQ.push(callback); + } + } + catch (LLThreadSafeQueueInterrupt e) + { + //thread is closing, drop request + return false; + } + + return true; +} + +void LLImageGLThread::executeCallbacks() +{ + LL_PROFILE_ZONE_SCOPED; + //executed from main thread + mCallbackQueue.runPending(); + + while (!mPendingCallbackQ.empty()) + { + if (mCallbackQueue.tryPost(mPendingCallbackQ.front())) + { + mPendingCallbackQ.pop(); + } + else + { + break; + } + } +} + void LLImageGLThread::run() { - // We must perform setup on this thread before actually servicing our - // WorkQueue, likewise cleanup afterwards. mWindow->makeContextCurrent(mContext); gGL.init(); - ThreadPool::run(); + mFunctionQueue.runUntilClose(); gGL.shutdown(); mWindow->destroySharedContext(mContext); } diff --git a/indra/llrender/llimagegl.h b/indra/llrender/llimagegl.h index 27496def1d..8264e4a5f2 100644 --- a/indra/llrender/llimagegl.h +++ b/indra/llrender/llimagegl.h @@ -37,7 +37,6 @@ #include "llunits.h" #include "llthreadsafequeue.h" #include "llrender.h" -#include "threadpool.h" #include "workqueue.h" class LLTextureAtlas ; @@ -199,7 +198,6 @@ private: void freePickMask(); LLPointer mSaveData; // used for destroyGL/restoreGL - LL::WorkQueue::weak_t mMainQueue; U8* mPickMask; //downsampled bitmap approximation of alpha channel. NULL if no alpha channel U16 mPickMaskWidth; U16 mPickMaskHeight; @@ -273,6 +271,7 @@ public: public: static void initClass(LLWindow* window, S32 num_catagories, BOOL skip_analyze_alpha = false); + static void updateClass(); static void cleanupClass() ; private: @@ -308,24 +307,34 @@ public: }; -class LLImageGLThread : public LLSimpleton, LL::ThreadPool +class LLImageGLThread : public LLThread { public: LLImageGLThread(LLWindow* window); // post a function to be executed on the LLImageGL background thread - template - bool post(CALLABLE&& func) - { - return getQueue().postIfOpen(std::forward(func)); - } + bool post(const std::function& func); + + //post a callback to be executed on the main thread + bool postCallback(const std::function& callback); + + void executeCallbacks(); void run() override; -private: + // Work Queue for background thread + LL::WorkQueue mFunctionQueue; + + // Work Queue for main thread (run from updateClass) + LL::WorkQueue mCallbackQueue; + LLWindow* mWindow; void* mContext; LLAtomicBool mFinished; + + std::queue> mPendingCallbackQ; + + static LLImageGLThread* sInstance; }; diff --git a/indra/llui/CMakeLists.txt b/indra/llui/CMakeLists.txt index 55c1655d7b..f781ff4110 100644 --- a/indra/llui/CMakeLists.txt +++ b/indra/llui/CMakeLists.txt @@ -308,10 +308,6 @@ if(LL_TESTS) ${BOOST_FIBER_LIBRARY} ${BOOST_CONTEXT_LIBRARY} ${BOOST_SYSTEM_LIBRARY} ${WINDOWS_LIBRARIES}) if(NOT LINUX) - if(WINDOWS) - LL_ADD_INTEGRATION_TEST(llurlentry llurlentry.cpp "imm32;${test_libs}") - else(WINDOWS) - LL_ADD_INTEGRATION_TEST(llurlentry llurlentry.cpp "${test_libs}") - endif(WINDOWS) + LL_ADD_INTEGRATION_TEST(llurlentry llurlentry.cpp "${test_libs}") endif(NOT LINUX) endif(LL_TESTS) diff --git a/indra/llui/llviewereventrecorder.cpp b/indra/llui/llviewereventrecorder.cpp index cb000aef74..5a44ec947a 100644 --- a/indra/llui/llviewereventrecorder.cpp +++ b/indra/llui/llviewereventrecorder.cpp @@ -28,6 +28,8 @@ #include "llui.h" #include "llleap.h" +LLViewerEventRecorder* LLSimpleton::sInstance = nullptr; + LLViewerEventRecorder::LLViewerEventRecorder() { clear(UNDEFINED); diff --git a/indra/llwindow/llwindowwin32.cpp b/indra/llwindow/llwindowwin32.cpp index 3f3dd43daf..e52624d66a 100644 --- a/indra/llwindow/llwindowwin32.cpp +++ b/indra/llwindow/llwindowwin32.cpp @@ -55,8 +55,6 @@ #include #include #include -#include -#include // std::pair // Require DirectInput version 8 #define DIRECTINPUT_VERSION 0x0800 @@ -176,19 +174,23 @@ DWORD LLWindowWin32::sWinIMESentenceMode = IME_SMODE_AUTOMATIC; LLCoordWindow LLWindowWin32::sWinIMEWindowPosition(-1,-1); // The following class LLWinImm delegates Windows IMM APIs. -// It was originally introduced to support US Windows XP, on which we needed -// to dynamically load IMM32.DLL and use GetProcAddress to resolve its entry -// points. Now that that's moot, we retain this wrapper only for hooks for -// metrics. +// We need this because some language versions of Windows, +// e.g., US version of Windows XP, doesn't install IMM32.DLL +// as a default, and we can't link against imm32.lib statically. +// I believe DLL loading of this type is best suited to do +// in a static initialization of a class. What I'm not sure is +// whether it follows the Linden Conding Standard... +// See http://wiki.secondlife.com/wiki/Coding_standards#Static_Members class LLWinImm { public: - static bool isAvailable() { return true; } + static bool isAvailable() { return sTheInstance.mHImmDll != NULL; } public: // Wrappers for IMM API. static BOOL isIME(HKL hkl); + static HWND getDefaultIMEWnd(HWND hwnd); static HIMC getContext(HWND hwnd); static BOOL releaseContext(HWND hwnd, HIMC himc); static BOOL getOpenStatus(HIMC himc); @@ -202,96 +204,236 @@ public: static BOOL setCompositionFont(HIMC himc, LPLOGFONTW logfont); static BOOL setCandidateWindow(HIMC himc, LPCANDIDATEFORM candidate_form); static BOOL notifyIME(HIMC himc, DWORD action, DWORD index, DWORD value); + +private: + LLWinImm(); + ~LLWinImm(); + +private: + // Pointers to IMM API. + BOOL (WINAPI *mImmIsIME)(HKL); + HWND (WINAPI *mImmGetDefaultIMEWnd)(HWND); + HIMC (WINAPI *mImmGetContext)(HWND); + BOOL (WINAPI *mImmReleaseContext)(HWND, HIMC); + BOOL (WINAPI *mImmGetOpenStatus)(HIMC); + BOOL (WINAPI *mImmSetOpenStatus)(HIMC, BOOL); + BOOL (WINAPI *mImmGetConversionStatus)(HIMC, LPDWORD, LPDWORD); + BOOL (WINAPI *mImmSetConversionStatus)(HIMC, DWORD, DWORD); + BOOL (WINAPI *mImmGetCompostitionWindow)(HIMC, LPCOMPOSITIONFORM); + BOOL (WINAPI *mImmSetCompostitionWindow)(HIMC, LPCOMPOSITIONFORM); + LONG (WINAPI *mImmGetCompositionString)(HIMC, DWORD, LPVOID, DWORD); + BOOL (WINAPI *mImmSetCompositionString)(HIMC, DWORD, LPVOID, DWORD, LPVOID, DWORD); + BOOL (WINAPI *mImmSetCompositionFont)(HIMC, LPLOGFONTW); + BOOL (WINAPI *mImmSetCandidateWindow)(HIMC, LPCANDIDATEFORM); + BOOL (WINAPI *mImmNotifyIME)(HIMC, DWORD, DWORD, DWORD); + +private: + HMODULE mHImmDll; + static LLWinImm sTheInstance; }; +LLWinImm LLWinImm::sTheInstance; + +LLWinImm::LLWinImm() : mHImmDll(NULL) +{ + // Check system metrics + if ( !GetSystemMetrics( SM_IMMENABLED ) ) + return; + + mHImmDll = LoadLibraryA("Imm32"); + if (mHImmDll != NULL) + { + mImmIsIME = (BOOL (WINAPI *)(HKL)) GetProcAddress(mHImmDll, "ImmIsIME"); + mImmGetDefaultIMEWnd = (HWND (WINAPI *)(HWND)) GetProcAddress(mHImmDll, "ImmGetDefaultIMEWnd"); + mImmGetContext = (HIMC (WINAPI *)(HWND)) GetProcAddress(mHImmDll, "ImmGetContext"); + mImmReleaseContext = (BOOL (WINAPI *)(HWND, HIMC)) GetProcAddress(mHImmDll, "ImmReleaseContext"); + mImmGetOpenStatus = (BOOL (WINAPI *)(HIMC)) GetProcAddress(mHImmDll, "ImmGetOpenStatus"); + mImmSetOpenStatus = (BOOL (WINAPI *)(HIMC, BOOL)) GetProcAddress(mHImmDll, "ImmSetOpenStatus"); + mImmGetConversionStatus = (BOOL (WINAPI *)(HIMC, LPDWORD, LPDWORD)) GetProcAddress(mHImmDll, "ImmGetConversionStatus"); + mImmSetConversionStatus = (BOOL (WINAPI *)(HIMC, DWORD, DWORD)) GetProcAddress(mHImmDll, "ImmSetConversionStatus"); + mImmGetCompostitionWindow = (BOOL (WINAPI *)(HIMC, LPCOMPOSITIONFORM)) GetProcAddress(mHImmDll, "ImmGetCompositionWindow"); + mImmSetCompostitionWindow = (BOOL (WINAPI *)(HIMC, LPCOMPOSITIONFORM)) GetProcAddress(mHImmDll, "ImmSetCompositionWindow"); + mImmGetCompositionString= (LONG (WINAPI *)(HIMC, DWORD, LPVOID, DWORD)) GetProcAddress(mHImmDll, "ImmGetCompositionStringW"); + mImmSetCompositionString= (BOOL (WINAPI *)(HIMC, DWORD, LPVOID, DWORD, LPVOID, DWORD)) GetProcAddress(mHImmDll, "ImmSetCompositionStringW"); + mImmSetCompositionFont = (BOOL (WINAPI *)(HIMC, LPLOGFONTW)) GetProcAddress(mHImmDll, "ImmSetCompositionFontW"); + mImmSetCandidateWindow = (BOOL (WINAPI *)(HIMC, LPCANDIDATEFORM)) GetProcAddress(mHImmDll, "ImmSetCandidateWindow"); + mImmNotifyIME = (BOOL (WINAPI *)(HIMC, DWORD, DWORD, DWORD)) GetProcAddress(mHImmDll, "ImmNotifyIME"); + + if (mImmIsIME == NULL || + mImmGetDefaultIMEWnd == NULL || + mImmGetContext == NULL || + mImmReleaseContext == NULL || + mImmGetOpenStatus == NULL || + mImmSetOpenStatus == NULL || + mImmGetConversionStatus == NULL || + mImmSetConversionStatus == NULL || + mImmGetCompostitionWindow == NULL || + mImmSetCompostitionWindow == NULL || + mImmGetCompositionString == NULL || + mImmSetCompositionString == NULL || + mImmSetCompositionFont == NULL || + mImmSetCandidateWindow == NULL || + mImmNotifyIME == NULL) + { + // If any of the above API entires are not found, we can't use IMM API. + // So, turn off the IMM support. We should log some warning message in + // the case, since it is very unusual; these APIs are available from + // the beginning, and all versions of IMM32.DLL should have them all. + // Unfortunately, this code may be executed before initialization of + // the logging channel (LL_WARNS()), and we can't do it here... Yes, this + // is one of disadvantages to use static constraction to DLL loading. + FreeLibrary(mHImmDll); + mHImmDll = NULL; + + // If we unload the library, make sure all the function pointers are cleared + mImmIsIME = NULL; + mImmGetDefaultIMEWnd = NULL; + mImmGetContext = NULL; + mImmReleaseContext = NULL; + mImmGetOpenStatus = NULL; + mImmSetOpenStatus = NULL; + mImmGetConversionStatus = NULL; + mImmSetConversionStatus = NULL; + mImmGetCompostitionWindow = NULL; + mImmSetCompostitionWindow = NULL; + mImmGetCompositionString = NULL; + mImmSetCompositionString = NULL; + mImmSetCompositionFont = NULL; + mImmSetCandidateWindow = NULL; + mImmNotifyIME = NULL; + } + } +} + + // static BOOL LLWinImm::isIME(HKL hkl) { - return ImmIsIME(hkl); + if ( sTheInstance.mImmIsIME ) + return sTheInstance.mImmIsIME(hkl); + return FALSE; } // static HIMC LLWinImm::getContext(HWND hwnd) { - return ImmGetContext(hwnd); + if ( sTheInstance.mImmGetContext ) + return sTheInstance.mImmGetContext(hwnd); + return 0; } //static BOOL LLWinImm::releaseContext(HWND hwnd, HIMC himc) { - return ImmReleaseContext(hwnd, himc); + if ( sTheInstance.mImmIsIME ) + return sTheInstance.mImmReleaseContext(hwnd, himc); + return FALSE; } // static BOOL LLWinImm::getOpenStatus(HIMC himc) { - return ImmGetOpenStatus(himc); + if ( sTheInstance.mImmGetOpenStatus ) + return sTheInstance.mImmGetOpenStatus(himc); + return FALSE; } // static BOOL LLWinImm::setOpenStatus(HIMC himc, BOOL status) { - return ImmSetOpenStatus(himc, status); + if ( sTheInstance.mImmSetOpenStatus ) + return sTheInstance.mImmSetOpenStatus(himc, status); + return FALSE; } // static BOOL LLWinImm::getConversionStatus(HIMC himc, LPDWORD conversion, LPDWORD sentence) { - return ImmGetConversionStatus(himc, conversion, sentence); + if ( sTheInstance.mImmGetConversionStatus ) + return sTheInstance.mImmGetConversionStatus(himc, conversion, sentence); + return FALSE; } // static BOOL LLWinImm::setConversionStatus(HIMC himc, DWORD conversion, DWORD sentence) { - return ImmSetConversionStatus(himc, conversion, sentence); + if ( sTheInstance.mImmSetConversionStatus ) + return sTheInstance.mImmSetConversionStatus(himc, conversion, sentence); + return FALSE; } // static BOOL LLWinImm::getCompositionWindow(HIMC himc, LPCOMPOSITIONFORM form) { - return ImmGetCompositionWindow(himc, form); + if ( sTheInstance.mImmGetCompostitionWindow ) + return sTheInstance.mImmGetCompostitionWindow(himc, form); + return FALSE; } // static BOOL LLWinImm::setCompositionWindow(HIMC himc, LPCOMPOSITIONFORM form) { - return ImmSetCompositionWindow(himc, form); + if ( sTheInstance.mImmSetCompostitionWindow ) + return sTheInstance.mImmSetCompostitionWindow(himc, form); + return FALSE; } // static LONG LLWinImm::getCompositionString(HIMC himc, DWORD index, LPVOID data, DWORD length) { - return ImmGetCompositionString(himc, index, data, length); + if ( sTheInstance.mImmGetCompositionString ) + return sTheInstance.mImmGetCompositionString(himc, index, data, length); + return FALSE; } // static BOOL LLWinImm::setCompositionString(HIMC himc, DWORD index, LPVOID pComp, DWORD compLength, LPVOID pRead, DWORD readLength) { - return ImmSetCompositionString(himc, index, pComp, compLength, pRead, readLength); + if ( sTheInstance.mImmSetCompositionString ) + return sTheInstance.mImmSetCompositionString(himc, index, pComp, compLength, pRead, readLength); + return FALSE; } // static BOOL LLWinImm::setCompositionFont(HIMC himc, LPLOGFONTW pFont) { - return ImmSetCompositionFont(himc, pFont); + if ( sTheInstance.mImmSetCompositionFont ) + return sTheInstance.mImmSetCompositionFont(himc, pFont); + return FALSE; } // static BOOL LLWinImm::setCandidateWindow(HIMC himc, LPCANDIDATEFORM form) { - return ImmSetCandidateWindow(himc, form); + if ( sTheInstance.mImmSetCandidateWindow ) + return sTheInstance.mImmSetCandidateWindow(himc, form); + return FALSE; } // static BOOL LLWinImm::notifyIME(HIMC himc, DWORD action, DWORD index, DWORD value) { - return ImmNotifyIME(himc, action, index, value); + if ( sTheInstance.mImmNotifyIME ) + return sTheInstance.mImmNotifyIME(himc, action, index, value); + return FALSE; } + +// ---------------------------------------------------------------------------------------- +LLWinImm::~LLWinImm() +{ + if (mHImmDll != NULL) + { + FreeLibrary(mHImmDll); + mHImmDll = NULL; + } +} + + class LLMonitorInfo { public: @@ -326,32 +468,6 @@ private: static LLMonitorInfo sMonitorInfo; -// Thread that owns the Window Handle -// This whole struct is private to LLWindowWin32, which needs to mess with its -// members, which is why it's a struct rather than a class. In effect, we make -// the containing class a friend. -struct LLWindowWin32::LLWindowWin32Thread : public LL::ThreadPool -{ - static const int MAX_QUEUE_SIZE = 2048; - - LLThreadSafeQueue mMessageQueue; - - LLWindowWin32Thread(); - - void run() override; - - template - void post(CALLABLE&& func) - { - getQueue().post(std::forward(func)); - } - - // call PeekMessage and pull enqueue messages for later processing - void gatherInput(); - HWND mWindowHandle = NULL; - HDC mhDC = 0; -}; - LLWindowWin32::LLWindowWin32(LLWindowCallbacks* callbacks, const std::string& title, const std::string& name, S32 x, S32 y, S32 width, @@ -363,7 +479,8 @@ LLWindowWin32::LLWindowWin32(LLWindowCallbacks* callbacks, : LLWindow(callbacks, fullscreen, flags) { sMainThreadId = LLThread::currentID(); - mWindowThread = new LLWindowWin32Thread(); + mWindowThread = new LLWindowWin32Thread(this); + mWindowThread->start(); //MAINT-516 -- force a load of opengl32.dll just in case windows went sideways LoadLibrary(L"opengl32.dll"); @@ -434,6 +551,7 @@ LLWindowWin32::LLWindowWin32(LLWindowCallbacks* callbacks, // Make an instance of our window then define the window class mhInstance = GetModuleHandle(NULL); + mWndProc = NULL; // Init Direct Input - needed for joystick / Spacemouse @@ -857,13 +975,17 @@ void LLWindowWin32::close() // Something killed the window while we were busy destroying gl or handle somehow got broken LL_WARNS("Window") << "Failed to destroy Window, invalid handle!" << LL_ENDL; } + mWindowHandle = NULL; + mWindowThread->mFinished = true; }); - // Even though the above lambda might not yet have run, we've already - // bound mWindowHandle into it by value, which should suffice for the - // operations we're asking. That's the last time WE should touch it. - mWindowHandle = NULL; - mWindowThread->close(); + + while (!mWindowThread->isStopped()) + { + //nudge window thread + PostMessage(mWindowHandle, WM_USER + 0x0017, 0xB0B0, 0x1337); + std::this_thread::sleep_for(std::chrono::milliseconds(1)); + } } BOOL LLWindowWin32::isValid() @@ -1156,7 +1278,51 @@ BOOL LLWindowWin32::switchContext(BOOL fullscreen, const LLCoordScreen& size, BO << " Fullscreen: " << mFullscreen << LL_ENDL; - recreateWindow(window_rect, dw_ex_style, dw_style); + auto oldHandle = mWindowHandle; + + //zero out mWindowHandle and mhDC before destroying window so window thread falls back to peekmessage + mWindowHandle = 0; + mhDC = 0; + + if (oldHandle && !destroy_window_handler(oldHandle)) + { + LL_WARNS("Window") << "Failed to properly close window before recreating it!" << LL_ENDL; + } + + mWindowHandle = NULL; + mhDC = 0; + + mWindowThread->post( + [this, window_rect, dw_ex_style, dw_style]() + { + mWindowHandle = CreateWindowEx(dw_ex_style, + mWindowClassName, + mWindowTitle, + WS_CLIPSIBLINGS | WS_CLIPCHILDREN | dw_style, + window_rect.left, // x pos + window_rect.top, // y pos + window_rect.right - window_rect.left, // width + window_rect.bottom - window_rect.top, // height + NULL, + NULL, + mhInstance, + NULL); + + if (mWindowHandle) + { + mhDC = GetDC(mWindowHandle); + } + } + ); + + // HACK wait for above handle to become populated + // TODO: use a future + int count = 1024; + while (!mhDC && count > 0) + { + Sleep(10); + --count; + } if (mWindowHandle) { @@ -1484,7 +1650,48 @@ const S32 max_format = (S32)num_formats - 1; mhDC = 0; // Zero The Device Context } - recreateWindow(window_rect, dw_ex_style, dw_style); + auto oldHandle = mWindowHandle; + mWindowHandle = NULL; + mhDC = 0; + + // Destroy The Window + if (oldHandle && !destroy_window_handler(oldHandle)) + { + LL_WARNS("Window") << "Failed to properly close window!" << LL_ENDL; + } + + mWindowThread->post( + [this, window_rect, dw_ex_style, dw_style]() + { + mWindowHandle = CreateWindowEx(dw_ex_style, + mWindowClassName, + mWindowTitle, + WS_CLIPSIBLINGS | WS_CLIPCHILDREN | dw_style, + window_rect.left, // x pos + window_rect.top, // y pos + window_rect.right - window_rect.left, // width + window_rect.bottom - window_rect.top, // height + NULL, + NULL, + mhInstance, + NULL); + + if (mWindowHandle) + { + mhDC = GetDC(mWindowHandle); + } + } + ); + + // HACK wait for above handle to become populated + // TODO: use a future + int count = 1024; + while (!mhDC && count > 0) + { + PostMessage(oldHandle, WM_USER + 8, 0x1717, 0x3b3b); + Sleep(10); + --count; + } if (mWindowHandle) { @@ -1621,64 +1828,6 @@ const S32 max_format = (S32)num_formats - 1; return TRUE; } -void LLWindowWin32::recreateWindow(RECT window_rect, DWORD dw_ex_style, DWORD dw_style) -{ - auto oldHandle = mWindowHandle; - - // zero out mWindowHandle and mhDC before destroying window so window - // thread falls back to peekmessage - mWindowHandle = 0; - mhDC = 0; - - if (oldHandle && !destroy_window_handler(oldHandle)) - { - LL_WARNS("Window") << "Failed to properly close window before recreating it!" << LL_ENDL; - } - - std::promise> promise; - mWindowThread->post( - [this, window_rect, dw_ex_style, dw_style, &promise]() - { - auto handle = CreateWindowEx(dw_ex_style, - mWindowClassName, - mWindowTitle, - WS_CLIPSIBLINGS | WS_CLIPCHILDREN | dw_style, - window_rect.left, // x pos - window_rect.top, // y pos - window_rect.right - window_rect.left, // width - window_rect.bottom - window_rect.top, // height - NULL, - NULL, - mhInstance, - NULL); - - if (! handle) - { - // Failed to create window: clear the variables. This - // assignment is valid because we're running on mWindowThread. - mWindowThread->mWindowHandle = NULL; - mWindowThread->mhDC = 0; - } - else - { - // Update mWindowThread's own mWindowHandle and mhDC. - mWindowThread->mWindowHandle = handle; - mWindowThread->mhDC = GetDC(handle); - } - - // It's important to wake up the future either way. - promise.set_value(std::make_pair(mWindowThread->mWindowHandle, mWindowThread->mhDC)); - } - ); - - auto future = promise.get_future(); - // This blocks until mWindowThread processes CreateWindowEx() and calls - // promise.set_value(). - auto pair = future.get(); - mWindowHandle = pair.first; - mhDC = pair.second; -} - void* LLWindowWin32::createSharedContext() { S32 attribs[] = @@ -2032,14 +2181,12 @@ void LLWindowWin32::gatherInput() } - if (mWindowThread->getQueue().size()) + if (mWindowThread->mFunctionQueue.size() > 0) { LL_PROFILE_ZONE_NAMED("gi - PostMessage"); if (mWindowHandle) - { - // post a nonsense user message to wake up the Window Thread in - // case any functions are pending and no windows events came - // through this frame + { // post a nonsense user message to wake up the Window Thread in case any functions are pending + // and no windows events came through this frame PostMessage(mWindowHandle, WM_USER + 0x0017, 0xB0B0, 0x1337); } } @@ -2129,6 +2276,17 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_ if (NULL != window_imp) { + // Has user provided their own window callback? + if (NULL != window_imp->mWndProc) + { + LL_PROFILE_ZONE_NAMED("mwp - WndProc"); + if (!window_imp->mWndProc(h_wnd, u_msg, w_param, l_param)) + { + // user has handled window message + return 0; + } + } + // Juggle to make sure we can get negative positions for when // mouse is outside window. LLCoordWindow window_coord((S32)(S16)LOWORD(l_param), (S32)(S16)HIWORD(l_param)); @@ -4409,32 +4567,35 @@ std::vector LLWindowWin32::getDynamicFallbackFontList() #endif // LL_WINDOWS -inline LLWindowWin32::LLWindowWin32Thread::LLWindowWin32Thread() - : ThreadPool("Window Thread", 1, MAX_QUEUE_SIZE) +inline LLWindowWin32Thread::LLWindowWin32Thread(LLWindowWin32* window) + : LLThread("Window Thread"), + mWindow(window), + mFunctionQueue(MAX_QUEUE_SIZE) { + } -void LLWindowWin32::LLWindowWin32Thread::run() +inline void LLWindowWin32Thread::run() { - sWindowThreadId = std::this_thread::get_id(); - while (! getQueue().done()) + sWindowThreadId = getID(); + while (!mFinished) { LL_PROFILE_ZONE_SCOPED; - if (mWindowHandle != 0) + if (mWindow && mWindow->mWindowHandle != 0) { MSG msg; BOOL status; - if (mhDC == 0) + if (mWindow->mhDC == 0) { LL_PROFILE_ZONE_NAMED("w32t - PeekMessage"); - status = PeekMessage(&msg, mWindowHandle, 0, 0, PM_REMOVE); + status = PeekMessage(&msg, mWindow->mWindowHandle, 0, 0, PM_REMOVE); } else { LL_PROFILE_ZONE_NAMED("w32t - GetMessage"); - status = GetMessage(&msg, mWindowHandle, 0, 0); + status = GetMessage(&msg, mWindow->mWindowHandle, 0, 0); } if (status > 0) { @@ -4448,7 +4609,11 @@ void LLWindowWin32::LLWindowWin32Thread::run() { LL_PROFILE_ZONE_NAMED("w32t - Function Queue"); //process any pending functions - getQueue().runPending(); + std::function curFunc; + while (mFunctionQueue.tryPopBack(curFunc)) + { + curFunc(); + } } #if 0 @@ -4460,6 +4625,11 @@ void LLWindowWin32::LLWindowWin32Thread::run() } } +void LLWindowWin32Thread::post(const std::function& func) +{ + mFunctionQueue.pushFront(func); +} + void LLWindowWin32::post(const std::function& func) { mFunctionQueue.pushFront(func); diff --git a/indra/llwindow/llwindowwin32.h b/indra/llwindow/llwindowwin32.h index 5966061177..d082080807 100644 --- a/indra/llwindow/llwindowwin32.h +++ b/indra/llwindow/llwindowwin32.h @@ -36,12 +36,44 @@ #include "llthread.h" #include "llthreadsafequeue.h" #include "llmutex.h" -#include "workqueue.h" // Hack for async host by name #define LL_WM_HOST_RESOLVED (WM_APP + 1) typedef void (*LLW32MsgCallback)(const MSG &msg); +class LLWindowWin32; + +// Thread that owns the Window Handle +class LLWindowWin32Thread : public LLThread +{ +public: + class Message + { + public: + LRESULT mMsg; + }; + + static const int MAX_QUEUE_SIZE = 2048; + + LLThreadSafeQueue mMessageQueue; + LLThreadSafeQueue> mFunctionQueue; + + bool mFinished = false; + + LLWindowWin32Thread(LLWindowWin32* window); + + void run() override; + + void post(const std::function& func); + +private: + + // call PeekMessage and pull enqueue messages for later processing + void gatherInput(); + LLWindowWin32* mWindow = nullptr; + +}; + class LLWindowWin32 : public LLWindow { public: @@ -186,6 +218,7 @@ protected: HGLRC mhRC = 0; // OpenGL rendering context HDC mhDC = 0; // Windows Device context handle HINSTANCE mhInstance; // handle to application instance + WNDPROC mWndProc; // user-installable window proc RECT mOldMouseClip; // Screen rect to which the mouse cursor was globally constrained before we changed it in clipMouse() WPARAM mLastSizeWParam; F32 mOverrideAspectRatio; @@ -237,15 +270,14 @@ protected: BOOL mMouseVanish; - struct LLWindowWin32Thread; - LLWindowWin32Thread* mWindowThread = nullptr; - LLThreadSafeQueue> mFunctionQueue; - LLThreadSafeQueue> mMouseQueue; - void post(const std::function& func); - void postMouseButtonEvent(const std::function& func); - void recreateWindow(RECT window_rect, DWORD dw_ex_style, DWORD dw_style); + LLWindowWin32Thread* mWindowThread = nullptr; + LLThreadSafeQueue> mFunctionQueue; + LLThreadSafeQueue> mMouseQueue; + void post(const std::function& func); + void postMouseButtonEvent(const std::function& func); friend class LLWindowManager; + friend class LLWindowWin32Thread; }; class LLSplashScreenWin32 : public LLSplashScreen diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index 6d090be33a..631089f6ce 100644 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -393,6 +393,7 @@ set(viewer_SOURCE_FILES llloginhandler.cpp lllogininstance.cpp llmachineid.cpp + llmainlooprepeater.cpp llmanip.cpp llmaniprotate.cpp llmanipscale.cpp @@ -1031,6 +1032,7 @@ set(viewer_HEADER_FILES llloginhandler.h lllogininstance.h llmachineid.h + llmainlooprepeater.h llmanip.h llmaniprotate.h llmanipscale.h @@ -1602,7 +1604,6 @@ if (WINDOWS) ${WINDOWS_LIBRARIES} comdlg32 dxguid - imm32 kernel32 odbc32 odbccp32 diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index 607e531e62..f15b5d0981 100644 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -3858,17 +3858,6 @@ Value 1 - MainWorkTime - - Comment - Max time per frame devoted to mainloop work queue (in milliseconds) - Persist - 1 - Type - F32 - Value - 0.1 - QueueInventoryFetchTimeout Comment @@ -12674,20 +12663,6 @@ Value 50 - ThreadPoolSizes - - Comment - Map of size overrides for specific thread pools. - Persist - 1 - Type - LLSD - Value - - General - 4 - - ThrottleBandwidthKBPS Comment diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index 93e5c2e341..89756d0881 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -233,12 +233,11 @@ #include "llavatariconctrl.h" #include "llgroupiconctrl.h" #include "llviewerassetstats.h" -#include "workqueue.h" -using namespace LL; // Include for security api initialization #include "llsecapi.h" #include "llmachineid.h" +#include "llmainlooprepeater.h" #include "llcleanup.h" #include "llcoproceduremanager.h" @@ -367,10 +366,6 @@ BOOL gLogoutInProgress = FALSE; BOOL gSimulateMemLeak = FALSE; -// We don't want anyone, especially threads working on the graphics pipeline, -// to have to block due to this WorkQueue being full. -WorkQueue gMainloopWork("mainloop", 1024*1024); - //////////////////////////////////////////////////////////// // Internal globals... that should be removed. static std::string gArgs; @@ -386,6 +381,42 @@ static std::string gLaunchFileOnQuit; // Used on Win32 for other apps to identify our window (eg, win_setup) const char* const VIEWER_WINDOW_CLASSNAME = "Second Life"; +//-- LLDeferredTaskList ------------------------------------------------------ + +/** + * A list of deferred tasks. + * + * We sometimes need to defer execution of some code until the viewer gets idle, + * e.g. removing an inventory item from within notifyObservers() may not work out. + * + * Tasks added to this list will be executed in the next LLAppViewer::idle() iteration. + * All tasks are executed only once. + */ +class LLDeferredTaskList: public LLSingleton +{ + LLSINGLETON_EMPTY_CTOR(LLDeferredTaskList); + LOG_CLASS(LLDeferredTaskList); + + friend class LLAppViewer; + typedef boost::signals2::signal signal_t; + + void addTask(const signal_t::slot_type& cb) + { + mSignal.connect(cb); + } + + void run() + { + if (!mSignal.empty()) + { + mSignal(); + mSignal.disconnect_all_slots(); + } + } + + signal_t mSignal; +}; + //---------------------------------------------------------------------------- // List of entries from strings.xml to always replace @@ -943,6 +974,9 @@ bool LLAppViewer::init() } LL_INFOS("InitInfo") << "Cache initialization is done." << LL_ENDL ; + // Initialize the repeater service. + LLMainLoopRepeater::instance().start(); + // Initialize event recorder LLViewerEventRecorder::createInstance(); @@ -2158,6 +2192,8 @@ bool LLAppViewer::cleanup() SUBSYSTEM_CLEANUP(LLProxy); LLCore::LLHttp::cleanup(); + LLMainLoopRepeater::instance().stop(); + ll_close_fail_log(); LLError::LLCallStacks::cleanup(); @@ -4452,7 +4488,7 @@ bool LLAppViewer::initCache() void LLAppViewer::addOnIdleCallback(const boost::function& cb) { - gMainloopWork.post(cb); + LLDeferredTaskList::instance().addTask(cb); } void LLAppViewer::loadKeyBindings() @@ -4850,6 +4886,7 @@ void LLAppViewer::idle() LLNotificationsUI::LLToast::updateClass(); LLSmoothInterpolation::updateInterpolants(); LLMortician::updateClass(); + LLImageGL::updateClass(); LLFilePickerThread::clearDead(); //calls LLFilePickerThread::notify() LLDirPickerThread::clearDead(); F32 dt_raw = idle_timer.getElapsedTimeAndResetF32(); @@ -5226,19 +5263,8 @@ void LLAppViewer::idle() } } - // Service the WorkQueue we use for replies from worker threads. - // Use function statics for the timeslice setting so we only have to fetch - // and convert MainWorkTime once. - static F32 MainWorkTimeRaw = gSavedSettings.getF32("MainWorkTime"); - static F32Milliseconds MainWorkTimeMs(MainWorkTimeRaw); - // MainWorkTime is specified in fractional milliseconds, but std::chrono - // uses integer representations. What if we want less than a microsecond? - // Use nanoseconds. We're very sure we will never need to specify a - // MainWorkTime that would be larger than we could express in - // std::chrono::nanoseconds. - static std::chrono::nanoseconds MainWorkTimeNanoSec{ - std::chrono::nanoseconds::rep(MainWorkTimeMs.value() * 1000000)}; - gMainloopWork.runFor(MainWorkTimeNanoSec); + // Execute deferred tasks. + LLDeferredTaskList::instance().run(); // Handle shutdown process, for example, // wait for floaters to close, send quit message, diff --git a/indra/newview/llenvironment.cpp b/indra/newview/llenvironment.cpp index 1a66f10b8f..dba24b3d02 100644 --- a/indra/newview/llenvironment.cpp +++ b/indra/newview/llenvironment.cpp @@ -824,6 +824,7 @@ std::string env_selection_to_string(LLEnvironment::EnvSelection_t sel) #undef RTNENUM } +LLEnvironment* LLSimpleton::sInstance = nullptr; //------------------------------------------------------------------------- LLEnvironment::LLEnvironment(): mCloudScrollDelta(), diff --git a/indra/newview/llmainlooprepeater.cpp b/indra/newview/llmainlooprepeater.cpp new file mode 100644 index 0000000000..6736e9a950 --- /dev/null +++ b/indra/newview/llmainlooprepeater.cpp @@ -0,0 +1,88 @@ +/** + * @file llmachineid.cpp + * @brief retrieves unique machine ids + * + * $LicenseInfo:firstyear=2009&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#include "llviewerprecompiledheaders.h" +#include "llapr.h" +#include "llevents.h" +#include "llmainlooprepeater.h" + + + +// LLMainLoopRepeater +//----------------------------------------------------------------------------- + + +LLMainLoopRepeater::LLMainLoopRepeater(void): + mQueue(0) +{ + ; // No op. +} + + +void LLMainLoopRepeater::start(void) +{ + if(mQueue != 0) return; + + mQueue = new LLThreadSafeQueue(1024); + mMainLoopConnection = LLEventPumps::instance(). + obtain("mainloop").listen(LLEventPump::inventName(), boost::bind(&LLMainLoopRepeater::onMainLoop, this, _1)); + mRepeaterConnection = LLEventPumps::instance(). + obtain("mainlooprepeater").listen(LLEventPump::inventName(), boost::bind(&LLMainLoopRepeater::onMessage, this, _1)); +} + + +void LLMainLoopRepeater::stop(void) +{ + mMainLoopConnection.release(); + mRepeaterConnection.release(); + + delete mQueue; + mQueue = 0; +} + + +bool LLMainLoopRepeater::onMainLoop(LLSD const &) +{ + LLSD message; + while(mQueue->tryPopBack(message)) { + std::string pump = message["pump"].asString(); + if(pump.length() == 0 ) continue; // No pump. + LLEventPumps::instance().obtain(pump).post(message["payload"]); + } + return false; +} + + +bool LLMainLoopRepeater::onMessage(LLSD const & event) +{ + try { + mQueue->pushFront(event); + } catch(LLThreadSafeQueueError & e) { + LL_WARNS() << "could not repeat message (" << e.what() << ")" << + event.asString() << LL_ENDL; + } + return false; +} diff --git a/indra/newview/llmainlooprepeater.h b/indra/newview/llmainlooprepeater.h new file mode 100644 index 0000000000..2ec3a74e4a --- /dev/null +++ b/indra/newview/llmainlooprepeater.h @@ -0,0 +1,64 @@ +/** + * @file llmainlooprepeater.h + * @brief a service for repeating messages on the main loop. + * + * $LicenseInfo:firstyear=2010&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#ifndef LL_LLMAINLOOPREPEATER_H +#define LL_LLMAINLOOPREPEATER_H + + +#include "llsd.h" +#include "llthreadsafequeue.h" + + +// +// A service which creates the pump 'mainlooprepeater' to which any thread can +// post a message that will be re-posted on the main loop. +// +// The posted message should contain two map elements: pump and payload. The +// pump value is a string naming the pump to which the message should be +// re-posted. The payload value is what will be posted to the designated pump. +// +class LLMainLoopRepeater: + public LLSingleton +{ + LLSINGLETON(LLMainLoopRepeater); +public: + // Start the repeater service. + void start(void); + + // Stop the repeater service. + void stop(void); + +private: + LLTempBoundListener mMainLoopConnection; + LLTempBoundListener mRepeaterConnection; + LLThreadSafeQueue * mQueue; + + bool onMainLoop(LLSD const &); + bool onMessage(LLSD const & event); +}; + + +#endif diff --git a/indra/newview/llselectmgr.cpp b/indra/newview/llselectmgr.cpp index bc00c518e9..53247031b4 100644 --- a/indra/newview/llselectmgr.cpp +++ b/indra/newview/llselectmgr.cpp @@ -97,6 +97,8 @@ #include "llglheaders.h" #include "llinventoryobserver.h" +LLSelectMgr* LLSimpleton::sInstance = nullptr; + LLViewerObject* getSelectedParentObject(LLViewerObject *object) ; // // Consts diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp index 9a4149948c..57c5074804 100644 --- a/indra/newview/llstartup.cpp +++ b/indra/newview/llstartup.cpp @@ -205,9 +205,6 @@ #include "llstacktrace.h" -#include "threadpool.h" - - #if LL_WINDOWS #include "lldxhardware.h" #endif @@ -304,20 +301,6 @@ void callback_cache_name(const LLUUID& id, const std::string& full_name, bool is // local classes // -void launchThreadPool() -{ - LLSD poolSizes{ gSavedSettings.getLLSD("ThreadPoolSizes") }; - LLSD sizeSpec{ poolSizes["General"] }; - LLSD::Integer size{ sizeSpec.isInteger()? sizeSpec.asInteger() : 3 }; - LL_DEBUGS("ThreadPool") << "Instantiating General pool with " - << size << " threads" << LL_ENDL; - // Use a function-static ThreadPool: static duration, but instantiated - // only on demand. - // We don't want anyone, especially the main thread, to have to block - // due to this ThreadPool being full. - static LL::ThreadPool pool("General", size, 1024*1024); -} - void update_texture_fetch() { LLAppViewer::getTextureCache()->update(1); // unpauses the texture cache thread @@ -1506,9 +1489,6 @@ bool idle_startup() gAgentCamera.resetCamera(); display_startup(); - // start up the ThreadPool we'll use for textures et al. - launchThreadPool(); - // Initialize global class data needed for surfaces (i.e. textures) LL_DEBUGS("AppInit") << "Initializing sky..." << LL_ENDL; // Initialize all of the viewer object classes for the first time (doing things like texture fetches. diff --git a/indra/newview/llviewercamera.cpp b/indra/newview/llviewercamera.cpp index 5d8e80cc41..5ebce115f6 100644 --- a/indra/newview/llviewercamera.cpp +++ b/indra/newview/llviewercamera.cpp @@ -54,6 +54,8 @@ // System includes #include // for setprecision +LLViewerCamera* LLSimpleton::sInstance = nullptr; + LLTrace::CountStatHandle<> LLViewerCamera::sVelocityStat("camera_velocity"); LLTrace::CountStatHandle<> LLViewerCamera::sAngularVelocityStat("camera_angular_velocity"); diff --git a/indra/newview/llviewertexture.cpp b/indra/newview/llviewertexture.cpp index 498e4ef8bc..fbc5830a5c 100644 --- a/indra/newview/llviewertexture.cpp +++ b/indra/newview/llviewertexture.cpp @@ -679,9 +679,6 @@ void LLViewerTexture::init(bool firstinit) mVolumeList[LLRender::LIGHT_TEX].clear(); mVolumeList[LLRender::SCULPT_TEX].clear(); - - mMainQueue = LL::WorkQueue::getInstance("mainloop"); - mImageQueue = LL::WorkQueue::getInstance("LLImageGL"); } //virtual @@ -1625,26 +1622,17 @@ void LLViewerFetchedTexture::scheduleCreateTexture() { mNeedsCreateTexture = TRUE; #if LL_WINDOWS //flip to 0 to revert to single-threaded OpenGL texture uploads - auto mainq = mMainQueue.lock(); - if (mainq) - { - mainq->postTo( - mImageQueue, - // work to be done on LLImageGL worker thread - [this]() - { - //actually create the texture on a background thread - createTexture(); - }, - // callback to be run on main thread - [this]() - { - //finalize on main thread - postCreateTexture(); - unref(); - }); - } - else + if (!LLImageGLThread::sInstance->post([this]() + { + //actually create the texture on a background thread + createTexture(); + LLImageGLThread::sInstance->postCallback([this]() + { + //finalize on main thread + postCreateTexture(); + unref(); + }); + })) #endif { gTextureList.mCreateTextureList.insert(this); diff --git a/indra/newview/llviewertexture.h b/indra/newview/llviewertexture.h index 4cd4c7cd39..f9f1bfef44 100644 --- a/indra/newview/llviewertexture.h +++ b/indra/newview/llviewertexture.h @@ -35,7 +35,6 @@ #include "llrender.h" #include "llmetricperformancetester.h" #include "httpcommon.h" -#include "workqueue.h" #include #include @@ -214,9 +213,6 @@ protected: //do not use LLPointer here. LLViewerMediaTexture* mParcelMedia ; - LL::WorkQueue::weak_t mMainQueue; - LL::WorkQueue::weak_t mImageQueue; - static F32 sTexelPixelRatio; public: static const U32 sCurrentFileVersion; diff --git a/indra/newview/llworld.cpp b/indra/newview/llworld.cpp index 5f62908009..0a8457eb2c 100644 --- a/indra/newview/llworld.cpp +++ b/indra/newview/llworld.cpp @@ -62,6 +62,8 @@ #include +LLWorld* LLSimpleton::sInstance = nullptr; + // // Globals // -- cgit v1.3 From 106d52c6ee9b10dd7a7baca3b09a01073c61949d Mon Sep 17 00:00:00 2001 From: Nat Goodspeed Date: Thu, 4 Nov 2021 16:40:05 -0400 Subject: SL-16202: Instantiate LLSimpleton::sInstance generically instead of requiring a separate declaration for each subclass. The previous way produces errors in clang. (cherry picked from commit 8458ad8890cf0a11804996210d7bcfbdaa3eec2e) --- indra/llcommon/llsingleton.h | 3 +++ indra/llui/llviewereventrecorder.cpp | 2 -- indra/newview/llenvironment.cpp | 1 - indra/newview/llselectmgr.cpp | 2 -- indra/newview/llviewercamera.cpp | 2 -- indra/newview/llworld.cpp | 2 -- 6 files changed, 3 insertions(+), 9 deletions(-) (limited to 'indra/llcommon') diff --git a/indra/llcommon/llsingleton.h b/indra/llcommon/llsingleton.h index 10a8ecfedb..24d01812c9 100644 --- a/indra/llcommon/llsingleton.h +++ b/indra/llcommon/llsingleton.h @@ -865,4 +865,7 @@ public: } }; +template +T* LLSimpleton::sInstance{ nullptr }; + #endif diff --git a/indra/llui/llviewereventrecorder.cpp b/indra/llui/llviewereventrecorder.cpp index 5a44ec947a..cb000aef74 100644 --- a/indra/llui/llviewereventrecorder.cpp +++ b/indra/llui/llviewereventrecorder.cpp @@ -28,8 +28,6 @@ #include "llui.h" #include "llleap.h" -LLViewerEventRecorder* LLSimpleton::sInstance = nullptr; - LLViewerEventRecorder::LLViewerEventRecorder() { clear(UNDEFINED); diff --git a/indra/newview/llenvironment.cpp b/indra/newview/llenvironment.cpp index 0b914f07ab..4bec7fa111 100644 --- a/indra/newview/llenvironment.cpp +++ b/indra/newview/llenvironment.cpp @@ -824,7 +824,6 @@ std::string env_selection_to_string(LLEnvironment::EnvSelection_t sel) #undef RTNENUM } -LLEnvironment* LLSimpleton::sInstance = nullptr; //------------------------------------------------------------------------- LLEnvironment::LLEnvironment(): mCloudScrollDelta(), diff --git a/indra/newview/llselectmgr.cpp b/indra/newview/llselectmgr.cpp index e7670b5a73..6f136e50e0 100644 --- a/indra/newview/llselectmgr.cpp +++ b/indra/newview/llselectmgr.cpp @@ -97,8 +97,6 @@ #include "llglheaders.h" #include "llinventoryobserver.h" -LLSelectMgr* LLSimpleton::sInstance = nullptr; - LLViewerObject* getSelectedParentObject(LLViewerObject *object) ; // // Consts diff --git a/indra/newview/llviewercamera.cpp b/indra/newview/llviewercamera.cpp index 5ebce115f6..5d8e80cc41 100644 --- a/indra/newview/llviewercamera.cpp +++ b/indra/newview/llviewercamera.cpp @@ -54,8 +54,6 @@ // System includes #include // for setprecision -LLViewerCamera* LLSimpleton::sInstance = nullptr; - LLTrace::CountStatHandle<> LLViewerCamera::sVelocityStat("camera_velocity"); LLTrace::CountStatHandle<> LLViewerCamera::sAngularVelocityStat("camera_angular_velocity"); diff --git a/indra/newview/llworld.cpp b/indra/newview/llworld.cpp index 4cb63d0ab8..d5cce6a52a 100644 --- a/indra/newview/llworld.cpp +++ b/indra/newview/llworld.cpp @@ -62,8 +62,6 @@ #include -LLWorld* LLSimpleton::sInstance = nullptr; - // // Globals // -- cgit v1.3 From f997bcd186d00e30132f32be007bb3978bf3a8f5 Mon Sep 17 00:00:00 2001 From: Nat Goodspeed Date: Thu, 11 Nov 2021 10:23:16 -0500 Subject: SL-16094: Stylish braces! (cherry picked from commit 18de6c9b989cc7060f2a314f5b68cc102677823b) --- indra/llcommon/llsingleton.h | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'indra/llcommon') diff --git a/indra/llcommon/llsingleton.h b/indra/llcommon/llsingleton.h index 24d01812c9..da2d6fd984 100644 --- a/indra/llcommon/llsingleton.h +++ b/indra/llcommon/llsingleton.h @@ -859,9 +859,16 @@ public: static inline T& instance() { return *getInstance(); } static inline bool instanceExists() { return sInstance != nullptr; } +<<<<<<< HEAD static void deleteSingleton() { delete sInstance; sInstance = nullptr; +======= + static void deleteSingleton() + { + delete sInstance; + sInstance = nullptr; +>>>>>>> 18de6c9b98 (SL-16094: Stylish braces!) } }; -- cgit v1.3 From 3171aaad9b1f2757f8b0d8cbb784a45a7bbebafa Mon Sep 17 00:00:00 2001 From: Nat Goodspeed Date: Fri, 19 Nov 2021 14:57:36 -0500 Subject: SL-16094: fix merge glitch --- indra/llcommon/llsingleton.h | 6 ------ 1 file changed, 6 deletions(-) (limited to 'indra/llcommon') diff --git a/indra/llcommon/llsingleton.h b/indra/llcommon/llsingleton.h index da2d6fd984..f85f961287 100644 --- a/indra/llcommon/llsingleton.h +++ b/indra/llcommon/llsingleton.h @@ -859,16 +859,10 @@ public: static inline T& instance() { return *getInstance(); } static inline bool instanceExists() { return sInstance != nullptr; } -<<<<<<< HEAD - static void deleteSingleton() { - delete sInstance; - sInstance = nullptr; -======= static void deleteSingleton() { delete sInstance; sInstance = nullptr; ->>>>>>> 18de6c9b98 (SL-16094: Stylish braces!) } }; -- cgit v1.3