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
31namespace WTF {
32
33static DoublyLinkedList<PlatformThreadSpecificKey>& destructorsList()
34{
35    DEFINE_STATIC_LOCAL(DoublyLinkedList<PlatformThreadSpecificKey>, staticList, ());
36    return staticList;
37}
38
39static Mutex& destructorsMutex()
40{
41    DEFINE_STATIC_LOCAL(Mutex, staticMutex, ());
42    return staticMutex;
43}
44
45class PlatformThreadSpecificKey : public DoublyLinkedListNode<PlatformThreadSpecificKey> {
46public:
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
71private:
72    void (*m_destructor)(void *);
73    DWORD m_tlsKey;
74    PlatformThreadSpecificKey* m_prev;
75    PlatformThreadSpecificKey* m_next;
76};
77
78long& tlsKeyCount()
79{
80    static long count;
81    return count;
82}
83
84DWORD* tlsKeys()
85{
86    static DWORD keys[kMaxTlsKeySize];
87    return keys;
88}
89
90void threadSpecificKeyCreate(ThreadSpecificKey* key, void (*destructor)(void *))
91{
92    *key = new PlatformThreadSpecificKey(destructor);
93
94    MutexLocker locker(destructorsMutex());
95    destructorsList().push(*key);
96}
97
98void threadSpecificKeyDelete(ThreadSpecificKey key)
99{
100    MutexLocker locker(destructorsMutex());
101    destructorsList().remove(key);
102    delete key;
103}
104
105void threadSpecificSet(ThreadSpecificKey key, void* data)
106{
107    key->setValue(data);
108}
109
110void* threadSpecificGet(ThreadSpecificKey key)
111{
112    return key->value();
113}
114
115void 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(WINDOWS)
136