summaryrefslogtreecommitdiff
path: root/indra/llcommon/llsingleton.h
AgeCommit message (Collapse)Author
2021-05-12SL-10297: Use initializer_list<std::string> vs. <std::string_view>.Nat Goodspeed
This is somewhat more expensive for string literals, but switching to std::string_view implies more extensive changes, to be considered separately.
2021-05-12SL-10297: #include <string_view> in llsingleton.hNat Goodspeed
2021-05-12SL-10297: Simplify implementation of LLSingletonBase::logwarns() etc.Nat Goodspeed
Introduce 'string_params' typedef for std::initialization_list<std::string>, and make logwarns(), loginfos(), logdebugs() and logerrs() accept const string_params&. Eliminate the central log() function in llsingleton.cpp that used LL_VLOGS(). To cache the result of a (moderately expensive) Log::shouldLog() call, LL_VLOGS() wants its CallSite object to be static -- but of course the shouldLog() result will differ for different ELevel values, so LL_VLOGS() instantiates a static array of CallSite instances. It seems silly to funnel distinct logwarns(), etc., functions through a common log() function only to have LL_VLOGS() tease apart ELevel values again. Instead, make logwarns() directly invoke LL_WARNS(), and similarly for the rest. To reduce boilerplate in these distinct functions, teach std::ostream how to stream a string_params instance by looping over its elements. Then each logwarns(), etc., function can simply stream its string_params argument to LL_WARNS() or whichever. In particular, eliminate the LLERROR_CRASH macro in logerrs(). The fact that it invokes LL_ERRS() ensures that its LL_ENDL macro will crash the viewer.
2021-05-10SL-10297: Make LLSingletonBase::llerrs() et al. runtime variadic.Nat Goodspeed
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.
2020-05-06DRTVWR-476: Merge branch 'master' of lindenlab/viewer into DRTVWR-476-boost-1.72Nat Goodspeed
2020-04-03DRTVWR-476: Cherry-pick debug aids from commit 77b0c53 (fiber-mutex)Nat Goodspeed
2020-03-25DRTVWR-476: Log calls to LLParamSingleton::initParamSingleton().Nat Goodspeed
2020-03-25SL-11216: Remove LLSingletonBase::cleanupAll().Nat Goodspeed
Remove call from LLAppViewer::cleanup(). Instead, make each LLSingleton<T>::deleteSingleton() call cleanupSingleton() just before destroying the instance. Since deleteSingleton() is not a destructor, it's fine to call cleanupSingleton() from there; and since deleteAll() calls deleteSingleton() on every remaining instance, the former cleanupAll() functionality has been subsumed into deleteAll(). Since cleanupSingleton() is now called at exactly one point in the instance's lifetime, we no longer need a bool indicating whether it has been called. The previous protocol of calling cleanupAll() before deleteAll() implemented a two-phase cleanup strategy for the application. That is no longer needed. Moreover, the cleanupAll() / deleteAll() sequence created a time window during which individual LLSingleton<T> instances weren't usable (to the extent that their cleanupSingleton() methods released essential resources) but still existed -- so a getInstance() call would return the crippled instance rather than recreating it. Remove cleanupAll() calls from tests; adjust to new order of expected side effects: instead of A::cleanupSingleton(), B::cleanupSingleton(), ~A(), ~B(), now we get A::cleanupSingleton(), ~A(), B::cleanupSingleton(), ~B().
2020-03-25DRTVWR-494: Move most LLSingleton cleanup back to destructorNat Goodspeed
instead of deleteSingleton(). Specifically, clear static SingletonData and remove the instance from the MasterList in the destructor. Empirically, some consumers are manually deleting LLSingleton instances, instead of calling deleteSingleton(). If deleteSingleton() handles cleanup rather than the destructor, we're left with dangling pointers in the Master List. We don't also call cleanupSingleton() from the destructor because only deleteSingleton() promises to call cleanupSingleton(). Hopefully whoever is directly deleting an LLSingleton subclass instance isn't relying on cleanupSingleton().
2020-03-25DRTVWR-494: LLParamSingleton::initParamSingleton() returns reference.Nat Goodspeed
2020-03-25DRTVWR-494: LLParamSingleton::initParamSingleton() on main thread.Nat Goodspeed
When calling LLParamSingleton::initParamSingleton() on a secondary thread, use LLMainThreadTask::dispatch() to construct the instance on the main thread -- as with LLSingleton::getInstance().
2020-03-25DRTVWR-494: LLParamSingleton<T>::initParamSingleton() now returns T*.Nat Goodspeed
So does LLLockedSingleton<T>::construct().
2020-03-25DRTVWR-494: Dispatch all LLSingleton construction to the main thread.Nat Goodspeed
Given the viewer's mutually-dependent LLSingletons, given that different threads might simultaneously request different LLSingletons from such a chain of circular dependencies, the key to avoiding deadlock is to serialize all LLSingleton construction on one thread: the main thread. Add comments to LLSingleton::getInstance() explaining the problem and the solution. Recast LLSingleton's static SingletonData to use LockStatic. Instead of using Locker, and simply trusting that every reference to sData is within the dynamic scope of a Locker instance, LockStatic enforces that: you can only access SingletonData members via LockStatic. Reorganize the switch in getInstance() to group the CONSTRUCTING error, the INITIALIZING/INITIALIZED success case, and the DELETED/UNINITIALIZED construction case. When [re]constructing an instance, on the main thread, retain the lock and call constructSingleton() (and capture_dependency()) directly. On a secondary thread, unlock LockStatic and use LLMainThreadTask::dispatch() to call getInstance() on the main thread. Since we might end up enqueuing multiple such tasks, it's important to let getInstance() notice when the instance has already been constructed and simply return the existing pointer. Add loginfos() method, sibling to logerrs(), logwarns() and logdebugs(). Produce loginfos() messages when dispatching to the main thread, when actually running on the main thread and when resuming the suspended requesting thread. Make deleteSingleton() manage all associated state, instead of delegating some of that work to ~LLSingleton(). Now, within LockStatic, extract the instance pointer and set state to DELETED; that lets subsequent code, which retains the only remaining pointer to the instance, remove the master-list entry, call the subclass cleanupSingleton() and destructor without needing to hold the lock. In fact, entirely remove ~LLSingleton(). Import LLSingletonBase::cleanup_() method to wrap the call to subclass cleanupSingleton() in try/catch. Remove cleanupAll() calls from llsingleton_test.cpp, and reorder the success cases to reflect the fact that T::cleanupSingleton() is called immediately before ~T() for each distinct LLSingleton subclass T. When getInstance() on a secondary thread dispatches to the main thread, it necessarily unlocks its LockStatic lock. But an LLSingleton dependency chain strongly depends on the function stack on which getInstance() is invoked -- the task dispatched to the main thread doesn't know the dependencies tracked on the requesting thread stack. So, once the main thread delivers the instance pointer, the requesting thread captures its own dependencies for that instance. Back in the requesting thread, obtaining the current EInitState to pass to capture_dependencies() would have required relocking LockStatic. Instead, I've convinced myself that (a) capture_dependencies() only wanted to know EInitState to produce an error for CONSTRUCTING, and (b) in CONSTRUCTING state, we never get as far as capture_dependencies() because getInstance() produces an error first. Eliminate the EInitState parameter from all capture_dependencies() methods. Remove the LLSingletonBase::capture_dependency() stanza that tested EInitState. Make the capture_dependencies() variants that accepted LockStatic instead accept LLSingletonBase*. That lets getInstance(), in the LLMainThreadTask case, pass the newly-returned instance pointer. For symmetry, make pop_initializing() accept LLSingletonBase* as well, instead of accepting LockStatic and extracting mInstance.
2020-03-25DRTVWR-494: Streamline LLSingleton state machine.Nat Goodspeed
The CONSTRUCTED state was only briefly set between constructSingleton() and finishInitializing(). But as no consumer code is executed between setting CONSTRUCTED and setting INITIALIZING, it was impossible to reach the switch statement in either getInstance() method in state CONSTRUCTED. So there was no point in state CONSTRUCTED. Remove it. With CONSTRUCTED gone, we only ever call finishInitializing() right after constructSingleton(). Merge finishInitializing() into constructSingleton().
2020-03-25DRTVWR-494: Encapsulate redundant VS boilerplate around <mutex>.Nat Goodspeed
2020-03-25DRTVWR-494: Improve thread safety of LLSingleton machinery.Nat Goodspeed
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. (transplanted from dca0f16266c7bddedb51ae7d7dca468ba87060d5)
2019-11-13Merge in from viewer-release 6.3.5Dave Houlton
2019-08-20DRTVWR-493: Defend LL[Param]Singleton against ctor/init exceptions.Nat Goodspeed
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-19DRTVWR-493: Improve exception safety of LLSingleton initialization.Nat Goodspeed
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-14DRTVWR-493: Work around static initialization order problem.Nat Goodspeed
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-12DRTVWR-493: Rely on recursive_mutex to handle circularityNat Goodspeed
from LLParamSingleton::initSingleton().
2019-08-12Automated merge with ssh://bitbucket.org/andreykproductengine/drtvwr-493Nat Goodspeed
2019-08-12DRTVWR-493: Permit LLParamSingleton::initSingleton() circularity.Nat Goodspeed
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-12DRTVWR-493 LLWearableType to LLParamSingletonandreykproductengine
2019-08-12DRTVWR-493: Streamline LLParamSingleton, LLLockedSingleton.Nat Goodspeed
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-07-25DRTVWR-493 LLImage to LLParamSingletonandreykproductengine
2019-01-04Added new LLSINGLETON macro that includes override keyword.Rider Linden
2017-04-24DRTVWR-418: Remove final shutdown cleanup as a cause of crashes.Nat Goodspeed
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-03-13DRTVWR-418: Ignore logging that requires resurrecting singletons.Nat Goodspeed
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.
2016-09-15MAINT-5232: Normalize LLSingleton subclasses.Nat Goodspeed
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-06MAINT-5232: Make LLSingleton's 'initializing' stack coro-specific.Nat Goodspeed
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-03MAINT-5232: Add DEBUG logging to LLSingleton dependency tracking.Nat Goodspeed
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-08-30Automated merge with ssh://bitbucket.org/lindenlab/viewer-releaseNat Goodspeed
2015-11-10remove execute permission from many files that should not have itOz Linden
2015-06-30MAINT-5232: Add tests for new LLSingleton dependency functionality.Nat Goodspeed
2015-06-26MAINT-5232: Use LLError::Log::demangle() to log LLSingleton classes.Nat Goodspeed
2015-06-26MAINT-5232: Loosen LLSingleton circularity constraints slightly.Nat Goodspeed
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-25MAINT-5232: Correct forward declaration of LLSingleton_manage_master.Nat Goodspeed
The forward declaration said it was a 'friend class', whereas the actual definition is a struct. MSVC dislikes that.
2015-06-25MAINT-5232: Try to avoid circularity between LLError and LLSingleton.Nat Goodspeed
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-24MAINT-5232: Introduce inter-LLSingleton dependency tracking.Nat Goodspeed
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-05-28MAINT-5232: Stop documenting deprecated alternative LLSingleton usage.Nat Goodspeed
2015-05-22MAINT-5232: Clean up some dubious LLSingleton methods.Nat Goodspeed
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.
2013-08-09second phase summer cleaningRichard Linden
replace llinfos, lldebugs, etc with new LL_INFOS(), LL_DEBUGS(), etc.
2013-06-05merge with viewer-releaseRichard Linden
2013-05-20BUILDFIX: mac gcc fixRichard Linden
2013-05-02SH-4080 WIP interesting: random crash on MacRichard Linden
added comments to llsingleton.h
2013-04-29SH-4080 WIP interesting: random crash on MacRichard Linden
fixed singleton unit test resurrecting a singleton now properly calls initSingleton()
2013-04-27SH-4080 WIP interesting: random crash on MacRichard Linden
more singleton cleanup to eliminate crashes on startup/exit
2013-04-26SH-4080 WIP interesting: random crash on MacRichard Linden
fixed Mac crash related to non-reentrant singleton constructor
2013-04-26SH-4080 WIP interesting: random crash on MacRichard Linden
fixed Mac crash related to non-reentrant singleton constructor