Bug 1601859 - Vendor cubeb-pulse-rs. r=kinetik
[gecko.git] / mfbt / ThreadLocal.h
blob3b789f95ac02550f8f12dd3bbc2a4d38dcfffc49
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 /* Cross-platform lightweight thread local data wrappers. */
9 #ifndef mozilla_ThreadLocal_h
10 #define mozilla_ThreadLocal_h
12 #if !defined(XP_WIN)
13 # include <pthread.h>
14 #endif
16 #include "mozilla/Assertions.h"
17 #include "mozilla/Attributes.h"
18 #include "mozilla/TypeTraits.h"
20 namespace mozilla {
22 namespace detail {
24 #ifdef XP_MACOSX
25 # if defined(__has_feature)
26 # if __has_feature(cxx_thread_local)
27 # define MACOSX_HAS_THREAD_LOCAL
28 # endif
29 # endif
30 #endif
33 * Thread Local Storage helpers.
35 * Usage:
37 * Do not directly instantiate this class. Instead, use the
38 * MOZ_THREAD_LOCAL macro to declare or define instances. The macro
39 * takes a type name as its argument.
41 * Declare like this:
42 * extern MOZ_THREAD_LOCAL(int) tlsInt;
43 * Define like this:
44 * MOZ_THREAD_LOCAL(int) tlsInt;
45 * or:
46 * static MOZ_THREAD_LOCAL(int) tlsInt;
48 * Only static-storage-duration (e.g. global variables, or static class members)
49 * objects of this class should be instantiated. This class relies on
50 * zero-initialization, which is implicit for static-storage-duration objects.
51 * It doesn't have a custom default constructor, to avoid static initializers.
53 * API usage:
55 * // Create a TLS item.
56 * //
57 * // Note that init() should be invoked before the first use of set()
58 * // or get(). It is ok to call it multiple times. This must be
59 * // called in a way that avoids possible races with other threads.
60 * MOZ_THREAD_LOCAL(int) tlsKey;
61 * if (!tlsKey.init()) {
62 * // deal with the error
63 * }
65 * // Set the TLS value
66 * tlsKey.set(123);
68 * // Get the TLS value
69 * int value = tlsKey.get();
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 typedef uintptr_t Type;
81 template <typename S>
82 struct Helper<S*> {
83 typedef S* Type;
86 #if defined(XP_WIN)
88 * ThreadLocalKeyStorage uses Thread Local APIs that are declared in
89 * processthreadsapi.h. To use this class on Windows, include that file
90 * (or windows.h) before including ThreadLocal.h.
92 * TLS_OUT_OF_INDEXES is a #define that is used to detect whether
93 * an appropriate header has been included prior to this file
95 # if defined(TLS_OUT_OF_INDEXES)
96 /* Despite not being used for MOZ_THREAD_LOCAL, we expose an implementation for
97 * Windows for cases where it's not desirable to use thread_local */
98 template <typename T>
99 class ThreadLocalKeyStorage {
100 public:
101 ThreadLocalKeyStorage() : mKey(TLS_OUT_OF_INDEXES) {}
103 inline bool initialized() const { return mKey != TLS_OUT_OF_INDEXES; }
105 inline void init() { mKey = TlsAlloc(); }
107 inline T get() const {
108 void* h = TlsGetValue(mKey);
109 return static_cast<T>(reinterpret_cast<typename Helper<T>::Type>(h));
112 inline bool set(const T aValue) {
113 void* h =
114 reinterpret_cast<void*>(static_cast<typename Helper<T>::Type>(aValue));
115 return TlsSetValue(mKey, h);
118 private:
119 unsigned long mKey;
121 # endif
122 #else
123 template <typename T>
124 class ThreadLocalKeyStorage {
125 public:
126 constexpr ThreadLocalKeyStorage() : mKey(0), mInited(false) {}
128 inline bool initialized() const { return mInited; }
130 inline void init() { mInited = !pthread_key_create(&mKey, nullptr); }
132 inline T get() const {
133 void* h = pthread_getspecific(mKey);
134 return static_cast<T>(reinterpret_cast<typename Helper<T>::Type>(h));
137 inline bool set(const T aValue) {
138 void* h =
139 reinterpret_cast<void*>(static_cast<typename Helper<T>::Type>(aValue));
140 return !pthread_setspecific(mKey, h);
143 private:
144 pthread_key_t mKey;
145 bool mInited;
147 #endif
149 template <typename T>
150 class ThreadLocalNativeStorage {
151 public:
152 // __thread does not allow non-trivial constructors, but we can
153 // instead rely on zero-initialization.
154 inline bool initialized() const { return true; }
156 inline void init() {}
158 inline T get() const { return mValue; }
160 inline bool set(const T aValue) {
161 mValue = aValue;
162 return true;
165 private:
166 T mValue;
169 template <typename T, template <typename U> class Storage>
170 class ThreadLocal : public Storage<T> {
171 public:
172 MOZ_MUST_USE inline bool init();
174 void infallibleInit() {
175 MOZ_RELEASE_ASSERT(init(), "Infallible TLS initialization failed");
178 inline T get() const;
180 inline void set(const T aValue);
182 using Type = T;
185 template <typename T, template <typename U> class Storage>
186 inline bool ThreadLocal<T, Storage>::init() {
187 static_assert(mozilla::IsPointer<T>::value || mozilla::IsIntegral<T>::value,
188 "mozilla::ThreadLocal must be used with a pointer or "
189 "integral type");
190 static_assert(sizeof(T) <= sizeof(void*),
191 "mozilla::ThreadLocal can't be used for types larger than "
192 "a pointer");
194 if (!Storage<T>::initialized()) {
195 Storage<T>::init();
197 return Storage<T>::initialized();
200 template <typename T, template <typename U> class Storage>
201 inline T ThreadLocal<T, Storage>::get() const {
202 MOZ_ASSERT(Storage<T>::initialized());
203 return Storage<T>::get();
206 template <typename T, template <typename U> class Storage>
207 inline void ThreadLocal<T, Storage>::set(const T aValue) {
208 MOZ_ASSERT(Storage<T>::initialized());
209 bool succeeded = Storage<T>::set(aValue);
210 if (!succeeded) {
211 MOZ_CRASH();
215 #if (defined(XP_WIN) || defined(MACOSX_HAS_THREAD_LOCAL)) && \
216 !defined(__MINGW32__)
217 # define MOZ_THREAD_LOCAL(TYPE) \
218 thread_local ::mozilla::detail::ThreadLocal< \
219 TYPE, ::mozilla::detail::ThreadLocalNativeStorage>
220 #elif defined(HAVE_THREAD_TLS_KEYWORD)
221 # define MOZ_THREAD_LOCAL(TYPE) \
222 __thread ::mozilla::detail::ThreadLocal< \
223 TYPE, ::mozilla::detail::ThreadLocalNativeStorage>
224 #else
225 # define MOZ_THREAD_LOCAL(TYPE) \
226 ::mozilla::detail::ThreadLocal<TYPE, \
227 ::mozilla::detail::ThreadLocalKeyStorage>
228 #endif
230 } // namespace detail
231 } // namespace mozilla
233 #endif /* mozilla_ThreadLocal_h */