Unreviewed, rolling out r234489.
[WebKit-https.git] / Source / WTF / wtf / ThreadSpecific.h
1 /*
2  * Copyright (C) 2008, 2016 Apple Inc. All rights reserved.
3  * Copyright (C) 2009 Jian Li <jianli@chromium.org>
4  * Copyright (C) 2012 Patrick Gansterer <paroga@paroga.com>
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  *
10  * 1.  Redistributions of source code must retain the above copyright
11  *     notice, this list of conditions and the following disclaimer. 
12  * 2.  Redistributions in binary form must reproduce the above copyright
13  *     notice, this list of conditions and the following disclaimer in the
14  *     documentation and/or other materials provided with the distribution. 
15  * 3.  Neither the name of Apple Inc. ("Apple") nor the names of
16  *     its contributors may be used to endorse or promote products derived
17  *     from this software without specific prior written permission. 
18  *
19  * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
20  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
21  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22  * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
23  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
24  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
26  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
28  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29  */
30
31 /* Thread local storage is implemented by using either pthread API or Windows
32  * native API. There is subtle semantic discrepancy for the cleanup function
33  * implementation as noted below:
34  *   @ In pthread implementation, the destructor function will be called
35  *     repeatedly if there is still non-NULL value associated with the function.
36  *   @ In Windows native implementation, the destructor function will be called
37  *     only once.
38  * This semantic discrepancy does not impose any problem because nowhere in
39  * WebKit the repeated call bahavior is utilized.
40  */
41
42 #ifndef WTF_ThreadSpecific_h
43 #define WTF_ThreadSpecific_h
44
45 #include <wtf/MainThread.h>
46 #include <wtf/Noncopyable.h>
47 #include <wtf/StdLibExtras.h>
48
49 #if USE(PTHREADS)
50 #include <pthread.h>
51
52 #if OS(HURD)
53 // PTHREAD_KEYS_MAX is not defined in bionic nor in Hurd, so explicitly define it here.
54 #define PTHREAD_KEYS_MAX 1024
55 #else
56 #include <limits.h>
57 #endif
58
59 #elif OS(WINDOWS)
60 #include <windows.h>
61 #endif
62
63 namespace WTF {
64
65 #if OS(WINDOWS) && CPU(X86)
66 #define THREAD_SPECIFIC_CALL __stdcall
67 #else
68 #define THREAD_SPECIFIC_CALL
69 #endif
70
71 enum class CanBeGCThread {
72     False,
73     True
74 };
75
76 template<typename T, CanBeGCThread canBeGCThread = CanBeGCThread::False> class ThreadSpecific {
77     WTF_MAKE_NONCOPYABLE(ThreadSpecific);
78 public:
79     ThreadSpecific();
80     bool isSet(); // Useful as a fast check to see if this thread has set this value.
81     T* operator->();
82     operator T*();
83     T& operator*();
84
85 private:
86     // Not implemented. It's technically possible to destroy a thread specific key, but one would need
87     // to make sure that all values have been destroyed already (usually, that all threads that used it
88     // have exited). It's unlikely that any user of this call will be in that situation - and having
89     // a destructor defined can be confusing, given that it has such strong pre-requisites to work correctly.
90     ~ThreadSpecific();
91
92     struct Data {
93         WTF_MAKE_NONCOPYABLE(Data);
94         WTF_MAKE_FAST_ALLOCATED;
95     public:
96         using PointerType = typename std::remove_const<T>::type*;
97
98         Data(ThreadSpecific<T, canBeGCThread>* owner)
99             : owner(owner)
100         {
101             // Set up thread-specific value's memory pointer before invoking constructor, in case any function it calls
102             // needs to access the value, to avoid recursion.
103             owner->setInTLS(this);
104             new (NotNull, storagePointer()) T();
105         }
106
107         ~Data()
108         {
109             storagePointer()->~T();
110             owner->setInTLS(nullptr);
111         }
112
113         PointerType storagePointer() const { return const_cast<PointerType>(reinterpret_cast<const T*>(&m_storage)); }
114
115         typename std::aligned_storage<sizeof(T), std::alignment_of<T>::value>::type m_storage;
116         ThreadSpecific<T, canBeGCThread>* owner;
117     };
118
119     T* get();
120     T* set();
121     void setInTLS(Data*);
122     void static THREAD_SPECIFIC_CALL destroy(void* ptr);
123
124 #if USE(PTHREADS)
125     pthread_key_t m_key { };
126 #elif OS(WINDOWS)
127     int m_index;
128 #endif
129 };
130
131 #if USE(PTHREADS)
132
133 typedef pthread_key_t ThreadSpecificKey;
134
135 static const constexpr ThreadSpecificKey InvalidThreadSpecificKey = PTHREAD_KEYS_MAX;
136
137 inline void threadSpecificKeyCreate(ThreadSpecificKey* key, void (*destructor)(void *))
138 {
139     int error = pthread_key_create(key, destructor);
140     if (error)
141         CRASH();
142 }
143
144 inline void threadSpecificKeyDelete(ThreadSpecificKey key)
145 {
146     int error = pthread_key_delete(key);
147     if (error)
148         CRASH();
149 }
150
151 inline void threadSpecificSet(ThreadSpecificKey key, void* value)
152 {
153     pthread_setspecific(key, value);
154 }
155
156 inline void* threadSpecificGet(ThreadSpecificKey key)
157 {
158     return pthread_getspecific(key);
159 }
160
161 template<typename T, CanBeGCThread canBeGCThread>
162 inline ThreadSpecific<T, canBeGCThread>::ThreadSpecific()
163 {
164     int error = pthread_key_create(&m_key, destroy);
165     if (error)
166         CRASH();
167 }
168
169 template<typename T, CanBeGCThread canBeGCThread>
170 inline T* ThreadSpecific<T, canBeGCThread>::get()
171 {
172     Data* data = static_cast<Data*>(pthread_getspecific(m_key));
173     if (data)
174         return data->storagePointer();
175     return nullptr;
176 }
177
178 template<typename T, CanBeGCThread canBeGCThread>
179 inline void ThreadSpecific<T, canBeGCThread>::setInTLS(Data* data)
180 {
181     pthread_setspecific(m_key, data);
182 }
183
184 #elif OS(WINDOWS)
185
186 // The maximum number of FLS keys that can be created. For simplification, we assume that:
187 // 1) Once the instance of ThreadSpecific<> is created, it will not be destructed until the program dies.
188 // 2) We do not need to hold many instances of ThreadSpecific<> data. This fixed number should be far enough.
189 const int kMaxFlsKeySize = 128;
190
191 WTF_EXPORT_PRIVATE long& flsKeyCount();
192 WTF_EXPORT_PRIVATE DWORD* flsKeys();
193
194 typedef DWORD ThreadSpecificKey;
195
196 static const constexpr ThreadSpecificKey InvalidThreadSpecificKey = FLS_OUT_OF_INDEXES;
197
198 inline void threadSpecificKeyCreate(ThreadSpecificKey* key, void (THREAD_SPECIFIC_CALL *destructor)(void *))
199 {
200     DWORD flsKey = FlsAlloc(destructor);
201     if (flsKey == FLS_OUT_OF_INDEXES)
202         CRASH();
203
204     *key = flsKey;
205 }
206
207 inline void threadSpecificKeyDelete(ThreadSpecificKey key)
208 {
209     FlsFree(key);
210 }
211
212 inline void threadSpecificSet(ThreadSpecificKey key, void* data)
213 {
214     FlsSetValue(key, data);
215 }
216
217 inline void* threadSpecificGet(ThreadSpecificKey key)
218 {
219     return FlsGetValue(key);
220 }
221
222 template<typename T, CanBeGCThread canBeGCThread>
223 inline ThreadSpecific<T, canBeGCThread>::ThreadSpecific()
224     : m_index(-1)
225 {
226     DWORD flsKey = FlsAlloc(destroy);
227     if (flsKey == FLS_OUT_OF_INDEXES)
228         CRASH();
229
230     m_index = InterlockedIncrement(&flsKeyCount()) - 1;
231     if (m_index >= kMaxFlsKeySize)
232         CRASH();
233     flsKeys()[m_index] = flsKey;
234 }
235
236 template<typename T, CanBeGCThread canBeGCThread>
237 inline ThreadSpecific<T, canBeGCThread>::~ThreadSpecific()
238 {
239     FlsFree(flsKeys()[m_index]);
240 }
241
242 template<typename T, CanBeGCThread canBeGCThread>
243 inline T* ThreadSpecific<T, canBeGCThread>::get()
244 {
245     Data* data = static_cast<Data*>(FlsGetValue(flsKeys()[m_index]));
246     if (data)
247         return data->storagePointer();
248     return nullptr;
249 }
250
251 template<typename T, CanBeGCThread canBeGCThread>
252 inline void ThreadSpecific<T, canBeGCThread>::setInTLS(Data* data)
253 {
254     FlsSetValue(flsKeys()[m_index], data);
255 }
256
257 #else
258 #error ThreadSpecific is not implemented for this platform.
259 #endif
260
261 template<typename T, CanBeGCThread canBeGCThread>
262 inline void THREAD_SPECIFIC_CALL ThreadSpecific<T, canBeGCThread>::destroy(void* ptr)
263 {
264     Data* data = static_cast<Data*>(ptr);
265
266 #if USE(PTHREADS)
267     // We want get() to keep working while data destructor works, because it can be called indirectly by the destructor.
268     // Some pthreads implementations zero out the pointer before calling destroy(), so we temporarily reset it.
269     pthread_setspecific(data->owner->m_key, ptr);
270 #endif
271
272     delete data;
273 }
274
275 template<typename T, CanBeGCThread canBeGCThread>
276 inline T* ThreadSpecific<T, canBeGCThread>::set()
277 {
278     RELEASE_ASSERT(canBeGCThread == CanBeGCThread::True || !mayBeGCThread());
279     ASSERT(!get());
280     Data* data = new Data(this); // Data will set itself into TLS.
281     ASSERT(get() == data->storagePointer());
282     return data->storagePointer();
283 }
284
285 template<typename T, CanBeGCThread canBeGCThread>
286 inline bool ThreadSpecific<T, canBeGCThread>::isSet()
287 {
288     return !!get();
289 }
290
291 template<typename T, CanBeGCThread canBeGCThread>
292 inline ThreadSpecific<T, canBeGCThread>::operator T*()
293 {
294     if (T* ptr = get())
295         return ptr;
296     return set();
297 }
298
299 template<typename T, CanBeGCThread canBeGCThread>
300 inline T* ThreadSpecific<T, canBeGCThread>::operator->()
301 {
302     return operator T*();
303 }
304
305 template<typename T, CanBeGCThread canBeGCThread>
306 inline T& ThreadSpecific<T, canBeGCThread>::operator*()
307 {
308     return *operator T*();
309 }
310
311 } // namespace WTF
312
313 using WTF::ThreadSpecific;
314
315 #endif // WTF_ThreadSpecific_h