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