openspades/Sources/Core/ThreadLocalStorage.cpp

146 lines
3.5 KiB
C++
Raw Normal View History

2013-08-29 11:45:22 +09:00
/*
Copyright (c) 2013 yvt
2013-08-29 11:45:22 +09:00
This file is part of OpenSpades.
2013-08-29 11:45:22 +09:00
OpenSpades is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
2013-08-29 11:45:22 +09:00
OpenSpades 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 General Public License for more details.
2013-08-29 11:45:22 +09:00
You should have received a copy of the GNU General Public License
along with OpenSpades. If not, see <http://www.gnu.org/licenses/>.
2013-08-29 11:45:22 +09:00
*/
2013-08-18 16:18:06 +09:00
2017-03-23 15:34:32 +09:00
#include <algorithm>
#include <mutex>
#include <unordered_set>
2013-08-18 16:18:06 +09:00
#ifdef WIN32
#include <windows.h>
#else
#include <pthread.h>
#endif
#include "ThreadLocalStorage.h"
2013-08-18 16:18:06 +09:00
namespace spades {
2017-03-23 15:34:32 +09:00
namespace {
class ThreadLocalStorageImplInternal;
2017-03-23 15:34:32 +09:00
class TlsManager
{
public:
void AddTls(ThreadLocalStorageImplInternal *tls) {
std::lock_guard<std::mutex> lock{m_mutex};
2017-03-23 15:34:32 +09:00
m_allTlses.insert(tls);
}
void RemoveTls(ThreadLocalStorageImplInternal *tls) {
std::lock_guard<std::mutex> lock{m_mutex};
auto it = m_allTlses.find(tls);
2017-03-23 15:35:04 +09:00
SPAssert(it != m_allTlses.end());
2017-03-23 15:34:32 +09:00
m_allTlses.erase(it);
}
void ThreadExiting();
static TlsManager &GetInstance() {
// This object will NEVER be destroyed (until the program really exits)
static TlsManager *instance = new TlsManager();
return *instance;
}
private:
std::unordered_set<ThreadLocalStorageImplInternal *> m_allTlses;
std::mutex m_mutex;
};
class ThreadLocalStorageImplInternal : public ThreadLocalStorageImpl {
public:
ThreadLocalStorageImplInternal() {
// Be careful: this function can be called during static storage object construction
TlsManager::GetInstance().AddTls(this);
}
~ThreadLocalStorageImplInternal() {
TlsManager::GetInstance().RemoveTls(this);
}
void ThreadExiting() {
void *p = Get();
if (p)
destructor->Destruct(p);
}
};
}
void TlsManager::ThreadExiting() {
std::lock_guard<std::mutex> lock{m_mutex};
for (auto *tls: m_allTlses) {
tls->ThreadExiting();
2013-08-18 16:18:06 +09:00
}
2017-03-23 15:34:32 +09:00
}
2013-08-18 16:18:06 +09:00
void ThreadExiting() {
2017-03-23 15:34:32 +09:00
// Be careful: this function can be called during static storage object destruction
TlsManager::GetInstance().ThreadExiting();
2013-08-18 16:18:06 +09:00
}
2013-08-18 16:18:06 +09:00
#ifdef WIN32
class Win32ThreadLocalStorageImpl : public ThreadLocalStorageImplInternal {
2013-08-18 16:18:06 +09:00
DWORD key;
2013-08-18 16:18:06 +09:00
public:
Win32ThreadLocalStorageImpl() {
key = TlsAlloc();
if (key + 1 == 0) {
2013-08-18 16:18:06 +09:00
SPRaise("Failed to create Windows TLS key");
}
}
~Win32ThreadLocalStorageImpl() { TlsFree(key); }
void Set(void *value) override { TlsSetValue(key, value); }
void *Get() override { return TlsGetValue(key); }
2013-08-18 16:18:06 +09:00
};
2013-08-18 16:18:06 +09:00
ThreadLocalStorageImpl *ThreadLocalStorageImpl::Create() {
return new Win32ThreadLocalStorageImpl();
}
2013-08-18 16:18:06 +09:00
#else
class PThreadThreadLocalStorageImpl : public ThreadLocalStorageImplInternal {
2013-08-18 16:18:06 +09:00
pthread_key_t key;
2013-08-18 16:18:06 +09:00
public:
PThreadThreadLocalStorageImpl() {
if (pthread_key_create(&key, NULL)) {
2013-08-18 16:18:06 +09:00
SPRaise("Failed to create PThread TLS key");
}
}
~PThreadThreadLocalStorageImpl() { pthread_key_delete(key); }
void Set(void *value) override {
if (pthread_setspecific(key, value)) {
2013-08-18 16:18:06 +09:00
SPRaise("Failed to set TLS value");
}
}
void *Get() override { return pthread_getspecific(key); }
2013-08-18 16:18:06 +09:00
};
2013-08-18 16:18:06 +09:00
ThreadLocalStorageImpl *ThreadLocalStorageImpl::Create() {
return new PThreadThreadLocalStorageImpl();
}
#endif
}