From adeeabfc13c91dc99a1ea1949cd2f820c4150995 Mon Sep 17 00:00:00 2001
From: Richard Linden <none@none>
Date: Mon, 24 Sep 2012 18:56:01 -0700
Subject: [PATCH] SH-3275 WIP Run viewer metrics for object update messages
 moved LLThreadLocalPtr to llapr fixed various startup race conditions for
 LLThreadLocalPtr

---
 indra/llcommon/CMakeLists.txt     |   1 -
 indra/llcommon/llapr.cpp          |  82 +++++++++++++++++
 indra/llcommon/llapr.h            | 117 +++++++++++++++++++++++++
 indra/llcommon/llcommon.cpp       |   2 +
 indra/llcommon/llthread.cpp       |   8 +-
 indra/llcommon/llthread.h         |   1 -
 indra/llcommon/llthreadlocalptr.h | 141 ------------------------------
 indra/llcommon/lltrace.cpp        |  16 +++-
 indra/llcommon/lltrace.h          |  57 ++++++------
 9 files changed, 249 insertions(+), 176 deletions(-)
 delete mode 100644 indra/llcommon/llthreadlocalptr.h

diff --git a/indra/llcommon/CMakeLists.txt b/indra/llcommon/CMakeLists.txt
index eec2695dde9..f78751601c2 100644
--- a/indra/llcommon/CMakeLists.txt
+++ b/indra/llcommon/CMakeLists.txt
@@ -240,7 +240,6 @@ set(llcommon_HEADER_FILES
     llstringtable.h
     llsys.h
     llthread.h
-    llthreadlocalptr.h
     llthreadsafequeue.h
     lltimer.h
     lltrace.h
diff --git a/indra/llcommon/llapr.cpp b/indra/llcommon/llapr.cpp
index d1c44c94032..76749f8a911 100644
--- a/indra/llcommon/llapr.cpp
+++ b/indra/llcommon/llapr.cpp
@@ -54,6 +54,8 @@ void ll_init_apr()
 	{
 		LLAPRFile::sAPRFilePoolp = new LLVolatileAPRPool(FALSE) ;
 	}
+
+	LLThreadLocalPtrBase::initAllThreadLocalStorage();
 }
 
 
@@ -476,6 +478,86 @@ S32 LLAPRFile::seek(apr_seek_where_t where, S32 offset)
 	return LLAPRFile::seek(mFile, where, offset) ;
 }
 
+//
+//LLThreadLocalPtrBase
+//
+bool LLThreadLocalPtrBase::sInitialized = false;
+
+LLThreadLocalPtrBase::LLThreadLocalPtrBase(void (*cleanup_func)(void*))
+:	mCleanupFunc(cleanup_func),
+	mThreadKey(NULL)
+{
+	if (sInitialized)
+	{
+		initStorage();
+	}
+}
+
+LLThreadLocalPtrBase::LLThreadLocalPtrBase( const LLThreadLocalPtrBase& other)
+:	mCleanupFunc(other.mCleanupFunc),
+	mThreadKey(NULL)
+{
+	if (sInitialized)
+	{
+		initStorage();
+	}
+}
+
+LLThreadLocalPtrBase::~LLThreadLocalPtrBase()
+{
+	destroyStorage();
+}
+
+void LLThreadLocalPtrBase::set( void* value )
+{
+	llassert(sInitialized && mThreadKey);
+
+	apr_status_t result = apr_threadkey_private_set((void*)value, mThreadKey);
+	if (result != APR_SUCCESS)
+	{
+		ll_apr_warn_status(result);
+		llerrs << "Failed to set thread local data" << llendl;
+	}
+}
+
+void LLThreadLocalPtrBase::initStorage( )
+{
+	apr_status_t result = apr_threadkey_private_create(&mThreadKey, mCleanupFunc, gAPRPoolp);
+	if (result != APR_SUCCESS)
+	{
+		ll_apr_warn_status(result);
+		llerrs << "Failed to allocate thread local data" << llendl;
+	}
+}
+
+void LLThreadLocalPtrBase::destroyStorage()
+{
+	if (mThreadKey)
+	{
+		apr_status_t result = apr_threadkey_private_delete(mThreadKey);
+		if (result != APR_SUCCESS)
+		{
+			ll_apr_warn_status(result);
+			llerrs << "Failed to delete thread local data" << llendl;
+		}
+	}
+}
+
+void LLThreadLocalPtrBase::initAllThreadLocalStorage()
+{
+	if (!sInitialized)
+	{
+		sInitialized = true;
+		for (LLInstanceTracker<LLThreadLocalPtrBase>::instance_iter it = beginInstances(), end_it = endInstances();
+			it != end_it;
+			++it)
+		{
+			(*it).initStorage();
+		}
+	}
+}
+
+
 //
 //*******************************************************************************************************************************
 //static components of LLAPRFile
