rename thread_local_ptr => tls::pointer

This commit is contained in:
mutouyun 2018-12-15 19:30:22 +08:00
parent 0285e2d6e1
commit 44ab812925
6 changed files with 190 additions and 161 deletions

View File

@ -22,7 +22,7 @@ HEADERS += \
../include/ipc.h \ ../include/ipc.h \
../include/def.h \ ../include/def.h \
../include/rw_lock.h \ ../include/rw_lock.h \
../include/thread_local_ptr.h ../include/tls_pointer.h
SOURCES += \ SOURCES += \
../src/shm.cpp \ ../src/shm.cpp \
@ -31,7 +31,8 @@ SOURCES += \
unix { unix {
SOURCES += \ SOURCES += \
../src/platform/shm_linux.cpp ../src/platform/shm_linux.cpp \
../src/platform/tls_pointer_linux.cpp
LIBS += -lrt LIBS += -lrt
@ -44,7 +45,7 @@ else:win32 {
SOURCES += \ SOURCES += \
../src/platform/shm_win.cpp \ ../src/platform/shm_win.cpp \
../src/platform/thread_local_ptr_win.cpp ../src/platform/tls_pointer_win.cpp
LIBS += -lKernel32 LIBS += -lKernel32

View File

@ -1,100 +0,0 @@
#pragma once
#include <utility> // std::forward
#if defined(WINCE) || defined(_WIN32_WCE) || \
defined(WIN64) || defined(_WIN64) || defined(__WIN64__) || \
defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(__NT__)
#include <windows.h> // DWORD, ::Tls...
#define IPC_OS_WIN_
#else
#include <pthread.h> // pthread_...
#endif
namespace ipc {
#if defined(IPC_OS_WIN_)
#define IPC_THREAD_LOCAL_KEY_ DWORD
#define IPC_THREAD_LOCAL_SET(KEY, PTR) (::TlsSetValue(KEY, (LPVOID)PTR) == TRUE)
#define IPC_THREAD_LOCAL_GET(KEY) (::TlsGetValue(KEY))
void thread_local_create(IPC_THREAD_LOCAL_KEY_& key, void (*destructor)(void*));
void thread_local_delete(IPC_THREAD_LOCAL_KEY_ key);
#define IPC_THREAD_LOCAL_CREATE(KEY, DESTRUCTOR) thread_local_create(KEY, DESTRUCTOR)
#define IPC_THREAD_LOCAL_DELETE(KEY) thread_local_delete(KEY)
#else /*!IPC_OS_WIN_*/
#define IPC_THREAD_LOCAL_KEY_ pthread_key_t
#define IPC_THREAD_LOCAL_CREATE(KEY, DESTRUCTOR) pthread_key_create(&KEY, DESTRUCTOR)
#define IPC_THREAD_LOCAL_DELETE(KEY) pthread_key_delete(KEY)
#define IPC_THREAD_LOCAL_SET(KEY, PTR) (pthread_setspecific(KEY, (void*)PTR) == 0)
#define IPC_THREAD_LOCAL_GET(KEY) pthread_getspecific(KEY)
#endif/*!IPC_OS_WIN_*/
////////////////////////////////////////////////////////////////
/// Thread-local pointer
////////////////////////////////////////////////////////////////
/*
<Remarks>
1. In Windows, if you do not compile thread_local_ptr.cpp,
use thread_local_ptr will cause memory leaks.
2. You need to set the thread_local_ptr's storage manually:
```
thread_local_ptr<int> p;
if (!p) p = new int(123);
```
Just like an ordinary pointer. Or you could just call create:
```
thread_local_ptr<int> p;
p.create(123);
```
*/
template <typename T>
class thread_local_ptr {
IPC_THREAD_LOCAL_KEY_ key_;
public:
using value_type = T;
thread_local_ptr() {
IPC_THREAD_LOCAL_CREATE(key_, [](void* p) {
delete static_cast<T*>(p);
});
}
~thread_local_ptr() {
IPC_THREAD_LOCAL_DELETE(key_);
}
template <typename... P>
T* create(P&&... params) {
auto ptr = static_cast<T*>(*this);
if (ptr == nullptr) {
return (*this) = new T(std::forward<P>(params)...);
}
return ptr;
}
T* operator=(T* ptr) {
IPC_THREAD_LOCAL_SET(key_, ptr);
return ptr;
}
operator T*() const { return static_cast<T*>(IPC_THREAD_LOCAL_GET(key_)); }
T& operator* () { return *static_cast<T*>(*this); }
const T& operator* () const { return *static_cast<T*>(*this); }
T* operator->() { return static_cast<T*>(*this); }
const T* operator->() const { return static_cast<T*>(*this); }
};
} // namespace ipc

84
include/tls_pointer.h Normal file
View File

@ -0,0 +1,84 @@
#pragma once
#include <cstdint>
#include <utility>
#include <limits>
namespace ipc {
namespace tls {
using key_t = std::uint64_t;
using destructor_t = void (*)(void*);
enum : key_t {
invalid_value = (std::numeric_limits<key_t>::max)()
};
key_t create (destructor_t destructor = nullptr);
void release(key_t key);
bool set(key_t key, void* ptr);
void* get(key_t key);
////////////////////////////////////////////////////////////////
/// Thread-local pointer
////////////////////////////////////////////////////////////////
/*
<Remarks>
1. In Windows, if you do not compile thread_local_ptr.cpp,
use thread_local_ptr will cause memory leaks.
2. You need to set the thread_local_ptr's storage manually:
```
thread_local_ptr<int> p;
if (!p) p = new int(123);
```
Just like an ordinary pointer. Or you could just call create:
```
thread_local_ptr<int> p;
p.create(123);
```
*/
template <typename T>
class pointer {
key_t key_;
public:
using value_type = T;
pointer() {
key_ = tls::create([](void* p) { delete static_cast<T*>(p); });
}
~pointer() {
tls::release(key_);
}
template <typename... P>
T* create(P&&... params) {
auto ptr = static_cast<T*>(*this);
if (ptr == nullptr) {
return (*this) = new T { std::forward<P>(params)... };
}
return ptr;
}
T* operator=(T* ptr) {
set(key_, ptr);
return ptr;
}
operator T*() const { return static_cast<T*>(get(key_)); }
T& operator* () { return *static_cast<T*>(*this); }
const T& operator* () const { return *static_cast<T*>(*this); }
T* operator->() { return static_cast<T*>(*this); }
const T* operator->() const { return static_cast<T*>(*this); }
};
} // namespace tls
} // namespace ipc

View File

@ -13,7 +13,7 @@
#include "def.h" #include "def.h"
#include "circ_queue.h" #include "circ_queue.h"
#include "rw_lock.h" #include "rw_lock.h"
#include "thread_local_ptr.h" #include "tls_pointer.h"
namespace { namespace {
@ -36,7 +36,7 @@ using guard_t = std::unique_ptr<std::remove_pointer_t<handle_t>, void(*)(handle_
* https://sourceforge.net/p/mingw-w64/bugs/727/ * https://sourceforge.net/p/mingw-w64/bugs/727/
*/ */
/*thread_local*/ /*thread_local*/
thread_local_ptr<std::unordered_map<decltype(msg_t::id_), std::vector<byte_t>>> recv_caches__; tls::pointer<std::unordered_map<decltype(msg_t::id_), std::vector<byte_t>>> recv_caches__;
std::unordered_map<handle_t, queue_t> h2q__; std::unordered_map<handle_t, queue_t> h2q__;
rw_lock h2q_lc__; rw_lock h2q_lc__;

View File

@ -0,0 +1,29 @@
#include "tls_pointer.h"
#include <pthread.h> // pthread_...
namespace ipc {
namespace tls {
key_t create(destructor_t destructor) {
pthread_key_t k;
if (pthread_key_create(&k, destructor) == 0) {
return static_cast<key_t>(k);
}
return invalid_value;
}
void release(key_t key) {
pthread_key_delete(static_cast<pthread_key_t>(key));
}
bool set(key_t key, void* ptr) {
return pthread_setspecific(static_cast<pthread_key_t>(key), ptr) == 0;
}
void* get(key_t key) {
return pthread_getspecific(static_cast<pthread_key_t>(key));
}
} // namespace tls
} // namespace ipc

View File

@ -1,4 +1,4 @@
#include "thread_local_ptr.h" #include "tls_pointer.h"
#include <windows.h> // ::Tls... #include <windows.h> // ::Tls...
#include <unordered_map> // std::unordered_map #include <unordered_map> // std::unordered_map
@ -18,30 +18,31 @@ namespace ipc {
*/ */
namespace { namespace {
struct tls_data {
struct tls_data {
using destructor_t = void(*)(void*); using destructor_t = void(*)(void*);
using map_t = std::unordered_map<IPC_THREAD_LOCAL_KEY_, tls_data>; using map_t = std::unordered_map<tls::key_t, tls_data>;
static DWORD& key() { static DWORD& key() {
static IPC_THREAD_LOCAL_KEY_ rec_key = ::TlsAlloc(); static DWORD rec_key = ::TlsAlloc();
return rec_key; return rec_key;
} }
static map_t* records(map_t* rec) { static map_t* records(map_t* rec) {
IPC_THREAD_LOCAL_SET(key(), rec); ::TlsSetValue(key(), static_cast<LPVOID>(rec));
return rec; return rec;
} }
static map_t* records() { static map_t* records() {
return static_cast<map_t*>(IPC_THREAD_LOCAL_GET(key())); return static_cast<map_t*>(::TlsGetValue(key()));
} }
IPC_THREAD_LOCAL_KEY_ key_ = 0; tls::key_t key_ = tls::invalid_value;
destructor_t destructor_ = nullptr; destructor_t destructor_ = nullptr;
tls_data() = default; tls_data() = default;
tls_data(IPC_THREAD_LOCAL_KEY_ key, destructor_t destructor) tls_data(tls::key_t key, destructor_t destructor)
: key_ (key) : key_ (key)
, destructor_(destructor) , destructor_(destructor)
{} {}
@ -59,30 +60,43 @@ namespace {
} }
~tls_data() { ~tls_data() {
if (destructor_) destructor_(IPC_THREAD_LOCAL_GET(key_)); if (destructor_) destructor_(tls::get(key_));
} }
}; };
}
void thread_local_create(IPC_THREAD_LOCAL_KEY_& key, void (*destructor)(void*)) { } // internal-linkage
key = ::TlsAlloc();
if (key == TLS_OUT_OF_INDEXES) return; namespace tls {
key_t create(destructor_t destructor) {
key_t key = static_cast<key_t>(::TlsAlloc());
if (key == TLS_OUT_OF_INDEXES) return invalid_value;
auto rec = tls_data::records(); auto rec = tls_data::records();
if (!rec) rec = tls_data::records(new tls_data::map_t); if (!rec) rec = tls_data::records(new tls_data::map_t);
if (!rec) return; if (!rec) return key;
rec->emplace(key, tls_data{ key, destructor }); rec->emplace(key, tls_data{ key, destructor });
return key;
} }
void thread_local_delete(IPC_THREAD_LOCAL_KEY_ key) { void release(key_t key) {
auto rec = tls_data::records(); auto rec = tls_data::records();
if (!rec) return; if (!rec) return;
rec->erase(key); rec->erase(key);
::TlsFree(key); ::TlsFree(static_cast<DWORD>(key));
} }
//////////////////////////////////////////////////////////////// bool set(key_t key, void* ptr) {
/// Call destructors on thread exit return ::TlsSetValue(static_cast<DWORD>(key),
//////////////////////////////////////////////////////////////// static_cast<LPVOID>(ptr)) == TRUE;
}
void* get(key_t key) {
return static_cast<void*>(::TlsGetValue(static_cast<DWORD>(key)));
}
} // namespace tls
namespace {
void OnThreadExit() { void OnThreadExit() {
auto rec = tls_data::records(); auto rec = tls_data::records();
@ -95,6 +109,12 @@ void NTAPI OnTlsCallback(PVOID, DWORD dwReason, PVOID) {
if (dwReason == DLL_THREAD_DETACH) OnThreadExit(); if (dwReason == DLL_THREAD_DETACH) OnThreadExit();
} }
} // internal-linkage
////////////////////////////////////////////////////////////////
/// Call destructors on thread exit
////////////////////////////////////////////////////////////////
#if defined(_MSC_VER) #if defined(_MSC_VER)
#if defined(IPC_OS_WIN64_) #if defined(IPC_OS_WIN64_)
@ -102,8 +122,7 @@ void NTAPI OnTlsCallback(PVOID, DWORD dwReason, PVOID) {
#pragma comment(linker, "/INCLUDE:_tls_used") #pragma comment(linker, "/INCLUDE:_tls_used")
#pragma comment(linker, "/INCLUDE:_tls_xl_b__") #pragma comment(linker, "/INCLUDE:_tls_xl_b__")
extern "C" extern "C" {
{
# pragma const_seg(".CRT$XLB") # pragma const_seg(".CRT$XLB")
extern const PIMAGE_TLS_CALLBACK _tls_xl_b__; extern const PIMAGE_TLS_CALLBACK _tls_xl_b__;
const PIMAGE_TLS_CALLBACK _tls_xl_b__ = OnTlsCallback; const PIMAGE_TLS_CALLBACK _tls_xl_b__ = OnTlsCallback;
@ -115,8 +134,7 @@ extern "C"
#pragma comment(linker, "/INCLUDE:__tls_used") #pragma comment(linker, "/INCLUDE:__tls_used")
#pragma comment(linker, "/INCLUDE:__tls_xl_b__") #pragma comment(linker, "/INCLUDE:__tls_xl_b__")
extern "C" extern "C" {
{
# pragma data_seg(".CRT$XLB") # pragma data_seg(".CRT$XLB")
PIMAGE_TLS_CALLBACK _tls_xl_b__ = OnTlsCallback; PIMAGE_TLS_CALLBACK _tls_xl_b__ = OnTlsCallback;
# pragma data_seg() # pragma data_seg()
@ -131,15 +149,13 @@ extern "C"
#if defined(__MINGW64__) || (__MINGW64_VERSION_MAJOR) || \ #if defined(__MINGW64__) || (__MINGW64_VERSION_MAJOR) || \
(__MINGW32_MAJOR_VERSION > 3) || ((__MINGW32_MAJOR_VERSION == 3) && (__MINGW32_MINOR_VERSION >= 18)) (__MINGW32_MAJOR_VERSION > 3) || ((__MINGW32_MAJOR_VERSION == 3) && (__MINGW32_MINOR_VERSION >= 18))
extern "C" extern "C" {
{
IPC_CRTALLOC__(".CRT$XLB") PIMAGE_TLS_CALLBACK _tls_xl_b__ = OnTlsCallback; IPC_CRTALLOC__(".CRT$XLB") PIMAGE_TLS_CALLBACK _tls_xl_b__ = OnTlsCallback;
} }
#else /*!__MINGW*/ #else /*!__MINGW*/
extern "C" extern "C" {
{
ULONG _tls_index__ = 0; ULONG _tls_index__ = 0;
IPC_CRTALLOC__(".tls$AAA") char _tls_start__ = 0; IPC_CRTALLOC__(".tls$AAA") char _tls_start__ = 0;
@ -150,8 +166,7 @@ extern "C"
IPC_CRTALLOC__(".CRT$XLZ") PIMAGE_TLS_CALLBACK _tls_xl_z__ = 0; IPC_CRTALLOC__(".CRT$XLZ") PIMAGE_TLS_CALLBACK _tls_xl_z__ = 0;
} }
extern "C" NX_CRTALLOC_(".tls") const IMAGE_TLS_DIRECTORY _tls_used = extern "C" NX_CRTALLOC_(".tls") const IMAGE_TLS_DIRECTORY _tls_used = {
{
(ULONG_PTR)(&_tls_start__ + 1), (ULONG_PTR)(&_tls_start__ + 1),
(ULONG_PTR) &_tls_end__, (ULONG_PTR) &_tls_end__,
(ULONG_PTR) &_tls_index__, (ULONG_PTR) &_tls_index__,