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