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  * Copyright (C) 2012 Patrick Gansterer <paroga (at) paroga.com>
      5  *
      6  * Redistribution and use in source and binary forms, with or without
      7  * modification, are permitted provided that the following conditions
      8  * are met:
      9  *
     10  * 1.  Redistributions of source code must retain the above copyright
     11  *     notice, this list of conditions and the following disclaimer.
     12  * 2.  Redistributions in binary form must reproduce the above copyright
     13  *     notice, this list of conditions and the following disclaimer in the
     14  *     documentation and/or other materials provided with the distribution.
     15  * 3.  Neither the name of Apple Computer, Inc. ("Apple") nor the names of
     16  *     its contributors may be used to endorse or promote products derived
     17  *     from this software without specific prior written permission.
     18  *
     19  * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
     20  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
     21  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
     22  * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
     23  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
     24  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
     25  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
     26  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     27  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
     28  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     29  */
     30 
     31 /* Thread local storage is implemented by using either pthread API or Windows
     32  * native API. There is subtle semantic discrepancy for the cleanup function
     33  * implementation as noted below:
     34  *   @ In pthread implementation, the destructor function will be called
     35  *     repeatedly if there is still non-NULL value associated with the function.
     36  *   @ In Windows native implementation, the destructor function will be called
     37  *     only once.
     38  * This semantic discrepancy does not impose any problem because nowhere in
     39  * WebKit the repeated call bahavior is utilized.
     40  */
     41 
     42 #ifndef WTF_ThreadSpecific_h
     43 #define WTF_ThreadSpecific_h
     44 
     45 #include "wtf/Noncopyable.h"
     46 #include "wtf/StdLibExtras.h"
     47 #include "wtf/WTF.h"
     48 #include "wtf/WTFExport.h"
     49 
     50 #if USE(PTHREADS)
     51 #include <pthread.h>
     52 #elif OS(WIN)
     53 #include <windows.h>
     54 #endif
     55 
     56 namespace WTF {
     57 
     58 #if OS(WIN)
     59 // ThreadSpecificThreadExit should be called each time when a thread is detached.
     60 // This is done automatically for threads created with WTF::createThread.
     61 WTF_EXPORT void ThreadSpecificThreadExit();
     62 #endif
     63 
     64 template<typename T> class ThreadSpecific {
     65     WTF_MAKE_NONCOPYABLE(ThreadSpecific);
     66 public:
     67     ThreadSpecific();
     68     bool isSet(); // Useful as a fast check to see if this thread has set this value.
     69     T* operator->();
     70     operator T*();
     71     T& operator*();
     72 
     73 private:
     74 #if OS(WIN)
     75     WTF_EXPORT friend void ThreadSpecificThreadExit();
     76 #endif
     77 
     78     // Not implemented. It's technically possible to destroy a thread specific key, but one would need
     79     // to make sure that all values have been destroyed already (usually, that all threads that used it
     80     // have exited). It's unlikely that any user of this call will be in that situation - and having
     81     // a destructor defined can be confusing, given that it has such strong pre-requisites to work correctly.
     82     ~ThreadSpecific();
     83 
     84     T* get();
     85     void set(T*);
     86     void static destroy(void* ptr);
     87 
     88     struct Data {
     89         WTF_MAKE_NONCOPYABLE(Data);
     90     public:
     91         Data(T* value, ThreadSpecific<T>* owner) : value(value), owner(owner) {}
     92 
     93         T* value;
     94         ThreadSpecific<T>* owner;
     95 #if OS(WIN)
     96         void (*destructor)(void*);
     97 #endif
     98     };
     99 
    100 #if USE(PTHREADS)
    101     pthread_key_t m_key;
    102 #elif OS(WIN)
    103     int m_index;
    104 #endif
    105 };
    106 
    107 #if USE(PTHREADS)
    108 
    109 typedef pthread_key_t ThreadSpecificKey;
    110 
    111 inline void threadSpecificKeyCreate(ThreadSpecificKey* key, void (*destructor)(void *))
    112 {
    113     int error = pthread_key_create(key, destructor);
    114     if (error)
    115         CRASH();
    116 }
    117 
    118 inline void threadSpecificKeyDelete(ThreadSpecificKey key)
    119 {
    120     int error = pthread_key_delete(key);
    121     if (error)
    122         CRASH();
    123 }
    124 
    125 inline void threadSpecificSet(ThreadSpecificKey key, void* value)
    126 {
    127     pthread_setspecific(key, value);
    128 }
    129 
    130 inline void* threadSpecificGet(ThreadSpecificKey key)
    131 {
    132     return pthread_getspecific(key);
    133 }
    134 
    135 template<typename T>
    136 inline ThreadSpecific<T>::ThreadSpecific()
    137 {
    138     int error = pthread_key_create(&m_key, destroy);
    139     if (error)
    140         CRASH();
    141 }
    142 
    143 template<typename T>
    144 inline T* ThreadSpecific<T>::get()
    145 {
    146     Data* data = static_cast<Data*>(pthread_getspecific(m_key));
    147     return data ? data->value : 0;
    148 }
    149 
    150 template<typename T>
    151 inline void ThreadSpecific<T>::set(T* ptr)
    152 {
    153     ASSERT(!get());
    154     pthread_setspecific(m_key, new Data(ptr, this));
    155 }
    156 
    157 #elif OS(WIN)
    158 
    159 // TLS_OUT_OF_INDEXES is not defined on WinCE.
    160 #ifndef TLS_OUT_OF_INDEXES
    161 #define TLS_OUT_OF_INDEXES 0xffffffff
    162 #endif
    163 
    164 // The maximum number of TLS keys that can be created. For simplification, we assume that:
    165 // 1) Once the instance of ThreadSpecific<> is created, it will not be destructed until the program dies.
    166 // 2) We do not need to hold many instances of ThreadSpecific<> data. This fixed number should be far enough.
    167 const int kMaxTlsKeySize = 256;
    168 
    169 WTF_EXPORT long& tlsKeyCount();
    170 WTF_EXPORT DWORD* tlsKeys();
    171 
    172 class PlatformThreadSpecificKey;
    173 typedef PlatformThreadSpecificKey* ThreadSpecificKey;
    174 
    175 WTF_EXPORT void threadSpecificKeyCreate(ThreadSpecificKey*, void (*)(void *));
    176 WTF_EXPORT void threadSpecificKeyDelete(ThreadSpecificKey);
    177 WTF_EXPORT void threadSpecificSet(ThreadSpecificKey, void*);
    178 WTF_EXPORT void* threadSpecificGet(ThreadSpecificKey);
    179 
    180 template<typename T>
    181 inline ThreadSpecific<T>::ThreadSpecific()
    182     : m_index(-1)
    183 {
    184     DWORD tlsKey = TlsAlloc();
    185     if (tlsKey == TLS_OUT_OF_INDEXES)
    186         CRASH();
    187 
    188     m_index = InterlockedIncrement(&tlsKeyCount()) - 1;
    189     if (m_index >= kMaxTlsKeySize)
    190         CRASH();
    191     tlsKeys()[m_index] = tlsKey;
    192 }
    193 
    194 template<typename T>
    195 inline ThreadSpecific<T>::~ThreadSpecific()
    196 {
    197     // Does not invoke destructor functions. They will be called from ThreadSpecificThreadExit when the thread is detached.
    198     TlsFree(tlsKeys()[m_index]);
    199 }
    200 
    201 template<typename T>
    202 inline T* ThreadSpecific<T>::get()
    203 {
    204     Data* data = static_cast<Data*>(TlsGetValue(tlsKeys()[m_index]));
    205     return data ? data->value : 0;
    206 }
    207 
    208 template<typename T>
    209 inline void ThreadSpecific<T>::set(T* ptr)
    210 {
    211     ASSERT(!get());
    212     Data* data = new Data(ptr, this);
    213     data->destructor = &ThreadSpecific<T>::destroy;
    214     TlsSetValue(tlsKeys()[m_index], data);
    215 }
    216 
    217 #else
    218 #error ThreadSpecific is not implemented for this platform.
    219 #endif
    220 
    221 template<typename T>
    222 inline void ThreadSpecific<T>::destroy(void* ptr)
    223 {
    224     if (isShutdown())
    225         return;
    226 
    227     Data* data = static_cast<Data*>(ptr);
    228 
    229 #if USE(PTHREADS)
    230     // We want get() to keep working while data destructor works, because it can be called indirectly by the destructor.
    231     // Some pthreads implementations zero out the pointer before calling destroy(), so we temporarily reset it.
    232     pthread_setspecific(data->owner->m_key, ptr);
    233 #endif
    234 
    235     data->value->~T();
    236     fastFree(data->value);
    237 
    238 #if USE(PTHREADS)
    239     pthread_setspecific(data->owner->m_key, 0);
    240 #elif OS(WIN)
    241     TlsSetValue(tlsKeys()[data->owner->m_index], 0);
    242 #else
    243 #error ThreadSpecific is not implemented for this platform.
    244 #endif
    245 
    246     delete data;
    247 }
    248 
    249 template<typename T>
    250 inline bool ThreadSpecific<T>::isSet()
    251 {
    252     return !!get();
    253 }
    254 
    255 template<typename T>
    256 inline ThreadSpecific<T>::operator T*()
    257 {
    258     T* ptr = static_cast<T*>(get());
    259     if (!ptr) {
    260         // Set up thread-specific value's memory pointer before invoking constructor, in case any function it calls
    261         // needs to access the value, to avoid recursion.
    262         ptr = static_cast<T*>(fastZeroedMalloc(sizeof(T)));
    263         set(ptr);
    264         new (NotNull, ptr) T;
    265     }
    266     return ptr;
    267 }
    268 
    269 template<typename T>
    270 inline T* ThreadSpecific<T>::operator->()
    271 {
    272     return operator T*();
    273 }
    274 
    275 template<typename T>
    276 inline T& ThreadSpecific<T>::operator*()
    277 {
    278     return *operator T*();
    279 }
    280 
    281 } // namespace WTF
    282 
    283 using WTF::ThreadSpecific;
    284 
    285 #endif // WTF_ThreadSpecific_h
    286