Commit Graph

48 Commits (9edad026f4494de1a6f02ecc3f477faa27a361ef)

Author SHA1 Message Date
Nat Goodspeed c6ebb20069 DRTVWR-494: Improve thread safety of LLSingleton machinery.
Remove warnings about LLSingleton not being thread-safe because, at this point,
we have devoted considerable effort to trying to make it thread-safe.

Add LLSingleton<T>::Locker, a nested class which both provides a function-
static mutex and a scoped lock that uses it. Instantiating Locker, which has a
nullary constructor, replaces the somewhat cumbersome idiom of declaring a
std::unique_lock<std::recursive_mutex> lk(getMutex);

This eliminates (or rather, absorbs) the typedefs and getMutex() method from
LLParamSingleton. Replace explicit std::unique_lock declarations in
LLParamSingleton methods with Locker declarations.

Remove LLSingleton<T>::SingletonInitializer nested struct. Instead of
getInstance() relying on function-static initialization to protect (only)
constructSingleton() calls, explicitly use a Locker instance to cover its
whole scope, and make the UNINITIALIZED case call constructSingleton().
Rearrange cases so that after constructSingleton(), control falls through to
the CONSTRUCTED case and the finishInitializing() call.

Use a Locker instance in other public-facing methods too: instanceExists(),
wasDeleted(), ~LLSingleton(). Make destructor protected so it can only be called
via deleteSingleton() (but must be accessible to subclasses for overrides).

Remove LLSingletonBase::get_master() and get_initializing(), which permitted
directly manipulating the master list and the initializing stack without any
locking mechanism. Replace with get_initializing_size().

Similarly, replace LLSingleton_manage_master::get_initializing() with
get_initializing_size(). Use in constructSingleton() in place of
get_initializing().size().

Remove LLSingletonBase::capture_dependency()'s list_t parameter, which
accepted the list returned by get_initializing(). Encapsulate that retrieval
within the scope of the new lock in capture_dependency().

Add LLSingleton_manage_master::capture_dependency(LLSingletonBase*, EInitState)
to forward (or not) a call to LLSingletonBase::capture_dependency(). Nullary
LLSingleton<T>::capture_dependency() calls new LLSingleton_manage_master method.

Equip LLSingletonBase::MasterList with a mutex of its own, separate from the
one donated by the LLSingleton machinery, to serialize use of MasterList data
members. Introduce MasterList::Lock nested class to lock the MasterList mutex
while providing a reference to the MasterList instance. Introduce subclasses
LockedMaster, which provides a reference to the actual mMaster master list
while holding the MasterList lock; and LockedInitializing, which does the same
for the initializing list. Make mMaster and get_initializing_() private so
that consuming code can *only* access those lists via LockedInitializing and
LockedMaster.

Make MasterList::cleanup_initializing_() private, with a LockedInitializing
public forwarding method. This avoids another call to MasterList::instance(),
and also mandates that the lock is currently held during every call.

Similarly, move LLSingletonBase::log_initializing() to a LockedInitializing
log() method.
2019-11-23 22:18:45 -05:00
Nat Goodspeed 54b98cb8c1 DRTVWR-493: Defend LL[Param]Singleton against ctor/init exceptions.
An exception in the LLSingleton subclass constructor, or in its
initSingleton() method, could leave the LLSingleton machinery in a bad state:
the failing instance would remain in the MasterList, also on the stack of
initializing LLSingletons. Catch exceptions in either and perform relevant
cleanup.

This problem is highlighted by test programs, in which LL_ERRS throws an
exception rather than crashing the whole process.

In the relevant catch clauses, clean up the initializing stack BEFORE logging.
Otherwise we get tangled up recording bogus dependencies.

Move capture_dependency() out of finishInitializing(): it must be called by
every valid getInstance() call, both from LLSingleton and LLParamSingleton.

Introduce new CONSTRUCTED EInitState value to distinguish "have called the
constructor but not yet the initSingleton() method" from "currently within
initSingleton() method." This is transient, but we execute the 'switch' on
state within that moment. One could argue that the previous enum used
INITIALIZING for current CONSTRUCTED, and INITIALIZED meant INITIALIZING too,
but this is clearer.

Introduce template LLSingletonBase::classname() helper methods to clarify
verbose demangle(typeid(stuff).name()) calls.

Similarly, introduce LLSingleton::pop_initializing() shorthand method.
2019-08-20 12:36:06 -04:00
Nat Goodspeed 310db14bee DRTVWR-493: Improve exception safety of LLSingleton initialization.
Add try/catch clauses to constructSingleton() (to catch exceptions in the
subclass constructor) and finishInitializing() (to catch exceptions in the
subclass initSingleton() method). Each of these catch clauses rethrows the
exception -- they're for cleanup, not for ultimate handling.

