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