remove tls

This commit is contained in:
mutouyun 2021-07-10 14:22:31 +08:00
parent a97b12f71d
commit 69e1586b5a
9 changed files with 7 additions and 412 deletions

View File

@ -1,112 +0,0 @@
#pragma once
#include <memory> // std::unique_ptr
#include <utility> // std::forward
#include <cstddef> // std::size_t
#include "libipc/export.h"
namespace ipc {
namespace tls {
using key_t = std::size_t;
using destructor_t = void (*)(void *);
struct key_info {
key_t key_;
};
IPC_EXPORT bool create (key_info * pkey, destructor_t destructor = nullptr);
IPC_EXPORT void release(key_info const * pkey);
IPC_EXPORT bool set(key_info const * pkey, void * ptr);
IPC_EXPORT void * get(key_info const * pkey);
////////////////////////////////////////////////////////////////
/// Thread-local pointer
////////////////////////////////////////////////////////////////
/**
* @remarks
* You need to set the ipc::tls::pointer's storage manually:
* ```
* tls::pointer<int> p;
* if (!p) p = new int(123);
* ```
* It would be like an ordinary pointer.
* Or you could just call create_once to 'new' this pointer automatically.
* ```
* tls::pointer<int> p;
* p.create_once(123);
* ```
*/
template <typename T>
class pointer : public key_info {
pointer(pointer const &) = delete;
pointer & operator=(pointer const &) = delete;
void destruct() const {
delete static_cast<T*>(tls::get(this));
}
public:
using value_type = T;
pointer() {
tls::create(this, [](void* p) {
delete static_cast<T*>(p);
});
}
~pointer() {
destruct();
tls::release(this);
}
template <typename... P>
T* create(P&&... params) {
destruct();
std::unique_ptr<T> ptr { new T(std::forward<P>(params)...) };
if (!tls::set(this, ptr.get())) {
return nullptr;
}
return ptr.release();
}
template <typename... P>
T* create_once(P&&... params) {
auto p = static_cast<T*>(tls::get(this));
if (p == nullptr) {
std::unique_ptr<T> ptr { new T(std::forward<P>(params)...) };
if (!tls::set(this, ptr.get())) {
return nullptr;
}
p = ptr.release();
}
return p;
}
T* operator=(T* p) {
set(this, p);
return p;
}
explicit operator T *() const {
return static_cast<T *>(tls::get(this));
}
explicit operator bool() const {
return tls::get(this) != nullptr;
}
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,6 @@
#include "libipc/ipc.h" #include "libipc/ipc.h"
#include "libipc/def.h" #include "libipc/def.h"
#include "libipc/shm.h" #include "libipc/shm.h"
#include "libipc/tls_pointer.h"
#include "libipc/pool_alloc.h" #include "libipc/pool_alloc.h"
#include "libipc/queue.h" #include "libipc/queue.h"
#include "libipc/policy.h" #include "libipc/policy.h"
@ -253,19 +252,6 @@ struct conn_info_head {
ipc::waiter cc_waiter_, wt_waiter_, rd_waiter_; ipc::waiter cc_waiter_, wt_waiter_, rd_waiter_;
ipc::shm::handle acc_h_; ipc::shm::handle acc_h_;
/*
* <Remarks> thread_local may have some bugs.
*
* <Reference>
* - https://sourceforge.net/p/mingw-w64/bugs/727/
* - https://sourceforge.net/p/mingw-w64/bugs/527/
* - https://github.com/Alexpux/MINGW-packages/issues/2519
* - https://github.com/ChaiScript/ChaiScript/issues/402
* - https://developercommunity.visualstudio.com/content/problem/124121/thread-local-variables-fail-to-be-initialized-when.html
* - https://software.intel.com/en-us/forums/intel-c-compiler/topic/684827
*/
ipc::tls::pointer<ipc::unordered_map<msg_id_t, cache_t>> recv_cache_;
conn_info_head(char const * name) conn_info_head(char const * name)
: name_ {name} : name_ {name}
, cc_id_ {(cc_acc() == nullptr) ? 0 : cc_acc()->fetch_add(1, std::memory_order_relaxed)} , cc_id_ {(cc_acc() == nullptr) ? 0 : cc_acc()->fetch_add(1, std::memory_order_relaxed)}
@ -286,7 +272,8 @@ struct conn_info_head {
} }
auto& recv_cache() { auto& recv_cache() {
return *recv_cache_.create_once(); thread_local ipc::unordered_map<msg_id_t, cache_t> tls;
return tls;
} }
}; };

View File

@ -11,7 +11,6 @@
#include "libipc/def.h" #include "libipc/def.h"
#include "libipc/rw_lock.h" #include "libipc/rw_lock.h"
#include "libipc/tls_pointer.h"
#include "libipc/pool_alloc.h" #include "libipc/pool_alloc.h"
#include "libipc/utility/concept.h" #include "libipc/utility/concept.h"
@ -155,18 +154,16 @@ private:
}; };
friend class alloc_proxy; friend class alloc_proxy;
using ref_t = alloc_proxy&; using ref_t = alloc_proxy&;
using tls_t = tls::pointer<alloc_proxy>;
tls_t tls_;
std::function<ref_t()> get_alloc_; std::function<ref_t()> get_alloc_;
public: public:
template <typename ... P> template <typename ... P>
async_wrapper(P ... pars) { async_wrapper(P ... pars) {
get_alloc_ = [this, pars ...]()->ref_t { get_alloc_ = [this, pars ...]()->ref_t {
return *tls_.create_once(this, pars ...); thread_local alloc_proxy tls(pars ...);
return tls;
}; };
} }

