Home | History | Annotate | Download | only in wtf
      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