diff --git a/indra/llcommon/llapr.h b/indra/llcommon/llapr.h
index af33ce666f1..eb0bf627a0a 100644
--- a/indra/llcommon/llapr.h
+++ b/indra/llcommon/llapr.h
@@ -49,6 +49,7 @@
 #include "apr_signal.h"
 #include "apr_atomic.h"
 #include "llstring.h"
+#include "llinstancetracker.h"
 
 extern LL_COMMON_API apr_thread_mutex_t* gLogMutexp;
 extern apr_thread_mutex_t* gCallStacksLogMutexp;
@@ -255,6 +256,122 @@ class LL_COMMON_API LLAPRFile : boost::noncopyable
 //*******************************************************************************************************************************
 };
 
+class LLThreadLocalPtrBase : LLInstanceTracker<LLThreadLocalPtrBase>
+{
+public:
+	LLThreadLocalPtrBase(void (*cleanup_func)(void*) );
+	LLThreadLocalPtrBase(const LLThreadLocalPtrBase& other);
+	~LLThreadLocalPtrBase();
+
+protected:
+	friend void LL_COMMON_API ll_init_apr();
+	void set(void* value);
+
+	LL_FORCE_INLINE void* get()
+	{
+		void* ptr;
+		//apr_status_t result =
+		apr_threadkey_private_get(&ptr, mThreadKey);
+		//if (result != APR_SUCCESS)
+		//{
+		//	ll_apr_warn_status(s);
+		//	llerrs << "Failed to get thread local data" << llendl;
+		//}
+		return ptr;
+	}
+
+	LL_FORCE_INLINE const void* get() const
+	{
+		void* ptr;
+		//apr_status_t result =
+		apr_threadkey_private_get(&ptr, mThreadKey);
+		//if (result != APR_SUCCESS)
+		//{
+		//	ll_apr_warn_status(s);
+		//	llerrs << "Failed to get thread local data" << llendl;
+		//}
+		return ptr;
+	}
+
+	void initStorage();
+
+	void destroyStorage();
+
+	static void initAllThreadLocalStorage();
+
+private:
+	void (*mCleanupFunc)(void*);
+	apr_threadkey_t* mThreadKey;
+	static bool		sInitialized;
+};
+
+template <typename T>
+class LLThreadLocalPtr : public LLThreadLocalPtrBase
+{
+public:
+
+	LLThreadLocalPtr()
+	:	LLThreadLocalPtrBase(&cleanup)
+	{}
+
+	LLThreadLocalPtr(T* value)
+		:	LLThreadLocalPtrBase(&cleanup)
+	{
+		set(value);
+	}
+
+
+	LLThreadLocalPtr(const LLThreadLocalPtr<T>& other)
+	:	LLThreadLocalPtrBase(other, &cleanup)
+	{
+		set(other.get());		
+	}
+
+	T* get()
+	{
+		return (T*)LLThreadLocalPtrBase::get();
+	}
+
+	const T* get() const
+	{
+		return (const T*)LLThreadLocalPtrBase::get();
+	}
+
+	T* operator -> ()
+	{
+		return (T*)get();
+	}
+
+	const T* operator -> () const
+	{
+		return (T*)get();
+	}
+
+	T& operator*()
+	{
+		return *(T*)get();
+	}
+
+	const T& operator*() const
+	{
+		return *(T*)get();
+	}
+
+	LLThreadLocalPtr<T>& operator = (T* value)
+	{
+		set((void*)value);
+		return *this;
+	}
+
+private:
+
+	static void cleanup(void* ptr)
+	{
+		delete reinterpret_cast<T*>(ptr);
+	}
+
+};
+
 /**
  * @brief Function which appropriately logs error or remains quiet on
  * APR_SUCCESS.
diff --git a/indra/llcommon/llcommon.cpp b/indra/llcommon/llcommon.cpp
index 8be9e4f4de2..512e7da8400 100644
--- a/indra/llcommon/llcommon.cpp
+++ b/indra/llcommon/llcommon.cpp
@@ -44,6 +44,7 @@ void LLCommon::initClass()
 	}
 	LLTimer::initClass();
 	LLThreadSafeRefCount::initThreadSafeRefCount();
+	LLTrace::init();
 // 	LLWorkerThread::initClass();
 // 	LLFrameCallbackManager::initClass();
 }
@@ -61,4 +62,5 @@ void LLCommon::cleanupClass()
 		sAprInitialized = FALSE;
 	}
 	LLMemory::cleanupClass();
+	LLTrace::cleanup();
 }
diff --git a/indra/llcommon/llthread.cpp b/indra/llcommon/llthread.cpp
index f3ab8aa40cb..023004eedd1 100644
--- a/indra/llcommon/llthread.cpp
+++ b/indra/llcommon/llthread.cpp
@@ -66,9 +66,7 @@ U32 __thread LLThread::sThreadID = 0;
 #endif
 
 U32 LLThread::sIDIter = 0;
-
-LLTrace::MasterThreadTrace gMasterThreadTrace;
-LLThreadLocalPtr<LLTrace::ThreadTraceData> LLThread::sTraceData(&gMasterThreadTrace);
+LLThreadLocalPtr<LLTrace::ThreadTraceData> LLThread::sTraceData;
 
 
 LL_COMMON_API void assert_main_thread()
@@ -87,7 +85,7 @@ void *APR_THREAD_FUNC LLThread::staticRun(apr_thread_t *apr_threadp, void *datap
 {
 	LLThread *threadp = (LLThread *)datap;
 
-	sTraceData = new LLTrace::SlaveThreadTrace(gMasterThreadTrace);
+	sTraceData = new LLTrace::SlaveThreadTrace();
 
 #if !LL_DARWIN
 	sThreadIndex = threadp->mID;
@@ -155,7 +153,7 @@ void LLThread::shutdown()
 			//llinfos << "LLThread::~LLThread() Killing thread " << mName << " Status: " << mStatus << llendl;
 			// Now wait a bit for the thread to exit
 			// It's unclear whether I should even bother doing this - this destructor
-			// should netver get called unless we're already stopped, really...
+			// should never get called unless we're already stopped, really...
 			S32 counter = 0;
 			const S32 MAX_WAIT = 600;
 			while (counter < MAX_WAIT)
diff --git a/indra/llcommon/llthread.h b/indra/llcommon/llthread.h
index e2de4c8b85a..e50fa7653d2 100644
--- a/indra/llcommon/llthread.h
+++ b/indra/llcommon/llthread.h
@@ -31,7 +31,6 @@
 #include "llapr.h"
 #include "apr_thread_cond.h"
 #include "lltrace.h"
-#include "llthreadlocalptr.h"
 
 class LL_COMMON_API LLThread
 {
diff --git a/indra/llcommon/llthreadlocalptr.h b/indra/llcommon/llthreadlocalptr.h
deleted file mode 100644
index f02f4849ca4..00000000000
--- a/indra/llcommon/llthreadlocalptr.h
+++ /dev/null
@@ -1,141 +0,0 @@
-/** 
- * @file llthreadlocalptr.h
- * @brief manage thread local storage through non-copyable pointer
- *
- * $LicenseInfo:firstyear=2004&license=viewerlgpl$
- * Second Life Viewer Source Code
- * Copyright (C) 2012, Linden Research, Inc.
- * 
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation;
- * version 2.1 of the License only.
- * 
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- * 
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
- * 
- * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
- * $/LicenseInfo$
- */
-
-#ifndef LL_LLTHREAD_LOCAL_PTR_H
-#define LL_LLTHREAD_LOCAL_PTR_H
-
-#include "llapr.h"
-
-template <typename T>
-class LLThreadLocalPtr
-{
-public:
-	LLThreadLocalPtr(T* value = NULL, apr_pool_t* pool = NULL)
-	{
-		apr_status_t result = apr_threadkey_private_create(&mThreadKey, cleanup, pool);
-		if (result != APR_SUCCESS)
-		{
-			ll_apr_warn_status(result);
-			llerrs << "Failed to allocate thread local data" << llendl;
-		}
-		set(value);
-	}
-
-
-	~LLThreadLocalPtr()
-	{
-		apr_status_t result = apr_threadkey_private_delete(mThreadKey);
-		if (result != APR_SUCCESS)
-		{
-			ll_apr_warn_status(result);
-			llerrs << "Failed to delete thread local data" << llendl;
-		}
-	}
-
-	T* operator -> ()
-	{
-		return get();
-	}
-
-	const T* operator -> () const
-	{
-		return get();
-	}
-
-	T& operator*()
-	{
-		return *get();
-	}
-
-	const T& operator*() const
-	{
-		return *get();
-	}
-
-	LLThreadLocalPtr<T>& operator = (T* value)
-	{
-		set(value);
-		return *this;
-	}
-
-	void copyFrom(const LLThreadLocalPtr<T>& other)
-	{
-		set(other.get());
-	}
-
-	LL_FORCE_INLINE void set(T* value)
-	{
-		apr_status_t result = apr_threadkey_private_set((void*)value, mThreadKey);
-		if (result != APR_SUCCESS)
-		{
-			ll_apr_warn_status(result);
-			llerrs << "Failed to set thread local data" << llendl;
-		}
-	}
-
-	LL_FORCE_INLINE T* get()
-	{
-		T* ptr;
-		//apr_status_t result =
-		apr_threadkey_private_get((void**)&ptr, mThreadKey);
-		//if (result != APR_SUCCESS)
-		//{
-		//	ll_apr_warn_status(s);
-		//	llerrs << "Failed to get thread local data" << llendl;
-		//}
-		return ptr;
-	}
-
-	LL_FORCE_INLINE const T* get() const
-	{
-		T* ptr;
-		//apr_status_t result =
-		apr_threadkey_private_get((void**)&ptr, mThreadKey);
-		//if (result != APR_SUCCESS)
-		//{
-		//	ll_apr_warn_status(s);
-		//	llerrs << "Failed to get thread local data" << llendl;
-		//}
-		return ptr;
-	}
-
-
-private:
-	static void cleanup(void* ptr)
-	{
-		delete reinterpret_cast<T*>(ptr);
-	}
-
-	LLThreadLocalPtr(const LLThreadLocalPtr<T>& other)
-	{
-		// do not copy construct
-		llassert(false);
-	}
-
-	apr_threadkey_t* mThreadKey;
-};
-
-#endif // LL_LLTHREAD_LOCAL_PTR_H
diff --git a/indra/llcommon/lltrace.cpp b/indra/llcommon/lltrace.cpp
index 037c52f8c19..501414ebf34 100644
--- a/indra/llcommon/lltrace.cpp
+++ b/indra/llcommon/lltrace.cpp
@@ -32,7 +32,21 @@ namespace LLTrace
 {
 
 BlockTimer::Recorder::StackEntry BlockTimer::sCurRecorder;
-LLThreadLocalPtr<ThreadTraceData> ThreadTraceData::sCurThreadTrace;
+
+MasterThreadTrace *gMasterThreadTrace = NULL;
+LLThreadLocalPtr<ThreadTraceData> gCurThreadTrace;
+
+void init()
+{
+	gMasterThreadTrace = new MasterThreadTrace();
+	gCurThreadTrace = gMasterThreadTrace;
+}
+
+void cleanup()
+{
+	delete gMasterThreadTrace;
+}
+
 
 ///////////////////////////////////////////////////////////////////////
 // Sampler
diff --git a/indra/llcommon/lltrace.h b/indra/llcommon/lltrace.h
index 401ddfd6f34..3af05d67f9d 100644
--- a/indra/llcommon/lltrace.h
+++ b/indra/llcommon/lltrace.h
@@ -32,7 +32,6 @@
 
 #include "llmutex.h"
 #include "llmemory.h"
-#include "llthreadlocalptr.h"
 
 #include <list>
 
@@ -42,19 +41,29 @@
 
 namespace LLTrace
 {
+	void init();
+	void cleanup();
+
+	extern class MasterThreadTrace *gMasterThreadTrace;
+	extern LLThreadLocalPtr<class ThreadTraceData> gCurThreadTrace;
+
 	// one per thread per type
 	template<typename ACCUMULATOR>
 	class AccumulatorBuffer
 	{
 		static const U32 DEFAULT_ACCUMULATOR_BUFFER_SIZE = 64;
-	public:
-		AccumulatorBuffer()
+	private:
+		enum StaticAllocationMarker { STATIC_ALLOC };
+
+		AccumulatorBuffer(StaticAllocationMarker m)
 		:	mStorageSize(64),
-			mStorage(new ACCUMULATOR[DEFAULT_ACCUMULATOR_BUFFER_SIZE]),
-			mNextStorageSlot(0)
-		{}
+			mNextStorageSlot(0),
+			mStorage(new ACCUMULATOR[DEFAULT_ACCUMULATOR_BUFFER_SIZE])
+		{
+		}
+	public:
 
-		AccumulatorBuffer(const AccumulatorBuffer& other)
+		AccumulatorBuffer(const AccumulatorBuffer& other = getDefaultBuffer())
 		:	mStorageSize(other.mStorageSize),
 			mStorage(new ACCUMULATOR[other.mStorageSize]),
 			mNextStorageSlot(other.mNextStorageSlot)
@@ -116,6 +125,12 @@ namespace LLTrace
 			return next_slot;
 		}
 
+		static AccumulatorBuffer<ACCUMULATOR>& getDefaultBuffer()
+		{
+			static AccumulatorBuffer sBuffer;
+			return sBuffer;
+		}
+
 	private:
 		ACCUMULATOR*							mStorage;
 		size_t									mStorageSize;
@@ -124,15 +139,6 @@ namespace LLTrace
 	};
 	template<typename ACCUMULATOR> LLThreadLocalPtr<ACCUMULATOR> AccumulatorBuffer<ACCUMULATOR>::sPrimaryStorage;
 
-	template<typename ACCUMULATOR>
-	class PrimaryAccumulatorBuffer : public AccumulatorBuffer<ACCUMULATOR
-	{
-		PrimaryAccumulatorBuffer()
-		{
-			makePrimary();
-		}
-	};
-
 	template<typename ACCUMULATOR>
 	class Trace
 	{
@@ -140,7 +146,7 @@ namespace LLTrace
 		Trace(const std::string& name)
 		:	mName(name)
 		{
-			mAccumulatorIndex = getPrimaryBuffer().reserveSlot();
+			mAccumulatorIndex = AccumulatorBuffer<ACCUMULATOR>::getDefaultBuffer().reserveSlot();
 		}
 
 		LL_FORCE_INLINE ACCUMULATOR& getAccumulator()
@@ -148,12 +154,6 @@ namespace LLTrace
 			return AccumulatorBuffer<ACCUMULATOR>::getPrimaryStorage()[mAccumulatorIndex];
 		}
 
-		static PrimaryAccumulatorBuffer& getPrimaryBuffer()
-		{
-			static PrimaryAccumulatorBuffer sBuffer;
-			return sBuffer;
-		}
-
 	private:
 		std::string	mName;
 		size_t		mAccumulatorIndex;
@@ -347,9 +347,13 @@ namespace LLTrace
 	{
 	public:
 		Sampler() {}
-		Sampler(const Sampler& other);
+		Sampler(const Sampler& other)
+		:	mF32Stats(other.mF32Stats),
+			mS32Stats(other.mS32Stats),
+			mTimers(other.mTimers)
+		{}
 
-		~Sampler();
+		~Sampler() {}
 
 		void makePrimary()
 		{
@@ -438,7 +442,6 @@ namespace LLTrace
 	protected:
 		Sampler					mPrimarySampler;
 		std::list<Sampler*>		mActiveSamplers;
-		static LLThreadLocalPtr<ThreadTraceData> sCurThreadTrace;
 	};
 
 	class MasterThreadTrace : public ThreadTraceData
@@ -472,7 +475,7 @@ namespace LLTrace
 	{
 	public:
 		explicit 
-		SlaveThreadTrace(MasterThreadTrace& master_trace)
+		SlaveThreadTrace(MasterThreadTrace& master_trace = *gMasterThreadTrace)
 		:	mMaster(master_trace),
 			ThreadTraceData(master_trace),
 			mSharedData(mPrimarySampler)
-- 
GitLab