From 1beaedacadc8093c9df612992a873f9c89354bce Mon Sep 17 00:00:00 2001
From: Richard Linden <none@none>
Date: Thu, 17 Oct 2013 14:23:56 -0700
Subject: moved root timer to global variable added flag to LLInstanceTracker
 to allow multiple values per key made StatType allow multiple values per key
 to eliminate block timer related crash

---
 indra/llcommon/llfasttimer.cpp           |  9 +++++++--
 indra/llcommon/llfasttimer.h             |  2 +-
 indra/llcommon/llinstancetracker.h       | 27 ++++++++++++++++++++++-----
 indra/llcommon/lltrace.h                 |  5 +++--
 indra/llcommon/lltracethreadrecorder.cpp |  2 +-
 5 files changed, 34 insertions(+), 11 deletions(-)

diff --git a/indra/llcommon/llfasttimer.cpp b/indra/llcommon/llfasttimer.cpp
index 2db44adacf..d97fa74c24 100755
--- a/indra/llcommon/llfasttimer.cpp
+++ b/indra/llcommon/llfasttimer.cpp
@@ -131,10 +131,10 @@ struct SortTimerByName
     }
 };
 
+static BlockTimerStatHandle sRootTimer("root", NULL);
 BlockTimerStatHandle& BlockTimerStatHandle::getRootTimeBlock()
 {
-	static BlockTimerStatHandle root_timer("root", NULL);
-	return root_timer;
+	return sRootTimer;
 }
 
 void BlockTimerStatHandle::pushLog(LLSD log)
@@ -333,6 +333,11 @@ std::vector<BlockTimerStatHandle*>& BlockTimerStatHandle::getChildren()
 	return getTreeNode().mChildren;
 }
 
+bool BlockTimerStatHandle::hasChildren()
+{
+	return ! getTreeNode().mChildren.empty();
+}
+
 // static
 void BlockTimerStatHandle::logStats()
 {
diff --git a/indra/llcommon/llfasttimer.h b/indra/llcommon/llfasttimer.h
index 4821d6c386..614e7fdb4c 100755
--- a/indra/llcommon/llfasttimer.h
+++ b/indra/llcommon/llfasttimer.h
@@ -88,7 +88,6 @@ class BlockTimerStatHandle
 :	public StatType<TimeBlockAccumulator>
 {
 public:
-	typedef LLInstanceTracker<StatType<TimeBlockAccumulator>, std::string> instance_tracker_t;
 	BlockTimerStatHandle(const char* name, const char* description = "");
 
 	TimeBlockTreeNode& getTreeNode() const;
@@ -99,6 +98,7 @@ public:
 	typedef std::vector<BlockTimerStatHandle*>::const_iterator child_const_iter;
 	child_iter beginChildren();
 	child_iter endChildren();
+	bool hasChildren();
 	std::vector<BlockTimerStatHandle*>& getChildren();
 
 	StatType<TimeBlockAccumulator::CallCountFacet>& callCount() 
diff --git a/indra/llcommon/llinstancetracker.h b/indra/llcommon/llinstancetracker.h
index f2b982c4c3..1385475444 100755
--- a/indra/llcommon/llinstancetracker.h
+++ b/indra/llcommon/llinstancetracker.h
@@ -62,16 +62,22 @@ protected:
 
 LL_COMMON_API void assert_main_thread();
 
+enum EInstanceTrackerAllowKeyCollisions
+{
+	InstanceTrackerAllowKeyCollisions,
+	InstanceTrackerDisallowKeyCollisions
+};
+
 /// 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>
+template<typename T, typename KEY = void, EInstanceTrackerAllowKeyCollisions ALLOW_KEY_COLLISIONS = InstanceTrackerDisallowKeyCollisions>
 class LLInstanceTracker : public LLInstanceTrackerBase
 {
 	typedef LLInstanceTracker<T, KEY> self_t;
-	typedef typename std::map<KEY, T*> InstanceMap;
+	typedef typename std::multimap<KEY, T*> InstanceMap;
 	struct StaticData: public StaticBase
 	{
 		InstanceMap sMap;
@@ -208,7 +214,18 @@ private:
 	void add_(KEY key) 
 	{ 
 		mInstanceKey = key; 
-		getMap_()[key] = static_cast<T*>(this); 
+		InstanceMap& map = getMap_();
+		InstanceMap::iterator insertion_point_it = map.lower_bound(key);
+		if (ALLOW_KEY_COLLISIONS == InstanceTrackerDisallowKeyCollisions
+			&& insertion_point_it != map.end() 
+			&& insertion_point_it->first == key)
+		{
+			LL_ERRS() << "Key " << key << " already exists in instance map for " << typeid(T).name() << LL_ENDL;
+		}
+		else
+		{
+			map.insert(insertion_point_it, std::make_pair(key, static_cast<T*>(this)));
+		}
 	}
 	void remove_()
 	{
@@ -225,8 +242,8 @@ private:
 
 /// explicit specialization for default case where KEY is void
 /// use a simple std::set<T*>
-template<typename T>
-class LLInstanceTracker<T, void> : public LLInstanceTrackerBase
+template<typename T, EInstanceTrackerAllowKeyCollisions ALLOW_KEY_COLLISIONS>
+class LLInstanceTracker<T, void, ALLOW_KEY_COLLISIONS> : public LLInstanceTrackerBase
 {
 	typedef LLInstanceTracker<T, void> self_t;
 	typedef typename std::set<T*> InstanceSet;
diff --git a/indra/llcommon/lltrace.h b/indra/llcommon/lltrace.h
index cbdf4e4a6f..b499036af2 100644
--- a/indra/llcommon/lltrace.h
+++ b/indra/llcommon/lltrace.h
@@ -69,11 +69,12 @@ protected:
 template<typename ACCUMULATOR>
 class StatType 
 :	public StatBase,
-	public LLInstanceTracker<StatType<ACCUMULATOR>, std::string>
+	public LLInstanceTracker<StatType<ACCUMULATOR>, std::string, InstanceTrackerAllowKeyCollisions>
 {
 public:
+	typedef LLInstanceTracker<StatType<ACCUMULATOR>, std::string, InstanceTrackerAllowKeyCollisions> instance_tracker_t;
 	StatType(const char* name, const char* description)
-	:	LLInstanceTracker<StatType<ACCUMULATOR>, std::string>(name),
+	:	instance_tracker_t(name),
 		StatBase(name, description),
 		mAccumulatorIndex(AccumulatorBuffer<ACCUMULATOR>::getDefaultBuffer()->reserveSlot())
 	{}
diff --git a/indra/llcommon/lltracethreadrecorder.cpp b/indra/llcommon/lltracethreadrecorder.cpp
index 20e8a0bbaa..7b7da5343d 100644
--- a/indra/llcommon/lltracethreadrecorder.cpp
+++ b/indra/llcommon/lltracethreadrecorder.cpp
@@ -81,7 +81,7 @@ void ThreadRecorder::init()
 	BlockTimerStatHandle::getRootTimeBlock().getCurrentAccumulator().mActiveCount = 1;
 
 	claim_alloc(gTraceMemStat, this);
-	claim_alloc(gTraceMemStat, sizeof(BlockTimer));
+	claim_alloc(gTraceMemStat, mRootTimer);
 	claim_alloc(gTraceMemStat, sizeof(TimeBlockTreeNode) * mNumTimeBlockTreeNodes);
 }
 
-- 
cgit v1.2.3