Introduce LLSingletonBase::reset_initializing(list_t::size_t). The idea is
that since we can't know whether the exception happened before or after the
push_initializing() call in LLSingletonBase's constructor, we can't just pop
the stack. Instead, constructSingleton() captures the stack size before
attempting to construct the new LLSingleton subclass. On exception, it calls
reset_initializing() to restore the stack to that size.

Naturally that requires a corresponding LLSingleton_manage_master method,
whose MasterList specialization is a no-op.

finishInitializing()'s exception handling is a bit simpler because it has a
constructed LLSingleton subclass instance in hand, therefore
push_initializing() has definitely been called, therefore it can call
pop_initializing().

Break out new static capture_dependency() method from finishInitializing()
because, in the previous LLSingleton::getInstance() implementation, the logic
now wrapped in capture_dependency() was reached even in the INITIALIZED case.
TODO: Add a new EInitState to differentiate "have been constructed, now
calling initSingleton()" from "fully initialized, normal case" -- in the
latter control path we should not be calling capture_dependency().

The LLSingleton_manage_master<LLSingletonBase::MasterList> specialization's
get_initializing() function (which called get_initializing_from()) was
potentially dangerous. get_initializing() is called by push_initializing(),
which (in the general case) is called by LLSingletonBase's constructor. If
somehow the MasterList's LLSingletonBase constructor ended up calling
get_initializing(), it would have called get_initializing_from(), passing an
LLSingletonBase which had not yet been constructed into the MasterList. In
particular, its mInitializing map would not yet have been initialized at all.

Since the MasterList must not, by design, depend on any other LLSingletons,
LLSingleton_manage_master<LLSingletonBase::MasterList>::get_initializing()
need not return a list from the official mInitializing map anyway. It can, and
should, and now does, return a static dummy list. That obviates
get_initializing_from(), which is removed.

That in turn means we no longer need to pass get_initializing() an
LLSingletonBase*. Remove that parameter.
2019-08-19 11:44:56 -04:00
Nat Goodspeed 0e6a6c7775 DRTVWR-493: Work around static initialization order problem.
LLParamSingleton contained a static member mutex. Unfortunately that wasn't
guaranteed to be initialized by the time its getInstance() was entered. Use a
function-local static instead.
2019-08-14 13:57:13 -04:00
Nat Goodspeed 5196af8663 DRTVWR-493: Rely on recursive_mutex to handle circularity
from LLParamSingleton::initSingleton().
2019-08-12 17:47:48 -04:00
Nat Goodspeed a5f58663c0 Automated merge with ssh://bitbucket.org/andreykproductengine/drtvwr-493 2019-08-12 17:43:09 -04:00
Nat Goodspeed 4fce6dc435 DRTVWR-493: Permit LLParamSingleton::initSingleton() circularity.
This was forbidden, but AndreyK points out cases in which LLParamSingleton::
initSingleton() should in fact be allowed to circle back to its own instance()
method. Use a recursive_mutex instead of plain mutex to permit that; remove
LL_ERRS preventing it.

Add LLParamSingleton::instance() method that calls
LLParamSingleton::getInstance(). Inheriting LLSingleton::instance() called
LLSingleton::getInstance() -- not at all what we want.

Add LLParamSingleton unit tests.
2019-08-12 17:35:45 -04:00
andreykproductengine 3c552696bf DRTVWR-493 LLWearableType to LLParamSingleton 2019-08-12 22:56:15 +03:00
Nat Goodspeed 98be6e141c DRTVWR-493: Streamline LLParamSingleton, LLLockedSingleton.
Simplify LLSingleton::SingletonLifetimeManager to SingletonInitializer: that
struct has not been responsible for deletion ever since LLSingletonBase
acquired dependency-ordered deleteAll().

Move SingletonData::mInitState changes from SingletonLifetimeManager to
constructSingleton() method. Similarly, constructSingleton() now sets
SingletonData::mInstance instead of making its caller store the pointer.

Add variadic arguments to LLSingleton::constructSingleton() so we can reuse it
for LLParamSingleton.

Add finishInitializing() method to encapsulate logic reused for
getInstance()'s INITIALIZING and DELETED cases.

Make LLParamSingleton a subclass of LLSingleton, just as LLLockedSingleton is
a subclass of LLParamSingleton. Make LLParamSingleton a friend of LLSingleton,
so it can access private members of LLSingleton without also granting access
to any DERIVED_CLASS subclass. This eliminates the need for protected
getInitState().