View File

@ -1,41 +0,0 @@
#pragma once
#include <unordered_map> // std::unordered_map
#include <cassert> // assert
#include "libipc/tls_pointer.h"
#include "libipc/utility/utility.h"
namespace ipc {
namespace tls {
inline void tls_destruct(key_info const * pkey, void * p) {
assert(pkey != nullptr);
auto destructor = horrible_cast<destructor_t>(pkey->key_);
if (destructor != nullptr) destructor(p);
}
struct tls_recs : public std::unordered_map<key_info const *, void *> {
~tls_recs() {
for (auto & pair : *this) {
tls_destruct(pair.first, pair.second);
}
}
};
inline tls_recs * tls_get_recs() {
thread_local tls_recs * recs_ptr = nullptr;
if (recs_ptr == nullptr) {
recs_ptr = new tls_recs;
}
assert(recs_ptr != nullptr);
return recs_ptr;
}
inline void at_thread_exit() {
delete tls_get_recs();
}
} // namespace tls
} // namespace ipc

View File

@ -1,83 +0,0 @@
#include <pthread.h> // pthread_...
#include <atomic> // std::atomic_thread_fence
#include <cassert> // assert
#include "libipc/tls_pointer.h"
#include "libipc/utility/log.h"
#include "libipc/utility/utility.h"
namespace ipc {
namespace tls {
namespace {
namespace native {
using key_t = pthread_key_t;
bool create(key_t * pkey, void (*destructor)(void*)) {
assert(pkey != nullptr);
int err = ::pthread_key_create(pkey, destructor);
if (err != 0) {
ipc::error("[native::create] pthread_key_create failed [%d].\n", err);
return false;
}
return true;
}
bool release(key_t key) {
int err = ::pthread_key_delete(key);
if (err != 0) {
ipc::error("[native::release] pthread_key_delete failed [%d].\n", err);
return false;
}
return true;
}
bool set(key_t key, void * ptr) {
int err = ::pthread_setspecific(key, ptr);
if (err != 0) {
ipc::error("[native::set] pthread_setspecific failed [%d].\n", err);
return false;
}
return true;
}
void * get(key_t key) {
return ::pthread_getspecific(key);
}
} // namespace native
} // internal-linkage
bool create(key_info * pkey, destructor_t destructor) {
assert(pkey != nullptr);
native::key_t k;
if (!native::create(&k, destructor)) {
return false;
}
pkey->key_ = horrible_cast<key_t>(k);
std::atomic_thread_fence(std::memory_order_seq_cst);
return true;
}
void release(key_info const * pkey) {
assert(pkey != nullptr);
static_cast<void>(
native::release(horrible_cast<native::key_t>(pkey->key_)));
}
bool set(key_info const * pkey, void* ptr) {
assert(pkey != nullptr);
return native::set(horrible_cast<native::key_t>(pkey->key_), ptr);
}
void * get(key_info const * pkey) {
assert(pkey != nullptr);
return native::get(horrible_cast<native::key_t>(pkey->key_));
}
} // namespace tls
} // namespace ipc

