Age | Commit message (Collapse) | Author |
|
The pattern of requiring a lock to permit *any* access to a static instance of
something seems generally useful. Break out lockstatic.h; recast
LLInstanceTracker to use it.
Moving LockStatic to an external template class instead of a nested class in
LLInstanceTrackerBase leaves LLInstanceTrackerBase pretty empty. Get rid of it.
And *that* means we can move the definition of the StaticData used by each
LLInstanceTracker specialization into the class itself, rather than having to
define it beforehand in namespace LLInstanceTrackerStuff.
|
|
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().
|
|
|
|
No need to capture a separate list of completed LLEventTimer instances to
delete after the primary loop, since at this point we're looping over a
snapshot and can directly delete each completed timer.
|
|
|
|
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)
|
|
|
|
The previous implementation went to some effort to crash if anyone attempted
to create or destroy an LLInstanceTracker subclass instance during traversal.
That restriction is manageable within a single thread, but becomes unworkable
if it's possible that a given subclass might be used on more than one thread.
Remove LLInstanceTracker::instance_iter, beginInstances(), endInstances(),
also key_iter, beginKeys() and endKeys(). Instead, introduce key_snapshot()
and instance_snapshot(), the only means of iterating over LLInstanceTracker
instances. (These are intended to resemble functions, but in fact the current
implementation simply presents the classes.) Iterating over a captured
snapshot defends against container modifications during traversal. The term
'snapshot' reminds the coder that a new instance created during traversal will
not be considered. To defend against instance deletion during traversal, a
snapshot stores std::weak_ptrs which it lazily dereferences, skipping on the
fly any that have expired.
Dereferencing instance_snapshot::iterator gets you a reference rather than a
pointer. Because some use cases want to delete all existing instances, add an
instance_snapshot::deleteAll() method that extracts the pointer. Those cases
used to require explicitly copying instance pointers into a separate
container; instance_snapshot() now takes care of that. It remains the caller's
responsibility to ensure that all instances of that LLInstanceTracker subclass
were allocated on the heap.
Replace unkeyed static LLInstanceTracker::getInstance(T*) -- which returned
nullptr if that instance had been destroyed -- with new getWeak() method
returning std::weak_ptr<T>. Caller must detect expiration of that weak_ptr.
Adjust tests accordingly.
Use of std::weak_ptr to detect expired instances requires engaging
std::shared_ptr in the constructor. We now store shared_ptrs in the static
containers (std::map for keyed, std::set for unkeyed).
Make LLInstanceTrackerBase a template parameterized on the type of the static
data it manages. For that reason, hoist static data class declarations out of
the class definitions to an LLInstanceTrackerStuff namespace.
Remove the static atomic sIterationNestDepth and its methods incrementDepth(),
decrementDepth() and getDepth(), since they were used only to forbid creation
and destruction during traversal.
Add a std::mutex to static data. Introduce an internal LockStatic class that
locks the mutex while providing a pointer to static data, making that the only
way to access the static data.
The LLINSTANCETRACKER_DTOR_NOEXCEPT macro goes away because we no longer
expect ~LLInstanceTracker() to throw an exception in test programs.
That affects LLTrace::StatBase as well as LLInstanceTracker itself.
Adapt consumers to the new LLInstanceTracker API.
|
|
Moderately often I want to copy the (long) integration test program path from
build output and rerun the test program by hand. But typically we need
environment variables set as well so it can find its dynamic libraries. This
has resulted in my copying parts of several lines of build output, then
pasting to a command prompt, then hand-tweaking the pasted text so it makes
sense as a command.
Streamline run_build_test.py output so less hand-tweaking is needed.
|
|
following promotion of DRTVWR-481
|
|
|
|
|
|
|
|
|
|
following promotion of DRTVWR-499
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
DRTVWR-481
Merge
|
|
|
|
following promotion of DRTVWR-496
|
|
|
|
notification
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
fiexes
|
|
|
|
|
|
remembered user list
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|