LLParamSingleton::initParamSingleton() reuses LLSingleton::constructSingleton()
and finishInitializing(). Its getInstance() method completely replaces
LLSingleton::getInstance(): in most EInitStates, LLParamSingleton::getInstance()
is an error.

Use a std::mutex to serialize calls to LLParamSingleton::initParamSingleton()
and getInstance(). While LLSingleton::getInstance() relies on the "initialized
exactly once" guarantee for block-scope static declarations, LLParamSingleton
cannot rely on the same mechanism.

LLLockedSingleton is now a very succinct subclass of LLParamSingleton -- they
have very similar functionality.

Giving the LLSINGLETON() macro variadic arguments eliminates the need for a
separate LLPARAMSINGLETON() macro, while continuing to support existing usage.
2019-08-12 09:44:56 -04:00
andreykproductengine 17fae30f72 DRTVWR-493 LLImage to LLParamSingleton 2019-07-25 15:17:11 +03:00
Nat Goodspeed d415e019a6 DRTVWR-418: Remove final shutdown cleanup as a cause of crashes.
The recent LLSingleton work added a hook that would run during the C++
runtime's final destruction of static objects. When the LAST LLSingleton in
any module was destroyed, its destructor would call
LLSingletonBase::deleteAll(). That mechanism was intended to permit an
application consuming LLSingletons to skip making an explicit deleteAll()
call, knowing that all instantiated LLSingleton instances would eventually be
cleaned up anyway.

However -- experience proves that kicking off deleteAll() processing during
the C++ runtime's final cleanup is too late. Too much has already been
destroyed. That call tends to cause more shutdown crashes than it resolves.

This commit deletes that whole mechanism. Going forward, if you want to clean
up LLSingleton instances, you must explicitly call
LLSingletonBase::deleteAll() during the application lifetime. If you don't,
LLSingleton instances will simply be leaked -- which might be okay,
considering the application is terminating anyway.
2017-04-24 16:36:54 -04:00
Nat Goodspeed 1a8c8df686 DRTVWR-418: Ignore logging that requires resurrecting singletons.
The logging subsystem depends on two different LLSingletons for some reason.
It turns out to be very difficult to completely avoid executing any logging
calls after the LLSingletonBase::deleteAll(), but we really don't want to
resurrect those LLSingletons so late in the run for a couple stragglers.
Introduce LLSingleton::wasDeleted() query method, and use it in logging
subsystem to simply bypass last-millisecond logging requests.
2017-03-13 14:09:14 -04:00
Nat Goodspeed d2c3c2f9fe MAINT-5232: Normalize LLSingleton subclasses.
A shocking number of LLSingleton subclasses had public constructors -- and in
several instances, were being explicitly instantiated independently of the
LLSingleton machinery. This breaks the new LLSingleton dependency-tracking
machinery. It seems only fair that if you say you want an LLSingleton, there
should only be ONE INSTANCE!

Introduce LLSINGLETON() and LLSINGLETON_EMPTY_CTOR() macros. These handle the
friend class LLSingleton<whatevah>;
and explicitly declare a private nullary constructor.

To try to enforce the LLSINGLETON() convention, introduce a new pure virtual
LLSingleton method you_must_use_LLSINGLETON_macro() which is, as you might
suspect, defined by the macro. If you declare an LLSingleton subclass without
using LLSINGLETON() or LLSINGLETON_EMPTY_CTOR() in the class body, you can't
instantiate the subclass for lack of a you_must_use_LLSINGLETON_macro()
implementation -- which will hopefully remind the coder.

Trawl through ALL LLSingleton subclass definitions, sprinkling in
LLSINGLETON() or LLSINGLETON_EMPTY_CTOR() as appropriate. Remove all explicit
constructor declarations, public or private, along with relevant 'friend class
LLSingleton<myself>' declarations. Where destructors are declared, move them
into private section as well. Where the constructor was inline but nontrivial,
move out of class body.

Fix several LLSingleton abuses revealed by making ctors/dtors private:

LLGlobalEconomy was both an LLSingleton and the base class for
LLRegionEconomy, a non-LLSingleton. (Therefore every LLRegionEconomy instance
contained another instance of the LLGlobalEconomy "singleton.") Extract
LLBaseEconomy; LLGlobalEconomy is now a trivial subclass of that.
LLRegionEconomy, as you might suspect, now derives from LLBaseEconomy.

LLToolGrab, an LLSingleton, was also explicitly instantiated by
LLToolCompGun's constructor. Extract LLToolGrabBase, explicitly instantiated,
with trivial subclass LLToolGrab, the LLSingleton instance.

