OLD | NEW |
| (Empty) |
1 /* | |
2 * Copyright (C) 2008 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 Computer, 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/Noncopyable.h> | |
46 #include <wtf/StdLibExtras.h> | |
47 | |
48 #if USE(PTHREADS) | |
49 #include <pthread.h> | |
50 #elif OS(WINDOWS) | |
51 #include <windows.h> | |
52 #endif | |
53 | |
54 namespace WTF { | |
55 | |
56 #if OS(WINDOWS) | |
57 // ThreadSpecificThreadExit should be called each time when a thread is detached
. | |
58 // This is done automatically for threads created with WTF::createThread. | |
59 void ThreadSpecificThreadExit(); | |
60 #endif | |
61 | |
62 template<typename T> class ThreadSpecific { | |
63 WTF_MAKE_NONCOPYABLE(ThreadSpecific); | |
64 public: | |
65 ThreadSpecific(); | |
66 bool isSet(); // Useful as a fast check to see if this thread has set this v
alue. | |
67 T* operator->(); | |
68 operator T*(); | |
69 T& operator*(); | |
70 | |
71 private: | |
72 #if OS(WINDOWS) | |
73 friend void ThreadSpecificThreadExit(); | |
74 #endif | |
75 | |
76 // Not implemented. It's technically possible to destroy a thread specific k
ey, but one would need | |
77 // to make sure that all values have been destroyed already (usually, that a
ll threads that used it | |
78 // have exited). It's unlikely that any user of this call will be in that si
tuation - and having | |
79 // a destructor defined can be confusing, given that it has such strong pre-
requisites to work correctly. | |
80 ~ThreadSpecific(); | |
81 | |
82 T* get(); | |
83 void set(T*); | |
84 void static destroy(void* ptr); | |
85 | |
86 struct Data { | |
87 WTF_MAKE_NONCOPYABLE(Data); | |
88 public: | |
89 Data(T* value, ThreadSpecific<T>* owner) : value(value), owner(owner) {} | |
90 | |
91 T* value; | |
92 ThreadSpecific<T>* owner; | |
93 #if OS(WINDOWS) | |
94 void (*destructor)(void*); | |
95 #endif | |
96 }; | |
97 | |
98 #if USE(PTHREADS) | |
99 pthread_key_t m_key; | |
100 #elif OS(WINDOWS) | |
101 int m_index; | |
102 #endif | |
103 }; | |
104 | |
105 #if USE(PTHREADS) | |
106 | |
107 typedef pthread_key_t ThreadSpecificKey; | |
108 | |
109 inline void threadSpecificKeyCreate(ThreadSpecificKey* key, void (*destructor)(v
oid *)) | |
110 { | |
111 int error = pthread_key_create(key, destructor); | |
112 if (error) | |
113 CRASH(); | |
114 } | |
115 | |
116 inline void threadSpecificKeyDelete(ThreadSpecificKey key) | |
117 { | |
118 int error = pthread_key_delete(key); | |
119 if (error) | |
120 CRASH(); | |
121 } | |
122 | |
123 inline void threadSpecificSet(ThreadSpecificKey key, void* value) | |
124 { | |
125 pthread_setspecific(key, value); | |
126 } | |
127 | |
128 inline void* threadSpecificGet(ThreadSpecificKey key) | |
129 { | |
130 return pthread_getspecific(key); | |
131 } | |
132 | |
133 template<typename T> | |
134 inline ThreadSpecific<T>::ThreadSpecific() | |
135 { | |
136 int error = pthread_key_create(&m_key, destroy); | |
137 if (error) | |
138 CRASH(); | |
139 } | |
140 | |
141 template<typename T> | |
142 inline T* ThreadSpecific<T>::get() | |
143 { | |
144 Data* data = static_cast<Data*>(pthread_getspecific(m_key)); | |
145 return data ? data->value : 0; | |
146 } | |
147 | |
148 template<typename T> | |
149 inline void ThreadSpecific<T>::set(T* ptr) | |
150 { | |
151 ASSERT(!get()); | |
152 pthread_setspecific(m_key, new Data(ptr, this)); | |
153 } | |
154 | |
155 #elif OS(WINDOWS) | |
156 | |
157 // TLS_OUT_OF_INDEXES is not defined on WinCE. | |
158 #ifndef TLS_OUT_OF_INDEXES | |
159 #define TLS_OUT_OF_INDEXES 0xffffffff | |
160 #endif | |
161 | |
162 // The maximum number of TLS keys that can be created. For simplification, we as
sume that: | |
163 // 1) Once the instance of ThreadSpecific<> is created, it will not be destructe
d until the program dies. | |
164 // 2) We do not need to hold many instances of ThreadSpecific<> data. This fixed
number should be far enough. | |
165 const int kMaxTlsKeySize = 256; | |
166 | |
167 WTF_EXPORT_PRIVATE long& tlsKeyCount(); | |
168 WTF_EXPORT_PRIVATE DWORD* tlsKeys(); | |
169 | |
170 class PlatformThreadSpecificKey; | |
171 typedef PlatformThreadSpecificKey* ThreadSpecificKey; | |
172 | |
173 void threadSpecificKeyCreate(ThreadSpecificKey*, void (*)(void *)); | |
174 void threadSpecificKeyDelete(ThreadSpecificKey); | |
175 void threadSpecificSet(ThreadSpecificKey, void*); | |
176 void* threadSpecificGet(ThreadSpecificKey); | |
177 | |
178 template<typename T> | |
179 inline ThreadSpecific<T>::ThreadSpecific() | |
180 : m_index(-1) | |
181 { | |
182 DWORD tlsKey = TlsAlloc(); | |
183 if (tlsKey == TLS_OUT_OF_INDEXES) | |
184 CRASH(); | |
185 | |
186 m_index = InterlockedIncrement(&tlsKeyCount()) - 1; | |
187 if (m_index >= kMaxTlsKeySize) | |
188 CRASH(); | |
189 tlsKeys()[m_index] = tlsKey; | |
190 } | |
191 | |
192 template<typename T> | |
193 inline ThreadSpecific<T>::~ThreadSpecific() | |
194 { | |
195 // Does not invoke destructor functions. They will be called from ThreadSpec
ificThreadExit when the thread is detached. | |
196 TlsFree(tlsKeys()[m_index]); | |
197 } | |
198 | |
199 template<typename T> | |
200 inline T* ThreadSpecific<T>::get() | |
201 { | |
202 Data* data = static_cast<Data*>(TlsGetValue(tlsKeys()[m_index])); | |
203 return data ? data->value : 0; | |
204 } | |
205 | |
206 template<typename T> | |
207 inline void ThreadSpecific<T>::set(T* ptr) | |
208 { | |
209 ASSERT(!get()); | |
210 Data* data = new Data(ptr, this); | |
211 data->destructor = &ThreadSpecific<T>::destroy; | |
212 TlsSetValue(tlsKeys()[m_index], data); | |
213 } | |
214 | |
215 #else | |
216 #error ThreadSpecific is not implemented for this platform. | |
217 #endif | |
218 | |
219 template<typename T> | |
220 inline void ThreadSpecific<T>::destroy(void* ptr) | |
221 { | |
222 Data* data = static_cast<Data*>(ptr); | |
223 | |
224 #if USE(PTHREADS) | |
225 // We want get() to keep working while data destructor works, because it can
be called indirectly by the destructor. | |
226 // Some pthreads implementations zero out the pointer before calling destroy
(), so we temporarily reset it. | |
227 pthread_setspecific(data->owner->m_key, ptr); | |
228 #endif | |
229 | |
230 data->value->~T(); | |
231 fastFree(data->value); | |
232 | |
233 #if USE(PTHREADS) | |
234 pthread_setspecific(data->owner->m_key, 0); | |
235 #elif OS(WINDOWS) | |
236 TlsSetValue(tlsKeys()[data->owner->m_index], 0); | |
237 #else | |
238 #error ThreadSpecific is not implemented for this platform. | |
239 #endif | |
240 | |
241 delete data; | |
242 } | |
243 | |
244 template<typename T> | |
245 inline bool ThreadSpecific<T>::isSet() | |
246 { | |
247 return !!get(); | |
248 } | |
249 | |
250 template<typename T> | |
251 inline ThreadSpecific<T>::operator T*() | |
252 { | |
253 T* ptr = static_cast<T*>(get()); | |
254 if (!ptr) { | |
255 // Set up thread-specific value's memory pointer before invoking constru
ctor, in case any function it calls | |
256 // needs to access the value, to avoid recursion. | |
257 ptr = static_cast<T*>(fastZeroedMalloc(sizeof(T))); | |
258 set(ptr); | |
259 new (NotNull, ptr) T; | |
260 } | |
261 return ptr; | |
262 } | |
263 | |
264 template<typename T> | |
265 inline T* ThreadSpecific<T>::operator->() | |
266 { | |
267 return operator T*(); | |
268 } | |
269 | |
270 template<typename T> | |
271 inline T& ThreadSpecific<T>::operator*() | |
272 { | |
273 return *operator T*(); | |
274 } | |
275 | |
276 } // namespace WTF | |
277 | |
278 #endif // WTF_ThreadSpecific_h | |
OLD | NEW |