/** * @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 { 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 class LLThreadLocalPointer : public LLThreadLocalPointerBase { public: LLThreadLocalPointer() {} explicit LLThreadLocalPointer(T* value) { set(value); } LLThreadLocalPointer(const LLThreadLocalPointer& 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& operator = (T* value) { set((void*)value); return *this; } bool operator ==(const T* other) const { if (!sInitialized) return false; return get() == other; } }; template class LLThreadLocalSingleton { typedef enum e_init_state { UNINITIALIZED = 0, CONSTRUCTING, INITIALIZING, INITIALIZED, DELETED } EInitState; public: LLThreadLocalSingleton() {} virtual ~LLThreadLocalSingleton() { sInstance = NULL; setInitState(DELETED); } static void deleteSingleton() { delete sInstance; sInstance = NULL; setInitState(DELETED); } static DERIVED_TYPE* getInstance() { EInitState init_state = getInitState(); if (init_state == CONSTRUCTING) { llerrs << "Tried to access singleton " << typeid(DERIVED_TYPE).name() << " from singleton constructor!" << llendl; } if (init_state == DELETED) { llwarns << "Trying to access deleted singleton " << typeid(DERIVED_TYPE).name() << " creating new instance" << llendl; } if (!getIfExists()) { setInitState(CONSTRUCTING); sInstance = new DERIVED_TYPE(); setInitState(INITIALIZING); sInstance->initSingleton(); setInitState(INITIALIZED); } return getIfExists(); } static DERIVED_TYPE* getIfExists() { #if LL_DARWIN return sInstance.get(); #else return sInstance; #endif } // 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 getInitState() == INITIALIZED; } // Has this singleton already been deleted? // Use this to avoid accessing singletons from a static object's destructor static bool destroyed() { return getInitState() == DELETED; } private: static EInitState getInitState() { #if LL_DARWIN return (EInitState)(int)sInitState.get(); #else return sInitState; #endif } static void setInitState(EInitState state) { #if LL_DARWIN sInitState = (int*)state; #else sInitState = state; #endif } LLThreadLocalSingleton(const LLThreadLocalSingleton& other); virtual void initSingleton() {} #ifdef LL_WINDOWS static __declspec(thread) DERIVED_TYPE* sInstance; static __declspec(thread) EInitState sInitState; #elif LL_LINUX static __thread DERIVED_TYPE* sInstance; static __thread EInitState sInitState; #elif LL_DARWIN static LLThreadLocalPointer sInstance; static LLThreadLocalPointer sInitState; #endif }; #if LL_WINDOWS template __declspec(thread) DERIVED_TYPE* LLThreadLocalSingleton::sInstance = NULL; template __declspec(thread) typename LLThreadLocalSingleton::EInitState LLThreadLocalSingleton::sInitState = LLThreadLocalSingleton::UNINITIALIZED; #elif LL_LINUX template __thread DERIVED_TYPE* LLThreadLocalSingleton::sInstance = NULL; template __thread typename LLThreadLocalSingleton::EInitState LLThreadLocalSingleton::sInitState = LLThreadLocalSingleton::UNINITIALIZED; #elif LL_DARWIN template LLThreadLocalPointer LLThreadLocalSingleton::sInstance; template LLThreadLocalPointer LLThreadLocalSingleton::sInitState; #endif template class LLThreadLocalSingletonPointer { public: void operator =(DERIVED_TYPE* value) { sInstance = value; } LL_FORCE_INLINE static DERIVED_TYPE* getInstance() { #if LL_DARWIN return sInstance.get(); #else return sInstance; #endif } LL_FORCE_INLINE static void setInstance(DERIVED_TYPE* instance) { sInstance = instance; } private: #if LL_WINDOWS static __declspec(thread) DERIVED_TYPE* sInstance; #elif LL_LINUX static __thread DERIVED_TYPE* sInstance; #elif LL_DARWIN static LLThreadLocalPointer sInstance; #endif }; #if LL_WINDOWS template __declspec(thread) DERIVED_TYPE* LLThreadLocalSingletonPointer::sInstance = NULL; #elif LL_LINUX template __thread DERIVED_TYPE* LLThreadLocalSingletonPointer::sInstance = NULL; #elif LL_DARWIN template LLThreadLocalPointer LLThreadLocalSingletonPointer::sInstance; #endif #endif // LL_LLTHREADLOCALSTORAGE_H