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
33namespace WTF {
34
35static DoublyLinkedList<PlatformThreadSpecificKey>& destructorsList()
36{
37    static DoublyLinkedList<PlatformThreadSpecificKey> staticList;
38    return staticList;
39}
40
41static Mutex& destructorsMutex()
42{
43    static Mutex staticMutex;
44    return staticMutex;
45}
46
47class PlatformThreadSpecificKey : public DoublyLinkedListNode<PlatformThreadSpecificKey> {
48public:
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
73private:
74    void (*m_destructor)(void *);
75    DWORD m_tlsKey;
76    PlatformThreadSpecificKey* m_prev;
77    PlatformThreadSpecificKey* m_next;
78};
79
80long& tlsKeyCount()
81{
82    static long count;
83    return count;
84}
85
86DWORD* tlsKeys()
87{
88    static DWORD keys[kMaxTlsKeySize];
89    return keys;
90}
91
92void threadSpecificKeyCreate(ThreadSpecificKey* key, void (*destructor)(void *))
93{
94    // Use the original malloc() instead of fastMalloc() to use this function in FastMalloc code.
95    *key = static_cast<PlatformThreadSpecificKey*>(::malloc(sizeof(PlatformThreadSpecificKey)));
96    new (*key) PlatformThreadSpecificKey(destructor);
97
98    MutexLocker locker(destructorsMutex());
99    destructorsList().push(*key);
100}
101
102void threadSpecificKeyDelete(ThreadSpecificKey key)
103{
104    MutexLocker locker(destructorsMutex());
105    destructorsList().remove(key);
106    key->~PlatformThreadSpecificKey();
107    ::free(key);
108}
109
110void threadSpecificSet(ThreadSpecificKey key, void* data)
111{
112    key->setValue(data);
113}
114
115void* threadSpecificGet(ThreadSpecificKey key)
116{
117    return key->value();
118}
119
120void ThreadSpecificThreadExit()
121{
122    for (long i = 0; i < tlsKeyCount(); i++) {
123        // 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.
124        ThreadSpecific<int>::Data* data = static_cast<ThreadSpecific<int>::Data*>(TlsGetValue(tlsKeys()[i]));
125        if (data)
126            data->destructor(data);
127    }
128
129    MutexLocker locker(destructorsMutex());
130    PlatformThreadSpecificKey* key = destructorsList().head();
131    while (key) {
132        PlatformThreadSpecificKey* nextKey = key->next();
133        key->callDestructor();
134        key = nextKey;
135    }
136}
137
138} // namespace WTF
139
140#endif // !USE(PTHREADS)
141
142#endif // OS(WINDOWS)
143