View File

@ -1,100 +0,0 @@
#include <Windows.h>
#include "libipc/platform/tls_detail_win.h"
/**
* @remarks
* Windows doesn't support a per-thread destructor with its TLS primitives.
* So, here will build it manually by inserting a function to be called on each thread's exit.
*
* @see
* - https://www.codeproject.com/Articles/8113/Thread-Local-Storage-The-C-Way
* - https://src.chromium.org/viewvc/chrome/trunk/src/base/threading/thread_local_storage_win.cc
* - https://github.com/mirror/mingw-org-wsl/blob/master/src/libcrt/crt/tlssup.c
* - https://github.com/Alexpux/mingw-w64/blob/master/mingw-w64-crt/crt/tlssup.c
* - http://svn.boost.org/svn/boost/trunk/libs/thread/src/win32/tss_pe.cpp
*/
namespace ipc {
namespace tls {
namespace {
void NTAPI OnTlsCallback(PVOID, DWORD dwReason, PVOID) {
if (dwReason == DLL_THREAD_DETACH) {
ipc::tls::at_thread_exit();
}
}
} // internal-linkage
////////////////////////////////////////////////////////////////
/// Call destructors on thread exit
////////////////////////////////////////////////////////////////
#if defined(_MSC_VER)
#if defined(WIN64) || defined(_WIN64) || defined(__WIN64__)
#pragma comment(linker, "/INCLUDE:_tls_used")
#pragma comment(linker, "/INCLUDE:_tls_xl_b__")
extern "C" {
# pragma const_seg(".CRT$XLB")
extern const PIMAGE_TLS_CALLBACK _tls_xl_b__;
const PIMAGE_TLS_CALLBACK _tls_xl_b__ = OnTlsCallback;
# pragma const_seg()
}
#else /*!WIN64*/
#pragma comment(linker, "/INCLUDE:__tls_used")
#pragma comment(linker, "/INCLUDE:__tls_xl_b__")
extern "C" {
# pragma data_seg(".CRT$XLB")
PIMAGE_TLS_CALLBACK _tls_xl_b__ = OnTlsCallback;
# pragma data_seg()
}
#endif/*!WIN64*/
#elif defined(__GNUC__)
#define IPC_CRTALLOC__(x) __attribute__ ((section (x) ))
#if defined(__MINGW64__) || (__MINGW64_VERSION_MAJOR) || \
(__MINGW32_MAJOR_VERSION > 3) || ((__MINGW32_MAJOR_VERSION == 3) && (__MINGW32_MINOR_VERSION >= 18))
extern "C" {
IPC_CRTALLOC__(".CRT$XLB") PIMAGE_TLS_CALLBACK _tls_xl_b__ = OnTlsCallback;
}
#else /*!MINGW*/
extern "C" {
ULONG _tls_index__ = 0;
IPC_CRTALLOC__(".tls$AAA") char _tls_start__ = 0;
IPC_CRTALLOC__(".tls$ZZZ") char _tls_end__ = 0;
IPC_CRTALLOC__(".CRT$XLA") PIMAGE_TLS_CALLBACK _tls_xl_a__ = 0;
IPC_CRTALLOC__(".CRT$XLB") PIMAGE_TLS_CALLBACK _tls_xl_b__ = OnTlsCallback;
IPC_CRTALLOC__(".CRT$XLZ") PIMAGE_TLS_CALLBACK _tls_xl_z__ = 0;
}
extern "C" NX_CRTALLOC_(".tls") const IMAGE_TLS_DIRECTORY _tls_used = {
(ULONG_PTR)(&_tls_start__ + 1),
(ULONG_PTR) &_tls_end__,
(ULONG_PTR) &_tls_index__,
(ULONG_PTR) &_tls_xl_b__,
(ULONG)0, (ULONG)0
}
#endif/*!MINGW*/
#endif/*_MSC_VER, __GNUC__*/
} // namespace tls
} // namespace ipc

