Age | Commit message (Collapse) | Author |
|
Until we reimplement LLCoros on Boost.Fiber, we must hand-implement
coroutine-local data. That presently takes the form of a map keyed on
llcoro::id, whose values are the stacks of currently-initializing LLSingleton
instances.
But since the viewer launches an open-ended number of coroutines, we could end
up with an open-ended number of map entries unless we intentionally prune the
map. So every time we pop the stack to empty, remove that map entry.
This could result in thrashing, a given coroutine's 'initializing' stack being
created and deleted for almost every LLSingleton instantiated by that
coroutine -- but the number of different LLSingletons is necessarily static,
and the lifespan of each is the entire rest of the process. Even a couple
dozen LLSingletons won't thrash that badly.
|
|
The stack we maintain of which LLSingletons are currently initializing only
makes sense when associated with a particular C++ call stack. But each
coroutine introduces another C++ call stack!
Move the initializing stack from function-static storage to
LLSingletonBase::MasterList. Make it a map keyed by llcoro::id. Each coro then
has a stack of its own.
This introduces more dependencies on the MasterList singleton, requiring
additional LLSingleton_manage_master workarounds.
|
|
|
|
Previous logic could possibly leave mStartTime uninitialized, producing fatal
warnings with gcc 4.7.
|
|
Until now, the "main coroutine" (the initial context) of each thread left
LLCoros::Current() NULL. The trouble with that is that llcoro::get_id()
returns that CoroData* as an opaque token, and we want distinct values for
every stack in the process. That would not be true if the "main coroutine" on
thread A returned the same value (NULL) as the "main coroutine" on thread B,
and so forth. Give each thread's "main coroutine" a dummy heap CoroData
instance of its own.
|
|
|
|
|
|
|
|
We need LLSingleton machinery to be able to reference get_id() without also
depending on all the rest of LLCoros -- since LLCoros isa LLSingleton.
|
|
Change the module-static thread_specific_ptr to a function-static
thread_specific_ptr so it will be initialized on demand -- since LLSingleton
will need to rely on get_id(). Note that since LLCoros isa LLSingleton, we
must take great care to avoid circularity.
Introduce a private helper class LLCoros::Current to obtain and bind that
thread_specific_ptr. Change all existing internal references from the static
thread_specific_ptr to the new Current helper class.
|
|
Specifically, add DEBUG logging to the code that maintains the stack of
LLSingletons currently being initialized. This involves passing
LLSingletonBase's constructor the name of LLSingleton's template parameter
subclass, since during that constructor typeid(*this).name() will only produce
"LLSingletonBase".
Also add logdebugs() and oktolog() helper functions.
|
|
LLError machinery depends on two different LLSingletons. Its is_available()
function is primarily for LLSingleton itself to determine whether it is, or is
not, safe to log. Until both of LLError's LLSingletons have been constructed,
attempting to log LLSingleton operations could produce infinite recursion.
|
|
LLError::abbreviateFile() is specifically to avoid cluttering log output with
the prefix of an absolute file path on the original build system, pointless
for anyone trying to read the log.
|
|
LLError::abbreviateFile() is specifically to avoid cluttering log output with
the prefix of an absolute file path on the original build system, pointless
for anyone trying to read the log.
|
|
Raw lllog() doesn't work for varying log level, which is why LL_VLOGS()
exists.
|
|
|
|
Raw lllog() doesn't work for varying log level, which is why LL_VLOGS()
exists.
|
|
|
|
In some places we want to log the same information but with different severity
depending on specifics. In other cases we need to test the availability of the
logging subsystem before engaging it. LL_VLOGS() accepts an LLError::ELevel
argument that can differ with each call, while retaining the desirable feature
of deciding only once for each level.
|
|
|
|
|
|
|
|
|
|
|
|
for consistency with everything else, so we can use SUBSYSTEM_CLEANUP() macro
to call it.
|
|
Specifically, log as LLSingleton captures inter-Singleton dependencies. Also
log cleanupAll() calls to cleanupSingleton() and deleteAll() calls to
deleteSingleton(), since they happen in an implicitly-determined order. But do
not log anything during the implicit LLSingletonBase::deleteAll() call
triggered by the runtime destroying the last LLSingleton's static data. That's
too late in the run; even std::cerr might already have been destroyed!
|
|
|
|
Introduce corresponding llcleanup.cpp, llinitdestroyclass.cpp modules to
contain code that performs logging calls.
Track class::method names for LLInitClass<T> and LLDestroyClass<T> subclasses,
and log them when called. The order in which these calls occur could be
relevant to bugs, and could surface the need to convert to LLSingleton
dependencies.
|
|
clang gets nervous about expressions that call functions inside typeid(), even
though these particular typeid() calls are runtime expressions on runtime
values. Extract the offending calls to a previous statement.
|
|
|
|
This particular test relied on there being exactly one instance of the string
"indra" in the source file's __FILE__ path -- which is usually true, but not
if the developer clones the viewer source repo under a parent directory whose
path itself contains "indra". Fix to handle any number of occurrences.
|
|
This means that an exception derived from LLContinueError thrown in an
LLEventPump listener won't prevent other listeners on the same LLEventPump
from receiving that event.
|
|
|
|
|
|
Wrap coroutine call in try/catch in top-level coroutine wrapper function
LLCoros::toplevel(). Distinguish exception classes derived from
LLContinueError (log and continue) from all others (crash with LL_ERRS).
Enhance CRASH_ON_UNHANDLED_EXCEPTIONS() and LOG_UNHANDLED_EXCEPTIONS() macros
to accept a context string to supplement the log message. This lets us replace
many places that called boost::current_exception_diagnostic_information() with
LOG_UNHANDLED_EXCEPTIONS() instead, since the explicit calls were mostly to
log supplemental information.
Provide supplemental information (coroutine name, function parameters) for
some of the previous LOG_UNHANDLED_EXCEPTIONS() calls. This information
duplicates LL_DEBUGS() information at the top of these functions, but in a
typical log file we wouldn't see the LL_DEBUGS() message.
Eliminate a few catch (std::exception e) clauses: the information we get from
boost::current_exception_diagnostic_information() in a catch (...) clause
makes it unnecessary to distinguish.
In a few cases, add a final 'throw;' to a catch (...) clause: having logged
the local context info, propagate the exception to be caught by higher-level
try/catch.
In a couple places, couldn't resist reconciling indentation within a
particular function: tabs where the rest of the function uses tabs, spaces
where the rest of the function uses spaces.
In LLLogin::Impl::loginCoro(), eliminate some confusing comments about an
array of rewritten URIs that date back to a long-deleted implementation.
|
|
since Visual Studio doesn't know __PRETTY_FUNCTION__, and Boost already has a
portable macro to Do The Right Thing.
|
|
Turns out we have a surprising number of catch (...) clauses in the viewer
code base. If all we currently do is
LL_ERRS() << "unknown exception" << LL_ENDL;
then call CRASH_ON_UNHANDLED_EXCEPTION() instead. If what we do is
LL_WARNS() << "unknown exception" << LL_ENDL;
then call LOG_UNHANDLED_EXCEPTION() instead.
Since many places need LOG_UNHANDLED_EXCEPTION() and nobody catches
LLContinueError yet, eliminate LLContinueError& parameter from
LOG_UNHANDLED_EXCEPTION(). This permits us to use the same log message as
CRASH_ON_UNHANDLED_EXCEPTION(), just with a different severity level.
Where a catch (...) clause actually provides contextual information, or makes
an error string, add boost::current_exception_diagnostic_information() to try
to figure out actual exception class and message.
|
|
|
|
A level of preprocessor indirection lets us later change the implementation if
desired.
|
|
llexception_test.cpp is an unusual test source in that it need not be verified
on every build, so its invocation in indra/llcommon/CMakeLists.txt is
commented out with that remark. Its purpose is to help a developer decide what
base class(es) to use for LLException, how to throw and how to catch.
Our current conclusions are written up as comments in llexception_test.cpp.
Added CRASH_ON_UNHANDLED_EXCEPTION() and LOG_UNHANDLED_EXCEPTION() macros to
llexception.h -- macros to log __FILE__, __LINE__ and __PRETTY_FUNCTION__ of
the catch site. These invoke functions in llexception.cpp so we don't need to
#include llerror.h for every possible catch site.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|