mirror of
https://github.com/mutouyun/cpp-ipc.git
synced 2026-02-14 06:09:49 +08:00
fix tls bugs (win); modify data structure
This commit is contained in:
parent
9bc6604faa
commit
6b7c561496
@ -27,21 +27,21 @@ IPC_EXPORT void* get(key_t key);
|
|||||||
////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
/*
|
/*
|
||||||
<Remarks>
|
* <Remarks>
|
||||||
|
*
|
||||||
1. In Windows, if you do not compile thread_local_ptr.cpp,
|
* 1. In Windows, if you do not compile thread_local_ptr.cpp,
|
||||||
use thread_local_ptr will cause memory leaks.
|
* use thread_local_ptr will cause memory leaks.
|
||||||
|
*
|
||||||
2. You need to set the thread_local_ptr's storage manually:
|
* 2. You need to set the thread_local_ptr's storage manually:
|
||||||
```
|
* ```
|
||||||
thread_local_ptr<int> p;
|
* tls::pointer<int> p;
|
||||||
if (!p) p = new int(123);
|
* if (!p) p = new int(123);
|
||||||
```
|
* ```
|
||||||
Just like an ordinary pointer. Or you could just call create:
|
* Just like an ordinary pointer. Or you could just call create:
|
||||||
```
|
* ```
|
||||||
thread_local_ptr<int> p;
|
* tls::pointer<int> p;
|
||||||
p.create(123);
|
* p.create(123);
|
||||||
```
|
* ```
|
||||||
*/
|
*/
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
@ -51,8 +51,8 @@ class pointer {
|
|||||||
public:
|
public:
|
||||||
using value_type = T;
|
using value_type = T;
|
||||||
|
|
||||||
pointer() {
|
pointer()
|
||||||
key_ = tls::create([](void* p) { delete static_cast<T*>(p); });
|
: key_(tls::create([](void* p) { delete static_cast<T*>(p); })) {
|
||||||
}
|
}
|
||||||
|
|
||||||
~pointer() {
|
~pointer() {
|
||||||
@ -61,9 +61,13 @@ public:
|
|||||||
|
|
||||||
template <typename... P>
|
template <typename... P>
|
||||||
T* create(P&&... params) {
|
T* create(P&&... params) {
|
||||||
thread_local auto ptr = static_cast<T*>(*this);
|
thread_local auto ptr = static_cast<T*>(get(key_));
|
||||||
if (ptr == nullptr) {
|
if (ptr == nullptr) {
|
||||||
return ptr = (*this) = new T(std::forward<P>(params)...);
|
ptr = new T(std::forward<P>(params)...);
|
||||||
|
if (!set(key_, ptr)) {
|
||||||
|
delete ptr;
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return ptr;
|
return ptr;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -20,7 +20,7 @@ constexpr u1_t index_of(u2_t c) noexcept {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class conn_head {
|
class conn_head {
|
||||||
std::atomic<std::size_t> cc_ { 0 }; // connection counter
|
std::atomic<u2_t> cc_ { 0 }; // connection counter
|
||||||
|
|
||||||
ipc::spin_lock lc_;
|
ipc::spin_lock lc_;
|
||||||
std::atomic<bool> constructed_;
|
std::atomic<bool> constructed_;
|
||||||
|
|||||||
14
src/ipc.cpp
14
src/ipc.cpp
@ -28,17 +28,17 @@
|
|||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
using namespace ipc;
|
using namespace ipc;
|
||||||
using msg_id_t = std::size_t;
|
using msg_id_t = std::uint32_t;
|
||||||
|
|
||||||
template <std::size_t DataSize, std::size_t AlignSize>
|
template <std::size_t DataSize, std::size_t AlignSize>
|
||||||
struct msg_t;
|
struct msg_t;
|
||||||
|
|
||||||
template <std::size_t AlignSize>
|
template <std::size_t AlignSize>
|
||||||
struct msg_t<0, AlignSize> {
|
struct msg_t<0, AlignSize> {
|
||||||
msg_id_t conn_;
|
msg_id_t conn_;
|
||||||
msg_id_t id_;
|
msg_id_t id_;
|
||||||
int remain_;
|
std::int32_t remain_;
|
||||||
bool storage_;
|
bool storage_;
|
||||||
};
|
};
|
||||||
|
|
||||||
template <std::size_t DataSize, std::size_t AlignSize>
|
template <std::size_t DataSize, std::size_t AlignSize>
|
||||||
@ -46,7 +46,7 @@ struct msg_t : msg_t<0, AlignSize> {
|
|||||||
std::aligned_storage_t<DataSize, AlignSize> data_ {};
|
std::aligned_storage_t<DataSize, AlignSize> data_ {};
|
||||||
|
|
||||||
msg_t() = default;
|
msg_t() = default;
|
||||||
msg_t(msg_id_t c, msg_id_t i, int r, void const * d, std::size_t s)
|
msg_t(msg_id_t c, msg_id_t i, std::int32_t r, void const * d, std::size_t s)
|
||||||
: msg_t<0, AlignSize> { c, i, r, (d == nullptr) || (s == 0) } {
|
: msg_t<0, AlignSize> { c, i, r, (d == nullptr) || (s == 0) } {
|
||||||
if (!this->storage_) {
|
if (!this->storage_) {
|
||||||
std::memcpy(&data_, d, s);
|
std::memcpy(&data_, d, s);
|
||||||
@ -367,7 +367,7 @@ static buff_t recv(ipc::handle_t h, std::size_t tm) {
|
|||||||
continue; // ignore message to self
|
continue; // ignore message to self
|
||||||
}
|
}
|
||||||
// msg.remain_ may minus & abs(msg.remain_) < data_length
|
// msg.remain_ may minus & abs(msg.remain_) < data_length
|
||||||
auto remain = static_cast<std::size_t>(static_cast<int>(data_length) + msg.remain_);
|
auto remain = static_cast<std::size_t>(static_cast<std::int32_t>(data_length) + msg.remain_);
|
||||||
// find cache with msg.id_
|
// find cache with msg.id_
|
||||||
auto cac_it = rc.find(msg.id_);
|
auto cac_it = rc.find(msg.id_);
|
||||||
if (cac_it == rc.end()) {
|
if (cac_it == rc.end()) {
|
||||||
|
|||||||
@ -104,8 +104,8 @@ private:
|
|||||||
public:
|
public:
|
||||||
scope_alloc() = default;
|
scope_alloc() = default;
|
||||||
|
|
||||||
scope_alloc(scope_alloc&& rhs) { swap(rhs); }
|
scope_alloc(scope_alloc&& rhs) { swap(rhs); }
|
||||||
scope_alloc& operator=(scope_alloc&& rhs) { swap(rhs); return (*this); }
|
scope_alloc& operator=(scope_alloc rhs) { swap(rhs); return (*this); }
|
||||||
|
|
||||||
~scope_alloc() { free_all(); }
|
~scope_alloc() { free_all(); }
|
||||||
|
|
||||||
@ -211,32 +211,33 @@ public:
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
} // namespace detail
|
||||||
|
|
||||||
struct fixed_expand_policy {
|
struct fixed_expand_policy {
|
||||||
|
|
||||||
enum : std::size_t {
|
enum : std::size_t {
|
||||||
base_size = sizeof(void*) * 1024 / 2
|
base_size = sizeof(void*) * 1024
|
||||||
};
|
};
|
||||||
|
|
||||||
static std::size_t prev(std::size_t& e) {
|
constexpr static std::size_t prev(std::size_t e) noexcept {
|
||||||
if ((e /= 2) == 0) e = 1;
|
return ((e / 2) == 0) ? 1 : (e / 2);
|
||||||
return e;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::size_t next(std::size_t& e) {
|
constexpr static std::size_t next(std::size_t e) noexcept {
|
||||||
return e *= 2;
|
return e * 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <std::size_t BlockSize>
|
template <std::size_t BlockSize>
|
||||||
static std::size_t next(std::size_t & e) {
|
static std::size_t next(std::size_t & e) {
|
||||||
return ipc::detail::max<std::size_t>(BlockSize, base_size) * next(e);
|
auto n = ipc::detail::max<std::size_t>(BlockSize, base_size) * e;
|
||||||
|
e = next(e);
|
||||||
|
return n;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace detail
|
|
||||||
|
|
||||||
template <std::size_t BlockSize,
|
template <std::size_t BlockSize,
|
||||||
typename AllocP = scope_alloc<>,
|
typename AllocP = scope_alloc<>,
|
||||||
typename ExpandP = detail::fixed_expand_policy>
|
typename ExpandP = fixed_expand_policy>
|
||||||
class fixed_alloc : public detail::fixed_alloc_base {
|
class fixed_alloc : public detail::fixed_alloc_base {
|
||||||
public:
|
public:
|
||||||
using base_t = detail::fixed_alloc_base;
|
using base_t = detail::fixed_alloc_base;
|
||||||
@ -266,7 +267,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
fixed_alloc(fixed_alloc&& rhs) : fixed_alloc() { swap(rhs); }
|
fixed_alloc(fixed_alloc&& rhs) : fixed_alloc() { swap(rhs); }
|
||||||
fixed_alloc& operator=(fixed_alloc&& rhs) { swap(rhs); return (*this); }
|
fixed_alloc& operator=(fixed_alloc rhs) { swap(rhs); return (*this); }
|
||||||
|
|
||||||
template <typename A>
|
template <typename A>
|
||||||
void set_allocator(A && alc) {
|
void set_allocator(A && alc) {
|
||||||
@ -290,7 +291,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
void clear() {
|
void clear() {
|
||||||
ExpandP::prev(init_expand_);
|
init_expand_ = ExpandP::prev(init_expand_);
|
||||||
cursor_ = nullptr;
|
cursor_ = nullptr;
|
||||||
alloc_.~alloc_policy();
|
alloc_.~alloc_policy();
|
||||||
}
|
}
|
||||||
@ -328,15 +329,15 @@ protected:
|
|||||||
return reinterpret_cast<byte_t*>(p) + aligned_head_size + p->free_;
|
return reinterpret_cast<byte_t*>(p) + aligned_head_size + p->free_;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::size_t remain() const noexcept {
|
|
||||||
return (head_ == nullptr) ? 0 : head_->free_;
|
|
||||||
}
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
void swap(variable_alloc_base& rhs) {
|
void swap(variable_alloc_base& rhs) {
|
||||||
std::swap(head_, rhs.head_);
|
std::swap(head_, rhs.head_);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::size_t remain() const noexcept {
|
||||||
|
return (head_ == nullptr) ? 0 : head_->free_;
|
||||||
|
}
|
||||||
|
|
||||||
bool empty() const noexcept {
|
bool empty() const noexcept {
|
||||||
return remain() == 0;
|
return remain() == 0;
|
||||||
}
|
}
|
||||||
@ -373,8 +374,8 @@ private:
|
|||||||
public:
|
public:
|
||||||
variable_alloc() = default;
|
variable_alloc() = default;
|
||||||
|
|
||||||
variable_alloc(variable_alloc&& rhs) { swap(rhs); }
|
variable_alloc(variable_alloc&& rhs) { swap(rhs); }
|
||||||
variable_alloc& operator=(variable_alloc&& rhs) { swap(rhs); return (*this); }
|
variable_alloc& operator=(variable_alloc rhs) { swap(rhs); return (*this); }
|
||||||
|
|
||||||
template <typename A>
|
template <typename A>
|
||||||
void set_allocator(A && alc) {
|
void set_allocator(A && alc) {
|
||||||
@ -402,14 +403,14 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
void* alloc(std::size_t size) {
|
void* alloc(std::size_t size) {
|
||||||
if (size >= (ChunkSize - aligned_head_size)) {
|
if (size >= ChunkSize) {
|
||||||
return alloc_.alloc(size);
|
return alloc_.alloc(size);
|
||||||
}
|
}
|
||||||
if (remain() < size) {
|
if (remain() < size) {
|
||||||
auto it = reserves_.begin();
|
auto it = reserves_.begin();
|
||||||
if ((it == reserves_.end()) || (it->first < size)) {
|
if ((it == reserves_.end()) || (it->first < size)) {
|
||||||
head_ = static_cast<head_t*>(alloc_.alloc(ChunkSize));
|
head_ = static_cast<head_t*>(alloc_.alloc(ChunkSize + aligned_head_size));
|
||||||
head_->free_ = ChunkSize - aligned_head_size - size;
|
head_->free_ = ChunkSize - size;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
auto temp = it->second;
|
auto temp = it->second;
|
||||||
|
|||||||
12
src/memory/resource.h
Executable file → Normal file
12
src/memory/resource.h
Executable file → Normal file
@ -17,12 +17,18 @@
|
|||||||
namespace ipc {
|
namespace ipc {
|
||||||
namespace mem {
|
namespace mem {
|
||||||
|
|
||||||
using chunk_variable_alloc = variable_alloc<sizeof(void*) * 256 * 1024 /* 2MB(x64) */>;
|
namespace detail {
|
||||||
|
|
||||||
|
using chunk_variable_alloc =
|
||||||
|
static_wrapper<async_wrapper<variable_alloc<
|
||||||
|
sizeof(void*) * 1024 * 256 /* 2MB(x64) */ >>>;
|
||||||
|
|
||||||
template <std::size_t Size>
|
template <std::size_t Size>
|
||||||
using static_async_fixed = static_wrapper<async_wrapper<fixed_alloc<Size, chunk_variable_alloc>>>;
|
using static_async_fixed =
|
||||||
|
static_wrapper<async_wrapper<fixed_alloc<
|
||||||
|
Size, chunk_variable_alloc >>>;
|
||||||
|
|
||||||
using async_pool_alloc = static_alloc/*variable_wrapper<static_async_fixed>*/;
|
using async_pool_alloc = /*static_alloc*/variable_wrapper<static_async_fixed>;
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
using allocator = allocator_wrapper<T, async_pool_alloc>;
|
using allocator = allocator_wrapper<T, async_pool_alloc>;
|
||||||
|
|||||||
@ -131,7 +131,7 @@ constexpr bool operator!=(const allocator_wrapper<T, AllocP>&, const allocator_w
|
|||||||
////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
template <typename AllocP>
|
template <typename AllocP>
|
||||||
class default_alloc_recoverer {
|
class default_alloc_recycler {
|
||||||
public:
|
public:
|
||||||
using alloc_policy = AllocP;
|
using alloc_policy = AllocP;
|
||||||
|
|
||||||
@ -139,8 +139,11 @@ private:
|
|||||||
ipc::spin_lock master_lock_;
|
ipc::spin_lock master_lock_;
|
||||||
std::vector<alloc_policy> master_allocs_;
|
std::vector<alloc_policy> master_allocs_;
|
||||||
|
|
||||||
|
IPC_CONCEPT_(has_remain, remain());
|
||||||
|
IPC_CONCEPT_(has_empty , empty());
|
||||||
|
|
||||||
public:
|
public:
|
||||||
void swap(default_alloc_recoverer& rhs) {
|
void swap(default_alloc_recycler& rhs) {
|
||||||
IPC_UNUSED_ auto guard = ipc::detail::unique_lock(master_lock_);
|
IPC_UNUSED_ auto guard = ipc::detail::unique_lock(master_lock_);
|
||||||
master_allocs_.swap(rhs.master_allocs_);
|
master_allocs_.swap(rhs.master_allocs_);
|
||||||
}
|
}
|
||||||
@ -159,7 +162,9 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <typename A = AllocP>
|
template <typename A = AllocP>
|
||||||
auto try_replenish(alloc_policy & alc) -> ipc::require<detail::has_take<A>::value> {
|
auto try_replenish(alloc_policy & alc, std::size_t size)
|
||||||
|
-> ipc::require<detail::has_take<A>::value && has_remain<A>::value> {
|
||||||
|
if (alc.remain() >= size) return;
|
||||||
IPC_UNUSED_ auto guard = ipc::detail::unique_lock(master_lock_);
|
IPC_UNUSED_ auto guard = ipc::detail::unique_lock(master_lock_);
|
||||||
if (!master_allocs_.empty()) {
|
if (!master_allocs_.empty()) {
|
||||||
alc.take(std::move(master_allocs_.back()));
|
alc.take(std::move(master_allocs_.back()));
|
||||||
@ -168,8 +173,19 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <typename A = AllocP>
|
template <typename A = AllocP>
|
||||||
constexpr auto try_replenish(alloc_policy & /*alc*/) noexcept
|
auto try_replenish(alloc_policy & alc, std::size_t /*size*/)
|
||||||
-> ipc::require<!detail::has_take<A>::value> {}
|
-> ipc::require<detail::has_take<A>::value && !has_remain<A>::value && has_empty<A>::value> {
|
||||||
|
if (!alc.empty()) return;
|
||||||
|
IPC_UNUSED_ auto guard = ipc::detail::unique_lock(master_lock_);
|
||||||
|
if (!master_allocs_.empty()) {
|
||||||
|
alc.take(std::move(master_allocs_.back()));
|
||||||
|
master_allocs_.pop_back();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename A = AllocP>
|
||||||
|
constexpr auto try_replenish(alloc_policy & /*alc*/, std::size_t /*size*/) noexcept
|
||||||
|
-> ipc::require<!detail::has_take<A>::value || (!has_remain<A>::value && !has_empty<A>::value)> {}
|
||||||
|
|
||||||
void collect(alloc_policy && alc) {
|
void collect(alloc_policy && alc) {
|
||||||
IPC_UNUSED_ auto guard = ipc::detail::unique_lock(master_lock_);
|
IPC_UNUSED_ auto guard = ipc::detail::unique_lock(master_lock_);
|
||||||
@ -177,20 +193,30 @@ public:
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template <typename AllocP>
|
||||||
|
class empty_alloc_recycler {
|
||||||
|
public:
|
||||||
|
using alloc_policy = AllocP;
|
||||||
|
|
||||||
|
constexpr static void swap(empty_alloc_recycler&) noexcept {}
|
||||||
|
constexpr static void clear() noexcept {}
|
||||||
|
constexpr static void try_recover(alloc_policy&) noexcept {}
|
||||||
|
constexpr static auto try_replenish(alloc_policy&, std::size_t) noexcept {}
|
||||||
|
constexpr static void collect(alloc_policy&&) noexcept {}
|
||||||
|
};
|
||||||
|
|
||||||
template <typename AllocP,
|
template <typename AllocP,
|
||||||
template <typename> class RecovererP = default_alloc_recoverer>
|
template <typename> class RecyclerP = default_alloc_recycler>
|
||||||
class async_wrapper {
|
class async_wrapper {
|
||||||
public:
|
public:
|
||||||
using alloc_policy = AllocP;
|
using alloc_policy = AllocP;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
RecovererP<alloc_policy> recoverer_;
|
RecyclerP<alloc_policy> recycler_;
|
||||||
|
|
||||||
class alloc_proxy : public AllocP {
|
class alloc_proxy : public AllocP {
|
||||||
async_wrapper * w_ = nullptr;
|
async_wrapper * w_ = nullptr;
|
||||||
|
|
||||||
IPC_CONCEPT_(has_empty, empty());
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
alloc_proxy(alloc_proxy && rhs)
|
alloc_proxy(alloc_proxy && rhs)
|
||||||
: AllocP(std::move(rhs))
|
: AllocP(std::move(rhs))
|
||||||
@ -199,25 +225,18 @@ private:
|
|||||||
alloc_proxy(async_wrapper* w)
|
alloc_proxy(async_wrapper* w)
|
||||||
: AllocP(), w_(w) {
|
: AllocP(), w_(w) {
|
||||||
if (w_ == nullptr) return;
|
if (w_ == nullptr) return;
|
||||||
w_->recoverer_.try_recover(*this);
|
w_->recycler_.try_recover(*this);
|
||||||
}
|
}
|
||||||
|
|
||||||
~alloc_proxy() {
|
~alloc_proxy() {
|
||||||
if (w_ == nullptr) return;
|
if (w_ == nullptr) return;
|
||||||
w_->recoverer_.collect(std::move(*this));
|
w_->recycler_.collect(std::move(*this));
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename A = AllocP>
|
auto alloc(std::size_t size) {
|
||||||
auto alloc(std::size_t size) -> ipc::require<has_empty<A>::value, void*> {
|
if (w_ != nullptr) {
|
||||||
auto p = AllocP::alloc(size);
|
w_->recycler_.try_replenish(*this, size);
|
||||||
if (AllocP::empty() && (w_ != nullptr)) {
|
|
||||||
w_->recoverer_.try_replenish(*this);
|
|
||||||
}
|
}
|
||||||
return p;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename A = AllocP>
|
|
||||||
auto alloc(std::size_t size) -> ipc::require<!has_empty<A>::value, void*> {
|
|
||||||
return AllocP::alloc(size);
|
return AllocP::alloc(size);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -231,11 +250,11 @@ private:
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
void swap(async_wrapper& rhs) {
|
void swap(async_wrapper& rhs) {
|
||||||
recoverer_.swap(rhs.recoverer_);
|
recycler_.swap(rhs.recycler_);
|
||||||
}
|
}
|
||||||
|
|
||||||
void clear() {
|
void clear() {
|
||||||
recoverer_.clear();
|
recycler_.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
void* alloc(std::size_t size) {
|
void* alloc(std::size_t size) {
|
||||||
@ -326,10 +345,15 @@ struct default_mapping_policy {
|
|||||||
|
|
||||||
static const std::size_t table[classes_size];
|
static const std::size_t table[classes_size];
|
||||||
|
|
||||||
constexpr static std::size_t classify(std::size_t size) {
|
IPC_CONSTEXPR_ static std::size_t classify(std::size_t size) noexcept {
|
||||||
return (((size - 1) / base_size) < classes_size) ?
|
auto index = (size - 1) / base_size;
|
||||||
|
return (index < classes_size) ?
|
||||||
// always uses default_mapping_policy<sizeof(void*)>::table
|
// always uses default_mapping_policy<sizeof(void*)>::table
|
||||||
default_mapping_policy<>::table[((size - 1) / base_size)] : classes_size;
|
default_mapping_policy<>::table[index] : classes_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr static std::size_t block_size(std::size_t value) noexcept {
|
||||||
|
return (value + 1) * base_size;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -350,7 +374,7 @@ class variable_wrapper {
|
|||||||
template <typename F>
|
template <typename F>
|
||||||
constexpr static auto choose(std::size_t size, F&& f) {
|
constexpr static auto choose(std::size_t size, F&& f) {
|
||||||
return ipc::detail::static_switch<MappingP::classes_size>(MappingP::classify(size), [&f](auto index) {
|
return ipc::detail::static_switch<MappingP::classes_size>(MappingP::classify(size), [&f](auto index) {
|
||||||
return f(Fixed<(decltype(index)::value + 1) * MappingP::base_size>{});
|
return f(Fixed<MappingP::block_size(decltype(index)::value)>{});
|
||||||
}, [&f] {
|
}, [&f] {
|
||||||
return f(StaticAlloc{});
|
return f(StaticAlloc{});
|
||||||
});
|
});
|
||||||
@ -361,7 +385,7 @@ public:
|
|||||||
|
|
||||||
static void clear() {
|
static void clear() {
|
||||||
ipc::detail::static_for<MappingP::classes_size>([](auto index) {
|
ipc::detail::static_for<MappingP::classes_size>([](auto index) {
|
||||||
Fixed<(decltype(index)::value + 1) * MappingP::base_size>::clear();
|
Fixed<MappingP::block_size(decltype(index)::value)>::clear();
|
||||||
});
|
});
|
||||||
StaticAlloc::clear();
|
StaticAlloc::clear();
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,7 +1,9 @@
|
|||||||
#include "tls_pointer.h"
|
#include "tls_pointer.h"
|
||||||
|
#include "log.h"
|
||||||
|
|
||||||
#include <Windows.h> // ::Tls...
|
#include <Windows.h> // ::Tls...
|
||||||
#include <unordered_map> // std::unordered_map
|
#include <atomic>
|
||||||
|
#include <unordered_set> // std::unordered_set
|
||||||
|
|
||||||
namespace ipc {
|
namespace ipc {
|
||||||
|
|
||||||
@ -23,77 +25,125 @@ namespace {
|
|||||||
|
|
||||||
struct tls_data {
|
struct tls_data {
|
||||||
using destructor_t = void(*)(void*);
|
using destructor_t = void(*)(void*);
|
||||||
using map_t = std::unordered_map<tls::key_t, tls_data>;
|
|
||||||
|
|
||||||
static DWORD& key() {
|
DWORD win_key_;
|
||||||
static DWORD rec_key = ::TlsAlloc();
|
destructor_t destructor_;
|
||||||
return rec_key;
|
|
||||||
}
|
|
||||||
|
|
||||||
static map_t* records(map_t* rec) {
|
void destruct(void* data) {
|
||||||
::TlsSetValue(key(), static_cast<LPVOID>(rec));
|
if ((destructor_ != nullptr) && (data != nullptr)) {
|
||||||
return rec;
|
destructor_(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
static map_t* records() {
|
|
||||||
return static_cast<map_t*>(::TlsGetValue(key()));
|
|
||||||
}
|
|
||||||
|
|
||||||
tls::key_t key_ = tls::invalid_value;
|
|
||||||
destructor_t destructor_ = nullptr;
|
|
||||||
|
|
||||||
tls_data() = default;
|
|
||||||
|
|
||||||
tls_data(tls::key_t key, destructor_t destructor)
|
|
||||||
: key_ (key)
|
|
||||||
, destructor_(destructor)
|
|
||||||
{}
|
|
||||||
|
|
||||||
tls_data(tls_data&& rhs) : tls_data() {
|
|
||||||
(*this) = std::move(rhs);
|
|
||||||
}
|
|
||||||
|
|
||||||
tls_data& operator=(tls_data&& rhs) {
|
|
||||||
key_ = rhs.key_;
|
|
||||||
destructor_ = rhs.destructor_;
|
|
||||||
rhs.key_ = 0;
|
|
||||||
rhs.destructor_ = nullptr;
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
~tls_data() {
|
|
||||||
if (destructor_) destructor_(tls::get(key_));
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
using rec_t = std::unordered_set<tls_data*>;
|
||||||
|
|
||||||
|
DWORD& record_key() {
|
||||||
|
|
||||||
|
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_;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool record(tls_data* tls) {
|
||||||
|
auto rec = static_cast<rec_t*>(::TlsGetValue(record_key()));
|
||||||
|
if (rec == nullptr) {
|
||||||
|
if (FALSE == ::TlsSetValue(record_key(), static_cast<LPVOID>(rec = new rec_t))) {
|
||||||
|
ipc::error("[record] TlsSetValue failed[%lu].\n", ::GetLastError());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
rec->insert(tls);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void erase_record(tls_data* tls) {
|
||||||
|
auto rec = static_cast<rec_t*>(::TlsGetValue(record_key()));
|
||||||
|
if (rec == nullptr) return;
|
||||||
|
rec->erase(tls);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void clear_all_records() {
|
||||||
|
auto rec = static_cast<rec_t*>(::TlsGetValue(record_key()));
|
||||||
|
if (rec == nullptr) return;
|
||||||
|
for (auto tls : *rec) {
|
||||||
|
if (tls != nullptr) {
|
||||||
|
tls->destruct(::TlsGetValue(tls->win_key_));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
delete rec;
|
||||||
|
::TlsSetValue(record_key(), static_cast<LPVOID>(nullptr));
|
||||||
|
}
|
||||||
|
|
||||||
} // internal-linkage
|
} // internal-linkage
|
||||||
|
|
||||||
namespace tls {
|
namespace tls {
|
||||||
|
|
||||||
key_t create(destructor_t destructor) {
|
key_t create(destructor_t destructor) {
|
||||||
key_t key = static_cast<key_t>(::TlsAlloc());
|
record_key(); // gen record-key
|
||||||
if (key == TLS_OUT_OF_INDEXES) return invalid_value;
|
auto tls_dat = new tls_data { ::TlsAlloc(), destructor };
|
||||||
auto rec = tls_data::records();
|
std::atomic_thread_fence(std::memory_order_seq_cst);
|
||||||
if (rec == nullptr) rec = tls_data::records(new tls_data::map_t);
|
if (tls_dat->win_key_ == TLS_OUT_OF_INDEXES) {
|
||||||
if (rec == nullptr) return key;
|
ipc::error("[tls::create] TlsAlloc failed[%lu].\n", ::GetLastError());
|
||||||
rec->emplace(key, tls_data{ key, destructor });
|
delete tls_dat;
|
||||||
return key;
|
return invalid_value;
|
||||||
|
}
|
||||||
|
return reinterpret_cast<key_t>(tls_dat);
|
||||||
}
|
}
|
||||||
|
|
||||||
void release(key_t key) {
|
void release(key_t tls_key) {
|
||||||
auto rec = tls_data::records();
|
if (tls_key == invalid_value) {
|
||||||
if (rec == nullptr) return;
|
ipc::error("[tls::release] tls_key is invalid_value.\n");
|
||||||
rec->erase(key);
|
return;
|
||||||
::TlsFree(static_cast<DWORD>(key));
|
}
|
||||||
|
auto tls_dat = reinterpret_cast<tls_data*>(tls_key);
|
||||||
|
if (tls_dat == nullptr) {
|
||||||
|
ipc::error("[tls::release] tls_dat is nullptr.\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
erase_record(tls_dat);
|
||||||
|
::TlsFree(tls_dat->win_key_);
|
||||||
|
delete tls_dat;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool set(key_t key, void* ptr) {
|
bool set(key_t tls_key, void* ptr) {
|
||||||
return ::TlsSetValue(static_cast<DWORD>(key),
|
if (tls_key == invalid_value) {
|
||||||
static_cast<LPVOID>(ptr)) == TRUE;
|
ipc::error("[tls::set] tls_key is invalid_value.\n");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
auto tls_dat = reinterpret_cast<tls_data*>(tls_key);
|
||||||
|
if (tls_dat == nullptr) {
|
||||||
|
ipc::error("[tls::set] tls_dat is nullptr.\n");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (FALSE == ::TlsSetValue(tls_dat->win_key_, static_cast<LPVOID>(ptr))) {
|
||||||
|
ipc::error("[tls::set] TlsSetValue failed[%lu].\n", ::GetLastError());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
record(tls_dat);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void* get(key_t key) {
|
void* get(key_t tls_key) {
|
||||||
return static_cast<void*>(::TlsGetValue(static_cast<DWORD>(key)));
|
if (tls_key == invalid_value) {
|
||||||
|
ipc::error("[tls::get] tls_key is invalid_value.\n");
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
auto tls_dat = reinterpret_cast<tls_data*>(tls_key);
|
||||||
|
if (tls_dat == nullptr) {
|
||||||
|
ipc::error("[tls::get] tls_dat is nullptr.\n");
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
return ::TlsGetValue(tls_dat->win_key_);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace tls
|
} // namespace tls
|
||||||
@ -101,10 +151,7 @@ void* get(key_t key) {
|
|||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
void OnThreadExit() {
|
void OnThreadExit() {
|
||||||
auto rec = tls_data::records();
|
clear_all_records();
|
||||||
if (rec == nullptr) return;
|
|
||||||
delete rec;
|
|
||||||
tls_data::records(nullptr);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void NTAPI OnTlsCallback(PVOID, DWORD dwReason, PVOID) {
|
void NTAPI OnTlsCallback(PVOID, DWORD dwReason, PVOID) {
|
||||||
|
|||||||
@ -174,7 +174,7 @@ struct prod_cons_impl<wr<relat::multi , relat::multi, trans::unicast>>
|
|||||||
template <>
|
template <>
|
||||||
struct prod_cons_impl<wr<relat::single, relat::multi, trans::broadcast>> {
|
struct prod_cons_impl<wr<relat::single, relat::multi, trans::broadcast>> {
|
||||||
|
|
||||||
using rc_t = std::size_t;
|
using rc_t = std::uint32_t;
|
||||||
|
|
||||||
template <std::size_t DataSize, std::size_t AlignSize>
|
template <std::size_t DataSize, std::size_t AlignSize>
|
||||||
struct elem_t {
|
struct elem_t {
|
||||||
|
|||||||
@ -238,7 +238,7 @@ private slots:
|
|||||||
void test_prod_cons_1v3();
|
void test_prod_cons_1v3();
|
||||||
void test_prod_cons_performance();
|
void test_prod_cons_performance();
|
||||||
void test_queue();
|
void test_queue();
|
||||||
} /*unit__*/;
|
} unit__;
|
||||||
|
|
||||||
#include "test_circ.moc"
|
#include "test_circ.moc"
|
||||||
|
|
||||||
|
|||||||
0
test/test_ipc.cpp
Executable file → Normal file
0
test/test_ipc.cpp
Executable file → Normal file
11
test/test_mem.cpp
Executable file → Normal file
11
test/test_mem.cpp
Executable file → Normal file
@ -25,7 +25,7 @@ private slots:
|
|||||||
void test_alloc_free();
|
void test_alloc_free();
|
||||||
void test_static();
|
void test_static();
|
||||||
void test_pool();
|
void test_pool();
|
||||||
} /*unit__*/;
|
} unit__;
|
||||||
|
|
||||||
#include "test_mem.moc"
|
#include "test_mem.moc"
|
||||||
|
|
||||||
@ -178,9 +178,12 @@ void Unit::test_static() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Unit::test_pool() {
|
void Unit::test_pool() {
|
||||||
test_performance<ipc::mem::pool_alloc, alloc_FIFO , 8>::start();
|
// test_performance<ipc::mem::pool_alloc, alloc_FIFO , 8>::start();
|
||||||
test_performance<ipc::mem::pool_alloc, alloc_LIFO , 8>::start();
|
// for (;;) {
|
||||||
test_performance<ipc::mem::pool_alloc, alloc_random, 8>::start();
|
test_performance<ipc::mem::pool_alloc, alloc_FIFO , 8>::start();
|
||||||
|
test_performance<ipc::mem::pool_alloc, alloc_LIFO , 8>::start();
|
||||||
|
test_performance<ipc::mem::pool_alloc, alloc_random, 8>::start();
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
} // internal-linkage
|
} // internal-linkage
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user