SL-10297: Make LLSingletonBase::llerrs() et al. runtime variadic.
Instead of accepting a fixed list of (const char* p1="", etc.), accept
(std::initializer_list<std::string_view>). Accepting a
std::initializer_list<T> in your parameter list allows coding (e.g.)
func({T0, T1, T2, ... });
-- in other words, you can pass the initializer_list a brace-enclosed list of
an arbitrary number of instances of T.
Using std::string_view instead of const char* means we can pass *either* const
char* or std::string. string_view is cheaply constructed from either, allowing
uniform treatment within the function.
Constructing string_view from std::string simply extracts the pointer and
length from the std::string.
Constructing string_view from const char* (e.g. a "string literal") requires
scanning the string for its terminating nul byte -- but that would be
necessary even if the scan were deferred until the function body. Since
string_view stores the length, the scan still happens only once.
master
parent
ce65bc2f13
commit
95d8085fa4
|
|
@ -39,8 +39,7 @@
|
|||
#include <stdexcept>
|
||||
|
||||
namespace {
|
||||
void log(LLError::ELevel level,
|
||||
const char* p1, const char* p2, const char* p3, const char* p4);
|
||||
void log(LLError::ELevel level, std::initializer_list<std::string_view>);
|
||||
} // anonymous namespace
|
||||
|
||||
// Our master list of all LLSingletons is itself an LLSingleton. We used to
|
||||
|
|
@ -218,8 +217,8 @@ void LLSingletonBase::pop_initializing()
|
|||
|
||||
if (list.empty())
|
||||
{
|
||||
logerrs("Underflow in stack of currently-initializing LLSingletons at ",
|
||||
classname(this).c_str(), "::getInstance()");
|
||||
logerrs({"Underflow in stack of currently-initializing LLSingletons at ",
|
||||
classname(this), "::getInstance()"});
|
||||
}
|
||||
|
||||
// Now we know list.back() exists: capture it
|
||||
|
|
@ -240,9 +239,9 @@ void LLSingletonBase::pop_initializing()
|
|||
// Now validate the newly-popped LLSingleton.
|
||||
if (back != this)
|
||||
{
|
||||
logerrs("Push/pop mismatch in stack of currently-initializing LLSingletons: ",
|
||||
classname(this).c_str(), "::getInstance() trying to pop ",
|
||||
classname(back).c_str());
|
||||
logerrs({"Push/pop mismatch in stack of currently-initializing LLSingletons: ",
|
||||
classname(this), "::getInstance() trying to pop ",
|
||||
classname(back)});
|
||||
}
|
||||
|
||||
// log AFTER popping so logging singletons don't cry circularity
|
||||
|
|
@ -331,15 +330,15 @@ void LLSingletonBase::capture_dependency()
|
|||
//
|
||||
// Example: LLNotifications singleton initializes default channels.
|
||||
// Channels register themselves with singleton once done.
|
||||
logdebugs("LLSingleton circularity: ", out.str().c_str(),
|
||||
classname(this).c_str(), "");
|
||||
logdebugs({"LLSingleton circularity: ", out.str(),
|
||||
classname(this)});
|
||||
}
|
||||
else
|
||||
{
|
||||
// Actual circularity with other singleton (or single singleton is used extensively).
|
||||
// Dependency can be unclear.
|
||||
logwarns("LLSingleton circularity: ", out.str().c_str(),
|
||||
classname(this).c_str(), "");
|
||||
logwarns({"LLSingleton circularity: ", out.str(),
|
||||
classname(this)});
|
||||
}
|
||||
}
|
||||
else
|
||||
|
|
@ -352,8 +351,8 @@ void LLSingletonBase::capture_dependency()
|
|||
if (current->mDepends.insert(this).second)
|
||||
{
|
||||
// only log the FIRST time we hit this dependency!
|
||||
logdebugs(classname(current).c_str(),
|
||||
" depends on ", classname(this).c_str());
|
||||
logdebugs({classname(current),
|
||||
" depends on ", classname(this)});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -401,7 +400,7 @@ LLSingletonBase::vec_t LLSingletonBase::dep_sort()
|
|||
|
||||
void LLSingletonBase::cleanup_()
|
||||
{
|
||||
logdebugs("calling ", classname(this).c_str(), "::cleanupSingleton()");
|
||||
logdebugs({"calling ", classname(this), "::cleanupSingleton()"});
|
||||
try
|
||||
{
|
||||
cleanupSingleton();
|
||||
|
|
@ -427,23 +426,23 @@ void LLSingletonBase::deleteAll()
|
|||
if (! sp->mDeleteSingleton)
|
||||
{
|
||||
// This Should Not Happen... but carry on.
|
||||
logwarns(name.c_str(), "::mDeleteSingleton not initialized!");
|
||||
logwarns({name, "::mDeleteSingleton not initialized!"});
|
||||
}
|
||||
else
|
||||
{
|
||||
// properly initialized: call it.
|
||||
logdebugs("calling ", name.c_str(), "::deleteSingleton()");
|
||||
logdebugs({"calling ", name, "::deleteSingleton()"});
|
||||
// From this point on, DO NOT DEREFERENCE sp!
|
||||
sp->mDeleteSingleton();
|
||||
}
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
{
|
||||
logwarns("Exception in ", name.c_str(), "::deleteSingleton(): ", e.what());
|
||||
logwarns({"Exception in ", name, "::deleteSingleton(): ", e.what()});
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
logwarns("Unknown exception in ", name.c_str(), "::deleteSingleton()");
|
||||
logwarns({"Unknown exception in ", name, "::deleteSingleton()"});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -451,40 +450,47 @@ void LLSingletonBase::deleteAll()
|
|||
/*---------------------------- Logging helpers -----------------------------*/
|
||||
namespace {
|
||||
|
||||
void log(LLError::ELevel level,
|
||||
const char* p1, const char* p2, const char* p3, const char* p4)
|
||||
void log(LLError::ELevel level, std::initializer_list<std::string_view> args)
|
||||
{
|
||||
LL_VLOGS(level, "LLSingleton") << p1 << p2 << p3 << p4 << LL_ENDL;
|
||||
LL_VLOGS(level, "LLSingleton");
|
||||
for (auto arg : args)
|
||||
{
|
||||
LL_CONT << arg;
|
||||
}
|
||||
LL_ENDL;
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
//static
|
||||
void LLSingletonBase::logwarns(const char* p1, const char* p2, const char* p3, const char* p4)
|
||||
void LLSingletonBase::logwarns(std::initializer_list<std::string_view> args)
|
||||
{
|
||||
log(LLError::LEVEL_WARN, p1, p2, p3, p4);
|
||||
log(LLError::LEVEL_WARN, args);
|
||||
}
|
||||
|
||||
//static
|
||||
void LLSingletonBase::loginfos(const char* p1, const char* p2, const char* p3, const char* p4)
|
||||
void LLSingletonBase::loginfos(std::initializer_list<std::string_view> args)
|
||||
{
|
||||
log(LLError::LEVEL_INFO, p1, p2, p3, p4);
|
||||
log(LLError::LEVEL_INFO, args);
|
||||
}
|
||||
|
||||
//static
|
||||
void LLSingletonBase::logdebugs(const char* p1, const char* p2, const char* p3, const char* p4)
|
||||
void LLSingletonBase::logdebugs(std::initializer_list<std::string_view> args)
|
||||
{
|
||||
log(LLError::LEVEL_DEBUG, p1, p2, p3, p4);
|
||||
log(LLError::LEVEL_DEBUG, args);
|
||||
}
|
||||
|
||||
//static
|
||||
void LLSingletonBase::logerrs(const char* p1, const char* p2, const char* p3, const char* p4)
|
||||
void LLSingletonBase::logerrs(std::initializer_list<std::string_view> args)
|
||||
{
|
||||
log(LLError::LEVEL_ERROR, p1, p2, p3, p4);
|
||||
log(LLError::LEVEL_ERROR, args);
|
||||
// The other important side effect of LL_ERRS() is
|
||||
// https://www.youtube.com/watch?v=OMG7paGJqhQ (emphasis on OMG)
|
||||
std::ostringstream out;
|
||||
out << p1 << p2 << p3 << p4;
|
||||
for (auto arg : args)
|
||||
{
|
||||
out << arg;
|
||||
}
|
||||
auto crash = LLError::getFatalFunction();
|
||||
if (crash)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -34,6 +34,7 @@
|
|||
#include "lockstatic.h"
|
||||
#include "llthread.h" // on_main_thread()
|
||||
#include "llmainthreadtask.h"
|
||||
#include <initializer_list>
|
||||
|
||||
class LLSingletonBase: private boost::noncopyable
|
||||
{
|
||||
|
|
@ -111,14 +112,10 @@ protected:
|
|||
void capture_dependency();
|
||||
|
||||
// delegate logging calls to llsingleton.cpp
|
||||
static void logerrs(const char* p1, const char* p2="",
|
||||
const char* p3="", const char* p4="");
|
||||
static void logwarns(const char* p1, const char* p2="",
|
||||
const char* p3="", const char* p4="");
|
||||
static void loginfos(const char* p1, const char* p2="",
|
||||
const char* p3="", const char* p4="");
|
||||
static void logdebugs(const char* p1, const char* p2="",
|
||||
const char* p3="", const char* p4="");
|
||||
static void logerrs (std::initializer_list<std::string_view>);
|
||||
static void logwarns (std::initializer_list<std::string_view>);
|
||||
static void loginfos (std::initializer_list<std::string_view>);
|
||||
static void logdebugs(std::initializer_list<std::string_view>);
|
||||
static std::string demangle(const char* mangled);
|
||||
// these classname() declarations restate template functions declared in
|
||||
// llerror.h because we avoid #including that here
|
||||
|
|
@ -327,8 +324,8 @@ private:
|
|||
// init stack to its previous size BEFORE logging so log-machinery
|
||||
// LLSingletons don't record a dependency on DERIVED_TYPE!
|
||||
LLSingleton_manage_master<DERIVED_TYPE>().reset_initializing(prev_size);
|
||||
logwarns("Error constructing ", classname<DERIVED_TYPE>().c_str(),
|
||||
": ", err.what());
|
||||
logwarns({"Error constructing ", classname<DERIVED_TYPE>(),
|
||||
": ", err.what()});
|
||||
// There isn't a separate EInitState value meaning "we attempted
|
||||
// to construct this LLSingleton subclass but could not," so use
|
||||
// DELETED. That seems slightly more appropriate than UNINITIALIZED.
|
||||
|
|
@ -356,8 +353,8 @@ private:
|
|||
// BEFORE logging, so log-machinery LLSingletons don't record a
|
||||
// dependency on DERIVED_TYPE!
|
||||
pop_initializing(lk->mInstance);
|
||||
logwarns("Error in ", classname<DERIVED_TYPE>().c_str(),
|
||||
"::initSingleton(): ", err.what());
|
||||
logwarns({"Error in ", classname<DERIVED_TYPE>(),
|
||||
"::initSingleton(): ", err.what()});
|
||||
// Get rid of the instance entirely. This call depends on our
|
||||
// recursive_mutex. We could have a deleteSingleton(LockStatic&)
|
||||
// overload and pass lk, but we don't strictly need it.
|
||||
|
|
@ -506,9 +503,9 @@ public:
|
|||
case CONSTRUCTING:
|
||||
// here if DERIVED_TYPE's constructor (directly or indirectly)
|
||||
// calls DERIVED_TYPE::getInstance()
|
||||
logerrs("Tried to access singleton ",
|
||||
classname<DERIVED_TYPE>().c_str(),
|
||||
" from singleton constructor!");
|
||||
logerrs({"Tried to access singleton ",
|
||||
classname<DERIVED_TYPE>(),
|
||||
" from singleton constructor!"});
|
||||
return nullptr;
|
||||
|
||||
case INITIALIZING:
|
||||
|
|
@ -523,9 +520,9 @@ public:
|
|||
|
||||
case DELETED:
|
||||
// called after deleteSingleton()
|
||||
logwarns("Trying to access deleted singleton ",
|
||||
classname<DERIVED_TYPE>().c_str(),
|
||||
" -- creating new instance");
|
||||
logwarns({"Trying to access deleted singleton ",
|
||||
classname<DERIVED_TYPE>(),
|
||||
" -- creating new instance"});
|
||||
// fall through
|
||||
case UNINITIALIZED:
|
||||
case QUEUED:
|
||||
|
|
@ -552,8 +549,8 @@ public:
|
|||
} // unlock 'lk'
|
||||
|
||||
// Per the comment block above, dispatch to the main thread.
|
||||
loginfos(classname<DERIVED_TYPE>().c_str(),
|
||||
"::getInstance() dispatching to main thread");
|
||||
loginfos({classname<DERIVED_TYPE>(),
|
||||
"::getInstance() dispatching to main thread"});
|
||||
auto instance = LLMainThreadTask::dispatch(
|
||||
[](){
|
||||
// VERY IMPORTANT to call getInstance() on the main thread,
|
||||
|
|
@ -563,16 +560,16 @@ public:
|
|||
// the main thread processes them, only the FIRST such request
|
||||
// actually constructs the instance -- every subsequent one
|
||||
// simply returns the existing instance.
|
||||
loginfos(classname<DERIVED_TYPE>().c_str(),
|
||||
"::getInstance() on main thread");
|
||||
loginfos({classname<DERIVED_TYPE>(),
|
||||
"::getInstance() on main thread"});
|
||||
return getInstance();
|
||||
});
|
||||
// record the dependency chain tracked on THIS thread, not the main
|
||||
// thread (consider a getInstance() overload with a tag param that
|
||||
// suppresses dep tracking when dispatched to the main thread)
|
||||
capture_dependency(instance);
|
||||
loginfos(classname<DERIVED_TYPE>().c_str(),
|
||||
"::getInstance() returning on requesting thread");
|
||||
loginfos({classname<DERIVED_TYPE>(),
|
||||
"::getInstance() returning on requesting thread"});
|
||||
return instance;
|
||||
}
|
||||
|
||||
|
|
@ -641,16 +638,16 @@ private:
|
|||
// For organizational purposes this function shouldn't be called twice
|
||||
if (lk->mInitState != super::UNINITIALIZED)
|
||||
{
|
||||
super::logerrs("Tried to initialize singleton ",
|
||||
super::template classname<DERIVED_TYPE>().c_str(),
|
||||
" twice!");
|
||||
super::logerrs({"Tried to initialize singleton ",
|
||||
super::template classname<DERIVED_TYPE>(),
|
||||
" twice!"});
|
||||
return nullptr;
|
||||
}
|
||||
else if (on_main_thread())
|
||||
{
|
||||
// on the main thread, simply construct instance while holding lock
|
||||
super::logdebugs(super::template classname<DERIVED_TYPE>().c_str(),
|
||||
"::initParamSingleton()");
|
||||
super::logdebugs({super::template classname<DERIVED_TYPE>(),
|
||||
"::initParamSingleton()"});
|
||||
super::constructSingleton(lk, std::forward<Args>(args)...);
|
||||
return lk->mInstance;
|
||||
}
|
||||
|
|
@ -662,8 +659,8 @@ private:
|
|||
lk->mInitState = super::QUEUED;
|
||||
// very important to unlock here so main thread can actually process
|
||||
lk.unlock();
|
||||
super::loginfos(super::template classname<DERIVED_TYPE>().c_str(),
|
||||
"::initParamSingleton() dispatching to main thread");
|
||||
super::loginfos({super::template classname<DERIVED_TYPE>(),
|
||||
"::initParamSingleton() dispatching to main thread"});
|
||||
// Normally it would be the height of folly to reference-bind
|
||||
// 'args' into a lambda to be executed on some other thread! By
|
||||
// the time that thread executed the lambda, the references would
|
||||
|
|
@ -674,12 +671,12 @@ private:
|
|||
// references.
|
||||
auto instance = LLMainThreadTask::dispatch(
|
||||
[&](){
|
||||
super::loginfos(super::template classname<DERIVED_TYPE>().c_str(),
|
||||
"::initParamSingleton() on main thread");
|
||||
super::loginfos({super::template classname<DERIVED_TYPE>(),
|
||||
"::initParamSingleton() on main thread"});
|
||||
return initParamSingleton_(std::forward<Args>(args)...);
|
||||
});
|
||||
super::loginfos(super::template classname<DERIVED_TYPE>().c_str(),
|
||||
"::initParamSingleton() returning on requesting thread");
|
||||
super::loginfos({super::template classname<DERIVED_TYPE>(),
|
||||
"::initParamSingleton() returning on requesting thread"});
|
||||
return instance;
|
||||
}
|
||||
}
|
||||
|
|
@ -707,14 +704,14 @@ public:
|
|||
{
|
||||
case super::UNINITIALIZED:
|
||||
case super::QUEUED:
|
||||
super::logerrs("Uninitialized param singleton ",
|
||||
super::template classname<DERIVED_TYPE>().c_str());
|
||||
super::logerrs({"Uninitialized param singleton ",
|
||||
super::template classname<DERIVED_TYPE>()});
|
||||
break;
|
||||
|
||||
case super::CONSTRUCTING:
|
||||
super::logerrs("Tried to access param singleton ",
|
||||
super::template classname<DERIVED_TYPE>().c_str(),
|
||||
" from singleton constructor!");
|
||||
super::logerrs({"Tried to access param singleton ",
|
||||
super::template classname<DERIVED_TYPE>(),
|
||||
" from singleton constructor!"});
|
||||
break;
|
||||
|
||||
case super::INITIALIZING:
|
||||
|
|
@ -726,8 +723,8 @@ public:
|
|||
return lk->mInstance;
|
||||
|
||||
case super::DELETED:
|
||||
super::logerrs("Trying to access deleted param singleton ",
|
||||
super::template classname<DERIVED_TYPE>().c_str());
|
||||
super::logerrs({"Trying to access deleted param singleton ",
|
||||
super::template classname<DERIVED_TYPE>()});
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue