|
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 : public Noncopyable { |
|
65 public: |
|
66 ThreadSpecific(); |
|
67 T* operator->(); |
|
68 operator T*(); |
|
69 T& operator*(); |
|
70 ~ThreadSpecific(); |
|
71 |
|
72 private: |
|
73 #if !USE(PTHREADS) && !PLATFORM(QT) && !PLATFORM(GTK) && OS(WINDOWS) |
|
74 friend void ThreadSpecificThreadExit(); |
|
75 #endif |
|
76 |
|
77 T* get(); |
|
78 void set(T*); |
|
79 void static destroy(void* ptr); |
|
80 |
|
81 #if USE(PTHREADS) || PLATFORM(QT) || PLATFORM(GTK) || OS(WINDOWS) |
|
82 struct Data : Noncopyable { |
|
83 Data(T* value, ThreadSpecific<T>* owner) : value(value), owner(owner) {} |
|
84 #if PLATFORM(QT) |
|
85 ~Data() { owner->destroy(this); } |
|
86 #endif |
|
87 |
|
88 T* value; |
|
89 ThreadSpecific<T>* owner; |
|
90 #if !USE(PTHREADS) && !PLATFORM(QT) && !PLATFORM(GTK) |
|
91 void (*destructor)(void*); |
|
92 #endif |
|
93 }; |
|
94 #endif |
|
95 |
|
96 #if ENABLE(SINGLE_THREADED) |
|
97 T* m_value; |
|
98 #else |
|
99 #if USE(PTHREADS) |
|
100 pthread_key_t m_key; |
|
101 #elif PLATFORM(QT) |
|
102 QThreadStorage<Data*> m_key; |
|
103 #elif PLATFORM(GTK) |
|
104 GStaticPrivate m_key; |
|
105 #elif OS(WINDOWS) |
|
106 int m_index; |
|
107 #endif |
|
108 #endif |
|
109 }; |
|
110 |
|
111 #if ENABLE(SINGLE_THREADED) |
|
112 template<typename T> |
|
113 inline ThreadSpecific<T>::ThreadSpecific() |
|
114 : m_value(0) |
|
115 { |
|
116 } |
|
117 |
|
118 template<typename T> |
|
119 inline ThreadSpecific<T>::~ThreadSpecific() |
|
120 { |
|
121 } |
|
122 |
|
123 template<typename T> |
|
124 inline T* ThreadSpecific<T>::get() |
|
125 { |
|
126 return m_value; |
|
127 } |
|
128 |
|
129 template<typename T> |
|
130 inline void ThreadSpecific<T>::set(T* ptr) |
|
131 { |
|
132 ASSERT(!get()); |
|
133 m_value = ptr; |
|
134 } |
|
135 #else |
|
136 #if USE(PTHREADS) |
|
137 template<typename T> |
|
138 inline ThreadSpecific<T>::ThreadSpecific() |
|
139 { |
|
140 int error = pthread_key_create(&m_key, destroy); |
|
141 if (error) |
|
142 CRASH(); |
|
143 } |
|
144 |
|
145 template<typename T> |
|
146 inline ThreadSpecific<T>::~ThreadSpecific() |
|
147 { |
|
148 pthread_key_delete(m_key); // Does not invoke destructor functions. |
|
149 } |
|
150 |
|
151 template<typename T> |
|
152 inline T* ThreadSpecific<T>::get() |
|
153 { |
|
154 Data* data = static_cast<Data*>(pthread_getspecific(m_key)); |
|
155 return data ? data->value : 0; |
|
156 } |
|
157 |
|
158 template<typename T> |
|
159 inline void ThreadSpecific<T>::set(T* ptr) |
|
160 { |
|
161 ASSERT(!get()); |
|
162 pthread_setspecific(m_key, new Data(ptr, this)); |
|
163 } |
|
164 |
|
165 #elif PLATFORM(QT) |
|
166 |
|
167 template<typename T> |
|
168 inline ThreadSpecific<T>::ThreadSpecific() |
|
169 { |
|
170 } |
|
171 |
|
172 template<typename T> |
|
173 inline ThreadSpecific<T>::~ThreadSpecific() |
|
174 { |
|
175 // Does not invoke destructor functions. QThreadStorage will do it |
|
176 } |
|
177 |
|
178 template<typename T> |
|
179 inline T* ThreadSpecific<T>::get() |
|
180 { |
|
181 Data* data = static_cast<Data*>(m_key.localData()); |
|
182 return data ? data->value : 0; |
|
183 } |
|
184 |
|
185 template<typename T> |
|
186 inline void ThreadSpecific<T>::set(T* ptr) |
|
187 { |
|
188 ASSERT(!get()); |
|
189 Data* data = new Data(ptr, this); |
|
190 m_key.setLocalData(data); |
|
191 } |
|
192 |
|
193 #elif PLATFORM(GTK) |
|
194 |
|
195 template<typename T> |
|
196 inline ThreadSpecific<T>::ThreadSpecific() |
|
197 { |
|
198 g_static_private_init(&m_key); |
|
199 } |
|
200 |
|
201 template<typename T> |
|
202 inline ThreadSpecific<T>::~ThreadSpecific() |
|
203 { |
|
204 g_static_private_free(&m_key); |
|
205 } |
|
206 |
|
207 template<typename T> |
|
208 inline T* ThreadSpecific<T>::get() |
|
209 { |
|
210 Data* data = static_cast<Data*>(g_static_private_get(&m_key)); |
|
211 return data ? data->value : 0; |
|
212 } |
|
213 |
|
214 template<typename T> |
|
215 inline void ThreadSpecific<T>::set(T* ptr) |
|
216 { |
|
217 ASSERT(!get()); |
|
218 Data* data = new Data(ptr, this); |
|
219 g_static_private_set(&m_key, data, destroy); |
|
220 } |
|
221 |
|
222 #elif OS(WINDOWS) |
|
223 |
|
224 // TLS_OUT_OF_INDEXES is not defined on WinCE. |
|
225 #ifndef TLS_OUT_OF_INDEXES |
|
226 #define TLS_OUT_OF_INDEXES 0xffffffff |
|
227 #endif |
|
228 |
|
229 // The maximum number of TLS keys that can be created. For simplification, we assume that: |
|
230 // 1) Once the instance of ThreadSpecific<> is created, it will not be destructed until the program dies. |
|
231 // 2) We do not need to hold many instances of ThreadSpecific<> data. This fixed number should be far enough. |
|
232 const int kMaxTlsKeySize = 256; |
|
233 |
|
234 long& tlsKeyCount(); |
|
235 DWORD* tlsKeys(); |
|
236 |
|
237 template<typename T> |
|
238 inline ThreadSpecific<T>::ThreadSpecific() |
|
239 : m_index(-1) |
|
240 { |
|
241 DWORD tlsKey = TlsAlloc(); |
|
242 if (tlsKey == TLS_OUT_OF_INDEXES) |
|
243 CRASH(); |
|
244 |
|
245 m_index = InterlockedIncrement(&tlsKeyCount()) - 1; |
|
246 if (m_index >= kMaxTlsKeySize) |
|
247 CRASH(); |
|
248 tlsKeys()[m_index] = tlsKey; |
|
249 } |
|
250 |
|
251 template<typename T> |
|
252 inline ThreadSpecific<T>::~ThreadSpecific() |
|
253 { |
|
254 // Does not invoke destructor functions. They will be called from ThreadSpecificThreadExit when the thread is detached. |
|
255 TlsFree(tlsKeys()[m_index]); |
|
256 } |
|
257 |
|
258 template<typename T> |
|
259 inline T* ThreadSpecific<T>::get() |
|
260 { |
|
261 Data* data = static_cast<Data*>(TlsGetValue(tlsKeys()[m_index])); |
|
262 return data ? data->value : 0; |
|
263 } |
|
264 |
|
265 template<typename T> |
|
266 inline void ThreadSpecific<T>::set(T* ptr) |
|
267 { |
|
268 ASSERT(!get()); |
|
269 Data* data = new Data(ptr, this); |
|
270 data->destructor = &ThreadSpecific<T>::destroy; |
|
271 TlsSetValue(tlsKeys()[m_index], data); |
|
272 } |
|
273 |
|
274 #else |
|
275 #error ThreadSpecific is not implemented for this platform. |
|
276 #endif |
|
277 #endif |
|
278 |
|
279 template<typename T> |
|
280 inline void ThreadSpecific<T>::destroy(void* ptr) |
|
281 { |
|
282 #if !ENABLE(SINGLE_THREADED) |
|
283 Data* data = static_cast<Data*>(ptr); |
|
284 |
|
285 #if USE(PTHREADS) |
|
286 // We want get() to keep working while data destructor works, because it can be called indirectly by the destructor. |
|
287 // Some pthreads implementations zero out the pointer before calling destroy(), so we temporarily reset it. |
|
288 pthread_setspecific(data->owner->m_key, ptr); |
|
289 #elif PLATFORM(GTK) |
|
290 // See comment as above |
|
291 g_static_private_set(&data->owner->m_key, data, 0); |
|
292 #endif |
|
293 #if PLATFORM(QT) |
|
294 // See comment as above |
|
295 data->owner->m_key.setLocalData(data); |
|
296 #endif |
|
297 |
|
298 data->value->~T(); |
|
299 fastFree(data->value); |
|
300 |
|
301 #if USE(PTHREADS) |
|
302 pthread_setspecific(data->owner->m_key, 0); |
|
303 #elif PLATFORM(QT) |
|
304 // Do nothing here |
|
305 #elif PLATFORM(GTK) |
|
306 g_static_private_set(&data->owner->m_key, 0, 0); |
|
307 #elif OS(WINDOWS) |
|
308 TlsSetValue(tlsKeys()[data->owner->m_index], 0); |
|
309 #else |
|
310 #error ThreadSpecific is not implemented for this platform. |
|
311 #endif |
|
312 |
|
313 #if !PLATFORM(QT) |
|
314 delete data; |
|
315 #endif |
|
316 #endif |
|
317 } |
|
318 |
|
319 template<typename T> |
|
320 inline ThreadSpecific<T>::operator T*() |
|
321 { |
|
322 T* ptr = static_cast<T*>(get()); |
|
323 if (!ptr) { |
|
324 // Set up thread-specific value's memory pointer before invoking constructor, in case any function it calls |
|
325 // needs to access the value, to avoid recursion. |
|
326 ptr = static_cast<T*>(fastZeroedMalloc(sizeof(T))); |
|
327 set(ptr); |
|
328 new (ptr) T; |
|
329 } |
|
330 return ptr; |
|
331 } |
|
332 |
|
333 template<typename T> |
|
334 inline T* ThreadSpecific<T>::operator->() |
|
335 { |
|
336 return operator T*(); |
|
337 } |
|
338 |
|
339 template<typename T> |
|
340 inline T& ThreadSpecific<T>::operator*() |
|
341 { |
|
342 return *operator T*(); |
|
343 } |
|
344 |
|
345 } |
|
346 |
|
347 #endif |