summaryrefslogtreecommitdiff
path: root/indra/llcommon/llthreadlocalstorage.h
diff options
context:
space:
mode:
authorRichard Linden <none@none>2013-06-05 19:05:43 -0700
committerRichard Linden <none@none>2013-06-05 19:05:43 -0700
commit0a96b47663c99914c587cdcb8bcdc096bbf55fa3 (patch)
tree67bca4958927ed7f6df423de05e42cd271292391 /indra/llcommon/llthreadlocalstorage.h
parentdcfb18373eca7986a73d8b9a1d34970cc0a23ed9 (diff)
parenta74b5dfa923f8eeccc9b786143f0f832de3ad450 (diff)
merge with viewer-release
Diffstat (limited to 'indra/llcommon/llthreadlocalstorage.h')
-rw-r--r--indra/llcommon/llthreadlocalstorage.h357
1 files changed, 357 insertions, 0 deletions
diff --git a/indra/llcommon/llthreadlocalstorage.h b/indra/llcommon/llthreadlocalstorage.h
new file mode 100644
index 0000000000..a15f9185b1
--- /dev/null
+++ b/indra/llcommon/llthreadlocalstorage.h
@@ -0,0 +1,357 @@
+/**
+ * @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"
+
+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);
+
+ void* get() const;
+
+ void initStorage();
+ void destroyStorage();
+
+protected:
+ struct 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;
+ }
+
+ bool isNull() const { return !sInitialized || get() == NULL; }
+
+ bool notNull() const { return sInitialized && get() != NULL; }
+};
+
+template<typename DERIVED_TYPE>
+class LLThreadLocalSingleton
+{
+ typedef enum e_init_state
+ {
+ UNINITIALIZED = 0,
+ CONSTRUCTING,
+ INITIALIZING,
+ INITIALIZED,
+ DELETED
+ } EInitState;
+
+public:
+ LLThreadLocalSingleton()
+ {}
+
+ virtual ~LLThreadLocalSingleton()
+ {
+#if LL_DARWIN
+ pthread_setspecific(sInstanceKey, NULL);
+#else
+ sInstance = NULL;
+#endif
+ setInitState(DELETED);
+ }
+
+ static void deleteSingleton()
+ {
+ delete getIfExists();
+ }
+
+ 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 LL_DARWIN
+ createTLSInstance();
+#endif
+ if (!getIfExists())
+ {
+ setInitState(CONSTRUCTING);
+ DERIVED_TYPE* instancep = new DERIVED_TYPE();
+#if LL_DARWIN
+ S32 result = pthread_setspecific(sInstanceKey, (void*)instancep);
+ if (result != 0)
+ {
+ llerrs << "Could not set thread local storage" << llendl;
+ }
+#else
+ sInstance = instancep;
+#endif
+ setInitState(INITIALIZING);
+ instancep->initSingleton();
+ setInitState(INITIALIZED);
+ }
+
+ return getIfExists();
+ }
+
+ static DERIVED_TYPE* getIfExists()
+ {
+#if LL_DARWIN
+ return (DERIVED_TYPE*)pthread_getspecific(sInstanceKey);
+#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:
+#if LL_DARWIN
+ static void createTLSInitState()
+ {
+ static S32 key_created = pthread_key_create(&sInitStateKey, NULL);
+ if (key_created != 0)
+ {
+ llerrs << "Could not create thread local storage" << llendl;
+ }
+ }
+
+ static void createTLSInstance()
+ {
+ static S32 key_created = pthread_key_create(&sInstanceKey, NULL);
+ if (key_created != 0)
+ {
+ llerrs << "Could not create thread local storage" << llendl;
+ }
+ }
+#endif
+ static EInitState getInitState()
+ {
+#if LL_DARWIN
+ createTLSInitState();
+ return (EInitState)(int)pthread_getspecific(sInitStateKey);
+#else
+ return sInitState;
+#endif
+ }
+
+ static void setInitState(EInitState state)
+ {
+#if LL_DARWIN
+ createTLSInitState();
+ pthread_setspecific(sInitStateKey, (void*)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 pthread_key_t sInstanceKey;
+ static pthread_key_t sInitStateKey;
+#endif
+};
+
+#if LL_WINDOWS
+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;
+#elif LL_LINUX
+template<typename DERIVED_TYPE>
+__thread DERIVED_TYPE* LLThreadLocalSingleton<DERIVED_TYPE>::sInstance = NULL;
+
+template<typename DERIVED_TYPE>
+__thread typename LLThreadLocalSingleton<DERIVED_TYPE>::EInitState LLThreadLocalSingleton<DERIVED_TYPE>::sInitState = LLThreadLocalSingleton<DERIVED_TYPE>::UNINITIALIZED;
+#elif LL_DARWIN
+template<typename DERIVED_TYPE>
+pthread_key_t LLThreadLocalSingleton<DERIVED_TYPE>::sInstanceKey;
+
+template<typename DERIVED_TYPE>
+pthread_key_t LLThreadLocalSingleton<DERIVED_TYPE>::sInitStateKey;
+
+#endif
+
+template<typename DERIVED_TYPE>
+class LLThreadLocalSingletonPointer
+{
+public:
+ LL_FORCE_INLINE static DERIVED_TYPE* getInstance()
+ {
+#if LL_DARWIN
+ createTLSKey();
+ return (DERIVED_TYPE*)pthread_getspecific(sInstanceKey);
+#else
+ return sInstance;
+#endif
+ }
+
+ static void setInstance(DERIVED_TYPE* instance)
+ {
+#if LL_DARWIN
+ createTLSKey();
+ pthread_setspecific(sInstanceKey, (void*)instance);
+#else
+ sInstance = instance;
+#endif
+ }
+
+private:
+
+#if LL_WINDOWS
+ static __declspec(thread) DERIVED_TYPE* sInstance;
+#elif LL_LINUX
+ static __thread DERIVED_TYPE* sInstance;
+#elif LL_DARWIN
+ static void TLSError()
+ {
+ llerrs << "Could not create thread local storage" << llendl;
+ }
+ static void createTLSKey()
+ {
+ static S32 key_created = pthread_key_create(&sInstanceKey, NULL);
+ if (key_created != 0)
+ {
+ llerrs << "Could not create thread local storage" << llendl;
+ }
+ }
+ static pthread_key_t sInstanceKey;
+#endif
+};
+
+#if LL_WINDOWS
+template<typename DERIVED_TYPE>
+__declspec(thread) DERIVED_TYPE* LLThreadLocalSingletonPointer<DERIVED_TYPE>::sInstance = NULL;
+#elif LL_LINUX
+template<typename DERIVED_TYPE>
+__thread DERIVED_TYPE* LLThreadLocalSingletonPointer<DERIVED_TYPE>::sInstance = NULL;
+#elif LL_DARWIN
+template<typename DERIVED_TYPE>
+pthread_key_t LLThreadLocalSingletonPointer<DERIVED_TYPE>::sInstanceKey;
+#endif
+
+#endif // LL_LLTHREADLOCALSTORAGE_H