(WARNING: LLToolGrabBase methods have an unnerving tendency to go after
LLToolGrab::getInstance(). I DO NOT KNOW what should be the relationship
between the instance in LLToolCompGun and the LLToolGrab singleton instance.)

LLGridManager declared a variant constructor accepting (const std::string&),
with the comment:
// initialize with an explicity grid file for testing.
As there is no evidence of this being called from anywhere, delete it.

LLChicletBar's constructor accepted an optional (const LLSD&). As the LLSD
parameter wasn't used, and as there is no evidence of it being passed from
anywhere, delete the parameter.

LLViewerWindow::shutdownViews() was checking LLNavigationBar::
instanceExists(), then deleting its getInstance() pointer -- leaving a
dangling LLSingleton instance pointer, a land mine if any subsequent code
should attempt to reference it. Use deleteSingleton() instead.

~LLAppViewer() was calling LLViewerEventRecorder::instance() and then
explicitly calling ~LLViewerEventRecorder() on that instance -- leaving the
LLSingleton instance pointer pointing to an allocated-but-destroyed instance.
Use deleteSingleton() instead.
2016-09-15 20:18:12 -04:00
Nat Goodspeed 90f424980a MAINT-5232: Make LLSingleton's 'initializing' stack coro-specific.
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.
2016-09-06 21:07:38 -04:00
Nat Goodspeed c71e622229 MAINT-5232: Add DEBUG logging to LLSingleton dependency tracking.
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.
2016-09-03 11:30:53 -04:00
Nat Goodspeed c92eb7e591 Automated merge with ssh://bitbucket.org/lindenlab/viewer-release 2016-08-30 11:36:06 -04:00
Oz Linden c8726aba30 remove execute permission from many files that should not have it 2015-11-10 09:48:56 -05:00
Nat Goodspeed d4fb82c217 MAINT-5232: Add tests for new LLSingleton dependency functionality. 2015-06-30 14:49:18 -04:00
Nat Goodspeed 8fee1565eb MAINT-5232: Use LLError::Log::demangle() to log LLSingleton classes. 2015-06-26 15:28:57 -04:00
Nat Goodspeed 687efd84ea MAINT-5232: Loosen LLSingleton circularity constraints slightly.
LLSingleton explicitly supports circular dependencies: initialization
performed during an LLSingleton subclass's initSingleton() method may
recursively call that same subclass's getInstance() method. On the other hand,
circularity from a subclass constructor cannot be permitted, else
getInstance() would have to return a partially-constructed object.
Our dependency tracking circularity check initially forbade both. Loosen it to
permit references from within initSingleton().
2015-06-26 13:03:59 -04:00
Nat Goodspeed 0727519d93 MAINT-5232: Correct forward declaration of LLSingleton_manage_master.
The forward declaration said it was a 'friend class', whereas the actual
definition is a struct. MSVC dislikes that.
2015-06-25 16:07:27 -04:00
Nat Goodspeed 0ea1b2a164 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.
2015-06-25 16:04:01 -04:00
Nat Goodspeed d792baf9f7 MAINT-5232: Introduce inter-LLSingleton dependency tracking.
Introduce LLSingleton::cleanupSingleton() canonical method as the place to put
any subclass cleanup logic that might take nontrivial realtime or throw an
exception. Neither is appropriate in a destructor.
Track all extant LLSingleton subclass instances on a master list, which
permits adding LLSingletonBase::cleanupAll() and deleteAll() methods.
Also notice when any LLSingleton subclass constructor (or initSingleton()
method) calls instance() or getInstance() for another LLSingleton, and capture
that other LLSingleton instance as a dependency of the first. This permits
cleanupAll() and deleteAll() to perform a dependency sort on the master list,
thus cleaning up (or deleting) leaf LLSingletons AFTER the LLSingletons that
depend on them.
Make C++ runtime's final static destructor call LLSingletonBase::deleteAll()
instead of deleting individual LLSingleton instances in arbitrary order.
Eliminate "llerror.h" from llsingleton.h, a longstanding TODO.
2015-06-24 21:14:55 -04:00
Nat Goodspeed df8da8c013 MAINT-5232: Stop documenting deprecated alternative LLSingleton usage. 2015-05-28 17:03:30 -04:00
Nat Goodspeed 331e932857 MAINT-5232: Clean up some dubious LLSingleton methods.
Remove evil getIfExists() method, used by no one.
Remove evil destroyed() method, used in exactly three places -- one of which
is a test. Replace with equally evil instanceExists() method, which is used
EVERYWHERE -- sigh.
2015-05-22 14:02:24 -04:00
Richard Linden e340009fc5 second phase summer cleaning
replace llinfos, lldebugs, etc with new LL_INFOS(), LL_DEBUGS(), etc.
2013-08-09 17:11:19 -07:00
Richard Linden 0a96b47663 merge with viewer-release 2013-06-05 19:05:43 -07:00
Richard Linden 13f43fdc5b BUILDFIX: mac gcc fix 2013-05-20 18:56:40 -07:00
Richard Linden dd07e24053 SH-4080 WIP interesting: random crash on Mac
added comments to llsingleton.h
2013-05-02 19:38:35 -07:00
Richard Linden 41e5bf346e SH-4080 WIP interesting: random crash on Mac
fixed singleton unit test
resurrecting a singleton now properly calls initSingleton()
2013-04-29 10:58:37 -07:00
Richard Linden 215612bde8 SH-4080 WIP interesting: random crash on Mac
more singleton cleanup to eliminate crashes on startup/exit
2013-04-27 07:42:32 -07:00
Richard Linden a4e53da0b0 SH-4080 WIP interesting: random crash on Mac
fixed Mac crash related to non-reentrant singleton constructor
2013-04-26 16:14:44 -07:00
Richard Linden 81291381f8 SH-4080 WIP interesting: random crash on Mac
fixed Mac crash related to non-reentrant singleton constructor
2013-04-26 11:21:16 -07:00
Richard Linden 1a01542e22 BUILDFIX: singleton unit test could not resurrect singleton 2013-04-24 21:04:51 -07:00
Richard Linden 5622a47403 BUILDFIX: method name was wrong 2013-04-24 17:44:34 -07:00
Richard Linden 84af0e9852 SH-4080 WIP interesting: random crash on Mac
potential fix for crasher
cleaned up llsingleton
2013-04-24 14:13:45 -07:00
Graham Madarasz bf6182daa8 Update Mac and Windows breakpad builds to latest 2013-03-29 07:50:08 -07:00
Richard Linden cda2cdda51 SH-3406 WIP convert fast timers to lltrace system
made fast timer stack thread local
added LLThreadLocalSingleton
made LLThreadLocalPointer obey pointer rules for const
added LLThreadLocalSingletonPointer for fast thread local pointers
2013-01-03 00:30:54 -08:00
Logan Dethrow a8d49f7cf5 LLProxy code review fixes.
* Removed check_curl_code and check_curl_multi_code from the global namespace.
 * Added comments documenting which thread the public methods of LLProxy should be called from.
 * Corrected grammar in LLSingleton.h
 * Fixed a buffer scope problem in llpacketring.cpp.
