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