Bug 1399031 - Expose pthread_{get,set}specific-based TLS whether "native" TLS is supported or not. r?froydnj draft
authorMike Hommey <mh+mozilla@glandium.org>
Tue, 12 Sep 2017 15:37:31 +0900
changeset 663484 78dd3fae969a3d6227a70340c7abb916b69fade5
parent 663134 a73cc4e08bf5a005722c95b43f84ab0c8ff2bc7c
child 663485 2412bda447ee73078439b9c168b403253e1ef3e2
push id79465
push userbmo:mh+mozilla@glandium.org
push dateWed, 13 Sep 2017 05:35:00 +0000
reviewersfroydnj
bugs1399031
milestone57.0a1
Bug 1399031 - Expose pthread_{get,set}specific-based TLS whether "native" TLS is supported or not. r?froydnj There are use cases for wanting a specific TLS implementation independently of whether __thread or thread_local are supported. This is one step in that direction, making the pthread_{get,set}specific-based implementation available independently. We still keep everything under the mozilla::detail namespace because it's still better if people don't try to use mozilla::ThreadLocal directly.
mfbt/ThreadLocal.h
--- a/mfbt/ThreadLocal.h
+++ b/mfbt/ThreadLocal.h
@@ -24,20 +24,16 @@ namespace detail {
 #ifdef XP_MACOSX
 #  if defined(__has_feature)
 #    if __has_feature(cxx_thread_local)
 #      define MACOSX_HAS_THREAD_LOCAL
 #    endif
 #  endif
 #endif
 
-#if defined(HAVE_THREAD_TLS_KEYWORD) || defined(XP_WIN) || defined(MACOSX_HAS_THREAD_LOCAL)
-#define MOZ_HAS_THREAD_LOCAL
-#endif
-
 /*
  * Thread Local Storage helpers.
  *
  * Usage:
  *
  * Do not directly instantiate this class.  Instead, use the
  * MOZ_THREAD_LOCAL macro to declare or define instances.  The macro
  * takes a type name as its argument.
@@ -67,131 +63,146 @@ namespace detail {
  * }
  *
  * // Set the TLS value
  * tlsKey.set(123);
  *
  * // Get the TLS value
  * int value = tlsKey.get();
  */
+#ifndef XP_WIN
 template<typename T>
-class ThreadLocal
+class ThreadLocalKeyStorage
 {
-#ifndef MOZ_HAS_THREAD_LOCAL
-  typedef pthread_key_t key_t;
-
   // Integral types narrower than void* must be extended to avoid
   // warnings from valgrind on some platforms.  This helper type
   // achieves that without penalizing the common case of ThreadLocals
   // instantiated using a pointer type.
   template<typename S>
   struct Helper
   {
     typedef uintptr_t Type;
   };
 
   template<typename S>
   struct Helper<S *>
   {
     typedef S *Type;
   };
+
+public:
+  ThreadLocalKeyStorage()
+    : mKey(0), mInited(false)
+  {}
+
+  inline bool initialized() const {
+    return mInited;
+  }
+
+  inline void init() {
+    mInited = !pthread_key_create(&mKey, nullptr);
+  }
+
+  inline T get() const {
+    void* h = pthread_getspecific(mKey);
+    return static_cast<T>(reinterpret_cast<typename Helper<T>::Type>(h));
+  }
+
+  inline bool set(const T aValue) {
+    void* h = reinterpret_cast<void*>(static_cast<typename Helper<T>::Type>(aValue));
+    return !pthread_setspecific(mKey, h);
+  }
+
+private:
+  pthread_key_t mKey;
+  bool mInited;
+};
 #endif
 
+template<typename T>
+class ThreadLocalNativeStorage
+{
 public:
   // __thread does not allow non-trivial constructors, but we can
   // instead rely on zero-initialization.
-#ifndef MOZ_HAS_THREAD_LOCAL
-  ThreadLocal()
-    : mKey(0), mInited(false)
-  {}
-#endif
+  inline bool initialized() const {
+    return true;
+  }
 
-  bool initialized() const {
-#ifdef MOZ_HAS_THREAD_LOCAL
-    return true;
-#else
-    return mInited;
-#endif
+  inline void init() {
+  }
+
+  inline T get() const {
+    return mValue;
   }
 
+  inline bool set(const T aValue) {
+    mValue = aValue;
+    return true;
+  }
+
+private:
+  T mValue;
+};
+
+template<typename T, template <typename U> class Storage>
+class ThreadLocal: public Storage<T>
+{
+public:
   MOZ_MUST_USE inline bool init();
+
   void infallibleInit() {
     MOZ_RELEASE_ASSERT(init(), "Infallible TLS initialization failed");
   }
 
   inline T get() const;
 
   inline void set(const T aValue);
-
-private:
-#ifdef MOZ_HAS_THREAD_LOCAL
-  T mValue;
-#else
-  key_t mKey;
-  bool mInited;
-#endif
 };
 
-template<typename T>
+template<typename T, template <typename U> class Storage>
 inline bool
-ThreadLocal<T>::init()
+ThreadLocal<T, Storage>::init()
 {
   static_assert(mozilla::IsPointer<T>::value || mozilla::IsIntegral<T>::value,
                 "mozilla::ThreadLocal must be used with a pointer or "
                 "integral type");
   static_assert(sizeof(T) <= sizeof(void*),
                 "mozilla::ThreadLocal can't be used for types larger than "
                 "a pointer");
 
-#ifdef MOZ_HAS_THREAD_LOCAL
-  return true;
-#else
-  if (!initialized()) {
-    mInited = !pthread_key_create(&mKey, nullptr);
+  if (!Storage<T>::initialized()) {
+    Storage<T>::init();
   }
-  return mInited;
-#endif
+  return Storage<T>::initialized();
 }
 
-template<typename T>
+template<typename T, template <typename U> class Storage>
 inline T
-ThreadLocal<T>::get() const
+ThreadLocal<T, Storage>::get() const
 {
-#ifdef MOZ_HAS_THREAD_LOCAL
-  return mValue;
-#else
-  MOZ_ASSERT(initialized());
-  void* h;
-  h = pthread_getspecific(mKey);
-  return static_cast<T>(reinterpret_cast<typename Helper<T>::Type>(h));
-#endif
+  MOZ_ASSERT(Storage<T>::initialized());
+  return Storage<T>::get();
 }
 
-template<typename T>
+template<typename T, template <typename U> class Storage>
 inline void
-ThreadLocal<T>::set(const T aValue)
+ThreadLocal<T, Storage>::set(const T aValue)
 {
-#ifdef MOZ_HAS_THREAD_LOCAL
-  mValue = aValue;
-#else
-  MOZ_ASSERT(initialized());
-  void* h = reinterpret_cast<void*>(static_cast<typename Helper<T>::Type>(aValue));
-  bool succeeded = !pthread_setspecific(mKey, h);
+  MOZ_ASSERT(Storage<T>::initialized());
+  bool succeeded = Storage<T>::set(aValue);
   if (!succeeded) {
     MOZ_CRASH();
   }
-#endif
 }
 
-#ifdef MOZ_HAS_THREAD_LOCAL
 #if defined(XP_WIN) || defined(MACOSX_HAS_THREAD_LOCAL)
-#define MOZ_THREAD_LOCAL(TYPE) thread_local mozilla::detail::ThreadLocal<TYPE>
+#define MOZ_THREAD_LOCAL(TYPE) thread_local mozilla::detail::ThreadLocal<TYPE, mozilla::detail::ThreadLocalNativeStorage>
+#elif defined(HAVE_THREAD_TLS_KEYWORD)
+#define MOZ_THREAD_LOCAL(TYPE) __thread mozilla::detail::ThreadLocal<TYPE, mozilla::detail::ThreadLocalNativeStorage>
 #else
-#define MOZ_THREAD_LOCAL(TYPE) __thread mozilla::detail::ThreadLocal<TYPE>
-#endif
-#else
-#define MOZ_THREAD_LOCAL(TYPE) mozilla::detail::ThreadLocal<TYPE>
+#define MOZ_THREAD_LOCAL(TYPE) mozilla::detail::ThreadLocal<TYPE, mozilla::detail::ThreadLocalKeyStorage>
 #endif
 
 } // namespace detail
 } // namespace mozilla
 
 #endif /* mozilla_ThreadLocal_h */