View File

@ -1,46 +0,0 @@
#pragma once
#include <atomic> // std::atomic_thread_fence
#include <cassert> // assert
#include "libipc/tls_pointer.h"
#include "libipc/platform/tls_detail_win.h"
#include "libipc/utility/utility.h"
namespace ipc {
namespace tls {
bool create(key_info * pkey, destructor_t destructor) {
assert(pkey != nullptr);
pkey->key_ = horrible_cast<key_t>(destructor);
std::atomic_thread_fence(std::memory_order_seq_cst);
return true;
}
void release(key_info const * pkey) {
assert(pkey != nullptr);
assert(tls_get_recs() != nullptr);
tls_get_recs()->erase(pkey);
}
bool set(key_info const * pkey, void * ptr) {
assert(pkey != nullptr);
assert(tls_get_recs() != nullptr);
(*tls_get_recs())[pkey] = ptr;
return true;
}
void * get(key_info const * pkey) {
assert(pkey != nullptr);
assert(tls_get_recs() != nullptr);
auto const recs = tls_get_recs();
auto it = recs->find(pkey);
if (it == recs->end()) {
return nullptr;
}
return it->second;
}
} // namespace tls
} // namespace ipc

View File

@ -1,8 +0,0 @@
#if defined(WIN64) || defined(_WIN64) || defined(__WIN64__) || \
defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(__NT__) || \
defined(WINCE) || defined(_WIN32_WCE)
#include "libipc/platform/tls_pointer_win.h"
#else /*!WIN*/
#include "libipc/platform/tls_pointer_linux.h"
#endif/*!WIN*/

View File

@ -11,7 +11,6 @@
#include "capo/type_name.hpp" #include "capo/type_name.hpp"
#include "libipc/rw_lock.h" #include "libipc/rw_lock.h"
#include "libipc/tls_pointer.h"
#include "test.h" #include "test.h"
#include "thread_pool.h" #include "thread_pool.h"
@ -89,6 +88,7 @@ void test_lock_performance(int w, int r) {
// for (int i = 2; i <= ThreadMax; ++i) test_lock_performance(i, i); // for (int i = 2; i <= ThreadMax; ++i) test_lock_performance(i, i);
//} //}
#if 0 // disable ipc::tls
TEST(Thread, tls_main_thread) { TEST(Thread, tls_main_thread) {
ipc::tls::pointer<int> p; ipc::tls::pointer<int> p;
EXPECT_FALSE(p); EXPECT_FALSE(p);
@ -200,3 +200,4 @@ TEST(Thread, tls_benchmark) {
benchmark_tls<std_tls, Str>("std_tls: Str"); benchmark_tls<std_tls, Str>("std_tls: Str");
benchmark_tls<ipc_tls, Str>("ipc_tls: Str"); benchmark_tls<ipc_tls, Str>("ipc_tls: Str");
} }
#endif