mirror of
https://github.com/mutouyun/cpp-ipc.git
synced 2025-12-06 16:56:45 +08:00
update tls_pointer_win.cpp
This commit is contained in:
parent
e87d516b1d
commit
91cc1b7767
@ -3,7 +3,6 @@
|
||||
|
||||
#include <Windows.h> // ::Tls...
|
||||
#include <atomic>
|
||||
#include <unordered_set> // std::unordered_set
|
||||
|
||||
namespace ipc {
|
||||
|
||||
@ -26,59 +25,110 @@ namespace {
|
||||
struct tls_data {
|
||||
using destructor_t = void(*)(void*);
|
||||
|
||||
unsigned index_;
|
||||
DWORD win_key_;
|
||||
destructor_t destructor_;
|
||||
|
||||
void destruct(void* data) {
|
||||
if ((destructor_ != nullptr) && (data != nullptr)) {
|
||||
destructor_(data);
|
||||
bool valid() const noexcept {
|
||||
return win_key_ != TLS_OUT_OF_INDEXES;
|
||||
}
|
||||
|
||||
void* get() const {
|
||||
return ::TlsGetValue(win_key_);
|
||||
}
|
||||
|
||||
bool set(void* p) {
|
||||
return TRUE == ::TlsSetValue(win_key_, static_cast<LPVOID>(p));
|
||||
}
|
||||
|
||||
void destruct() {
|
||||
void* data = valid() ? get() : nullptr;
|
||||
if (data != nullptr) {
|
||||
if (destructor_ != nullptr) destructor_(data);
|
||||
set(nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
void clear_self() {
|
||||
if (valid()) {
|
||||
destruct();
|
||||
::TlsFree(win_key_);
|
||||
}
|
||||
delete this;
|
||||
}
|
||||
};
|
||||
|
||||
using rec_t = std::unordered_set<tls_data*>;
|
||||
struct tls_recs {
|
||||
tls_data* recs_[TLS_MINIMUM_AVAILABLE] {};
|
||||
unsigned index_ = 0;
|
||||
|
||||
DWORD& record_key() {
|
||||
bool insert(tls_data* data) noexcept {
|
||||
if (index_ >= TLS_MINIMUM_AVAILABLE) {
|
||||
ipc::error("[tls_recs] insert tls_data failed[index_ >= TLS_MINIMUM_AVAILABLE].\n");
|
||||
return false;
|
||||
}
|
||||
recs_[(data->index_ = index_++)] = data;
|
||||
return true;
|
||||
}
|
||||
|
||||
struct key_gen {
|
||||
bool erase(tls_data* data) noexcept {
|
||||
if (data->index_ >= TLS_MINIMUM_AVAILABLE) return false;
|
||||
recs_[data->index_] = nullptr;
|
||||
return true;
|
||||
}
|
||||
|
||||
tls_data* * begin() noexcept { return &recs_[0]; }
|
||||
tls_data* const * begin() const noexcept { return &recs_[0]; }
|
||||
tls_data* * end () noexcept { return &recs_[index_]; }
|
||||
tls_data* const * end () const noexcept { return &recs_[index_]; }
|
||||
};
|
||||
|
||||
struct key_gen {
|
||||
DWORD rec_key_;
|
||||
|
||||
key_gen() : rec_key_(::TlsAlloc()) {
|
||||
if (rec_key_ == TLS_OUT_OF_INDEXES) {
|
||||
ipc::error("[record_key] TlsAlloc failed[%lu].\n", ::GetLastError());
|
||||
}
|
||||
}
|
||||
~key_gen() { ::TlsFree(rec_key_); }
|
||||
};
|
||||
|
||||
static key_gen gen;
|
||||
return gen.rec_key_;
|
||||
~key_gen() {
|
||||
::TlsFree(rec_key_);
|
||||
rec_key_ = TLS_OUT_OF_INDEXES;
|
||||
}
|
||||
} gen__;
|
||||
|
||||
DWORD& record_key() noexcept {
|
||||
return gen__.rec_key_;
|
||||
}
|
||||
|
||||
bool record(tls_data* tls) {
|
||||
auto rec = static_cast<rec_t*>(::TlsGetValue(record_key()));
|
||||
bool record(tls_data* tls_dat) {
|
||||
if (record_key() == TLS_OUT_OF_INDEXES) return false;
|
||||
auto rec = static_cast<tls_recs*>(::TlsGetValue(record_key()));
|
||||
if (rec == nullptr) {
|
||||
if (FALSE == ::TlsSetValue(record_key(), static_cast<LPVOID>(rec = new rec_t))) {
|
||||
if (FALSE == ::TlsSetValue(record_key(), static_cast<LPVOID>(rec = new tls_recs))) {
|
||||
ipc::error("[record] TlsSetValue failed[%lu].\n", ::GetLastError());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
rec->insert(tls);
|
||||
return true;
|
||||
return rec->insert(tls_dat);
|
||||
}
|
||||
|
||||
static void erase_record(tls_data* tls) {
|
||||
auto rec = static_cast<rec_t*>(::TlsGetValue(record_key()));
|
||||
void erase_record(tls_data* tls_dat) {
|
||||
if (tls_dat == nullptr) return;
|
||||
if (record_key() == TLS_OUT_OF_INDEXES) return;
|
||||
auto rec = static_cast<tls_recs*>(::TlsGetValue(record_key()));
|
||||
if (rec == nullptr) return;
|
||||
rec->erase(tls);
|
||||
rec->erase(tls_dat);
|
||||
tls_dat->clear_self();
|
||||
}
|
||||
|
||||
static void clear_all_records() {
|
||||
auto rec = static_cast<rec_t*>(::TlsGetValue(record_key()));
|
||||
void clear_all_records() {
|
||||
if (record_key() == TLS_OUT_OF_INDEXES) return;
|
||||
auto rec = static_cast<tls_recs*>(::TlsGetValue(record_key()));
|
||||
if (rec == nullptr) return;
|
||||
for (auto tls : *rec) {
|
||||
if (tls != nullptr) {
|
||||
tls->destruct(::TlsGetValue(tls->win_key_));
|
||||
}
|
||||
for (auto tls_dat : *rec) {
|
||||
if (tls_dat != nullptr) tls_dat->destruct();
|
||||
}
|
||||
delete rec;
|
||||
::TlsSetValue(record_key(), static_cast<LPVOID>(nullptr));
|
||||
@ -90,11 +140,11 @@ namespace tls {
|
||||
|
||||
key_t create(destructor_t destructor) {
|
||||
record_key(); // gen record-key
|
||||
auto tls_dat = new tls_data { ::TlsAlloc(), destructor };
|
||||
auto tls_dat = new tls_data { unsigned(-1), ::TlsAlloc(), destructor };
|
||||
std::atomic_thread_fence(std::memory_order_seq_cst);
|
||||
if (tls_dat->win_key_ == TLS_OUT_OF_INDEXES) {
|
||||
if (!tls_dat->valid()) {
|
||||
ipc::error("[tls::create] TlsAlloc failed[%lu].\n", ::GetLastError());
|
||||
delete tls_dat;
|
||||
tls_dat->clear_self();
|
||||
return invalid_value;
|
||||
}
|
||||
return reinterpret_cast<key_t>(tls_dat);
|
||||
@ -111,8 +161,6 @@ void release(key_t tls_key) {
|
||||
return;
|
||||
}
|
||||
erase_record(tls_dat);
|
||||
::TlsFree(tls_dat->win_key_);
|
||||
delete tls_dat;
|
||||
}
|
||||
|
||||
bool set(key_t tls_key, void* ptr) {
|
||||
@ -125,7 +173,7 @@ bool set(key_t tls_key, void* ptr) {
|
||||
ipc::error("[tls::set] tls_dat is nullptr.\n");
|
||||
return false;
|
||||
}
|
||||
if (FALSE == ::TlsSetValue(tls_dat->win_key_, static_cast<LPVOID>(ptr))) {
|
||||
if (!tls_dat->set(ptr)) {
|
||||
ipc::error("[tls::set] TlsSetValue failed[%lu].\n", ::GetLastError());
|
||||
return false;
|
||||
}
|
||||
@ -143,19 +191,15 @@ void* get(key_t tls_key) {
|
||||
ipc::error("[tls::get] tls_dat is nullptr.\n");
|
||||
return nullptr;
|
||||
}
|
||||
return ::TlsGetValue(tls_dat->win_key_);
|
||||
return tls_dat->get();
|
||||
}
|
||||
|
||||
} // namespace tls
|
||||
|
||||
namespace {
|
||||
|
||||
void OnThreadExit() {
|
||||
clear_all_records();
|
||||
}
|
||||
|
||||
void NTAPI OnTlsCallback(PVOID, DWORD dwReason, PVOID) {
|
||||
if (dwReason == DLL_THREAD_DETACH) OnThreadExit();
|
||||
if (dwReason == DLL_THREAD_DETACH) clear_all_records();
|
||||
}
|
||||
|
||||
} // internal-linkage
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user