blob: 7a4e9dfb38cde0556ad7edfe296142a291fc96e5 [file] [log] [blame]
/*
* Copyright (C) 2009 Jian Li <jianli@chromium.org>
* Copyright (C) 2012 Patrick Gansterer <paroga@paroga.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public License
* along with this library; see the file COPYING.LIB. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*
*/
#include "config.h"
#include "ThreadSpecific.h"
#if OS(WINDOWS)
#include "StdLibExtras.h"
#include "ThreadingPrimitives.h"
#include "wtf/DoublyLinkedList.h"
namespace WTF {
static DoublyLinkedList<PlatformThreadSpecificKey>& destructorsList()
{
DEFINE_STATIC_LOCAL(DoublyLinkedList<PlatformThreadSpecificKey>, staticList, ());
return staticList;
}
static Mutex& destructorsMutex()
{
DEFINE_STATIC_LOCAL(Mutex, staticMutex, ());
return staticMutex;
}
class PlatformThreadSpecificKey : public DoublyLinkedListNode<PlatformThreadSpecificKey> {
public:
friend class DoublyLinkedListNode<PlatformThreadSpecificKey>;
PlatformThreadSpecificKey(void (*destructor)(void *))
: m_destructor(destructor)
{
m_tlsKey = TlsAlloc();
if (m_tlsKey == TLS_OUT_OF_INDEXES)
CRASH();
}
~PlatformThreadSpecificKey()
{
TlsFree(m_tlsKey);
}
void setValue(void* data) { TlsSetValue(m_tlsKey, data); }
void* value() { return TlsGetValue(m_tlsKey); }
void callDestructor()
{
if (void* data = value())
m_destructor(data);
}
private:
void (*m_destructor)(void *);
DWORD m_tlsKey;
PlatformThreadSpecificKey* m_prev;
PlatformThreadSpecificKey* m_next;
};
long& tlsKeyCount()
{
static long count;
return count;
}
DWORD* tlsKeys()
{
static DWORD keys[kMaxTlsKeySize];
return keys;
}
void threadSpecificKeyCreate(ThreadSpecificKey* key, void (*destructor)(void *))
{
*key = new PlatformThreadSpecificKey(destructor);
MutexLocker locker(destructorsMutex());
destructorsList().push(*key);
}
void threadSpecificKeyDelete(ThreadSpecificKey key)
{
MutexLocker locker(destructorsMutex());
destructorsList().remove(key);
delete key;
}
void threadSpecificSet(ThreadSpecificKey key, void* data)
{
key->setValue(data);
}
void* threadSpecificGet(ThreadSpecificKey key)
{
return key->value();
}
void ThreadSpecificThreadExit()
{
for (long i = 0; i < tlsKeyCount(); i++) {
// 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.
ThreadSpecific<int>::Data* data = static_cast<ThreadSpecific<int>::Data*>(TlsGetValue(tlsKeys()[i]));
if (data)
data->destructor(data);
}
MutexLocker locker(destructorsMutex());
PlatformThreadSpecificKey* key = destructorsList().head();
while (key) {
PlatformThreadSpecificKey* nextKey = key->next();
key->callDestructor();
key = nextKey;
}
}
} // namespace WTF
#endif // OS(WINDOWS)