MAINT-5232: Try to avoid circularity between LLError and LLSingleton.

Part of LLError's logging infrastructure is implemented with an LLSingleton.
Therefore, attempts to log from within LLSingleton machinery could potentially
go south if LLError's LLSingleton is not yet initialized.
Introduce LLError::is_available() in llerrorcontrol.h and llerror.cpp.
Make LLSingletonBase::logwarns() and logerrs() consult LLError::is_available()
before attempting to use LL_WARNS or LL_ERRS, respectively.
Moreover, make all LLSingleton internal logging use logwarns() and logerrs()
instead of directly engaging LL_ERRS or LL_WARNS.
meow-7.2.2
Nat Goodspeed 2015-06-25 16:04:01 -04:00
parent d792baf9f7
commit 0ea1b2a164
4 changed files with 58 additions and 22 deletions

View File

@ -402,6 +402,11 @@ namespace
namespace LLError
{
bool is_available()
{
return Globals::instanceExists();
}
class SettingsConfig : public LLRefCount
{
friend class Settings;

View File

@ -189,6 +189,11 @@ 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

View File

@ -28,9 +28,11 @@
#include "llsingleton.h"
#include "llerror.h"
#include "llerrorcontrol.h" // LLError::is_available()
#include "lldependencies.h"
#include <boost/foreach.hpp>
#include <algorithm>
#include <iostream> // std::cerr in dire emergency
#include <sstream>
#include <stdexcept>
@ -108,14 +110,14 @@ void LLSingletonBase::pop_initializing()
list_t& list(get_initializing());
if (list.empty())
{
LL_ERRS() << "Underflow in stack of currently-initializing LLSingletons at "
<< typeid(*this).name() << "::getInstance()" << LL_ENDL;
logerrs("Underflow in stack of currently-initializing LLSingletons at ",
typeid(*this).name(), "::getInstance()");
}
if (list.back() != this)
{
LL_ERRS() << "Push/pop mismatch in stack of currently-initializing LLSingletons: "
<< typeid(*this).name() << "::getInstance() trying to pop "
<< typeid(*list.back()).name() << LL_ENDL;
logerrs("Push/pop mismatch in stack of currently-initializing LLSingletons: ",
typeid(*this).name(), "::getInstance() trying to pop ",
typeid(*list.back()).name());
}
// Here we're sure that list.back() == this. Whew, pop it.
list.pop_back();
@ -151,8 +153,8 @@ void LLSingletonBase::capture_dependency()
// DEBUGGING: Initially, make this crump. We want to know how bad
// the problem is before we add it to the long, sad list of
// ominous warnings that everyone always ignores.
LL_ERRS() << "LLSingleton circularity: " << out.str()
<< typeid(*this).name() << LL_ENDL;
logerrs("LLSingleton circularity: ", out.str().c_str(),
typeid(*this).name());
}
else
{
@ -223,13 +225,13 @@ void LLSingletonBase::cleanupAll()
}
catch (const std::exception& e)
{
LL_WARNS() << "Exception in " << typeid(*sp).name()
<< "::cleanupSingleton(): " << e.what() << LL_ENDL;
logwarns("Exception in ", typeid(*sp).name(),
"::cleanupSingleton(): ", e.what());
}
catch (...)
{
LL_WARNS() << "Unknown exception in " << typeid(*sp).name()
<< "::cleanupSingleton()" << LL_ENDL;
logwarns("Unknown exception in ", typeid(*sp).name(),
"::cleanupSingleton()");
}
}
}
@ -250,7 +252,7 @@ void LLSingletonBase::deleteAll()
if (! sp->mDeleteSingleton)
{
// This Should Not Happen... but carry on.
LL_WARNS() << name << "::mDeleteSingleton not initialized!" << LL_ENDL;
logwarns(name, "::mDeleteSingleton not initialized!");
}
else
{
@ -261,13 +263,11 @@ void LLSingletonBase::deleteAll()
}
catch (const std::exception& e)
{
LL_WARNS() << "Exception in " << name
<< "::deleteSingleton(): " << e.what() << LL_ENDL;
logwarns("Exception in ", name, "::deleteSingleton(): ", e.what());
}
catch (...)
{
LL_WARNS() << "Unknown exception in " << name
<< "::deleteSingleton()" << LL_ENDL;
logwarns("Unknown exception in ", name, "::deleteSingleton()");
}
}
}
@ -307,13 +307,37 @@ void intrusive_ptr_release(LLSingletonBase::MasterRefcount* mrc)
/*---------------------------- Logging helpers -----------------------------*/
//static
void LLSingletonBase::logerrs(const char* p1, const char* p2, const char* p3)
void LLSingletonBase::logerrs(const char* p1, const char* p2, const char* p3, const char* p4)
{
LL_ERRS() << p1 << p2 << p3 << LL_ENDL;
// 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_ERRS() << 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;
// The other important side effect of LL_ERRS() is
// https://www.youtube.com/watch?v=OMG7paGJqhQ (emphasis on OMG)
LLError::crashAndLoop(std::string());
}
}
//static
void LLSingletonBase::logwarns(const char* p1, const char* p2, const char* p3)
void LLSingletonBase::logwarns(const char* p1, const char* p2, const char* p3, const char* p4)
{
LL_WARNS() << p1 << p2 << p3 << LL_ENDL;
// See logerrs() remarks about is_available().
if (LLError::is_available())
{
LL_WARNS() << p1 << p2 << p3 << p4 << LL_ENDL;
}
else
{
std::cerr << p1 << p2 << p3 << p4 << std::endl;
}
}

View File

@ -90,9 +90,11 @@ protected:
void capture_dependency();
// delegate LL_ERRS() logging to llsingleton.cpp
static void logerrs(const char* p1, const char* p2="", const char* p3="");
static void logerrs(const char* p1, const char* p2="",
const char* p3="", const char* p4="");
// delegate LL_WARNS() logging to llsingleton.cpp
static void logwarns(const char* p1, const char* p2="", const char* p3="");
static void logwarns(const char* p1, const char* p2="",
const char* p3="", const char* p4="");
// obtain canonical ref_ptr_t
static ref_ptr_t get_master_refcount();