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(WIN)
26
27 #include "StdLibExtras.h"
28 #include "ThreadingPrimitives.h"
29 #include "wtf/DoublyLinkedList.h"
30
31 namespace WTF {
32
destructorsList()33 static DoublyLinkedList<PlatformThreadSpecificKey>& destructorsList()
34 {
35 DEFINE_STATIC_LOCAL(DoublyLinkedList<PlatformThreadSpecificKey>, staticList, ());
36 return staticList;
37 }
38
destructorsMutex()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
PlatformThreadSpecificKey(void (* destructor)(void *))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
~PlatformThreadSpecificKey()57 ~PlatformThreadSpecificKey()
58 {
59 TlsFree(m_tlsKey);
60 }
61
setValue(void * data)62 void setValue(void* data) { TlsSetValue(m_tlsKey, data); }
value()63 void* value() { return TlsGetValue(m_tlsKey); }
64
callDestructor()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
tlsKeyCount()78 long& tlsKeyCount()
79 {
80 static long count;
81 return count;
82 }
83
tlsKeys()84 DWORD* tlsKeys()
85 {
86 static DWORD keys[kMaxTlsKeySize];
87 return keys;
88 }
89
threadSpecificKeyCreate(ThreadSpecificKey * key,void (* destructor)(void *))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
threadSpecificKeyDelete(ThreadSpecificKey key)98 void threadSpecificKeyDelete(ThreadSpecificKey key)
99 {
100 MutexLocker locker(destructorsMutex());
101 destructorsList().remove(key);
102 delete key;
103 }
104
threadSpecificSet(ThreadSpecificKey key,void * data)105 void threadSpecificSet(ThreadSpecificKey key, void* data)
106 {
107 key->setValue(data);
108 }
109
threadSpecificGet(ThreadSpecificKey key)110 void* threadSpecificGet(ThreadSpecificKey key)
111 {
112 return key->value();
113 }
114
ThreadSpecificThreadExit()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