summaryrefslogtreecommitdiff
path: root/indra/llcommon
diff options
context:
space:
mode:
authorNat Goodspeed <nat@lindenlab.com>2021-11-23 21:23:45 -0500
committerNat Goodspeed <nat@lindenlab.com>2021-11-23 21:23:45 -0500
commitd71e0a6d4778d4c67b8793ba569fee2db226bc8e (patch)
treedce713230aa611dbada3c6f78903d988b1ae06a4 /indra/llcommon
parent67ace0df9953ce3264048c3946720a9df492edfa (diff)
parent8852cb9cbd25df8d25fa43cf39b222ab8381ebd6 (diff)
SL-16094, SL-16400: Merge branch 'DRTVWR-546' into glthread
Diffstat (limited to 'indra/llcommon')
-rw-r--r--indra/llcommon/CMakeLists.txt5
-rw-r--r--indra/llcommon/llcoros.cpp9
-rw-r--r--indra/llcommon/llcoros.h2
-rw-r--r--indra/llcommon/llerror.cpp290
-rw-r--r--indra/llcommon/llevents.cpp19
-rw-r--r--indra/llcommon/llevents.h14
-rw-r--r--indra/llcommon/llregex.h89
-rw-r--r--indra/llcommon/llsingleton.h14
-rw-r--r--indra/llcommon/llsys.cpp39
-rw-r--r--indra/llcommon/llthreadsafequeue.h19
-rw-r--r--indra/llcommon/tests/threadsafeschedule_test.cpp4
-rw-r--r--indra/llcommon/tests/workqueue_test.cpp72
-rw-r--r--indra/llcommon/timing.cpp25
-rw-r--r--indra/llcommon/workqueue.cpp30
-rw-r--r--indra/llcommon/workqueue.h197
15 files changed, 378 insertions, 450 deletions
diff --git a/indra/llcommon/CMakeLists.txt b/indra/llcommon/CMakeLists.txt
index 78d6ea3090..9defa6b6c1 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
)
@@ -213,9 +213,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
@@ -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/llcoros.cpp b/indra/llcommon/llcoros.cpp
index 111c50af93..75fc0fec99 100644
--- a/indra/llcommon/llcoros.cpp
+++ b/indra/llcommon/llcoros.cpp
@@ -135,6 +135,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
@@ -150,6 +157,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 6c0bec3ef9..a94cfca19f 100644
--- a/indra/llcommon/llcoros.h
+++ b/indra/llcommon/llcoros.h
@@ -89,6 +89,8 @@ class LL_COMMON_API LLCoros: public LLSingleton<LLCoros>
{
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
diff --git a/indra/llcommon/llerror.cpp b/indra/llcommon/llerror.cpp
index f7af181927..a4a5cb2d24 100644
--- a/indra/llcommon/llerror.cpp
+++ b/indra/llcommon/llerror.cpp
@@ -442,6 +442,62 @@ namespace
typedef std::vector<LLError::RecorderPtr> Recorders;
typedef std::vector<LLError::CallSite*> 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<std::string, unsigned int> mUniqueLogMessages;
+
+ LLError::FatalFunction mCrashFunction;
+ LLError::TimeFunction mTimeFunction;
+
+ Recorders mRecorders;
+ LLMutex mRecorderMutex;
+
+ int mShouldLogCallCounter;
+
+ private:
+ SettingsConfig();
+ };
+
+ typedef LLPointer<SettingsConfig> SettingsConfigPtr;
+
+ SettingsConfig::SettingsConfig()
+ : LLRefCount(),
+ mDefaultLevel(LLError::LEVEL_DEBUG),
+ mLogAlwaysFlush(true),
+ mEnabledLogTypesMask(255),
+ mFunctionLevelMap(),
+ mClassLevelMap(),
+ mFileLevelMap(),
+ mTagLevelMap(),
+ mUniqueLogMessages(),
+ mCrashFunction(NULL),
+ mTimeFunction(NULL),
+ mRecorders(),
+ mRecorderMutex(),
+ mShouldLogCallCounter(0)
+ {
+ }
+
+ SettingsConfig::~SettingsConfig()
+ {
+ mRecorders.clear();
+ }
+
class Globals
{
public:
@@ -449,16 +505,31 @@ namespace
protected:
Globals();
public:
+ std::ostringstream messageStream;
+ bool messageStreamInUse;
std::string mFatalMessage;
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() {}
+ Globals::Globals()
+ : messageStream(),
+ messageStreamInUse(false),
+ callSites(),
+ mSettingsConfig(new SettingsConfig())
+ {
+ }
+
Globals* Globals::getInstance()
{
@@ -486,120 +557,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<std::string, unsigned int> mUniqueLogMessages;
-
- LLError::FatalFunction mCrashFunction;
- LLError::TimeFunction mTimeFunction;
-
- Recorders mRecorders;
-
- int mShouldLogCallCounter;
-
- private:
- SettingsConfig();
- };
-
- typedef LLPointer<SettingsConfig> 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([](const std::string&){}),
- 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<SettingsConfig *>(pSettingsStorage.get()));
- mSettingsConfig = newSettingsConfig;
- }
+ void Globals::restore(LLError::SettingsStoragePtr pSettingsStorage)
+ {
+ invalidateCallSites();
+ SettingsConfigPtr newSettingsConfig(dynamic_cast<SettingsConfig *>(pSettingsStorage.get()));
+ mSettingsConfig = newSettingsConfig;
+ }
}
namespace LLError
@@ -723,7 +705,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);
@@ -764,13 +746,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;
}
@@ -781,72 +763,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;
}
@@ -891,8 +878,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();
@@ -1019,7 +1007,8 @@ namespace LLError
{
return;
}
- SettingsConfigPtr s = Settings::getInstance()->getSettingsConfig();
+ SettingsConfigPtr s = Globals::getInstance()->getSettingsConfig();
+ LLMutexLock lock(&s->mRecorderMutex);
s->mRecorders.push_back(recorder);
}
@@ -1029,7 +1018,8 @@ namespace LLError
{
return;
}
- SettingsConfigPtr s = Settings::getInstance()->getSettingsConfig();
+ SettingsConfigPtr s = Globals::getInstance()->getSettingsConfig();
+ LLMutexLock lock(&s->mRecorderMutex);
s->mRecorders.erase(std::remove(s->mRecorders.begin(), s->mRecorders.end(), recorder),
s->mRecorders.end());
}
@@ -1041,11 +1031,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 <typename RECORDER>
std::pair<boost::shared_ptr<RECORDER>, Recorders::iterator>
- findRecorderPos()
+ findRecorderPos(SettingsConfigPtr &s)
{
- SettingsConfigPtr s = Settings::getInstance()->getSettingsConfig();
// Since we promise to return an iterator, use a classic iterator
// loop.
auto end{s->mRecorders.end()};
@@ -1076,7 +1067,9 @@ namespace LLError
template <typename RECORDER>
boost::shared_ptr<RECORDER> findRecorder()
{
- return findRecorderPos<RECORDER>().first;
+ SettingsConfigPtr s = Globals::getInstance()->getSettingsConfig();
+ LLMutexLock lock(&s->mRecorderMutex);
+ return findRecorderPos<RECORDER>(s).first;
}
// Remove an entry from SettingsConfig::mRecorders whose RecorderPtr
@@ -1085,10 +1078,11 @@ namespace LLError
template <typename RECORDER>
bool removeRecorder()
{
- auto found = findRecorderPos<RECORDER>();
+ SettingsConfigPtr s = Globals::getInstance()->getSettingsConfig();
+ LLMutexLock lock(&s->mRecorderMutex);
+ auto found = findRecorderPos<RECORDER>(s);
if (found.first)
{
- SettingsConfigPtr s = Settings::getInstance()->getSettingsConfig();
s->mRecorders.erase(found.second);
}
return bool(found.first);
@@ -1187,10 +1181,11 @@ namespace
{
LL_PROFILE_ZONE_SCOPED
LLError::ELevel level = site.mLevel;
- LLError::SettingsConfigPtr s = LLError::Settings::getInstance()->getSettingsConfig();
+ 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)
@@ -1326,7 +1321,8 @@ namespace LLError
return false;
}
- SettingsConfigPtr s = Settings::getInstance()->getSettingsConfig();
+ Globals *g = Globals::getInstance();
+ SettingsConfigPtr s = g->getSettingsConfig();
s->mShouldLogCallCounter++;
@@ -1356,7 +1352,7 @@ namespace LLError
: false);
site.mCached = true;
- Globals::getInstance()->addCallSite(site);
+ g->addCallSite(site);
return site.mShouldLog = site.mLevel >= compareLevel;
}
@@ -1371,7 +1367,7 @@ namespace LLError
}
Globals* g = Globals::getInstance();
- SettingsConfigPtr s = Settings::getInstance()->getSettingsConfig();
+ SettingsConfigPtr s = g->getSettingsConfig();
std::string message = out.str();
@@ -1416,12 +1412,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)
@@ -1467,7 +1463,7 @@ namespace LLError
int shouldLogCallCount()
{
- SettingsConfigPtr s = Settings::getInstance()->getSettingsConfig();
+ SettingsConfigPtr s = Globals::getInstance()->getSettingsConfig();
return s->mShouldLogCallCounter;
}
@@ -1579,8 +1575,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;
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 <cctype>
// external library headers
#include <boost/range/iterator_range.hpp>
-#include <boost/make_shared.hpp>
#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<LLStandardSignal>()),
+ mSignal(std::make_shared<LLStandardSignal>()),
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<LLStandardSignal>();
+ mSignal = std::make_shared<LLStandardSignal>();
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<LLStandardSignal> signal(mSignal);
+ std::shared_ptr<LLStandardSignal> 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..ae6e5aabc9 100644
--- a/indra/llcommon/llevents.h
+++ b/indra/llcommon/llevents.h
@@ -49,8 +49,6 @@
#endif
#include <boost/bind.hpp>
-#include <boost/shared_ptr.hpp>
-#include <boost/enable_shared_from_this.hpp>
#include <boost/utility.hpp> // noncopyable
#include <boost/optional/optional.hpp>
#include <boost/visit_each.hpp>
@@ -571,7 +569,7 @@ protected:
const NameList& before);
/// implement the dispatching
- boost::shared_ptr<LLStandardSignal> mSignal;
+ std::shared_ptr<LLStandardSignal> mSignal;
/// valve open?
bool mEnabled;
@@ -745,14 +743,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<T>...) 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 <typename T>
- T* get_pointer(const weak_ptr<T>& ptr) { return shared_ptr<T>(ptr).get(); }
-}
-
#endif /* ! defined(LL_LLEVENTS_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 <boost/regex.hpp>
+
+template <typename S, typename M, typename R>
+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 <typename S, typename R>
+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 <typename S, typename M, typename R>
+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 <typename S, typename R>
+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/llsingleton.h b/indra/llcommon/llsingleton.h
index 6042c0906c..f85f961287 100644
--- a/indra/llcommon/llsingleton.h
+++ b/indra/llcommon/llsingleton.h
@@ -847,13 +847,14 @@ template<class T>
class LLSimpleton
{
public:
- template <typename... ARGS>
- static void createInstance(ARGS&&... args)
- {
+ static T* sInstance;
+
+ static void createInstance()
+ {
llassert(sInstance == nullptr);
- sInstance = new T(std::forward<ARGS>(args)...);
+ sInstance = new T();
}
-
+
static inline T* getInstance() { return sInstance; }
static inline T& instance() { return *getInstance(); }
static inline bool instanceExists() { return sInstance != nullptr; }
@@ -863,9 +864,6 @@ public:
delete sInstance;
sInstance = nullptr;
}
-
-private:
- static T* sInstance;
};
template <class T>
diff --git a/indra/llcommon/llsys.cpp b/indra/llcommon/llsys.cpp
index 306ef05b6d..18f4684b49 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 <boost/bind.hpp>
#include <boost/circular_buffer.hpp>
-#include <boost/regex.hpp>
#include <boost/foreach.hpp>
#include <boost/lexical_cast.hpp>
#include <boost/range.hpp>
@@ -101,39 +101,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 <typename S, typename M, typename R>
-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 <typename S, typename M, typename R>
-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("")
{
@@ -377,7 +344,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;
@@ -1044,7 +1011,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/llcommon/llthreadsafequeue.h b/indra/llcommon/llthreadsafequeue.h
index 2806506550..a588175074 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 <typename T>
- bool pushIfOpen(T&& element);
-
// Try to add an element to the queue without blocking. Returns
// true only if the element was actually added.
template <typename T>
@@ -319,8 +314,8 @@ bool LLThreadSafeQueue<ElementT, QueueT>::push_(lock_t& lock, T&& element)
template <typename ElementT, typename QueueT>
-template <typename T>
-bool LLThreadSafeQueue<ElementT, QueueT>::pushIfOpen(T&& element)
+template<typename T>
+void LLThreadSafeQueue<ElementT, QueueT>::push(T&& element)
{
LL_PROFILE_ZONE_SCOPED;
lock_t lock1(mLock);
@@ -330,10 +325,12 @@ bool LLThreadSafeQueue<ElementT, QueueT>::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<T>(element)))
- return true;
+ return;
// Storage Full. Wait for signal.
mCapacityCond.wait(lock1);
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<WorkQueue::Error>(
- [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/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 fbdbea2051..1e89d87cff 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
@@ -146,13 +130,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 96574a18b9..8e4b38c2f3 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 <chrono>
-#include <exception> // std::current_exception
#include <functional> // std::function
+#include <queue>
#include <string>
+#include <utility> // std::pair
+#include <vector>
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 <typename CALLABLE>
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)));
}
@@ -109,47 +83,6 @@ namespace LL
}
/**
- * post work for a particular time, unless the queue is closed before
- * we can post
- */
- template <typename CALLABLE>
- 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 <typename CALLABLE>
- 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 <typename CALLABLE>
- 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 <typename CALLABLE>
- static bool postMaybe(weak_t target, CALLABLE&& callable)
- {
- return postMaybe(target, TimePoint::clock::now(),
- std::forward<CALLABLE>(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 <typename CALLABLE, typename FOLLOWUP>
- 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 <typename CALLABLE, typename FOLLOWUP>
- bool postTo(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 <typename CALLABLE>
- 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 <typename CALLABLE>
- auto waitForResult(CALLABLE&& callable)
+ bool postTo(WorkQueue::weak_t target,
+ CALLABLE&& callable, FOLLOWUP&& callback)
{
- return waitForResult(TimePoint::clock::now(), std::move(callable));
+ return postTo(target, TimePoint::clock::now(), std::move(callable), std::move(callback));
}
/*--------------------------- worker API ---------------------------*/
@@ -271,23 +233,6 @@ namespace LL
bool runUntil(const TimePoint& until);
private:
- template <typename CALLABLE, typename FOLLOWUP>
- static auto makeReplyLambda(CALLABLE&& callable, FOLLOWUP&& callback);
- /// general case: arbitrary C++ return type
- template <typename CALLABLE, typename FOLLOWUP, typename RETURNTYPE>
- struct MakeReplyLambda;
- /// specialize for CALLABLE returning void
- template <typename CALLABLE, typename FOLLOWUP>
- struct MakeReplyLambda<CALLABLE, FOLLOWUP, void>;
-
- /// general case: arbitrary C++ return type
- template <typename CALLABLE, typename RETURNTYPE>
- struct WaitForResult;
- /// specialize for CALLABLE returning void
- template <typename CALLABLE>
- struct WaitForResult<CALLABLE, void>;
-
- 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);
@@ -309,8 +254,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<Rep, Period>& interval,
CALLABLE&& callable):
mTarget(target),
@@ -357,8 +302,8 @@ namespace LL
}
private:
- weak_t mTarget;
- TimePoint mStart;
+ WorkQueue::weak_t mTarget;
+ WorkQueue::TimePoint mStart;
std::chrono::duration<Rep, Period> mInterval;
CALLABLE mCallable;
};