diff options
| -rw-r--r-- | indra/llaudio/llaudiodecodemgr.cpp | 1 | ||||
| -rw-r--r-- | indra/llcommon/CMakeLists.txt | 1 | ||||
| -rw-r--r-- | indra/llcommon/llapr.cpp | 2 | ||||
| -rw-r--r-- | indra/llcommon/llfasttimer.cpp | 41 | ||||
| -rw-r--r-- | indra/llcommon/llfasttimer.h | 45 | ||||
| -rw-r--r-- | indra/llcommon/llsingleton.h | 52 | ||||
| -rw-r--r-- | indra/llcommon/llthreadlocalpointer.h | 164 | ||||
| -rw-r--r-- | indra/llcommon/llthreadlocalstorage.h | 254 | ||||
| -rw-r--r-- | indra/llcommon/lltrace.cpp | 13 | ||||
| -rw-r--r-- | indra/llcommon/lltrace.h | 32 | ||||
| -rw-r--r-- | indra/llcommon/lltracethreadrecorder.cpp | 33 | ||||
| -rw-r--r-- | indra/llcommon/lltracethreadrecorder.h | 9 | ||||
| -rw-r--r-- | indra/llmessage/llbuffer.cpp | 1 | ||||
| -rw-r--r-- | indra/llmessage/lldispatcher.cpp | 1 | 
14 files changed, 383 insertions, 266 deletions
| diff --git a/indra/llaudio/llaudiodecodemgr.cpp b/indra/llaudio/llaudiodecodemgr.cpp index 6c97a64ed7..bcff03ceaa 100644 --- a/indra/llaudio/llaudiodecodemgr.cpp +++ b/indra/llaudio/llaudiodecodemgr.cpp @@ -40,6 +40,7 @@  #include "vorbis/codec.h"  #include "vorbis/vorbisfile.h" +#include <iterator>  extern LLAudioEngine *gAudiop; diff --git a/indra/llcommon/CMakeLists.txt b/indra/llcommon/CMakeLists.txt index 5b76703af7..6f5fe1832a 100644 --- a/indra/llcommon/CMakeLists.txt +++ b/indra/llcommon/CMakeLists.txt @@ -242,6 +242,7 @@ set(llcommon_HEADER_FILES      llstringtable.h      llsys.h      llthread.h +    llthreadlocalstorage.h      llthreadsafequeue.h      lltimer.h      lltrace.h diff --git a/indra/llcommon/llapr.cpp b/indra/llcommon/llapr.cpp index 092c276936..d911f258b6 100644 --- a/indra/llcommon/llapr.cpp +++ b/indra/llcommon/llapr.cpp @@ -29,7 +29,7 @@  #include "linden_common.h"  #include "llapr.h"  #include "apr_dso.h" -#include "llthreadlocalpointer.h" +#include "llthreadlocalstorage.h"  apr_pool_t *gAPRPoolp = NULL; // Global APR memory pool  LLVolatileAPRPool *LLAPRFile::sAPRFilePoolp = NULL ; //global volatile APR memory pool. diff --git a/indra/llcommon/llfasttimer.cpp b/indra/llcommon/llfasttimer.cpp index 7c90b946af..ad8cf7296e 100644 --- a/indra/llcommon/llfasttimer.cpp +++ b/indra/llcommon/llfasttimer.cpp @@ -70,8 +70,6 @@ U64         TimeBlock::sClockResolution = 1000000000; // Nanosecond resolution  U64         TimeBlock::sClockResolution = 1000000; // Microsecond resolution  #endif -LLThreadLocalPointer<CurTimerData> TimeBlock::sCurTimerData; -  static LLMutex*			sLogLock = NULL;  static std::queue<LLSD> sLogQueue; @@ -118,7 +116,7 @@ struct SortTimerByName  	}  }; -TimeBlock& TimeBlock::getRootTimer() +TimeBlock& TimeBlock::getRootTimeBlock()  {  	static TimeBlock root_timer("root", true, NULL);  	return root_timer; @@ -185,7 +183,7 @@ void TimeBlock::processTimes()  {  	get_clock_count(); // good place to calculate clock frequency  	U64 cur_time = getCPUClockCount64(); -	CurTimerData* cur_data = sCurTimerData.get(); +	BlockTimerStackRecord* stack_record = ThreadTimerStack::getInstance();  	// set up initial tree  	for (LLInstanceTracker<TimeBlock>::instance_iter it = LLInstanceTracker<TimeBlock>::beginInstances(), end_it = LLInstanceTracker<TimeBlock>::endInstances();  @@ -193,11 +191,11 @@ void TimeBlock::processTimes()  		++it)  	{  		TimeBlock& timer = *it; -		if (&timer == &TimeBlock::getRootTimer()) continue; +		if (&timer == &TimeBlock::getRootTimeBlock()) continue;  		// bootstrap tree construction by attaching to last timer to be on stack  		// when this timer was called -		if (timer.getParent() == &TimeBlock::getRootTimer()) +		if (timer.getParent() == &TimeBlock::getRootTimeBlock())  		{  			TimeBlockAccumulator* accumulator = timer.getPrimaryAccumulator(); @@ -214,20 +212,21 @@ void TimeBlock::processTimes()  	// bump timers up tree if they have been flagged as being in the wrong place  	// do this in a bottom up order to promote descendants first before promoting ancestors  	// this preserves partial order derived from current frame's observations -	for(timer_tree_bottom_up_iterator_t it = begin_timer_tree_bottom_up(TimeBlock::getRootTimer()); +	for(timer_tree_bottom_up_iterator_t it = begin_timer_tree_bottom_up(TimeBlock::getRootTimeBlock());  		it != end_timer_tree_bottom_up();  		++it)  	{  		TimeBlock* timerp = *it;  		// sort timers by time last called, so call graph makes sense -		if (timerp->getTreeNode().mNeedsSorting) +		TimeBlockTreeNode& tree_node = timerp->getTreeNode(); +		if (tree_node.mNeedsSorting)  		{ -			std::sort(timerp->beginChildren(), timerp->endChildren(), SortTimerByName()); +			std::sort(tree_node.mChildren.begin(), tree_node.mChildren.end(), SortTimerByName());  		}  		// skip root timer -		if (timerp != &TimeBlock::getRootTimer()) +		if (timerp != &TimeBlock::getRootTimeBlock())  		{  			TimeBlockAccumulator* accumulator = timerp->getPrimaryAccumulator(); @@ -250,27 +249,27 @@ void TimeBlock::processTimes()  	}  	// walk up stack of active timers and accumulate current time while leaving timing structures active -	BlockTimer* cur_timer = cur_data->mCurTimer; -	TimeBlockAccumulator* accumulator = cur_data->mTimerData->getPrimaryAccumulator(); +	BlockTimer* cur_timer = stack_record->mActiveTimer; +	TimeBlockAccumulator* accumulator = stack_record->mTimeBlock->getPrimaryAccumulator();  	// root defined by parent pointing to self -	while(cur_timer && cur_timer->mLastTimerData.mCurTimer != cur_timer) +	while(cur_timer && cur_timer->mLastTimerData.mActiveTimer != cur_timer)  	{  		U64 cumulative_time_delta = cur_time - cur_timer->mStartTime; -		U64 self_time_delta = cumulative_time_delta - cur_data->mChildTime; -		cur_data->mChildTime = 0; +		U64 self_time_delta = cumulative_time_delta - stack_record->mChildTime; +		stack_record->mChildTime = 0;  		accumulator->mSelfTimeCounter += self_time_delta;  		accumulator->mTotalTimeCounter += cumulative_time_delta;  		cur_timer->mStartTime = cur_time; -		cur_data = &cur_timer->mLastTimerData; -		cur_data->mChildTime += cumulative_time_delta; -		if (cur_data->mTimerData) +		stack_record = &cur_timer->mLastTimerData; +		stack_record->mChildTime += cumulative_time_delta; +		if (stack_record->mTimeBlock)  		{ -			accumulator = cur_data->mTimerData->getPrimaryAccumulator(); +			accumulator = stack_record->mTimeBlock->getPrimaryAccumulator();  		} -		cur_timer = cur_timer->mLastTimerData.mCurTimer; +		cur_timer = cur_timer->mLastTimerData.mActiveTimer;  	} @@ -374,7 +373,7 @@ void TimeBlock::dumpCurTimes()  	LLTrace::Recording& last_frame_recording = frame_recording.getLastRecordingPeriod();  	// walk over timers in depth order and output timings -	for(timer_tree_dfs_iterator_t it = begin_timer_tree(TimeBlock::getRootTimer()); +	for(timer_tree_dfs_iterator_t it = begin_timer_tree(TimeBlock::getRootTimeBlock());  		it != end_timer_tree();  		++it)  	{ diff --git a/indra/llcommon/llfasttimer.h b/indra/llcommon/llfasttimer.h index 4d820d0664..995eebd16a 100644 --- a/indra/llcommon/llfasttimer.h +++ b/indra/llcommon/llfasttimer.h @@ -38,13 +38,29 @@ class LLMutex;  namespace LLTrace  { -struct CurTimerData +struct BlockTimerStackRecord  { -	class BlockTimer*	mCurTimer; -	class TimeBlock*	mTimerData; +	class BlockTimer*	mActiveTimer; +	class TimeBlock*	mTimeBlock;  	U64					mChildTime;  }; +class ThreadTimerStack  +:	public BlockTimerStackRecord,  +	public LLThreadLocalSingleton<ThreadTimerStack> +{ +	friend LLThreadLocalSingleton<ThreadTimerStack>; +	ThreadTimerStack()  +	{} + +public: +	ThreadTimerStack& operator=(const BlockTimerStackRecord& other) +	{ +		BlockTimerStackRecord::operator=(other); +		return *this; +	} +}; +  class BlockTimer  {  public: @@ -58,7 +74,7 @@ public:  private:  	U64				mStartTime; -	CurTimerData	mLastTimerData; +	BlockTimerStackRecord	mLastTimerData;  };  // stores a "named" timer instance to be reused via multiple BlockTimer stack instances @@ -67,7 +83,7 @@ class TimeBlock  	public LLInstanceTracker<TimeBlock>  {  public: -	TimeBlock(const char* name, bool open = false, TimeBlock* parent = &getRootTimer()); +	TimeBlock(const char* name, bool open = false, TimeBlock* parent = &getRootTimeBlock());  	TimeBlockTreeNode& getTreeNode() const;  	TimeBlock* getParent() const { return getTreeNode().getParent(); } @@ -92,7 +108,7 @@ public:  		return static_cast<TraceType<TimeBlockAccumulator::SelfTimeAspect>&>(*(TraceType<TimeBlockAccumulator>*)this);  	} -	static TimeBlock& getRootTimer(); +	static TimeBlock& getRootTimeBlock();  	static void pushLog(LLSD sd);  	static void setLogLock(LLMutex* mutex);  	static void writeLog(std::ostream& os); @@ -252,7 +268,6 @@ public:  	static std::string							sLogName;  	static bool									sMetricLog,  												sLog;	 -	static LLThreadLocalPointer<CurTimerData>	sCurTimerData;  	static U64									sClockResolution;  }; @@ -261,8 +276,8 @@ LL_FORCE_INLINE BlockTimer::BlockTimer(TimeBlock& timer)  #if FAST_TIMER_ON  	mStartTime = TimeBlock::getCPUClockCount64(); -	CurTimerData* cur_timer_data = TimeBlock::sCurTimerData.get(); -	TimeBlockAccumulator* accumulator = cur_timer_data->mTimerData->getPrimaryAccumulator(); +	BlockTimerStackRecord* cur_timer_data = ThreadTimerStack::getIfExists(); +	TimeBlockAccumulator* accumulator = cur_timer_data->mTimeBlock->getPrimaryAccumulator();  	accumulator->mActiveCount++;  	// keep current parent as long as it is active when we are  	accumulator->mMoveUpTree |= (accumulator->mParent->getPrimaryAccumulator()->mActiveCount == 0); @@ -270,8 +285,8 @@ LL_FORCE_INLINE BlockTimer::BlockTimer(TimeBlock& timer)  	// store top of stack  	mLastTimerData = *cur_timer_data;  	// push new information -	cur_timer_data->mCurTimer = this; -	cur_timer_data->mTimerData = &timer; +	cur_timer_data->mActiveTimer = this; +	cur_timer_data->mTimeBlock = &timer;  	cur_timer_data->mChildTime = 0;  #endif  } @@ -280,8 +295,8 @@ LL_FORCE_INLINE BlockTimer::~BlockTimer()  {  #if FAST_TIMER_ON  	U64 total_time = TimeBlock::getCPUClockCount64() - mStartTime; -	CurTimerData* cur_timer_data = TimeBlock::sCurTimerData.get(); -	TimeBlockAccumulator* accumulator = cur_timer_data->mTimerData->getPrimaryAccumulator(); +	BlockTimerStackRecord* cur_timer_data = ThreadTimerStack::getIfExists(); +	TimeBlockAccumulator* accumulator = cur_timer_data->mTimeBlock->getPrimaryAccumulator();  	accumulator->mCalls++;  	accumulator->mSelfTimeCounter += total_time - cur_timer_data->mChildTime; @@ -290,12 +305,12 @@ LL_FORCE_INLINE BlockTimer::~BlockTimer()  	// store last caller to bootstrap tree creation  	// do this in the destructor in case of recursion to get topmost caller -	accumulator->mLastCaller = mLastTimerData.mTimerData; +	accumulator->mLastCaller = mLastTimerData.mTimeBlock;  	// we are only tracking self time, so subtract our total time delta from parents  	mLastTimerData.mChildTime += total_time; -	*TimeBlock::sCurTimerData = mLastTimerData; +	*ThreadTimerStack::getIfExists() = mLastTimerData;  #endif  } diff --git a/indra/llcommon/llsingleton.h b/indra/llcommon/llsingleton.h index 49d99f2cd0..f6b0a7194b 100644 --- a/indra/llcommon/llsingleton.h +++ b/indra/llcommon/llsingleton.h @@ -90,7 +90,7 @@ template <typename DERIVED_TYPE>  class LLSingleton : private boost::noncopyable  { -private: +protected:  	typedef enum e_init_state  	{  		UNINITIALIZED, @@ -124,7 +124,7 @@ private:  public:  	virtual ~LLSingleton()  	{ -		SingletonInstanceData& data = getData(); +		SingletonInstanceData& data = getSingletonData();  		data.mSingletonInstance = NULL;  		data.mInitState = DELETED;  	} @@ -151,29 +151,15 @@ public:  	 */  	static void deleteSingleton()  	{ -		delete getData().mSingletonInstance; -		getData().mSingletonInstance = NULL; -		getData().mInitState = DELETED; -	} - -	static SingletonInstanceData& getData() -	{ -		// this is static to cache the lookup results -		static void * & registry = LLSingletonRegistry::get<DERIVED_TYPE>(); - -		// *TODO - look into making this threadsafe -		if(NULL == registry) -		{ -			static SingletonInstanceData data; -			registry = &data; -		} - -		return *static_cast<SingletonInstanceData *>(registry); +		SingletonInstanceData& data = getSingletonData(); +		delete data.mSingletonInstance; +		data.mSingletonInstance = NULL; +		data.mInitState = DELETED;  	}  	static DERIVED_TYPE* getInstance()  	{ -		SingletonInstanceData& data = getData(); +		SingletonInstanceData& data = getSingletonData();  		if (data.mInitState == CONSTRUCTING)  		{ @@ -197,6 +183,12 @@ public:  		return data.mSingletonInstance;  	} +	static DERIVED_TYPE* getIfExists() +	{ +		SingletonInstanceData& data = getSingletonData(); +		return data.mSingletonInstance; +	} +  	// Reference version of getInstance()  	// Preferred over getInstance() as it disallows checking for NULL  	static DERIVED_TYPE& instance() @@ -208,17 +200,31 @@ public:  	// Use this to avoid accessing singletons before the can safely be constructed  	static bool instanceExists()  	{ -		return getData().mInitState == INITIALIZED; +		return getSingletonData().mInitState == INITIALIZED;  	}  	// Has this singleton already been deleted?  	// Use this to avoid accessing singletons from a static object's destructor  	static bool destroyed()  	{ -		return getData().mInitState == DELETED; +		return getSingletonData().mInitState == DELETED;  	}  private: +	static SingletonInstanceData& getSingletonData() +	{ +		// this is static to cache the lookup results +		static void * & registry = LLSingletonRegistry::get<DERIVED_TYPE>(); + +		// *TODO - look into making this threadsafe +		if(NULL == registry) +		{ +			static SingletonInstanceData data; +			registry = &data; +		} + +		return *static_cast<SingletonInstanceData *>(registry); +	}  	virtual void initSingleton() {}  }; diff --git a/indra/llcommon/llthreadlocalpointer.h b/indra/llcommon/llthreadlocalpointer.h deleted file mode 100644 index d40a8b5a27..0000000000 --- a/indra/llcommon/llthreadlocalpointer.h +++ /dev/null @@ -1,164 +0,0 @@ -/**  - * @file llthreadlocalpointer.h - * @author Richard - * @brief Pointer class that manages a distinct value per thread - * - * $LicenseInfo:firstyear=2004&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, 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_LLTHREADLOCALPOINTER_H -#define LL_LLTHREADLOCALPOINTER_H - -#include "llinstancetracker.h" -#include "llapr.h" - -class LLThreadLocalPointerBase : public LLInstanceTracker<LLThreadLocalPointerBase> -{ -public: -	LLThreadLocalPointerBase() -	:	mThreadKey(NULL) -	{ -		if (sInitialized) -		{ -			initStorage(); -		} -	} - -	LLThreadLocalPointerBase( const LLThreadLocalPointerBase& other) -		:	mThreadKey(NULL) -	{ -		if (sInitialized) -		{ -			initStorage(); -		} -	} - -	~LLThreadLocalPointerBase() -	{ -		destroyStorage(); -	} - -	static void initAllThreadLocalStorage(); -	static void destroyAllThreadLocalStorage(); - -protected: -	void set(void* value); - -	LL_FORCE_INLINE void* get() -	{ -		// llassert(sInitialized); -		void* ptr; -		apr_status_t result = -		apr_threadkey_private_get(&ptr, mThreadKey); -		if (result != APR_SUCCESS) -		{ -			ll_apr_warn_status(result); -			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(result); -			llerrs << "Failed to get thread local data" << llendl; -		} -		return ptr; -	} - -	void initStorage(); -	void destroyStorage(); - -protected: -	apr_threadkey_t* mThreadKey; -	static bool		sInitialized; -}; - -template <typename T> -class LLThreadLocalPointer : public LLThreadLocalPointerBase -{ -public: - -	LLThreadLocalPointer() -	{} - -	explicit LLThreadLocalPointer(T* value) -	{ -		set(value); -	} - - -	LLThreadLocalPointer(const LLThreadLocalPointer<T>& other) -	:	LLThreadLocalPointerBase(other) -	{ -		set(other.get());		 -	} - -	LL_FORCE_INLINE T* get() -	{ -		return (T*)LLThreadLocalPointerBase::get(); -	} - -	const T* get() const -	{ -		return (const T*)LLThreadLocalPointerBase::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(); -	} - -	LLThreadLocalPointer<T>& operator = (T* value) -	{ -		set((void*)value); -		return *this; -	} - -	bool operator ==(T* other) -	{ -		if (!sInitialized) return false; -		return get() == other; -	} -}; - -#endif // LL_LLTHREADLOCALPOINTER_H diff --git a/indra/llcommon/llthreadlocalstorage.h b/indra/llcommon/llthreadlocalstorage.h new file mode 100644 index 0000000000..fdf0c18085 --- /dev/null +++ b/indra/llcommon/llthreadlocalstorage.h @@ -0,0 +1,254 @@ +/**  + * @file llthreadlocalstorage.h + * @author Richard + * @brief Class wrappers for thread local storage + * + * $LicenseInfo:firstyear=2004&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, 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_LLTHREADLOCALSTORAGE_H +#define LL_LLTHREADLOCALSTORAGE_H + +#include "llinstancetracker.h" +#include "llapr.h" + +class LLThreadLocalPointerBase : public LLInstanceTracker<LLThreadLocalPointerBase> +{ +public: +	LLThreadLocalPointerBase() +	:	mThreadKey(NULL) +	{ +		if (sInitialized) +		{ +			initStorage(); +		} +	} + +	LLThreadLocalPointerBase( const LLThreadLocalPointerBase& other) +		:	mThreadKey(NULL) +	{ +		if (sInitialized) +		{ +			initStorage(); +		} +	} + +	~LLThreadLocalPointerBase() +	{ +		destroyStorage(); +	} + +	static void initAllThreadLocalStorage(); +	static void destroyAllThreadLocalStorage(); + +protected: +	void set(void* value); + +	LL_FORCE_INLINE void* get() const +	{ +		// llassert(sInitialized); +		void* ptr; +		apr_status_t result = +		apr_threadkey_private_get(&ptr, mThreadKey); +		if (result != APR_SUCCESS) +		{ +			ll_apr_warn_status(result); +			llerrs << "Failed to get thread local data" << llendl; +		} +		return ptr; +	} + +	void initStorage(); +	void destroyStorage(); + +protected: +	apr_threadkey_t* mThreadKey; +	static bool		sInitialized; +}; + +template <typename T> +class LLThreadLocalPointer : public LLThreadLocalPointerBase +{ +public: + +	LLThreadLocalPointer() +	{} + +	explicit LLThreadLocalPointer(T* value) +	{ +		set(value); +	} + + +	LLThreadLocalPointer(const LLThreadLocalPointer<T>& other) +	:	LLThreadLocalPointerBase(other) +	{ +		set(other.get());		 +	} + +	LL_FORCE_INLINE T* get() const +	{ +		return (T*)LLThreadLocalPointerBase::get(); +	} + +	T* operator -> () const +	{ +		return (T*)get(); +	} + +	T& operator*() const +	{ +		return *(T*)get(); +	} + +	LLThreadLocalPointer<T>& operator = (T* value) +	{ +		set((void*)value); +		return *this; +	} + +	bool operator ==(const T* other) const +	{ +		if (!sInitialized) return false; +		return get() == other; +	} +}; + +template<typename DERIVED_TYPE> +class LLThreadLocalSingleton +{ +	typedef enum e_init_state +	{ +		UNINITIALIZED = 0, +		CONSTRUCTING, +		INITIALIZING, +		INITIALIZED, +		DELETED +	} EInitState; + +public: +	LLThreadLocalSingleton() +	{} +	 +	virtual ~LLThreadLocalSingleton() +	{ +		sInstance = NULL; +		sInitState = DELETED; +	} + +	static void deleteSingleton() +	{ +		delete sInstance; +		sInstance = NULL; +		sInitState = DELETED; +	} + +	static DERIVED_TYPE* getInstance() +	{ +		if (sInitState == CONSTRUCTING) +		{ +			llerrs << "Tried to access singleton " << typeid(DERIVED_TYPE).name() << " from singleton constructor!" << llendl; +		} + +		if (sInitState == DELETED) +		{ +			llwarns << "Trying to access deleted singleton " << typeid(DERIVED_TYPE).name() << " creating new instance" << llendl; +		} + +		if (!sInstance)  +		{ +			sInitState = CONSTRUCTING; +			sInstance = new DERIVED_TYPE();  +			sInitState = INITIALIZING; +			sInstance->initSingleton();  +			sInitState = INITIALIZED;	 +		} + +		return sInstance; +	} + +	static DERIVED_TYPE* getIfExists() +	{ +		return sInstance; +	} + +	// Reference version of getInstance() +	// Preferred over getInstance() as it disallows checking for NULL +	static DERIVED_TYPE& instance() +	{ +		return *getInstance(); +	} + +	// Has this singleton been created uet? +	// Use this to avoid accessing singletons before the can safely be constructed +	static bool instanceExists() +	{ +		return sInitState == INITIALIZED; +	} + +	// Has this singleton already been deleted? +	// Use this to avoid accessing singletons from a static object's destructor +	static bool destroyed() +	{ +		return sInitState == DELETED; +	} +private: +	LLThreadLocalSingleton(const LLThreadLocalSingleton& other); +	virtual void initSingleton() {} + +	static __declspec(thread) DERIVED_TYPE* sInstance; +	static __declspec(thread) EInitState sInitState; +}; + +template<typename DERIVED_TYPE> +__declspec(thread) DERIVED_TYPE* LLThreadLocalSingleton<DERIVED_TYPE>::sInstance = NULL; + +template<typename DERIVED_TYPE> +__declspec(thread) typename LLThreadLocalSingleton<DERIVED_TYPE>::EInitState LLThreadLocalSingleton<DERIVED_TYPE>::sInitState = LLThreadLocalSingleton<DERIVED_TYPE>::UNINITIALIZED; + +template<typename DERIVED_TYPE> +class LLThreadLocalSingletonPointer +{ +public: +	void operator =(DERIVED_TYPE* value) +	{ +		sInstance = value; +	} + +	LL_FORCE_INLINE static DERIVED_TYPE* getInstance() +	{ +		return sInstance; +	} + +	LL_FORCE_INLINE static void setInstance(DERIVED_TYPE* instance) +	{ +		sInstance = instance; +	} + +private: +	static __declspec(thread) DERIVED_TYPE* sInstance; +}; + +template<typename DERIVED_TYPE> +__declspec(thread) DERIVED_TYPE* LLThreadLocalSingletonPointer<DERIVED_TYPE>::sInstance = NULL; + +#endif // LL_LLTHREADLOCALSTORAGE_H diff --git a/indra/llcommon/lltrace.cpp b/indra/llcommon/lltrace.cpp index 9d0c93b352..9cadd70dd8 100644 --- a/indra/llcommon/lltrace.cpp +++ b/indra/llcommon/lltrace.cpp @@ -60,12 +60,23 @@ MasterThreadRecorder& getMasterThreadRecorder()  	return *gMasterThreadRecorder;  } -LLThreadLocalPointer<ThreadRecorder>& get_thread_recorder() +LLThreadLocalPointer<ThreadRecorder>& get_thread_recorder_ptr()  {  	static LLThreadLocalPointer<ThreadRecorder> s_thread_recorder;  	return s_thread_recorder;  } +const LLThreadLocalPointer<ThreadRecorder>& get_thread_recorder() +{ +	return get_thread_recorder_ptr(); +} + +void set_thread_recorder(ThreadRecorder* recorder) +{ +	get_thread_recorder_ptr() = recorder; +} + +  TimeBlockTreeNode::TimeBlockTreeNode()   :	mBlock(NULL),  	mParent(NULL), diff --git a/indra/llcommon/lltrace.h b/indra/llcommon/lltrace.h index 05191cafaa..285d4389af 100644 --- a/indra/llcommon/lltrace.h +++ b/indra/llcommon/lltrace.h @@ -34,7 +34,7 @@  #include "llrefcount.h"  #include "llunit.h"  #include "llapr.h" -#include "llthreadlocalpointer.h" +#include "llthreadlocalstorage.h"  #include <list> @@ -70,7 +70,8 @@ namespace LLTrace  	void cleanup();  	bool isInitialized(); -	LLThreadLocalPointer<class ThreadRecorder>& get_thread_recorder(); +	const LLThreadLocalPointer<class ThreadRecorder>& get_thread_recorder(); +	void set_thread_recorder(class ThreadRecorder*);  	class MasterThreadRecorder& getMasterThreadRecorder(); @@ -106,9 +107,9 @@ namespace LLTrace  		~AccumulatorBuffer()  		{ -			if (sPrimaryStorage == mStorage) +			if (LLThreadLocalSingletonPointer<ACCUMULATOR>::getInstance() == mStorage)  			{ -				sPrimaryStorage = getDefaultBuffer()->mStorage; +				LLThreadLocalSingletonPointer<ACCUMULATOR>::setInstance(getDefaultBuffer()->mStorage);  			}  			delete[] mStorage;  		} @@ -151,17 +152,17 @@ namespace LLTrace  		void makePrimary()  		{ -			sPrimaryStorage = mStorage; +			LLThreadLocalSingletonPointer<ACCUMULATOR>::setInstance(mStorage);  		}  		bool isPrimary() const  		{ -			return sPrimaryStorage == mStorage; +			return LLThreadLocalSingletonPointer<ACCUMULATOR>::getInstance() == mStorage;  		}  		LL_FORCE_INLINE static ACCUMULATOR* getPrimaryStorage()   		{  -			return sPrimaryStorage.get();  +			return LLThreadLocalSingletonPointer<ACCUMULATOR>::getInstance();   		}  		// NOTE: this is not thread-safe.  We assume that slots are reserved in the main thread before any child threads are spawned @@ -214,7 +215,6 @@ namespace LLTrace  		{  			// this buffer is allowed to leak so that trace calls from global destructors have somewhere to put their data  			// so as not to trigger an access violation -			//TODO: make this thread local but need to either demand-init apr or remove apr dependency  			static self_t* sBuffer = new AccumulatorBuffer(StaticAllocationMarker());  			static bool sInitialized = false;  			if (!sInitialized) @@ -229,9 +229,7 @@ namespace LLTrace  		ACCUMULATOR*								mStorage;  		size_t										mStorageSize;  		size_t										mNextStorageSlot; -		static LLThreadLocalPointer<ACCUMULATOR>	sPrimaryStorage;  	}; -	template<typename ACCUMULATOR> LLThreadLocalPointer<ACCUMULATOR> AccumulatorBuffer<ACCUMULATOR>::sPrimaryStorage;  	//TODO: replace with decltype when C++11 is enabled  	template<typename T> @@ -250,10 +248,9 @@ namespace LLTrace  		TraceType(const char* name, const char* description = NULL)  		:	LLInstanceTracker<TraceType<ACCUMULATOR>, std::string>(name),  			mName(name), -			mDescription(description ? description : "")	 -		{ -			mAccumulatorIndex = AccumulatorBuffer<ACCUMULATOR>::getDefaultBuffer()->reserveSlot(); -		} +			mDescription(description ? description : ""), +			mAccumulatorIndex(AccumulatorBuffer<ACCUMULATOR>::getDefaultBuffer()->reserveSlot()) +		{}  		LL_FORCE_INLINE ACCUMULATOR* getPrimaryAccumulator() const  		{ @@ -263,13 +260,12 @@ namespace LLTrace  		size_t getIndex() const { return mAccumulatorIndex; } -		std::string& getName() { return mName; }  		const std::string& getName() const { return mName; }  	protected: -		std::string	mName; -		std::string mDescription; -		size_t		mAccumulatorIndex; +		const std::string	mName; +		const std::string	mDescription; +		const size_t		mAccumulatorIndex;  	};  	template<typename T> diff --git a/indra/llcommon/lltracethreadrecorder.cpp b/indra/llcommon/lltracethreadrecorder.cpp index 156b0ef26b..9fb789c62d 100644 --- a/indra/llcommon/lltracethreadrecorder.cpp +++ b/indra/llcommon/lltracethreadrecorder.cpp @@ -39,18 +39,17 @@ namespace LLTrace  ThreadRecorder::ThreadRecorder()  {  	//NB: the ordering of initialization in this function is very fragile due to a large number of implicit dependencies -	get_thread_recorder() = this; +	set_thread_recorder(this); +	TimeBlock& root_time_block = TimeBlock::getRootTimeBlock(); -	mRootTimerData = new CurTimerData(); -	mRootTimerData->mTimerData = &TimeBlock::getRootTimer(); -	TimeBlock::sCurTimerData = mRootTimerData; +	ThreadTimerStack* timer_stack = ThreadTimerStack::getInstance(); +	timer_stack->mTimeBlock = &root_time_block; +	timer_stack->mActiveTimer = NULL;  	mNumTimeBlockTreeNodes = AccumulatorBuffer<TimeBlockAccumulator>::getDefaultBuffer()->size();  	mTimeBlockTreeNodes = new TimeBlockTreeNode[mNumTimeBlockTreeNodes]; -	mFullRecording.start(); - -	TimeBlock& root_timer = TimeBlock::getRootTimer(); +	mThreadRecording.start();  	// initialize time block parent pointers  	for (LLInstanceTracker<TimeBlock>::instance_iter it = LLInstanceTracker<TimeBlock>::beginInstances(), end_it = LLInstanceTracker<TimeBlock>::endInstances();  @@ -60,15 +59,15 @@ ThreadRecorder::ThreadRecorder()  		TimeBlock& time_block = *it;  		TimeBlockTreeNode& tree_node = mTimeBlockTreeNodes[it->getIndex()];  		tree_node.mBlock = &time_block; -		tree_node.mParent = &root_timer; +		tree_node.mParent = &root_time_block; -		it->getPrimaryAccumulator()->mParent = &root_timer; +		it->getPrimaryAccumulator()->mParent = &root_time_block;  	} -	mRootTimer = new BlockTimer(root_timer); -	mRootTimerData->mCurTimer = mRootTimer; +	mRootTimer = new BlockTimer(root_time_block); +	timer_stack->mActiveTimer = mRootTimer; -	TimeBlock::getRootTimer().getPrimaryAccumulator()->mActiveCount = 1; +	TimeBlock::getRootTimeBlock().getPrimaryAccumulator()->mActiveCount = 1;  }  ThreadRecorder::~ThreadRecorder() @@ -79,9 +78,7 @@ ThreadRecorder::~ThreadRecorder()  	{  		mActiveRecordings.front().mTargetRecording->stop();  	} -	get_thread_recorder() = NULL; -	TimeBlock::sCurTimerData = NULL; -	delete mRootTimerData; +	set_thread_recorder(NULL);  	delete[] mTimeBlockTreeNodes;  } @@ -196,12 +193,12 @@ SlaveThreadRecorder::~SlaveThreadRecorder()  void SlaveThreadRecorder::pushToMaster()  { -	mFullRecording.stop(); +	mThreadRecording.stop();  	{  		LLMutexLock(getMasterThreadRecorder().getSlaveListMutex()); -		mSharedData.appendFrom(mFullRecording); +		mSharedData.appendFrom(mThreadRecording);  	} -	mFullRecording.start(); +	mThreadRecording.start();  }  void SlaveThreadRecorder::SharedData::appendFrom( const Recording& source ) diff --git a/indra/llcommon/lltracethreadrecorder.h b/indra/llcommon/lltracethreadrecorder.h index d09527eced..337035974c 100644 --- a/indra/llcommon/lltracethreadrecorder.h +++ b/indra/llcommon/lltracethreadrecorder.h @@ -62,13 +62,12 @@ namespace LLTrace  			void moveBaselineToTarget();  		}; -		Recording					mFullRecording; +		Recording					mThreadRecording;  		std::list<ActiveRecording>	mActiveRecordings; -		struct CurTimerData*	mRootTimerData; -		class BlockTimer*		mRootTimer; -		TimeBlockTreeNode*		mTimeBlockTreeNodes; -		size_t					mNumTimeBlockTreeNodes; +		class BlockTimer*				mRootTimer; +		TimeBlockTreeNode*				mTimeBlockTreeNodes; +		size_t							mNumTimeBlockTreeNodes;  	};  	class LL_COMMON_API MasterThreadRecorder : public ThreadRecorder diff --git a/indra/llmessage/llbuffer.cpp b/indra/llmessage/llbuffer.cpp index 01da20f060..1722b48f44 100644 --- a/indra/llmessage/llbuffer.cpp +++ b/indra/llmessage/llbuffer.cpp @@ -32,6 +32,7 @@  #include "llmath.h"  #include "llstl.h"  #include "llthread.h" +#include <iterator>  #define ASSERT_LLBUFFERARRAY_MUTEX_LOCKED llassert(!mMutexp || mMutexp->isSelfLocked()); diff --git a/indra/llmessage/lldispatcher.cpp b/indra/llmessage/lldispatcher.cpp index b2dc414a68..7ac3651a76 100644 --- a/indra/llmessage/lldispatcher.cpp +++ b/indra/llmessage/lldispatcher.cpp @@ -29,6 +29,7 @@  #include "lldispatcher.h"  #include <algorithm> +#include <iterator>  #include "llstl.h"  #include "message.h" | 
