ThreadLocal.h 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196
  1. /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
  2. /* This Source Code Form is subject to the terms of the Mozilla Public
  3. * License, v. 2.0. If a copy of the MPL was not distributed with this
  4. * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
  5. /* Cross-platform lightweight thread local data wrappers. */
  6. #ifndef mozilla_ThreadLocal_h
  7. #define mozilla_ThreadLocal_h
  8. #if !defined(XP_WIN)
  9. # include <pthread.h>
  10. # include <signal.h>
  11. #endif
  12. #include "mozilla/Assertions.h"
  13. #include "mozilla/Attributes.h"
  14. #include "mozilla/TypeTraits.h"
  15. namespace mozilla {
  16. // sig_safe_t denotes an atomic type which can be read or stored in a single
  17. // instruction. This means that data of this type is safe to be manipulated
  18. // from a signal handler, or other similar asynchronous execution contexts.
  19. #if defined(XP_WIN)
  20. typedef unsigned long sig_safe_t;
  21. #else
  22. typedef sig_atomic_t sig_safe_t;
  23. #endif
  24. namespace detail {
  25. #if defined(HAVE_THREAD_TLS_KEYWORD) || defined(XP_WIN)
  26. #define MOZ_HAS_THREAD_LOCAL
  27. #endif
  28. /*
  29. * Thread Local Storage helpers.
  30. *
  31. * Usage:
  32. *
  33. * Do not directly instantiate this class. Instead, use the
  34. * MOZ_THREAD_LOCAL macro to declare or define instances. The macro
  35. * takes a type name as its argument.
  36. *
  37. * Declare like this:
  38. * extern MOZ_THREAD_LOCAL(int) tlsInt;
  39. * Define like this:
  40. * MOZ_THREAD_LOCAL(int) tlsInt;
  41. * or:
  42. * static MOZ_THREAD_LOCAL(int) tlsInt;
  43. *
  44. * Only static-storage-duration (e.g. global variables, or static class members)
  45. * objects of this class should be instantiated. This class relies on
  46. * zero-initialization, which is implicit for static-storage-duration objects.
  47. * It doesn't have a custom default constructor, to avoid static initializers.
  48. *
  49. * API usage:
  50. *
  51. * // Create a TLS item.
  52. * //
  53. * // Note that init() should be invoked before the first use of set()
  54. * // or get(). It is ok to call it multiple times. This must be
  55. * // called in a way that avoids possible races with other threads.
  56. * MOZ_THREAD_LOCAL(int) tlsKey;
  57. * if (!tlsKey.init()) {
  58. * // deal with the error
  59. * }
  60. *
  61. * // Set the TLS value
  62. * tlsKey.set(123);
  63. *
  64. * // Get the TLS value
  65. * int value = tlsKey.get();
  66. */
  67. template<typename T>
  68. class ThreadLocal
  69. {
  70. #ifndef MOZ_HAS_THREAD_LOCAL
  71. typedef pthread_key_t key_t;
  72. // Integral types narrower than void* must be extended to avoid
  73. // warnings from valgrind on some platforms. This helper type
  74. // achieves that without penalizing the common case of ThreadLocals
  75. // instantiated using a pointer type.
  76. template<typename S>
  77. struct Helper
  78. {
  79. typedef uintptr_t Type;
  80. };
  81. template<typename S>
  82. struct Helper<S *>
  83. {
  84. typedef S *Type;
  85. };
  86. #endif
  87. bool initialized() const {
  88. #ifdef MOZ_HAS_THREAD_LOCAL
  89. return true;
  90. #else
  91. return mInited;
  92. #endif
  93. }
  94. public:
  95. // __thread does not allow non-trivial constructors, but we can
  96. // instead rely on zero-initialization.
  97. #ifndef MOZ_HAS_THREAD_LOCAL
  98. ThreadLocal()
  99. : mKey(0), mInited(false)
  100. {}
  101. #endif
  102. MOZ_MUST_USE inline bool init();
  103. inline T get() const;
  104. inline void set(const T aValue);
  105. private:
  106. #ifdef MOZ_HAS_THREAD_LOCAL
  107. T mValue;
  108. #else
  109. key_t mKey;
  110. bool mInited;
  111. #endif
  112. };
  113. template<typename T>
  114. inline bool
  115. ThreadLocal<T>::init()
  116. {
  117. static_assert(mozilla::IsPointer<T>::value || mozilla::IsIntegral<T>::value,
  118. "mozilla::ThreadLocal must be used with a pointer or "
  119. "integral type");
  120. static_assert(sizeof(T) <= sizeof(void*),
  121. "mozilla::ThreadLocal can't be used for types larger than "
  122. "a pointer");
  123. #ifdef MOZ_HAS_THREAD_LOCAL
  124. return true;
  125. #else
  126. if (!initialized()) {
  127. mInited = !pthread_key_create(&mKey, nullptr);
  128. }
  129. return mInited;
  130. #endif
  131. }
  132. template<typename T>
  133. inline T
  134. ThreadLocal<T>::get() const
  135. {
  136. #ifdef MOZ_HAS_THREAD_LOCAL
  137. return mValue;
  138. #else
  139. MOZ_ASSERT(initialized());
  140. void* h;
  141. h = pthread_getspecific(mKey);
  142. return static_cast<T>(reinterpret_cast<typename Helper<T>::Type>(h));
  143. #endif
  144. }
  145. template<typename T>
  146. inline void
  147. ThreadLocal<T>::set(const T aValue)
  148. {
  149. #ifdef MOZ_HAS_THREAD_LOCAL
  150. mValue = aValue;
  151. #else
  152. MOZ_ASSERT(initialized());
  153. void* h = reinterpret_cast<void*>(static_cast<typename Helper<T>::Type>(aValue));
  154. bool succeeded = !pthread_setspecific(mKey, h);
  155. if (!succeeded) {
  156. MOZ_CRASH();
  157. }
  158. #endif
  159. }
  160. #ifdef MOZ_HAS_THREAD_LOCAL
  161. #if defined(XP_WIN)
  162. #define MOZ_THREAD_LOCAL(TYPE) thread_local mozilla::detail::ThreadLocal<TYPE>
  163. #else
  164. #define MOZ_THREAD_LOCAL(TYPE) __thread mozilla::detail::ThreadLocal<TYPE>
  165. #endif
  166. #else
  167. #define MOZ_THREAD_LOCAL(TYPE) mozilla::detail::ThreadLocal<TYPE>
  168. #endif
  169. } // namespace detail
  170. } // namespace mozilla
  171. #endif /* mozilla_ThreadLocal_h */