Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(232)

Side by Side Diff: third_party/WebKit/Source/wtf/ThreadSpecific.h

Issue 2764833002: Move files in wtf/ to platform/wtf/ (Part 7). (Closed)
Patch Set: Rebase. Created 3 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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
OLDNEW
« no previous file with comments | « third_party/WebKit/Source/wtf/ThreadSafeRefCounted.h ('k') | third_party/WebKit/Source/wtf/Threading.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698