Home | History | Annotate | Download | only in wtf
      1 /*
      2  * Copyright (C) 2009 Jian Li <jianli (at) chromium.org>
      3  * Copyright (C) 2012 Patrick Gansterer <paroga (at) paroga.com>
      4  *
      5  * This library is free software; you can redistribute it and/or
      6  * modify it under the terms of the GNU Library General Public
      7  * License as published by the Free Software Foundation; either
      8  * version 2 of the License, or (at your option) any later version.
      9  *
     10  * This library is distributed in the hope that it will be useful,
     11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
     12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     13  * Library General Public License for more details.
     14  *
     15  * You should have received a copy of the GNU Library General Public License
     16  * along with this library; see the file COPYING.LIB.  If not, write to
     17  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
     18  * Boston, MA 02110-1301, USA.
     19  *
     20  */
     21 
     22 #include "config.h"
     23 #include "ThreadSpecific.h"
     24 
     25 #if OS(WIN)
     26 
     27 #include "StdLibExtras.h"
     28 #include "ThreadingPrimitives.h"
     29 #include "wtf/DoublyLinkedList.h"
     30 
     31 namespace WTF {
     32 
     33 static DoublyLinkedList<PlatformThreadSpecificKey>& destructorsList()
     34 {
     35     DEFINE_STATIC_LOCAL(DoublyLinkedList<PlatformThreadSpecificKey>, staticList, ());
     36     return staticList;
     37 }
     38 
     39 static Mutex& destructorsMutex()
     40 {
     41     DEFINE_STATIC_LOCAL(Mutex, staticMutex, ());
     42     return staticMutex;
     43 }
     44 
     45 class PlatformThreadSpecificKey : public DoublyLinkedListNode<PlatformThreadSpecificKey> {
     46 public:
     47     friend class DoublyLinkedListNode<PlatformThreadSpecificKey>;
     48 
     49     PlatformThreadSpecificKey(void (*destructor)(void *))
     50         : m_destructor(destructor)
     51     {
     52         m_tlsKey = TlsAlloc();
     53         if (m_tlsKey == TLS_OUT_OF_INDEXES)
     54             CRASH();
     55     }
     56 
     57     ~PlatformThreadSpecificKey()
     58     {
     59         TlsFree(m_tlsKey);
     60     }
     61 
     62     void setValue(void* data) { TlsSetValue(m_tlsKey, data); }
     63     void* value() { return TlsGetValue(m_tlsKey); }
     64 
     65     void callDestructor()
     66     {
     67        if (void* data = value())
     68             m_destructor(data);
     69     }
     70 
     71 private:
     72     void (*m_destructor)(void *);
     73     DWORD m_tlsKey;
     74     PlatformThreadSpecificKey* m_prev;
     75     PlatformThreadSpecificKey* m_next;
     76 };
     77 
     78 long& tlsKeyCount()
     79 {
     80     static long count;
     81     return count;
     82 }
     83 
     84 DWORD* tlsKeys()
     85 {
     86     static DWORD keys[kMaxTlsKeySize];
     87     return keys;
     88 }
     89 
     90 void threadSpecificKeyCreate(ThreadSpecificKey* key, void (*destructor)(void *))
     91 {
     92     *key = new PlatformThreadSpecificKey(destructor);
     93 
     94     MutexLocker locker(destructorsMutex());
     95     destructorsList().push(*key);
     96 }
     97 
     98 void threadSpecificKeyDelete(ThreadSpecificKey key)
     99 {
    100     MutexLocker locker(destructorsMutex());
    101     destructorsList().remove(key);
    102     delete key;
    103 }
    104 
    105 void threadSpecificSet(ThreadSpecificKey key, void* data)
    106 {
    107     key->setValue(data);
    108 }
    109 
    110 void* threadSpecificGet(ThreadSpecificKey key)
    111 {
    112     return key->value();
    113 }
    114 
    115 void ThreadSpecificThreadExit()
    116 {
    117     for (long i = 0; i < tlsKeyCount(); i++) {
    118         // The layout of ThreadSpecific<T>::Data does not depend on T. So we are safe to do the static cast to ThreadSpecific<int> in order to access its data member.
    119         ThreadSpecific<int>::Data* data = static_cast<ThreadSpecific<int>::Data*>(TlsGetValue(tlsKeys()[i]));
    120         if (data)
    121             data->destructor(data);
    122     }
    123 
    124     MutexLocker locker(destructorsMutex());
    125     PlatformThreadSpecificKey* key = destructorsList().head();
    126     while (key) {
    127         PlatformThreadSpecificKey* nextKey = key->next();
    128         key->callDestructor();
    129         key = nextKey;
    130     }
    131 }
    132 
    133 } // namespace WTF
    134 
    135 #endif // OS(WIN)
    136