summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--indra/llcommon/lleventtimer.cpp3
-rw-r--r--indra/llcommon/llfasttimer.cpp31
-rw-r--r--indra/llcommon/llinstancetracker.cpp17
-rw-r--r--indra/llcommon/llinstancetracker.h706
-rw-r--r--indra/llcommon/llleaplistener.cpp8
-rw-r--r--indra/llcommon/llthreadlocalstorage.cpp12
-rw-r--r--indra/llcommon/lltrace.h2
-rw-r--r--indra/llcommon/lltracethreadrecorder.cpp12
-rw-r--r--indra/llcommon/tests/llinstancetracker_test.cpp107
-rw-r--r--indra/llcommon/tests/llleap_test.cpp28
-rw-r--r--indra/llrender/llgl.cpp6
-rw-r--r--indra/llui/llconsole.cpp4
-rw-r--r--indra/llui/lllayoutstack.cpp6
-rw-r--r--indra/llui/llnotificationslistener.cpp8
-rw-r--r--indra/llwindow/llwindow.cpp16
-rw-r--r--indra/llxml/llcontrol.h2
-rw-r--r--indra/newview/llappviewer.cpp26
-rw-r--r--indra/newview/llchathistory.cpp4
-rw-r--r--indra/newview/llimprocessing.cpp4
-rw-r--r--indra/newview/llscenemonitor.cpp44
-rw-r--r--indra/newview/lltoast.cpp23
-rw-r--r--indra/newview/llviewercontrollistener.cpp12
22 files changed, 548 insertions, 533 deletions
diff --git a/indra/llcommon/lleventtimer.cpp b/indra/llcommon/lleventtimer.cpp
index 0d96e03da4..3986dee3ac 100644
--- a/indra/llcommon/lleventtimer.cpp
+++ b/indra/llcommon/lleventtimer.cpp
@@ -58,9 +58,8 @@ LLEventTimer::~LLEventTimer()
void LLEventTimer::updateClass()
{
std::list<LLEventTimer*> completed_timers;
- for (instance_iter iter = beginInstances(); iter != endInstances(); )
+ for (auto& timer : instance_snapshot())
{
- LLEventTimer& timer = *iter++;
F32 et = timer.mEventTimer.getElapsedTimeF32();
if (timer.mEventTimer.getStarted() && et > timer.mPeriod) {
timer.mEventTimer.reset();
diff --git a/indra/llcommon/llfasttimer.cpp b/indra/llcommon/llfasttimer.cpp
index 3d28cd15b0..08ea668964 100644
--- a/indra/llcommon/llfasttimer.cpp
+++ b/indra/llcommon/llfasttimer.cpp
@@ -193,27 +193,26 @@ TimeBlockTreeNode& BlockTimerStatHandle::getTreeNode() const
void BlockTimer::bootstrapTimerTree()
{
- for (BlockTimerStatHandle::instance_tracker_t::instance_iter it = BlockTimerStatHandle::instance_tracker_t::beginInstances(), end_it = BlockTimerStatHandle::instance_tracker_t::endInstances();
- it != end_it;
- ++it)
+ for (auto& base : BlockTimerStatHandle::instance_snapshot())
{
- BlockTimerStatHandle& timer = static_cast<BlockTimerStatHandle&>(*it);
+ // because of indirect derivation from LLInstanceTracker, have to downcast
+ BlockTimerStatHandle& timer = static_cast<BlockTimerStatHandle&>(base);
if (&timer == &BlockTimer::getRootTimeBlock()) continue;
// bootstrap tree construction by attaching to last timer to be on stack
// when this timer was called
if (timer.getParent() == &BlockTimer::getRootTimeBlock())
-{
+ {
TimeBlockAccumulator& accumulator = timer.getCurrentAccumulator();
if (accumulator.mLastCaller)
- {
+ {
timer.setParent(accumulator.mLastCaller);
accumulator.mParent = accumulator.mLastCaller;
- }
+ }
// no need to push up tree on first use, flag can be set spuriously
accumulator.mMoveUpTree = false;
- }
+ }
}
}
@@ -306,12 +305,10 @@ void BlockTimer::processTimes()
updateTimes();
// reset for next frame
- for (BlockTimerStatHandle::instance_tracker_t::instance_iter it = BlockTimerStatHandle::instance_tracker_t::beginInstances(),
- end_it = BlockTimerStatHandle::instance_tracker_t::endInstances();
- it != end_it;
- ++it)
+ for (auto& base : BlockTimerStatHandle::instance_snapshot())
{
- BlockTimerStatHandle& timer = static_cast<BlockTimerStatHandle&>(*it);
+ // because of indirect derivation from LLInstanceTracker, have to downcast
+ BlockTimerStatHandle& timer = static_cast<BlockTimerStatHandle&>(base);
TimeBlockAccumulator& accumulator = timer.getCurrentAccumulator();
accumulator.mLastCaller = NULL;
@@ -362,12 +359,10 @@ void BlockTimer::logStats()
LLSD sd;
{
- for (BlockTimerStatHandle::instance_tracker_t::instance_iter it = BlockTimerStatHandle::instance_tracker_t::beginInstances(),
- end_it = BlockTimerStatHandle::instance_tracker_t::endInstances();
- it != end_it;
- ++it)
+ for (auto& base : BlockTimerStatHandle::instance_snapshot())
{
- BlockTimerStatHandle& timer = static_cast<BlockTimerStatHandle&>(*it);
+ // because of indirect derivation from LLInstanceTracker, have to downcast
+ BlockTimerStatHandle& timer = static_cast<BlockTimerStatHandle&>(base);
LLTrace::PeriodicRecording& frame_recording = LLTrace::get_frame_recording();
sd[timer.getName()]["Time"] = (LLSD::Real) (frame_recording.getLastRecording().getSum(timer).value());
sd[timer.getName()]["Calls"] = (LLSD::Integer) (frame_recording.getLastRecording().getSum(timer.callCount()));
diff --git a/indra/llcommon/llinstancetracker.cpp b/indra/llcommon/llinstancetracker.cpp
index 3f990f4869..accb4286e8 100644
--- a/indra/llcommon/llinstancetracker.cpp
+++ b/indra/llcommon/llinstancetracker.cpp
@@ -34,18 +34,5 @@
// external library headers
// other Linden headers
-void LLInstanceTrackerBase::StaticBase::incrementDepth()
-{
- ++sIterationNestDepth;
-}
-
-void LLInstanceTrackerBase::StaticBase::decrementDepth()
-{
- llassert(sIterationNestDepth);
- --sIterationNestDepth;
-}
-
-U32 LLInstanceTrackerBase::StaticBase::getDepth()
-{
- return sIterationNestDepth;
-}
+// This .cpp file is required by our CMake test macro. It contributes no code
+// to the viewer.
diff --git a/indra/llcommon/llinstancetracker.h b/indra/llcommon/llinstancetracker.h
index 363d0bcbd5..76b201ad8c 100644
--- a/indra/llcommon/llinstancetracker.h
+++ b/indra/llcommon/llinstancetracker.h
@@ -28,354 +28,456 @@
#ifndef LL_LLINSTANCETRACKER_H
#define LL_LLINSTANCETRACKER_H
-#include <atomic>
#include <map>
+#include <set>
+#include <vector>
#include <typeinfo>
+#include <mutex>
+#include <memory>
+#include <type_traits>
-#include "llstringtable.h"
#include <boost/iterator/transform_iterator.hpp>
#include <boost/iterator/indirect_iterator.hpp>
+#include <boost/iterator/filter_iterator.hpp>
-// As of 2017-05-06, as far as nat knows, only clang supports __has_feature().
-// Unfortunately VS2013's preprocessor shortcut logic doesn't prevent it from
-// producing (fatal) warnings for defined(__clang__) && __has_feature(...).
-// Have to work around that.
-#if ! defined(__clang__)
-#define __has_feature(x) 0
-#endif // __clang__
-
-#if defined(LL_TEST_llinstancetracker) && __has_feature(cxx_noexcept)
-// ~LLInstanceTracker() performs llassert_always() validation. That's fine in
-// production code, since the llassert_always() is implemented as an LL_ERRS
-// message, which will crash-with-message. In our integration test executable,
-// though, this llassert_always() throws an exception instead so we can test
-// error conditions and continue running the test. However -- as of C++11,
-// destructors are implicitly noexcept(true). Unless we mark
-// ~LLInstanceTracker() noexcept(false), the test executable crashes even on
-// the ATTEMPT to throw.
-#define LLINSTANCETRACKER_DTOR_NOEXCEPT noexcept(false)
-#else
-// If we're building for production, or in fact building *any other* test, or
-// we're using a compiler that doesn't support __has_feature(), or we're not
-// compiling with a C++ version that supports noexcept -- don't specify it.
-#define LLINSTANCETRACKER_DTOR_NOEXCEPT
-#endif
-
+/*****************************************************************************
+* LLInstanceTrackerBase
+*****************************************************************************/
/**
* Base class manages "class-static" data that must actually have singleton
* semantics: one instance per process, rather than one instance per module as
* sometimes happens with data simply declared static.
*/
+namespace LLInstanceTrackerStuff
+{
+ struct StaticBase
+ {
+ // We need to be able to lock static data while manipulating it.
+ typedef std::mutex mutex_t;
+ mutex_t mMutex;
+ };
+} // namespace LLInstanceTrackerStuff
+
+template <class Static>
class LL_COMMON_API LLInstanceTrackerBase
{
protected:
- /// It's not essential to derive your STATICDATA (for use with
- /// getStatic()) from StaticBase; it's just that both known
- /// implementations do.
- struct StaticBase
+ typedef Static StaticData;
+
+ // Instantiate this class to obtain a pointer to the canonical static
+ // instance of class Static while holding a lock on that instance. Use of
+ // Static::mMutex presumes either that Static is derived from StaticBase,
+ // or that Static declares some other suitable mMutex.
+ class LockStatic
{
- StaticBase():
- sIterationNestDepth(0)
+ typedef std::unique_lock<decltype(Static::mMutex)> lock_t;
+ public:
+ LockStatic():
+ mData(getStatic()),
+ mLock(mData->mMutex)
{}
-
- void incrementDepth();
- void decrementDepth();
- U32 getDepth();
- private:
-#ifdef LL_WINDOWS
- std::atomic_uint32_t sIterationNestDepth;
-#else
- std::atomic_uint sIterationNestDepth;
-#endif
- };
+ Static* get() const { return mData; }
+ operator Static*() const { return get(); }
+ Static* operator->() const { return get(); }
+ // sometimes we must explicitly unlock...
+ void unlock()
+ {
+ // but once we do, access is no longer permitted
+ mData = nullptr;
+ mLock.unlock();
+ }
+ protected:
+ Static* mData;
+ lock_t mLock;
+ private:
+ Static* getStatic()
+ {
+ static Static sData;
+ return &sData;
+ }
+ };
};
-LL_COMMON_API void assert_main_thread();
-
+/*****************************************************************************
+* LLInstanceTracker with key
+*****************************************************************************/
enum EInstanceTrackerAllowKeyCollisions
{
- LLInstanceTrackerErrorOnCollision,
- LLInstanceTrackerReplaceOnCollision
+ LLInstanceTrackerErrorOnCollision,
+ LLInstanceTrackerReplaceOnCollision
};
+namespace LLInstanceTrackerStuff
+{
+ template <typename KEY, typename VALUE>
+ struct StaticMap: public StaticBase
+ {
+ typedef std::map<KEY, VALUE> InstanceMap;
+ InstanceMap mMap;
+ };
+} // LLInstanceTrackerStuff
+
/// This mix-in class adds support for tracking all instances of the specified class parameter T
/// The (optional) key associates a value of type KEY with a given instance of T, for quick lookup
/// If KEY is not provided, then instances are stored in a simple set
/// @NOTE: see explicit specialization below for default KEY==void case
-/// @NOTE: this class is not thread-safe unless used as read-only
-template<typename T, typename KEY = void, EInstanceTrackerAllowKeyCollisions KEY_COLLISION_BEHAVIOR = LLInstanceTrackerErrorOnCollision>
-class LLInstanceTracker : public LLInstanceTrackerBase
+template<typename T, typename KEY = void,
+ EInstanceTrackerAllowKeyCollisions KEY_COLLISION_BEHAVIOR = LLInstanceTrackerErrorOnCollision>
+class LLInstanceTracker :
+ public LLInstanceTrackerBase<LLInstanceTrackerStuff::StaticMap<KEY, std::shared_ptr<T>>>
{
- typedef LLInstanceTracker<T, KEY> self_t;
- typedef typename std::multimap<KEY, T*> InstanceMap;
- struct StaticData: public StaticBase
- {
- InstanceMap sMap;
- };
- static StaticData& getStatic() { static StaticData sData; return sData;}
- static InstanceMap& getMap_() { return getStatic().sMap; }
+ typedef LLInstanceTrackerBase<LLInstanceTrackerStuff::StaticMap<KEY, std::shared_ptr<T>>> super;
+ using typename super::StaticData;
+ using typename super::LockStatic;
+ typedef typename StaticData::InstanceMap InstanceMap;
public:
- class instance_iter : public boost::iterator_facade<instance_iter, T, boost::forward_traversal_tag>
- {
- public:
- typedef boost::iterator_facade<instance_iter, T, boost::forward_traversal_tag> super_t;
-
- instance_iter(const typename InstanceMap::iterator& it)
- : mIterator(it)
- {
- getStatic().incrementDepth();
- }
-
- ~instance_iter()
- {
- getStatic().decrementDepth();
- }
-
-
- private:
- friend class boost::iterator_core_access;
-
- void increment() { mIterator++; }
- bool equal(instance_iter const& other) const
- {
- return mIterator == other.mIterator;
- }
-
- T& dereference() const
- {
- return *(mIterator->second);
- }
-
- typename InstanceMap::iterator mIterator;
- };
-
- class key_iter : public boost::iterator_facade<key_iter, KEY, boost::forward_traversal_tag>
- {
- public:
- typedef boost::iterator_facade<key_iter, KEY, boost::forward_traversal_tag> super_t;
-
- key_iter(typename InstanceMap::iterator it)
- : mIterator(it)
- {
- getStatic().incrementDepth();
- }
-
- key_iter(const key_iter& other)
- : mIterator(other.mIterator)
- {
- getStatic().incrementDepth();
- }
-
- ~key_iter()
- {
- getStatic().decrementDepth();
- }
-
-
- private:
- friend class boost::iterator_core_access;
-
- void increment() { mIterator++; }
- bool equal(key_iter const& other) const
- {
- return mIterator == other.mIterator;
- }
-
- KEY& dereference() const
- {
- return const_cast<KEY&>(mIterator->first);
- }
-
- typename InstanceMap::iterator mIterator;
- };
-
- static T* getInstance(const KEY& k)
- {
- const InstanceMap& map(getMap_());
- typename InstanceMap::const_iterator found = map.find(k);
- return (found == map.end()) ? NULL : found->second;
- }
-
- static instance_iter beginInstances()
- {
- return instance_iter(getMap_().begin());
- }
-
- static instance_iter endInstances()
- {
- return instance_iter(getMap_().end());
- }
-
- static S32 instanceCount()
- {
- return getMap_().size();
- }
-
- static key_iter beginKeys()
- {
- return key_iter(getMap_().begin());
- }
- static key_iter endKeys()
- {
- return key_iter(getMap_().end());
- }
+ // snapshot of std::pair<const KEY, std::shared_ptr<T>> pairs
+ class snapshot
+ {
+ // It's very important that what we store in this snapshot are
+ // weak_ptrs, NOT shared_ptrs. That's how we discover whether any
+ // instance has been deleted during the lifespan of a snapshot.
+ typedef std::vector<std::pair<const KEY, std::weak_ptr<T>>> VectorType;
+ // Dereferencing our iterator produces a std::shared_ptr for each
+ // instance that still exists. Since we store weak_ptrs, that involves
+ // two chained transformations:
+ // - a transform_iterator to lock the weak_ptr and return a shared_ptr
+ // - a filter_iterator to skip any shared_ptr that has become invalid.
+ // It is very important that we filter lazily, that is, during
+ // traversal. Any one of our stored weak_ptrs might expire during
+ // traversal.
+ typedef std::pair<const KEY, std::shared_ptr<T>> strong_pair;
+ // Note for future reference: nat has not yet had any luck (up to
+ // Boost 1.67) trying to use boost::transform_iterator with a hand-
+ // coded functor, only with actual functions. In my experience, an
+ // internal boost::result_of() operation fails, even with an explicit
+ // result_type typedef. But this works.
+ static strong_pair strengthen(typename VectorType::value_type& pair)
+ {
+ return { pair.first, pair.second.lock() };
+ }
+ static bool dead_skipper(const strong_pair& pair)
+ {
+ return bool(pair.second);
+ }
+
+ public:
+ snapshot():
+ // populate our vector with a snapshot of (locked!) InstanceMap
+ // note, this assigns pair<KEY, shared_ptr> to pair<KEY, weak_ptr>
+ mData(mLock->mMap.begin(), mLock->mMap.end())
+ {
+ // release the lock once we've populated mData
+ mLock.unlock();
+ }
+
+ // You can't make a transform_iterator (or anything else) that
+ // literally stores a C++ function (decltype(strengthen)) -- but you
+ // can make a transform_iterator based on a _function pointer._
+ typedef boost::transform_iterator<decltype(strengthen)*,
+ typename VectorType::iterator> strong_iterator;
+ typedef boost::filter_iterator<decltype(dead_skipper)*, strong_iterator> iterator;
+
+ iterator begin() { return make_iterator(mData.begin()); }
+ iterator end() { return make_iterator(mData.end()); }
+
+ private:
+ iterator make_iterator(typename VectorType::iterator iter)
+ {
+ // transform_iterator only needs the base iterator and the transform.
+ // filter_iterator wants the predicate and both ends of the range.
+ return iterator(dead_skipper,
+ strong_iterator(iter, strengthen),
+ strong_iterator(mData.end(), strengthen));
+ }
+
+ LockStatic mLock; // lock static data during construction
+ VectorType mData;
+ };
+
+ // iterate over this for references to each instance
+ class instance_snapshot: public snapshot
+ {
+ private:
+ static T& instance_getter(typename snapshot::iterator::reference pair)
+ {
+ return *pair.second;
+ }
+ public:
+ typedef boost::transform_iterator<decltype(instance_getter)*,
+ typename snapshot::iterator> iterator;
+ iterator begin() { return iterator(snapshot::begin(), instance_getter); }
+ iterator end() { return iterator(snapshot::end(), instance_getter); }
+
+ void deleteAll()
+ {
+ for (auto it(snapshot::begin()), end(snapshot::end()); it != end; ++it)
+ {
+ delete it->second.get();
+ }
+ }
+ };
+
+ // iterate over this for each key
+ class key_snapshot: public snapshot
+ {
+ private:
+ static KEY key_getter(typename snapshot::iterator::reference pair)
+ {
+ return pair.first;
+ }
+ public:
+ typedef boost::transform_iterator<decltype(key_getter)*,
+ typename snapshot::iterator> iterator;
+ iterator begin() { return iterator(snapshot::begin(), key_getter); }
+ iterator end() { return iterator(snapshot::end(), key_getter); }
+ };
+
+ static T* getInstance(const KEY& k)
+ {
+ LockStatic lock;
+ const InstanceMap& map(lock->mMap);
+ typename InstanceMap::const_iterator found = map.find(k);
+ return (found == map.end()) ? NULL : found->second.get();
+ }
+
+ static S32 instanceCount()
+ {
+ return LockStatic()->mMap.size();
+ }
protected:
- LLInstanceTracker(const KEY& key)
- {
- // make sure static data outlives all instances
- getStatic();
- add_(key);
- }
- virtual ~LLInstanceTracker() LLINSTANCETRACKER_DTOR_NOEXCEPT
- {
- // it's unsafe to delete instances of this type while all instances are being iterated over.
- llassert_always(getStatic().getDepth() == 0);
- remove_();
- }
- virtual void setKey(KEY key) { remove_(); add_(key); }
- virtual const KEY& getKey() const { return mInstanceKey; }
+ LLInstanceTracker(const KEY& key)
+ {
+ // We do not intend to manage the lifespan of this object with
+ // shared_ptr, so give it a no-op deleter. We store shared_ptrs in our
+ // InstanceMap specifically so snapshot can store weak_ptrs so we can
+ // detect deletions during traversals.
+ std::shared_ptr<T> ptr(static_cast<T*>(this), [](T*){});
+ LockStatic lock;
+ add_(lock, key, ptr);
+ }
+public:
+ virtual ~LLInstanceTracker()
+ {
+ LockStatic lock;
+ remove_(lock);
+ }
+protected:
+ virtual void setKey(KEY key)
+ {
+ LockStatic lock;
+ // Even though the shared_ptr we store in our map has a no-op deleter
+ // for T itself, letting the use count decrement to 0 will still
+ // delete the use-count object. Capture the shared_ptr we just removed
+ // and re-add it to the map with the new key.
+ auto ptr = remove_(lock);
+ add_(lock, key, ptr);
+ }
+public:
+ virtual const KEY& getKey() const { return mInstanceKey; }
private:
- LLInstanceTracker( const LLInstanceTracker& );
- const LLInstanceTracker& operator=( const LLInstanceTracker& );
-
- void add_(const KEY& key)
- {
- mInstanceKey = key;
- InstanceMap& map = getMap_();
- typename InstanceMap::iterator insertion_point_it = map.lower_bound(key);
- if (insertion_point_it != map.end()
- && insertion_point_it->first == key)
- { // found existing entry with that key
- switch(KEY_COLLISION_BEHAVIOR)
- {
- case LLInstanceTrackerErrorOnCollision:
- {
- // use assert here instead of LL_ERRS(), otherwise the error will be ignored since this call is made during global object initialization
- llassert_always_msg(false, "Instance with this same key already exists!");
- break;
- }
- case LLInstanceTrackerReplaceOnCollision:
- {
- // replace pointer, but leave key (should have compared equal anyway)
- insertion_point_it->second = static_cast<T*>(this);
- break;
- }
- default:
- break;
- }
- }
- else
- { // new key
- map.insert(insertion_point_it, std::make_pair(key, static_cast<T*>(this)));
- }
- }
- void remove_()
- {
- InstanceMap& map = getMap_();
- typename InstanceMap::iterator iter = map.find(mInstanceKey);
- if (iter != map.end())
- {
- map.erase(iter);
- }
- }
+ LLInstanceTracker( const LLInstanceTracker& ) = delete;
+ LLInstanceTracker& operator=( const LLInstanceTracker& ) = delete;
+
+ // for logging
+ template <typename K>
+ static K report(K key) { return key; }
+ static std::string report(const std::string& key) { return "'" + key + "'"; }
+ static std::string report(const char* key) { return report(std::string(key)); }
+
+ // caller must instantiate LockStatic
+ void add_(LockStatic& lock, const KEY& key, const std::shared_ptr<T>& ptr)
+ {
+ mInstanceKey = key;
+ InstanceMap& map = lock->mMap;
+ switch(KEY_COLLISION_BEHAVIOR)
+ {
+ case LLInstanceTrackerErrorOnCollision:
+ {
+ // map stores shared_ptr to self
+ auto pair = map.emplace(key, ptr);
+ if (! pair.second)
+ {
+ LL_ERRS("LLInstanceTracker") << "Instance with key " << report(key)
+ << " already exists!" << LL_ENDL;
+ }
+ break;
+ }
+ case LLInstanceTrackerReplaceOnCollision:
+ map[key] = ptr;
+ break;
+ default:
+ break;
+ }
+ }
+ std::shared_ptr<T> remove_(LockStatic& lock)
+ {
+ InstanceMap& map = lock->mMap;
+ typename InstanceMap::iterator iter = map.find(mInstanceKey);
+ if (iter != map.end())
+ {
+ auto ret = iter->second;
+ map.erase(iter);
+ return ret;
+ }
+ return {};
+ }
private:
- KEY mInstanceKey;
+ KEY mInstanceKey;
};
+/*****************************************************************************
+* LLInstanceTracker without key
+*****************************************************************************/
+namespace LLInstanceTrackerStuff
+{
+ template <typename VALUE>
+ struct StaticSet: public StaticBase
+ {
+ typedef std::set<VALUE> InstanceSet;
+ InstanceSet mSet;
+ };
+} // LLInstanceTrackerStuff
+
+// TODO:
+// - For the case of omitted KEY template parameter, consider storing
+// std::map<T*, std::shared_ptr<T>> instead of std::set<std::shared_ptr<T>>.
+// That might let us share more of the implementation between KEY and
+// non-KEY LLInstanceTracker subclasses.
+// - Even if not that, consider trying to unify the snapshot implementations.
+// The trouble is that the 'iterator' published by each (and by their
+// subclasses) must reflect the specific type of the callables that
+// distinguish them. (Maybe make instance_snapshot() and key_snapshot()
+// factory functions that pass lambdas to a factory function for the generic
+// template class?)
+
/// explicit specialization for default case where KEY is void
/// use a simple std::set<T*>
template<typename T, EInstanceTrackerAllowKeyCollisions KEY_COLLISION_BEHAVIOR>
-class LLInstanceTracker<T, void, KEY_COLLISION_BEHAVIOR> : public LLInstanceTrackerBase
+class LLInstanceTracker<T, void, KEY_COLLISION_BEHAVIOR> :
+ public LLInstanceTrackerBase<LLInstanceTrackerStuff::StaticSet<std::shared_ptr<T>>>
{
- typedef LLInstanceTracker<T, void> self_t;
- typedef typename std::set<T*> InstanceSet;
- struct StaticData: public StaticBase
- {
- InstanceSet sSet;
- };
- static StaticData& getStatic() { static StaticData sData; return sData; }
- static InstanceSet& getSet_() { return getStatic().sSet; }
+ typedef LLInstanceTrackerBase<LLInstanceTrackerStuff::StaticSet<std::shared_ptr<T>>> super;
+ using typename super::StaticData;
+ using typename super::LockStatic;
+ typedef typename StaticData::InstanceSet InstanceSet;
public:
+ /**
+ * Storing a dumb T* somewhere external is a bad idea, since
+ * LLInstanceTracker subclasses are explicitly destroyed rather than
+ * managed by smart pointers. It's legal to declare stack instances of an
+ * LLInstanceTracker subclass. But it's reasonable to store a
+ * std::weak_ptr<T>, which will become invalid when the T instance is
+ * destroyed.
+ */
+ std::weak_ptr<T> getWeak()
+ {
+ return mSelf;
+ }
+
+ static S32 instanceCount() { return LockStatic()->mSet.size(); }
- /**
- * Does a particular instance still exist? Of course, if you already have
- * a T* in hand, you need not call getInstance() to @em locate the
- * instance -- unlike the case where getInstance() accepts some kind of
- * key. Nonetheless this method is still useful to @em validate a
- * particular T*, since each instance's destructor removes itself from the
- * underlying set.
- */
- static T* getInstance(T* k)
- {
- const InstanceSet& set(getSet_());
- typename InstanceSet::const_iterator found = set.find(k);
- return (found == set.end())? NULL : *found;
- }
- static S32 instanceCount() { return getSet_().size(); }
-
- class instance_iter : public boost::iterator_facade<instance_iter, T, boost::forward_traversal_tag>
- {
- public:
- instance_iter(const typename InstanceSet::iterator& it)
- : mIterator(it)
- {
- getStatic().incrementDepth();
- }
-
- instance_iter(const instance_iter& other)
- : mIterator(other.mIterator)
- {
- getStatic().incrementDepth();
- }
-
- ~instance_iter()
- {
- getStatic().decrementDepth();
- }
-
- private:
- friend class boost::iterator_core_access;
-
- void increment() { mIterator++; }
- bool equal(instance_iter const& other) const
- {
- return mIterator == other.mIterator;
- }
-
- T& dereference() const
- {
- return **mIterator;
- }
-
- typename InstanceSet::iterator mIterator;
- };
-
- static instance_iter beginInstances() { return instance_iter(getSet_().begin()); }
- static instance_iter endInstances() { return instance_iter(getSet_().end()); }
+ // snapshot of std::shared_ptr<T> pointers
+ class snapshot
+ {
+ // It's very important that what we store in this snapshot are
+ // weak_ptrs, NOT shared_ptrs. That's how we discover whether any
+ // instance has been deleted during the lifespan of a snapshot.
+ typedef std::vector<std::weak_ptr<T>> VectorType;
+ // Dereferencing our iterator produces a std::shared_ptr for each
+ // instance that still exists. Since we store weak_ptrs, that involves
+ // two chained transformations:
+ // - a transform_iterator to lock the weak_ptr and return a shared_ptr
+ // - a filter_iterator to skip any shared_ptr that has become invalid.
+ typedef std::shared_ptr<T> strong_ptr;
+ static strong_ptr strengthen(typename VectorType::value_type& ptr)
+ {
+ return ptr.lock();
+ }
+ static bool dead_skipper(const strong_ptr& ptr)
+ {
+ return bool(ptr);
+ }
+
+ public:
+ snapshot():
+ // populate our vector with a snapshot of (locked!) InstanceSet
+ // note, this assigns stored shared_ptrs to weak_ptrs for snapshot
+ mData(mLock->mSet.begin(), mLock->mSet.end())
+ {
+ // release the lock once we've populated mData
+ mLock.unlock();
+ }
+
+ typedef boost::transform_iterator<decltype(strengthen)*,
+ typename VectorType::iterator> strong_iterator;
+ typedef boost::filter_iterator<decltype(dead_skipper)*, strong_iterator> iterator;
+
+ iterator begin() { return make_iterator(mData.begin()); }
+ iterator end() { return make_iterator(mData.end()); }
+
+ private:
+ iterator make_iterator(typename VectorType::iterator iter)
+ {
+ // transform_iterator only needs the base iterator and the transform.
+ // filter_iterator wants the predicate and both ends of the range.
+ return iterator(dead_skipper,
+ strong_iterator(iter, strengthen),
+ strong_iterator(mData.end(), strengthen));
+ }
+
+ LockStatic mLock; // lock static data during construction
+ VectorType mData;
+ };
+
+ // iterate over this for references to each instance
+ struct instance_snapshot: public snapshot
+ {
+ typedef boost::indirect_iterator<typename snapshot::iterator> iterator;
+ iterator begin() { return iterator(snapshot::begin()); }
+ iterator end() { return iterator(snapshot::end()); }
+
+ void deleteAll()
+ {
+ for (auto it(snapshot::begin()), end(snapshot::end()); it != end; ++it)
+ {
+ delete it->get();
+ }
+ }
+ };
protected:
- LLInstanceTracker()
- {
- // make sure static data outlives all instances
- getStatic();
- getSet_().insert(static_cast<T*>(this));
- }
- virtual ~LLInstanceTracker() LLINSTANCETRACKER_DTOR_NOEXCEPT
- {
- // it's unsafe to delete instances of this type while all instances are being iterated over.
- llassert_always(getStatic().getDepth() == 0);
- getSet_().erase(static_cast<T*>(this));
- }
-
- LLInstanceTracker(const LLInstanceTracker& other)
- {
- getSet_().insert(static_cast<T*>(this));
- }
+ LLInstanceTracker()
+ {
+ // Since we do not intend for this shared_ptr to manage lifespan, give
+ // it a no-op deleter.
+ std::shared_ptr<T> ptr(static_cast<T*>(this), [](T*){});
+ // save corresponding weak_ptr for future reference
+ mSelf = ptr;
+ // Also store it in our class-static set to track this instance.
+ LockStatic()->mSet.emplace(ptr);
+ }
+public:
+ virtual ~LLInstanceTracker()
+ {
+ // convert weak_ptr to shared_ptr because that's what we store in our
+ // InstanceSet
+ LockStatic()->mSet.erase(mSelf.lock());
+ }
+protected:
+ LLInstanceTracker(const LLInstanceTracker& other):
+ LLInstanceTracker()
+ {}
+
+private:
+ // Storing a weak_ptr to self is a bit like deriving from
+ // std::enable_shared_from_this(), except more explicit.
+ std::weak_ptr<T> mSelf;
};
#endif
diff --git a/indra/llcommon/llleaplistener.cpp b/indra/llcommon/llleaplistener.cpp
index fa5730f112..f50bacb1e8 100644
--- a/indra/llcommon/llleaplistener.cpp
+++ b/indra/llcommon/llleaplistener.cpp
@@ -228,13 +228,11 @@ void LLLeapListener::getAPIs(const LLSD& request) const
{
Response reply(LLSD(), request);
- for (LLEventAPI::instance_iter eai(LLEventAPI::beginInstances()),
- eaend(LLEventAPI::endInstances());
- eai != eaend; ++eai)
+ for (auto& ea : LLEventAPI::instance_snapshot())
{
LLSD info;
- info["desc"] = eai->getDesc();
- reply[eai->getName()] = info;
+ info["desc"] = ea.getDesc();
+ reply[ea.getName()] = info;
}
}
diff --git a/indra/llcommon/llthreadlocalstorage.cpp b/indra/llcommon/llthreadlocalstorage.cpp
index 8cef05caac..d8a063e8d5 100644
--- a/indra/llcommon/llthreadlocalstorage.cpp
+++ b/indra/llcommon/llthreadlocalstorage.cpp
@@ -93,11 +93,9 @@ void LLThreadLocalPointerBase::initAllThreadLocalStorage()
{
if (!sInitialized)
{
- for (LLInstanceTracker<LLThreadLocalPointerBase>::instance_iter it = beginInstances(), end_it = endInstances();
- it != end_it;
- ++it)
+ for (auto& base : instance_snapshot())
{
- (*it).initStorage();
+ base.initStorage();
}
sInitialized = true;
}
@@ -108,11 +106,9 @@ void LLThreadLocalPointerBase::destroyAllThreadLocalStorage()
{
if (sInitialized)
{
- //for (LLInstanceTracker<LLThreadLocalPointerBase>::instance_iter it = beginInstances(), end_it = endInstances();
- // it != end_it;
- // ++it)
+ //for (auto& base : instance_snapshot())
//{
- // (*it).destroyStorage();
+ // base.destroyStorage();
//}
sInitialized = false;
}
diff --git a/indra/llcommon/lltrace.h b/indra/llcommon/lltrace.h
index 79ff55b739..0d0cd6f581 100644
--- a/indra/llcommon/lltrace.h
+++ b/indra/llcommon/lltrace.h
@@ -57,7 +57,7 @@ class StatBase
{
public:
StatBase(const char* name, const char* description);
- virtual ~StatBase() LLINSTANCETRACKER_DTOR_NOEXCEPT {}
+ virtual ~StatBase() {}
virtual const char* getUnitLabel() const;
const std::string& getName() const { return mName; }
diff --git a/indra/llcommon/lltracethreadrecorder.cpp b/indra/llcommon/lltracethreadrecorder.cpp
index 181fc2f058..025dc57044 100644
--- a/indra/llcommon/lltracethreadrecorder.cpp
+++ b/indra/llcommon/lltracethreadrecorder.cpp
@@ -28,6 +28,7 @@
#include "lltracethreadrecorder.h"
#include "llfasttimer.h"
#include "lltrace.h"
+#include "llstl.h"
namespace LLTrace
{
@@ -64,16 +65,15 @@ void ThreadRecorder::init()
activate(&mThreadRecordingBuffers);
// initialize time block parent pointers
- for (BlockTimerStatHandle::instance_tracker_t::instance_iter it = BlockTimerStatHandle::instance_tracker_t::beginInstances(), end_it = BlockTimerStatHandle::instance_tracker_t::endInstances();
- it != end_it;
- ++it)
+ for (auto& base : BlockTimerStatHandle::instance_snapshot())
{
- BlockTimerStatHandle& time_block = static_cast<BlockTimerStatHandle&>(*it);
- TimeBlockTreeNode& tree_node = mTimeBlockTreeNodes[it->getIndex()];
+ // because of indirect derivation from LLInstanceTracker, have to downcast
+ BlockTimerStatHandle& time_block = static_cast<BlockTimerStatHandle&>(base);
+ TimeBlockTreeNode& tree_node = mTimeBlockTreeNodes[time_block.getIndex()];
tree_node.mBlock = &time_block;
tree_node.mParent = &root_time_block;
- it->getCurrentAccumulator().mParent = &root_time_block;
+ time_block.getCurrentAccumulator().mParent = &root_time_block;
}
mRootTimer = new BlockTimer(root_time_block);
diff --git a/indra/llcommon/tests/llinstancetracker_test.cpp b/indra/llcommon/tests/llinstancetracker_test.cpp
index d94fc0c56d..9b89159625 100644
--- a/indra/llcommon/tests/llinstancetracker_test.cpp
+++ b/indra/llcommon/tests/llinstancetracker_test.cpp
@@ -41,7 +41,6 @@
#include <boost/scoped_ptr.hpp>
// other Linden headers
#include "../test/lltut.h"
-#include "wrapllerrs.h"
struct Badness: public std::runtime_error
{
@@ -112,24 +111,22 @@ namespace tut
void object::test<2>()
{
ensure_equals(Unkeyed::instanceCount(), 0);
- Unkeyed* dangling = NULL;
+ std::weak_ptr<Unkeyed> dangling;
{
Unkeyed one;
ensure_equals(Unkeyed::instanceCount(), 1);
- Unkeyed* found = Unkeyed::getInstance(&one);
- ensure_equals(found, &one);
+ std::weak_ptr<Unkeyed> found = one.getWeak();
+ ensure(! found.expired());
{
boost::scoped_ptr<Unkeyed> two(new Unkeyed);
ensure_equals(Unkeyed::instanceCount(), 2);
- Unkeyed* found = Unkeyed::getInstance(two.get());
- ensure_equals(found, two.get());
}
ensure_equals(Unkeyed::instanceCount(), 1);
- // store an unwise pointer to a temp Unkeyed instance
- dangling = &one;
+ // store a weak pointer to a temp Unkeyed instance
+ dangling = found;
} // make that instance vanish
// check the now-invalid pointer to the destroyed instance
- ensure("getInstance(T*) failed to track destruction", ! Unkeyed::getInstance(dangling));
+ ensure("weak_ptr<Unkeyed> failed to track destruction", dangling.expired());
ensure_equals(Unkeyed::instanceCount(), 0);
}
@@ -142,7 +139,8 @@ namespace tut
// reimplement LLInstanceTracker using, say, a hash map instead of a
// std::map. We DO insist that every key appear exactly once.
typedef std::vector<std::string> StringVector;
- StringVector keys(Keyed::beginKeys(), Keyed::endKeys());
+ auto snap = Keyed::key_snapshot();
+ StringVector keys(snap.begin(), snap.end());
std::sort(keys.begin(), keys.end());
StringVector::const_iterator ki(keys.begin());
ensure_equals(*ki++, "one");
@@ -153,17 +151,15 @@ namespace tut
ensure("didn't reach end", ki == keys.end());
// Use a somewhat different approach to order independence with
- // beginInstances(): explicitly capture the instances we know in a
+ // instance_snapshot(): explicitly capture the instances we know in a
// set, and delete them as we iterate through.
typedef std::set<Keyed*> InstanceSet;
InstanceSet instances;
instances.insert(&one);
instances.insert(&two);
instances.insert(&three);
- for (Keyed::instance_iter ii(Keyed::beginInstances()), iend(Keyed::endInstances());
- ii != iend; ++ii)
+ for (auto& ref : Keyed::instance_snapshot())
{
- Keyed& ref = *ii;
ensure_equals("spurious instance", instances.erase(&ref), 1);
}
ensure_equals("unreported instance", instances.size(), 0);
@@ -180,11 +176,10 @@ namespace tut
instances.insert(&two);
instances.insert(&three);
- for (Unkeyed::instance_iter ii(Unkeyed::beginInstances()), iend(Unkeyed::endInstances()); ii != iend; ++ii)
- {
- Unkeyed& ref = *ii;
- ensure_equals("spurious instance", instances.erase(&ref), 1);
- }
+ for (auto& ref : Unkeyed::instance_snapshot())
+ {
+ ensure_equals("spurious instance", instances.erase(&ref), 1);
+ }
ensure_equals("unreported instance", instances.size(), 0);
}
@@ -192,49 +187,49 @@ namespace tut
template<> template<>
void object::test<5>()
{
- set_test_name("delete Keyed with outstanding instance_iter");
- std::string what;
- Keyed* keyed = new Keyed("delete Keyed with outstanding instance_iter");
- {
- WrapLLErrs wrapper;
- Keyed::instance_iter i(Keyed::beginInstances());
- what = wrapper.catch_llerrs([&keyed](){
- delete keyed;
- });
- }
- ensure(! what.empty());
+ std::string desc("delete Keyed with outstanding instance_snapshot");
+ set_test_name(desc);
+ Keyed* keyed = new Keyed(desc);
+ // capture a snapshot but do not yet traverse it
+ auto snapshot = Keyed::instance_snapshot();
+ // delete the one instance
+ delete keyed;
+ // traversing the snapshot should reflect the deletion
+ // avoid ensure_equals() because it requires the ability to stream the
+ // two values to std::ostream
+ ensure(snapshot.begin() == snapshot.end());
}
template<> template<>
void object::test<6>()
{
- set_test_name("delete Keyed with outstanding key_iter");
- std::string what;
- Keyed* keyed = new Keyed("delete Keyed with outstanding key_it");
- {
- WrapLLErrs wrapper;
- Keyed::key_iter i(Keyed::beginKeys());
- what = wrapper.catch_llerrs([&keyed](){
- delete keyed;
- });
- }
- ensure(! what.empty());
+ std::string desc("delete Keyed with outstanding key_snapshot");
+ set_test_name(desc);
+ Keyed* keyed = new Keyed(desc);
+ // capture a snapshot but do not yet traverse it
+ auto snapshot = Keyed::key_snapshot();
+ // delete the one instance
+ delete keyed;
+ // traversing the snapshot should reflect the deletion
+ // avoid ensure_equals() because it requires the ability to stream the
+ // two values to std::ostream
+ ensure(snapshot.begin() == snapshot.end());
}
template<> template<>
void object::test<7>()
{
- set_test_name("delete Unkeyed with outstanding instance_iter");
+ set_test_name("delete Unkeyed with outstanding instance_snapshot");
std::string what;
Unkeyed* unkeyed = new Unkeyed;
- {
- WrapLLErrs wrapper;
- Unkeyed::instance_iter i(Unkeyed::beginInstances());
- what = wrapper.catch_llerrs([&unkeyed](){
- delete unkeyed;
- });
- }
- ensure(! what.empty());
+ // capture a snapshot but do not yet traverse it
+ auto snapshot = Unkeyed::instance_snapshot();
+ // delete the one instance
+ delete unkeyed;
+ // traversing the snapshot should reflect the deletion
+ // avoid ensure_equals() because it requires the ability to stream the
+ // two values to std::ostream
+ ensure(snapshot.begin() == snapshot.end());
}
template<> template<>
@@ -246,11 +241,9 @@ namespace tut
// We can't use the iterator-range InstanceSet constructor because
// beginInstances() returns an iterator that dereferences to an
// Unkeyed&, not an Unkeyed*.
- for (Unkeyed::instance_iter uki(Unkeyed::beginInstances()),
- ukend(Unkeyed::endInstances());
- uki != ukend; ++uki)
+ for (auto& ref : Unkeyed::instance_snapshot())
{
- existing.insert(&*uki);
+ existing.insert(&ref);
}
try
{
@@ -273,11 +266,9 @@ namespace tut
// instances was also present in the original set. If that's not true,
// it's because our new Unkeyed ended up in the updated set despite
// its constructor exception.
- for (Unkeyed::instance_iter uki(Unkeyed::beginInstances()),
- ukend(Unkeyed::endInstances());
- uki != ukend; ++uki)
+ for (auto& ref : Unkeyed::instance_snapshot())
{
- ensure("failed to remove instance", existing.find(&*uki) != existing.end());
+ ensure("failed to remove instance", existing.find(&ref) != existing.end());
}
}
} // namespace tut
diff --git a/indra/llcommon/tests/llleap_test.cpp b/indra/llcommon/tests/llleap_test.cpp
index bf0a74d10d..9d71e327d8 100644
--- a/indra/llcommon/tests/llleap_test.cpp
+++ b/indra/llcommon/tests/llleap_test.cpp
@@ -49,24 +49,28 @@ const size_t BUFFERED_LENGTH = 1023*1024; // try wrangling just under a megabyte
#endif
-void waitfor(const std::vector<LLLeap*>& instances, int timeout=60)
+// capture std::weak_ptrs to LLLeap instances so we can tell when they expire
+typedef std::vector<std::weak_ptr<LLLeap>> LLLeapVector;
+
+void waitfor(const LLLeapVector& instances, int timeout=60)
{
int i;
for (i = 0; i < timeout; ++i)
{
// Every iteration, test whether any of the passed LLLeap instances
// still exist (are still running).
- std::vector<LLLeap*>::const_iterator vli(instances.begin()), vlend(instances.end());
- for ( ; vli != vlend; ++vli)
+ bool found = false;
+ for (auto& ptr : instances)
{
- // getInstance() returns NULL if it's terminated/gone, non-NULL if
- // it's still running
- if (LLLeap::getInstance(*vli))
+ if (! ptr.expired())
+ {
+ found = true;
break;
+ }
}
// If we made it through all of 'instances' without finding one that's
// still running, we're done.
- if (vli == vlend)
+ if (! found)
{
/*==========================================================================*|
std::cout << instances.size() << " LLLeap instances terminated in "
@@ -86,8 +90,8 @@ void waitfor(const std::vector<LLLeap*>& instances, int timeout=60)
void waitfor(LLLeap* instance, int timeout=60)
{
- std::vector<LLLeap*> instances;
- instances.push_back(instance);
+ LLLeapVector instances;
+ instances.push_back(instance->getWeak());
waitfor(instances, timeout);
}
@@ -218,11 +222,11 @@ namespace tut
NamedTempFile script("py",
"import time\n"
"time.sleep(1)\n");
- std::vector<LLLeap*> instances;
+ LLLeapVector instances;
instances.push_back(LLLeap::create(get_test_name(),
- sv(list_of(PYTHON)(script.getName()))));
+ sv(list_of(PYTHON)(script.getName())))->getWeak());
instances.push_back(LLLeap::create(get_test_name(),
- sv(list_of(PYTHON)(script.getName()))));
+ sv(list_of(PYTHON)(script.getName())))->getWeak());
// In this case we're simply establishing that two LLLeap instances
// can coexist without throwing exceptions or bombing in any other
// way. Wait for them to terminate.
diff --git a/indra/llrender/llgl.cpp b/indra/llrender/llgl.cpp
index c0f0cec80b..a24de45fde 100644
--- a/indra/llrender/llgl.cpp
+++ b/indra/llrender/llgl.cpp
@@ -2376,9 +2376,8 @@ void LLGLNamePool::release(GLuint name)
//static
void LLGLNamePool::upkeepPools()
{
- for (tracker_t::instance_iter iter = beginInstances(); iter != endInstances(); ++iter)
+ for (auto& pool : instance_snapshot())
{
- LLGLNamePool & pool = *iter;
pool.upkeep();
}
}
@@ -2386,9 +2385,8 @@ void LLGLNamePool::upkeepPools()
//static
void LLGLNamePool::cleanupPools()
{
- for (tracker_t::instance_iter iter = beginInstances(); iter != endInstances(); ++iter)
+ for (auto& pool : instance_snapshot())
{
- LLGLNamePool & pool = *iter;
pool.cleanup();
}
}
diff --git a/indra/llui/llconsole.cpp b/indra/llui/llconsole.cpp
index 5f50e46233..7817d99aef 100644
--- a/indra/llui/llconsole.cpp
+++ b/indra/llui/llconsole.cpp
@@ -369,9 +369,9 @@ LLConsole::Paragraph::Paragraph (LLWString str, const LLColor4 &color, F32 add_t
// static
void LLConsole::updateClass()
{
- for (instance_iter it = beginInstances(); it != endInstances(); ++it)
+ for (auto& con : instance_snapshot())
{
- it->update();
+ con.update();
}
}
diff --git a/indra/llui/lllayoutstack.cpp b/indra/llui/lllayoutstack.cpp
index 4a464b3507..4aae1e374b 100644
--- a/indra/llui/lllayoutstack.cpp
+++ b/indra/llui/lllayoutstack.cpp
@@ -636,10 +636,10 @@ void LLLayoutStack::createResizeBar(LLLayoutPanel* panelp)
//static
void LLLayoutStack::updateClass()
{
- for (instance_iter it = beginInstances(); it != endInstances(); ++it)
+ for (auto& layout : instance_snapshot())
{
- it->updateLayout();
- it->mAnimatedThisFrame = false;
+ layout.updateLayout();
+ layout.mAnimatedThisFrame = false;
}
}
diff --git a/indra/llui/llnotificationslistener.cpp b/indra/llui/llnotificationslistener.cpp
index be26416cbb..e73ba1fbe9 100644
--- a/indra/llui/llnotificationslistener.cpp
+++ b/indra/llui/llnotificationslistener.cpp
@@ -127,18 +127,16 @@ void LLNotificationsListener::listChannels(const LLSD& params) const
{
LLReqID reqID(params);
LLSD response(reqID.makeResponse());
- for (LLNotificationChannel::instance_iter cmi(LLNotificationChannel::beginInstances()),
- cmend(LLNotificationChannel::endInstances());
- cmi != cmend; ++cmi)
+ for (auto& cm : LLNotificationChannel::instance_snapshot())
{
LLSD channelInfo, parents;
- BOOST_FOREACH(const std::string& parent, cmi->getParents())
+ for (const std::string& parent : cm.getParents())
{
parents.append(parent);
}
channelInfo["parents"] = parents;
channelInfo["parent"] = parents.size()? parents[0] : "";
- response[cmi->getName()] = channelInfo;
+ response[cm.getName()] = channelInfo;
}
LLEventPumps::instance().obtain(params["reply"]).post(response);
}
diff --git a/indra/llwindow/llwindow.cpp b/indra/llwindow/llwindow.cpp
index 1b24250618..40e297bac1 100644
--- a/indra/llwindow/llwindow.cpp
+++ b/indra/llwindow/llwindow.cpp
@@ -457,9 +457,9 @@ LLCoordCommon LL_COORD_TYPE_WINDOW::convertToCommon() const
{
const LLCoordWindow& self = LLCoordWindow::getTypedCoords(*this);
- LLWindow* windowp = &(*LLWindow::beginInstances());
+ auto windowit = LLWindow::instance_snapshot().begin();
LLCoordGL out;
- windowp->convertCoords(self, &out);
+ windowit->convertCoords(self, &out);
return out.convert();
}
@@ -467,18 +467,18 @@ void LL_COORD_TYPE_WINDOW::convertFromCommon(const LLCoordCommon& from)
{
LLCoordWindow& self = LLCoordWindow::getTypedCoords(*this);
- LLWindow* windowp = &(*LLWindow::beginInstances());
+ auto windowit = LLWindow::instance_snapshot().begin();
LLCoordGL from_gl(from);
- windowp->convertCoords(from_gl, &self);
+ windowit->convertCoords(from_gl, &self);
}
LLCoordCommon LL_COORD_TYPE_SCREEN::convertToCommon() const
{
const LLCoordScreen& self = LLCoordScreen::getTypedCoords(*this);
- LLWindow* windowp = &(*LLWindow::beginInstances());
+ auto windowit = LLWindow::instance_snapshot().begin();
LLCoordGL out;
- windowp->convertCoords(self, &out);
+ windowit->convertCoords(self, &out);
return out.convert();
}
@@ -486,7 +486,7 @@ void LL_COORD_TYPE_SCREEN::convertFromCommon(const LLCoordCommon& from)
{
LLCoordScreen& self = LLCoordScreen::getTypedCoords(*this);
- LLWindow* windowp = &(*LLWindow::beginInstances());
+ auto windowit = LLWindow::instance_snapshot().begin();
LLCoordGL from_gl(from);
- windowp->convertCoords(from_gl, &self);
+ windowit->convertCoords(from_gl, &self);
}
diff --git a/indra/llxml/llcontrol.h b/indra/llxml/llcontrol.h
index de0d366492..39e1d3e615 100644
--- a/indra/llxml/llcontrol.h
+++ b/indra/llxml/llcontrol.h
@@ -200,8 +200,6 @@ public:
LLControlGroup(const std::string& name);
~LLControlGroup();
void cleanup();
-
- typedef LLInstanceTracker<LLControlGroup, std::string>::instance_iter instance_iter;
LLControlVariablePtr getControl(const std::string& name);
diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp
index b232a8c3bb..a76ac58724 100644
--- a/indra/newview/llappviewer.cpp
+++ b/indra/newview/llappviewer.cpp
@@ -1681,24 +1681,9 @@ bool LLAppViewer::cleanup()
gDirUtilp->deleteFilesInDir(logdir, "*-*-*-*-*.dmp");
}
- {
- // Kill off LLLeap objects. We can find them all because LLLeap is derived
- // from LLInstanceTracker. But collect instances first: LLInstanceTracker
- // specifically forbids adding/deleting instances while iterating.
- std::vector<LLLeap*> leaps;
- leaps.reserve(LLLeap::instanceCount());
- for (LLLeap::instance_iter li(LLLeap::beginInstances()), lend(LLLeap::endInstances());
- li != lend; ++li)
- {
- leaps.push_back(&*li);
- }
- // Okay, now trash them all. We don't have to NULL or erase the entry
- // in 'leaps' because the whole vector is going away momentarily.
- BOOST_FOREACH(LLLeap* leap, leaps)
- {
- delete leap;
- }
- } // destroy 'leaps'
+ // Kill off LLLeap objects. We can find them all because LLLeap is derived
+ // from LLInstanceTracker.
+ LLLeap::instance_snapshot().deleteAll();
//flag all elements as needing to be destroyed immediately
// to ensure shutdown order
@@ -2858,12 +2843,11 @@ bool LLAppViewer::initConfiguration()
// Let anyone else who cares know that we've populated our settings
// variables.
- for (LLControlGroup::key_iter ki(LLControlGroup::beginKeys()), kend(LLControlGroup::endKeys());
- ki != kend; ++ki)
+ for (const auto& key : LLControlGroup::key_snapshot())
{
// For each named instance of LLControlGroup, send an event saying
// we've initialized an LLControlGroup instance by that name.
- LLEventPumps::instance().obtain("LLControlGroup").post(LLSDMap("init", *ki));
+ LLEventPumps::instance().obtain("LLControlGroup").post(LLSDMap("init", key));
}
return true; // Config was successful.
diff --git a/indra/newview/llchathistory.cpp b/indra/newview/llchathistory.cpp
index 1099d4bc09..4131af828e 100644
--- a/indra/newview/llchathistory.cpp
+++ b/indra/newview/llchathistory.cpp
@@ -1344,10 +1344,8 @@ void LLChatHistory::appendMessage(const LLChat& chat, const LLSD &args, const LL
// We don't want multiple friendship offers to appear, this code checks if there are previous offers
// by iterating though all panels.
// Note: it might be better to simply add a "pending offer" flag somewhere
- for (LLToastNotifyPanel::instance_iter ti(LLToastNotifyPanel::beginInstances())
- , tend(LLToastNotifyPanel::endInstances()); ti != tend; ++ti)
+ for (auto& panel : LLToastNotifyPanel::instance_snapshot())
{
- LLToastNotifyPanel& panel = *ti;
LLIMToastNotifyPanel * imtoastp = dynamic_cast<LLIMToastNotifyPanel *>(&panel);
const std::string& notification_name = panel.getNotificationName();
if (notification_name == "OfferFriendship"
diff --git a/indra/newview/llimprocessing.cpp b/indra/newview/llimprocessing.cpp
index c3375a3779..c1dcc61010 100644
--- a/indra/newview/llimprocessing.cpp
+++ b/indra/newview/llimprocessing.cpp
@@ -1404,10 +1404,8 @@ void LLIMProcessing::processNewMessage(LLUUID from_id,
payload["sender"] = sender.getIPandPort();
bool add_notification = true;
- for (LLToastNotifyPanel::instance_iter ti(LLToastNotifyPanel::beginInstances())
- , tend(LLToastNotifyPanel::endInstances()); ti != tend; ++ti)
+ for (auto& panel : LLToastNotifyPanel::instance_snapshot())
{
- LLToastNotifyPanel& panel = *ti;
const std::string& notification_name = panel.getNotificationName();
if (notification_name == "OfferFriendship" && panel.isControlPanelEnabled())
{
diff --git a/indra/newview/llscenemonitor.cpp b/indra/newview/llscenemonitor.cpp
index 5ab0013055..2c0c38dc75 100644
--- a/indra/newview/llscenemonitor.cpp
+++ b/indra/newview/llscenemonitor.cpp
@@ -559,16 +559,14 @@ void LLSceneMonitor::dumpToFile(std::string file_name)
typedef StatType<CountAccumulator> trace_count;
- for (trace_count::instance_iter it = trace_count::beginInstances(), end_it = trace_count::endInstances();
- it != end_it;
- ++it)
+ for (auto& it : trace_count::instance_snapshot())
{
std::ostringstream row;
row << std::setprecision(10);
- row << it->getName();
+ row << it.getName();
- const char* unit_label = it->getUnitLabel();
+ const char* unit_label = it.getUnitLabel();
if(unit_label[0])
{
row << "(" << unit_label << ")";
@@ -579,8 +577,8 @@ void LLSceneMonitor::dumpToFile(std::string file_name)
for (S32 frame = 1; frame <= frame_count; frame++)
{
Recording& recording = scene_load_recording.getPrevRecording(frame_count - frame);
- samples += recording.getSampleCount(*it);
- row << ", " << recording.getSum(*it);
+ samples += recording.getSampleCount(it);
+ row << ", " << recording.getSum(it);
}
row << '\n';
@@ -593,15 +591,13 @@ void LLSceneMonitor::dumpToFile(std::string file_name)
typedef StatType<EventAccumulator> trace_event;
- for (trace_event::instance_iter it = trace_event::beginInstances(), end_it = trace_event::endInstances();
- it != end_it;
- ++it)
+ for (auto& it : trace_event::instance_snapshot())
{
std::ostringstream row;
row << std::setprecision(10);
- row << it->getName();
+ row << it.getName();
- const char* unit_label = it->getUnitLabel();
+ const char* unit_label = it.getUnitLabel();
if(unit_label[0])
{
row << "(" << unit_label << ")";
@@ -612,8 +608,8 @@ void LLSceneMonitor::dumpToFile(std::string file_name)
for (S32 frame = 1; frame <= frame_count; frame++)
{
Recording& recording = scene_load_recording.getPrevRecording(frame_count - frame);
- samples += recording.getSampleCount(*it);
- F64 mean = recording.getMean(*it);
+ samples += recording.getSampleCount(it);
+ F64 mean = recording.getMean(it);
if (llisnan(mean))
{
row << ", n/a";
@@ -634,15 +630,13 @@ void LLSceneMonitor::dumpToFile(std::string file_name)
typedef StatType<SampleAccumulator> trace_sample;
- for (trace_sample::instance_iter it = trace_sample::beginInstances(), end_it = trace_sample::endInstances();
- it != end_it;
- ++it)
+ for (auto& it : trace_sample::instance_snapshot())
{
std::ostringstream row;
row << std::setprecision(10);
- row << it->getName();
+ row << it.getName();
- const char* unit_label = it->getUnitLabel();
+ const char* unit_label = it.getUnitLabel();
if(unit_label[0])
{
row << "(" << unit_label << ")";
@@ -653,8 +647,8 @@ void LLSceneMonitor::dumpToFile(std::string file_name)
for (S32 frame = 1; frame <= frame_count; frame++)
{
Recording& recording = scene_load_recording.getPrevRecording(frame_count - frame);
- samples += recording.getSampleCount(*it);
- F64 mean = recording.getMean(*it);
+ samples += recording.getSampleCount(it);
+ F64 mean = recording.getMean(it);
if (llisnan(mean))
{
row << ", n/a";
@@ -674,15 +668,13 @@ void LLSceneMonitor::dumpToFile(std::string file_name)
}
typedef StatType<MemAccumulator> trace_mem;
- for (trace_mem::instance_iter it = trace_mem::beginInstances(), end_it = trace_mem::endInstances();
- it != end_it;
- ++it)
+ for (auto& it : trace_mem::instance_snapshot())
{
- os << it->getName() << "(KiB)";
+ os << it.getName() << "(KiB)";
for (S32 frame = 1; frame <= frame_count; frame++)
{
- os << ", " << scene_load_recording.getPrevRecording(frame_count - frame).getMax(*it).valueInUnits<LLUnits::Kilobytes>();
+ os << ", " << scene_load_recording.getPrevRecording(frame_count - frame).getMax(it).valueInUnits<LLUnits::Kilobytes>();
}
os << '\n';
diff --git a/indra/newview/lltoast.cpp b/indra/newview/lltoast.cpp
index 870e0d94f0..bf56a10d4d 100644
--- a/indra/newview/lltoast.cpp
+++ b/indra/newview/lltoast.cpp
@@ -612,11 +612,8 @@ S32 LLToast::notifyParent(const LLSD& info)
//static
void LLToast::updateClass()
{
- for (LLInstanceTracker<LLToast>::instance_iter iter = LLInstanceTracker<LLToast>::beginInstances();
- iter != LLInstanceTracker<LLToast>::endInstances(); )
+ for (auto& toast : LLInstanceTracker<LLToast>::instance_snapshot())
{
- LLToast& toast = *iter++;
-
toast.updateHoveredState();
}
}
@@ -624,22 +621,6 @@ void LLToast::updateClass()
// static
void LLToast::cleanupToasts()
{
- LLToast * toastp = NULL;
-
- while (LLInstanceTracker<LLToast>::instanceCount() > 0)
- {
- { // Need to scope iter to allow deletion
- LLInstanceTracker<LLToast>::instance_iter iter = LLInstanceTracker<LLToast>::beginInstances();
- toastp = &(*iter);
- }
-
- //LL_INFOS() << "Cleaning up toast id " << toastp->getNotificationID() << LL_ENDL;
-
- // LLToast destructor will remove it from the LLInstanceTracker.
- if (!toastp)
- break; // Don't get stuck in the loop if a null pointer somehow got on the list
-
- delete toastp;
- }
+ LLInstanceTracker<LLToast>::instance_snapshot().deleteAll();
}
diff --git a/indra/newview/llviewercontrollistener.cpp b/indra/newview/llviewercontrollistener.cpp
index d2484b2b23..3443bb644a 100644
--- a/indra/newview/llviewercontrollistener.cpp
+++ b/indra/newview/llviewercontrollistener.cpp
@@ -50,11 +50,9 @@ LLViewerControlListener::LLViewerControlListener()
std::ostringstream groupnames;
groupnames << "[\"group\"] is one of ";
const char* delim = "";
- for (LLControlGroup::key_iter cgki(LLControlGroup::beginKeys()),
- cgkend(LLControlGroup::endKeys());
- cgki != cgkend; ++cgki)
+ for (const auto& key : LLControlGroup::key_snapshot())
{
- groupnames << delim << '"' << *cgki << '"';
+ groupnames << delim << '"' << key << '"';
delim = ", ";
}
groupnames << '\n';
@@ -181,11 +179,9 @@ void LLViewerControlListener::groups(LLSD const & request)
{
// No Info, we're not looking up either a group or a control name.
Response response(LLSD(), request);
- for (LLControlGroup::key_iter cgki(LLControlGroup::beginKeys()),
- cgkend(LLControlGroup::endKeys());
- cgki != cgkend; ++cgki)
+ for (const auto& key : LLControlGroup::key_snapshot())
{
- response["groups"].append(*cgki);
+ response["groups"].append(key);
}
}