OLD | NEW |
1 /* | 1 // Copyright 2017 The Chromium Authors. All rights reserved. |
2 * Copyright (C) 2008 Apple Inc. All rights reserved. | 2 // Use of this source code is governed by a BSD-style license that can be |
3 * Copyright (C) 2009 Jian Li <jianli@chromium.org> | 3 // found in the LICENSE file. |
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 | 4 |
31 /* Thread local storage is implemented by using either pthread API or Windows | 5 #include "platform/wtf/ThreadSpecific.h" |
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 | 6 |
42 #ifndef WTF_ThreadSpecific_h | 7 // The contents of this header was moved to platform/wtf as part of |
43 #define WTF_ThreadSpecific_h | 8 // WTF migration project. See the following post for details: |
44 | 9 // https://groups.google.com/a/chromium.org/d/msg/blink-dev/tLdAZCTlcAA/bYXVT8gY
CAAJ |
45 #include "wtf/Allocator.h" | |
46 #include "wtf/Noncopyable.h" | |
47 #include "wtf/StackUtil.h" | |
48 #include "wtf/StdLibExtras.h" | |
49 #include "wtf/WTF.h" | |
50 #include "wtf/WTFExport.h" | |
51 #include "wtf/allocator/PartitionAllocator.h" | |
52 #include "wtf/allocator/Partitions.h" | |
53 | |
54 #if OS(POSIX) | |
55 #include <pthread.h> | |
56 #elif OS(WIN) | |
57 #include <windows.h> | |
58 #endif | |
59 | |
60 namespace WTF { | |
61 | |
62 #if OS(WIN) | |
63 // ThreadSpecificThreadExit should be called each time when a thread is | |
64 // detached. | |
65 // This is done automatically for threads created with WTF::createThread. | |
66 WTF_EXPORT void ThreadSpecificThreadExit(); | |
67 #endif | |
68 | |
69 template <typename T> | |
70 class ThreadSpecific { | |
71 USING_FAST_MALLOC(ThreadSpecific); | |
72 WTF_MAKE_NONCOPYABLE(ThreadSpecific); | |
73 | |
74 public: | |
75 ThreadSpecific(); | |
76 bool | |
77 isSet(); // Useful as a fast check to see if this thread has set this value. | |
78 T* operator->(); | |
79 operator T*(); | |
80 T& operator*(); | |
81 | |
82 private: | |
83 #if OS(WIN) | |
84 WTF_EXPORT friend void ThreadSpecificThreadExit(); | |
85 #endif | |
86 | |
87 // Not implemented. It's technically possible to destroy a thread specific | |
88 // key, but one would need to make sure that all values have been destroyed | |
89 // already (usually, that all threads that used it have exited). It's | |
90 // unlikely that any user of this call will be in that situation - and having | |
91 // a destructor defined can be confusing, given that it has such strong | |
92 // pre-requisites to work correctly. | |
93 ~ThreadSpecific(); | |
94 | |
95 T* get(); | |
96 void set(T*); | |
97 void static destroy(void* ptr); | |
98 | |
99 struct Data { | |
100 WTF_MAKE_NONCOPYABLE(Data); | |
101 | |
102 public: | |
103 Data(T* value, ThreadSpecific<T>* owner) : value(value), owner(owner) {} | |
104 | |
105 T* value; | |
106 ThreadSpecific<T>* owner; | |
107 #if OS(WIN) | |
108 void (*destructor)(void*); | |
109 #endif | |
110 }; | |
111 | |
112 #if OS(POSIX) | |
113 pthread_key_t m_key; | |
114 #elif OS(WIN) | |
115 int m_index; | |
116 #endif | |
117 // This member must only be accessed or modified on the main thread. | |
118 T* m_mainThreadStorage = nullptr; | |
119 }; | |
120 | |
121 #if OS(POSIX) | |
122 | |
123 typedef pthread_key_t ThreadSpecificKey; | |
124 | |
125 inline void threadSpecificKeyCreate(ThreadSpecificKey* key, | |
126 void (*destructor)(void*)) { | |
127 int error = pthread_key_create(key, destructor); | |
128 if (error) | |
129 CRASH(); | |
130 } | |
131 | |
132 inline void threadSpecificKeyDelete(ThreadSpecificKey key) { | |
133 int error = pthread_key_delete(key); | |
134 if (error) | |
135 CRASH(); | |
136 } | |
137 | |
138 inline void threadSpecificSet(ThreadSpecificKey key, void* value) { | |
139 pthread_setspecific(key, value); | |
140 } | |
141 | |
142 inline void* threadSpecificGet(ThreadSpecificKey key) { | |
143 return pthread_getspecific(key); | |
144 } | |
145 | |
146 template <typename T> | |
147 inline ThreadSpecific<T>::ThreadSpecific() { | |
148 int error = pthread_key_create(&m_key, destroy); | |
149 if (error) | |
150 CRASH(); | |
151 } | |
152 | |
153 template <typename T> | |
154 inline T* ThreadSpecific<T>::get() { | |
155 Data* data = static_cast<Data*>(pthread_getspecific(m_key)); | |
156 return data ? data->value : 0; | |
157 } | |
158 | |
159 template <typename T> | |
160 inline void ThreadSpecific<T>::set(T* ptr) { | |
161 DCHECK(!get()); | |
162 pthread_setspecific(m_key, new Data(ptr, this)); | |
163 } | |
164 | |
165 #elif OS(WIN) | |
166 | |
167 // TLS_OUT_OF_INDEXES is not defined on WinCE. | |
168 #ifndef TLS_OUT_OF_INDEXES | |
169 #define TLS_OUT_OF_INDEXES 0xffffffff | |
170 #endif | |
171 | |
172 // The maximum number of TLS keys that can be created. For simplification, we | |
173 // assume that: | |
174 // 1) Once the instance of ThreadSpecific<> is created, it will not be | |
175 // destructed until the program dies. | |
176 // 2) We do not need to hold many instances of ThreadSpecific<> data. This fixed | |
177 // number should be far enough. | |
178 const int kMaxTlsKeySize = 256; | |
179 | |
180 WTF_EXPORT long& tlsKeyCount(); | |
181 WTF_EXPORT DWORD* tlsKeys(); | |
182 | |
183 class PlatformThreadSpecificKey; | |
184 typedef PlatformThreadSpecificKey* ThreadSpecificKey; | |
185 | |
186 WTF_EXPORT void threadSpecificKeyCreate(ThreadSpecificKey*, void (*)(void*)); | |
187 WTF_EXPORT void threadSpecificKeyDelete(ThreadSpecificKey); | |
188 WTF_EXPORT void threadSpecificSet(ThreadSpecificKey, void*); | |
189 WTF_EXPORT void* threadSpecificGet(ThreadSpecificKey); | |
190 | |
191 template <typename T> | |
192 inline ThreadSpecific<T>::ThreadSpecific() : m_index(-1) { | |
193 DWORD tlsKey = TlsAlloc(); | |
194 if (tlsKey == TLS_OUT_OF_INDEXES) | |
195 CRASH(); | |
196 | |
197 m_index = InterlockedIncrement(&tlsKeyCount()) - 1; | |
198 if (m_index >= kMaxTlsKeySize) | |
199 CRASH(); | |
200 tlsKeys()[m_index] = tlsKey; | |
201 } | |
202 | |
203 template <typename T> | |
204 inline ThreadSpecific<T>::~ThreadSpecific() { | |
205 // Does not invoke destructor functions. They will be called from | |
206 // ThreadSpecificThreadExit when the thread is detached. | |
207 TlsFree(tlsKeys()[m_index]); | |
208 } | |
209 | |
210 template <typename T> | |
211 inline T* ThreadSpecific<T>::get() { | |
212 Data* data = static_cast<Data*>(TlsGetValue(tlsKeys()[m_index])); | |
213 return data ? data->value : 0; | |
214 } | |
215 | |
216 template <typename T> | |
217 inline void ThreadSpecific<T>::set(T* ptr) { | |
218 DCHECK(!get()); | |
219 Data* data = new Data(ptr, this); | |
220 data->destructor = &ThreadSpecific<T>::destroy; | |
221 TlsSetValue(tlsKeys()[m_index], data); | |
222 } | |
223 | |
224 #else | |
225 #error ThreadSpecific is not implemented for this platform. | |
226 #endif | |
227 | |
228 template <typename T> | |
229 inline void ThreadSpecific<T>::destroy(void* ptr) { | |
230 Data* data = static_cast<Data*>(ptr); | |
231 | |
232 #if OS(POSIX) | |
233 // We want get() to keep working while data destructor works, because it can | |
234 // be called indirectly by the destructor. Some pthreads implementations | |
235 // zero out the pointer before calling destroy(), so we temporarily reset it. | |
236 pthread_setspecific(data->owner->m_key, ptr); | |
237 #endif | |
238 | |
239 // Never call destructors on the main thread. This is fine because Blink no | |
240 // longer has a graceful shutdown sequence. Be careful to call this function | |
241 // (which can be re-entrant) while the pointer is still set, to avoid lazily | |
242 // allocating WTFThreadData after it is destroyed. | |
243 if (isMainThread()) | |
244 return; | |
245 | |
246 data->value->~T(); | |
247 Partitions::fastFree(data->value); | |
248 | |
249 #if OS(POSIX) | |
250 pthread_setspecific(data->owner->m_key, 0); | |
251 #elif OS(WIN) | |
252 TlsSetValue(tlsKeys()[data->owner->m_index], 0); | |
253 #else | |
254 #error ThreadSpecific is not implemented for this platform. | |
255 #endif | |
256 | |
257 delete data; | |
258 } | |
259 | |
260 template <typename T> | |
261 inline bool ThreadSpecific<T>::isSet() { | |
262 return !!get(); | |
263 } | |
264 | |
265 template <typename T> | |
266 inline ThreadSpecific<T>::operator T*() { | |
267 T* offThreadPtr; | |
268 #if defined(__GLIBC__) || OS(ANDROID) || OS(FREEBSD) | |
269 // TLS is fast on these platforms. | |
270 // TODO(csharrison): Qualify this statement for Android. | |
271 const bool mainThreadAlwaysChecksTLS = true; | |
272 T** ptr = &offThreadPtr; | |
273 offThreadPtr = static_cast<T*>(get()); | |
274 #else | |
275 const bool mainThreadAlwaysChecksTLS = false; | |
276 T** ptr = &m_mainThreadStorage; | |
277 if (UNLIKELY(mayNotBeMainThread())) { | |
278 offThreadPtr = static_cast<T*>(get()); | |
279 ptr = &offThreadPtr; | |
280 } | |
281 #endif | |
282 // Set up thread-specific value's memory pointer before invoking constructor, | |
283 // in case any function it calls needs to access the value, to avoid | |
284 // recursion. | |
285 if (UNLIKELY(!*ptr)) { | |
286 *ptr = static_cast<T*>(Partitions::fastZeroedMalloc( | |
287 sizeof(T), WTF_HEAP_PROFILER_TYPE_NAME(T))); | |
288 | |
289 // Even if we didn't realize we're on the main thread, we might still be. | |
290 // We need to double-check so that |m_mainThreadStorage| is populated. | |
291 if (!mainThreadAlwaysChecksTLS && UNLIKELY(ptr != &m_mainThreadStorage) && | |
292 isMainThread()) { | |
293 m_mainThreadStorage = *ptr; | |
294 } | |
295 | |
296 set(*ptr); | |
297 new (NotNull, *ptr) T; | |
298 } | |
299 return *ptr; | |
300 } | |
301 | |
302 template <typename T> | |
303 inline T* ThreadSpecific<T>::operator->() { | |
304 return operator T*(); | |
305 } | |
306 | |
307 template <typename T> | |
308 inline T& ThreadSpecific<T>::operator*() { | |
309 return *operator T*(); | |
310 } | |
311 | |
312 } // namespace WTF | |
313 | |
314 using WTF::ThreadSpecific; | |
315 | |
316 #endif // WTF_ThreadSpecific_h | |
OLD | NEW |