2011-09-06 16:54:53 -04:00
Logan Dethrow 342005cd92 Clarified the reason for adding the deleteSingleton method to LLSingleton. Added a simple unit test to verify the functionality of the deleteSingleton method. 2011-09-01 17:05:22 -04:00
Logan Dethrow 859dc52c30 STORM-1112 Protected LLProxy members during cross-thread calls to LLProxy::applyProxySettings() 2011-07-21 15:16:54 -04:00
Oz Linden 06b0d72efa Change license from GPL to LGPL (version 2.1) 2010-08-13 07:24:57 -04:00
James Cook 7d3b3cc474 Linker optimization - use "extern template" for commonly regenerated templates
Also replaced many duplicate calls to LLViewerCamera::getInstance() with local pointer.
Reviewed with Ambroff
2009-11-30 14:41:52 -08:00
brad kittenbrink c9ee582c12 Add on-demand allocation of LLSingletonRegistry::sSingletonMap so we don't rely on static initialization order.
reviewed by nat.
2009-08-06 15:53:09 -07:00
brad kittenbrink a8d216e194 Merged in my DEV-35401 "doubleton" fix. 2009-08-05 18:45:18 -07:00
brad kittenbrink 860a828639 Attemt at fixing "doubleton" problems across shared lib boundaries. Singletons now keep their SingletonInstaceData in a big global map in the llcommon module. 2009-08-05 14:58:30 -07:00
Richard Nelson eb853f55c0 svn merge -r 128442:129343 svn+ssh://svn.lindenlab.com/svn/linden/branches/skinning/skinning-18 into svn+ssh://svn.lindenlab.com/svn/linden/branches/viewer/viewer-2.0.0-3 2009-08-04 01:12:59 +00:00
Steven Bennetts 9ec432034d merge -r 122421-124917 viewer-2.0.0-2 -> viewer-2.0.0-3
ignore-dead-branch
2009-06-21 08:04:56 +00:00