1fb7398e2176ad963e9adfd6d3a43ff8518109bf
[WebKit-https.git] / Source / WTF / wtf / ThreadSpecificWin.cpp
1 /*
2  * Copyright (C) 2009 Jian Li <jianli@chromium.org>
3  * Copyright (C) 2012 Patrick Gansterer <paroga@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(WINDOWS)
26
27 #include "StdLibExtras.h"
28 #include "ThreadingPrimitives.h"
29 #include <wtf/DoublyLinkedList.h>
30
31 #if !USE(PTHREADS)
32
33 namespace WTF {
34
35 static DoublyLinkedList<PlatformThreadSpecificKey>& destructorsList()
36 {
37     DEFINE_STATIC_LOCAL(DoublyLinkedList<PlatformThreadSpecificKey>, staticList, ());
38     return staticList;
39 }
40
41 static Mutex& destructorsMutex()
42 {
43     DEFINE_STATIC_LOCAL(Mutex, staticMutex, ());
44     return staticMutex;
45 }
46
47 class PlatformThreadSpecificKey : public DoublyLinkedListNode<PlatformThreadSpecificKey> {
48 public:
49     friend class DoublyLinkedListNode<PlatformThreadSpecificKey>;
50
51     PlatformThreadSpecificKey(void (*destructor)(void *))
52         : m_destructor(destructor)
53     {
54         m_tlsKey = TlsAlloc();
55         if (m_tlsKey == TLS_OUT_OF_INDEXES)
56             CRASH();
57     }
58
59     ~PlatformThreadSpecificKey()
60     {
61         TlsFree(m_tlsKey);
62     }
63
64     void setValue(void* data) { TlsSetValue(m_tlsKey, data); }
65     void* value() { return TlsGetValue(m_tlsKey); }
66
67     void callDestructor()
68     {
69        if (void* data = value())
70             m_destructor(data);
71     }
72
73 private:
74     void (*m_destructor)(void *);
75     DWORD m_tlsKey;
76     PlatformThreadSpecificKey* m_prev;
77     PlatformThreadSpecificKey* m_next;
78 };
79
80 long& tlsKeyCount()
81 {
82     static long count;
83     return count;
84 }
85
86 DWORD* tlsKeys()
87 {
88     static DWORD keys[kMaxTlsKeySize];
89     return keys;
90 }
91
92 void threadSpecificKeyCreate(ThreadSpecificKey* key, void (*destructor)(void *))
93 {
94     *key = new PlatformThreadSpecificKey(destructor);
95
96     MutexLocker locker(destructorsMutex());
97     destructorsList().push(*key);
98 }
99
100 void threadSpecificKeyDelete(ThreadSpecificKey key)
101 {
102     MutexLocker locker(destructorsMutex());
103     destructorsList().remove(key);
104     delete key;
105 }
106
107 void threadSpecificSet(ThreadSpecificKey key, void* data)
108 {
109     key->setValue(data);
110 }
111
112 void* threadSpecificGet(ThreadSpecificKey key)
113 {
114     return key->value();
115 }
116
117 void ThreadSpecificThreadExit()
118 {
119     for (long i = 0; i < tlsKeyCount(); i++) {
120         // 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.
121         ThreadSpecific<int>::Data* data = static_cast<ThreadSpecific<int>::Data*>(TlsGetValue(tlsKeys()[i]));
122         if (data)
123             data->destructor(data);
124     }
125
126     MutexLocker locker(destructorsMutex());
127     PlatformThreadSpecificKey* key = destructorsList().head();
128     while (key) {
129         PlatformThreadSpecificKey* nextKey = key->next();
130         key->callDestructor();
131         key = nextKey;
132     }
133 }
134
135 } // namespace WTF
136
137 #endif // !USE(PTHREADS)
138
139 #endif // OS(WINDOWS)