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 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