| 1 | /* | 
| 2 |  * Copyright (C) 2008 Apple Inc. All rights reserved. | 
| 3 |  * Copyright (C) 2009 Jian Li <jianli@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 <QtCore/qthreadstorage.h> | 
| 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 |     if (!data->owner->m_key.hasLocalData()) | 
| 260 |         data->owner->m_key.setLocalData(data); | 
| 261 | #endif | 
| 262 |  | 
| 263 |     data->value->~T(); | 
| 264 |     fastFree(data->value); | 
| 265 |  | 
| 266 | #if USE(PTHREADS) | 
| 267 |     pthread_setspecific(data->owner->m_key, 0); | 
| 268 | #elif PLATFORM(QT) | 
| 269 |     // Do nothing here | 
| 270 | #elif OS(WINDOWS) | 
| 271 |     TlsSetValue(tlsKeys()[data->owner->m_index], 0); | 
| 272 | #else | 
| 273 | #error ThreadSpecific is not implemented for this platform. | 
| 274 | #endif | 
| 275 |  | 
| 276 | #if !PLATFORM(QT) | 
| 277 |     delete data; | 
| 278 | #endif | 
| 279 | #endif | 
| 280 | } | 
| 281 |  | 
| 282 | template<typename T> | 
| 283 | inline ThreadSpecific<T>::operator T*() | 
| 284 | { | 
| 285 |     T* ptr = static_cast<T*>(get()); | 
| 286 |     if (!ptr) { | 
| 287 |         // Set up thread-specific value's memory pointer before invoking constructor, in case any function it calls | 
| 288 |         // needs to access the value, to avoid recursion. | 
| 289 |         ptr = static_cast<T*>(fastMalloc(sizeof(T))); | 
| 290 |         set(ptr); | 
| 291 |         new (ptr) T; | 
| 292 |     } | 
| 293 |     return ptr; | 
| 294 | } | 
| 295 |  | 
| 296 | template<typename T> | 
| 297 | inline T* ThreadSpecific<T>::operator->() | 
| 298 | { | 
| 299 |     return operator T*(); | 
| 300 | } | 
| 301 |  | 
| 302 | template<typename T> | 
| 303 | inline T& ThreadSpecific<T>::operator*() | 
| 304 | { | 
| 305 |     return *operator T*(); | 
| 306 | } | 
| 307 |  | 
| 308 | } | 
| 309 |  | 
| 310 | #endif | 
| 311 |  |