diff --git a/indra/llcommon/llinstancetracker.cpp b/indra/llcommon/llinstancetracker.cpp index 293a1388f..5dc3ea5d7 100644 --- a/indra/llcommon/llinstancetracker.cpp +++ b/indra/llcommon/llinstancetracker.cpp @@ -35,13 +35,15 @@ //static void * & LLInstanceTrackerBase::getInstances(std::type_info const & info) { - static std::map instances; + typedef std::map InstancesMap; + static InstancesMap instances; - std::string k = info.name(); - if(instances.find(k) == instances.end()) - { - instances[k] = NULL; - } - - return instances[k]; + // std::map::insert() is just what we want here. You attempt to insert a + // (key, value) pair. If the specified key doesn't yet exist, it inserts + // the pair and returns a std::pair of (iterator, true). If the specified + // key DOES exist, insert() simply returns (iterator, false). One lookup + // handles both cases. + return instances.insert(InstancesMap::value_type(info.name(), + InstancesMap::mapped_type())) + .first->second; } diff --git a/indra/llcommon/llinstancetracker.h b/indra/llcommon/llinstancetracker.h index 46c72455a..d0cfba406 100644 --- a/indra/llcommon/llinstancetracker.h +++ b/indra/llcommon/llinstancetracker.h @@ -36,6 +36,7 @@ #define LL_LLINSTANCETRACKER_H #include +#include #include "string_table.h" #include @@ -48,6 +49,30 @@ class LL_COMMON_API LLInstanceTrackerBase : public boost::noncopyable { protected: static void * & getInstances(std::type_info const & info); + + /// Find or create a STATICDATA instance for the specified TRACKED class. + /// STATICDATA must be default-constructible. + template + static STATICDATA& getStatic() + { + void *& instances = getInstances(typeid(TRACKED)); + if (! instances) + { + instances = new STATICDATA; + } + return *static_cast(instances); + } + + /// It's not essential to derive your STATICDATA (for use with + /// getStatic()) from StaticBase; it's just that both known + /// implementations do. + struct StaticBase + { + StaticBase(): + sIterationNestDepth(0) + {} + S32 sIterationNestDepth; + }; }; /// This mix-in class adds support for tracking all instances of the specified class parameter T @@ -57,8 +82,15 @@ class LL_COMMON_API LLInstanceTrackerBase : public boost::noncopyable template class LLInstanceTracker : public LLInstanceTrackerBase { - typedef typename std::map InstanceMap; typedef LLInstanceTracker MyT; + typedef typename std::map InstanceMap; + struct StaticData: public StaticBase + { + InstanceMap sMap; + }; + static StaticData& getStatic() { return LLInstanceTrackerBase::getStatic(); } + static InstanceMap& getMap_() { return getStatic().sMap; } + public: class instance_iter : public boost::iterator_facade { @@ -68,12 +100,12 @@ public: instance_iter(const typename InstanceMap::iterator& it) : mIterator(it) { - ++sIterationNestDepth; + ++getStatic().sIterationNestDepth; } ~instance_iter() { - --sIterationNestDepth; + --getStatic().sIterationNestDepth; } @@ -102,18 +134,18 @@ public: key_iter(typename InstanceMap::iterator it) : mIterator(it) { - ++sIterationNestDepth; + ++getStatic().sIterationNestDepth; } key_iter(const key_iter& other) : mIterator(other.mIterator) { - ++sIterationNestDepth; + ++getStatic().sIterationNestDepth; } ~key_iter() { - --sIterationNestDepth; + --getStatic().sIterationNestDepth; } @@ -166,8 +198,8 @@ protected: virtual ~LLInstanceTracker() { // it's unsafe to delete instances of this type while all instances are being iterated over. - llassert(sIterationNestDepth == 0); - remove_(); + llassert_always(getStatic().sIterationNestDepth == 0); + remove_(); } virtual void setKey(KEY key) { remove_(); add_(key); } virtual const KEY& getKey() const { return mInstanceKey; } @@ -183,31 +215,24 @@ private: getMap_().erase(mInstanceKey); } - static InstanceMap& getMap_() - { - void * & instances = getInstances(typeid(MyT)); - if (! instances) - { - instances = new InstanceMap; - } - return * static_cast(instances); - } - private: - KEY mInstanceKey; - static S32 sIterationNestDepth; }; -template S32 LLInstanceTracker::sIterationNestDepth = 0; - /// explicit specialization for default case where KEY is T* /// use a simple std::set template class LLInstanceTracker : public LLInstanceTrackerBase { - typedef typename std::set InstanceSet; typedef LLInstanceTracker MyT; + typedef typename std::set InstanceSet; + struct StaticData: public StaticBase + { + InstanceSet sSet; + }; + static StaticData& getStatic() { return LLInstanceTrackerBase::getStatic(); } + static InstanceSet& getSet_() { return getStatic().sSet; } + public: /// for completeness of analogy with the generic implementation @@ -220,18 +245,18 @@ public: instance_iter(const typename InstanceSet::iterator& it) : mIterator(it) { - ++sIterationNestDepth; + ++getStatic().sIterationNestDepth; } instance_iter(const instance_iter& other) : mIterator(other.mIterator) { - ++sIterationNestDepth; + ++getStatic().sIterationNestDepth; } ~instance_iter() { - --sIterationNestDepth; + --getStatic().sIterationNestDepth; } private: @@ -263,7 +288,7 @@ protected: virtual ~LLInstanceTracker() { // it's unsafe to delete instances of this type while all instances are being iterated over. - llassert(sIterationNestDepth == 0); + llassert_always(getStatic().sIterationNestDepth == 0); getSet_().erase(static_cast(this)); } @@ -271,20 +296,6 @@ protected: { getSet_().insert(static_cast(this)); } - - static InstanceSet& getSet_() - { - void * & instances = getInstances(typeid(MyT)); - if (! instances) - { - instances = new InstanceSet; - } - return * static_cast(instances); - } - - static S32 sIterationNestDepth; }; -template S32 LLInstanceTracker::sIterationNestDepth = 0; - #endif diff --git a/indra/llcommon/llsingleton.h b/indra/llcommon/llsingleton.h index 00757be27..49d99f2cd 100644 --- a/indra/llcommon/llsingleton.h +++ b/indra/llcommon/llsingleton.h @@ -114,8 +114,7 @@ private: ~SingletonInstanceData() { - SingletonInstanceData& data = getData(); - if (data.mInitState != DELETED) + if (mInitState != DELETED) { deleteSingleton(); } @@ -130,7 +129,26 @@ public: data.mInitState = DELETED; } - // Can be used to control when the singleton is deleted. Not normally needed. + /** + * @brief Immediately delete the singleton. + * + * A subsequent call to LLProxy::getInstance() will construct a new + * instance of the class. + * + * LLSingletons are normally destroyed after main() has exited and the C++ + * runtime is cleaning up statically-constructed objects. Some classes + * derived from LLSingleton have objects that are part of a runtime system + * that is terminated before main() exits. Calling the destructor of those + * objects after the termination of their respective systems can cause + * crashes and other problems during termination of the project. Using this + * method to destroy the singleton early can prevent these crashes. + * + * An example where this is needed is for a LLSingleton that has an APR + * object as a member that makes APR calls on destruction. The APR system is + * shut down explicitly before main() exits. This causes a crash on exit. + * Using this method before the call to apr_terminate() and NOT calling + * getInstance() again will prevent the crash. + */ static void deleteSingleton() { delete getData().mSingletonInstance;