From 520148aaf14ab535b386c045e836af47645436ff Mon Sep 17 00:00:00 2001 From: Maged Michael Date: Tue, 15 Aug 2017 18:01:19 -0700 Subject: [PATCH] Fix destruction order Summary: - Added `hazptr.cpp` and `memory_resource.cpp`. Moved singleton code to source. - Changed the singleton for the default `hazptr_domain` to a global. - Changed hazptr_stats singleton to a global. - Moved the thread caching calls from the hazptr_domain functions to the constructor/destructor of hazptr_holder. - Changed the TLS singletons to TLS globals. - Changed some inlining directives. - Leak the hazptr_rec-s in the default domain Reviewed By: davidtgoldblatt, djwatson Differential Revision: D5553753 fbshipit-source-id: da69eecec55c0f78fb8ef5591f9aeffee99ff3fa --- folly/experimental/hazptr/bench/HazptrBench.h | 3 - folly/experimental/hazptr/example/SWMRList.h | 11 +- folly/experimental/hazptr/hazptr-impl.h | 344 ++++++++++++------ folly/experimental/hazptr/hazptr.cpp | 32 ++ folly/experimental/hazptr/hazptr.h | 6 +- folly/experimental/hazptr/memory_resource.cpp | 65 ++++ folly/experimental/hazptr/memory_resource.h | 47 +-- folly/experimental/hazptr/test/HazptrTest.cpp | 3 +- 8 files changed, 340 insertions(+), 171 deletions(-) create mode 100644 folly/experimental/hazptr/hazptr.cpp create mode 100644 folly/experimental/hazptr/memory_resource.cpp diff --git a/folly/experimental/hazptr/bench/HazptrBench.h b/folly/experimental/hazptr/bench/HazptrBench.h index 4aca6c53..22709e77 100644 --- a/folly/experimental/hazptr/bench/HazptrBench.h +++ b/folly/experimental/hazptr/bench/HazptrBench.h @@ -98,7 +98,6 @@ inline uint64_t bench(std::string name, int ops, const RepFunc& repFn) { inline uint64_t listBench(std::string name, int nthreads, int size) { int ops = 100000; auto repFn = [&] { - hazptr_holder dummy[100]; SWMRListSet s; auto init = [&] { for (int i = 0; i < size; ++i) { @@ -119,7 +118,6 @@ inline uint64_t listBench(std::string name, int nthreads, int size) { inline uint64_t holderBench(std::string name, int nthreads) { int ops = 100000; auto repFn = [&] { - hazptr_holder dummy[100]; auto init = [] {}; auto fn = [&](int tid) { for (int j = tid; j < ops; j += nthreads) { @@ -138,7 +136,6 @@ inline uint64_t retireBench(std::string name, int nthreads) { }; int ops = 100000; auto repFn = [&] { - hazptr_holder dummy[100]; auto init = [] {}; auto fn = [&](int tid) { for (int j = tid; j < ops; j += nthreads) { diff --git a/folly/experimental/hazptr/example/SWMRList.h b/folly/experimental/hazptr/example/SWMRList.h index 6df6a3c3..83755a63 100644 --- a/folly/experimental/hazptr/example/SWMRList.h +++ b/folly/experimental/hazptr/example/SWMRList.h @@ -53,7 +53,6 @@ class SWMRListSet { }; std::atomic head_ = {nullptr}; - hazptr_domain& domain_; /* Used by the single writer */ void locate_lower_bound(const T& v, std::atomic*& prev) const { @@ -67,9 +66,6 @@ class SWMRListSet { } public: - explicit SWMRListSet(hazptr_domain& domain = default_hazptr_domain()) - : domain_(domain) {} - ~SWMRListSet() { Node* next; for (auto p = head_.load(); p; p = next) { @@ -97,14 +93,15 @@ class SWMRListSet { prev->store(curr_next, std::memory_order_release); // ...and only then null out the removed node. curr->next_.store(nullptr, std::memory_order_release); - curr->retire(domain_); + curr->retire(); return true; } + /* Used by readers */ bool contains(const T& val) const { /* Acquire two hazard pointers for hand-over-hand traversal. */ - hazptr_holder hptr_prev(domain_); - hazptr_holder hptr_curr(domain_); + hazptr_holder hptr_prev; + hazptr_holder hptr_curr; while (true) { auto prev = &head_; auto curr = prev->load(std::memory_order_acquire); diff --git a/folly/experimental/hazptr/hazptr-impl.h b/folly/experimental/hazptr/hazptr-impl.h index 4dd0de88..12c4fd39 100644 --- a/folly/experimental/hazptr/hazptr-impl.h +++ b/folly/experimental/hazptr/hazptr-impl.h @@ -69,16 +69,15 @@ namespace folly { namespace hazptr { /** - * helper classes and functions + * Helper classes and functions */ /** hazptr_stats */ class hazptr_stats; -hazptr_stats& hazptr_stats(); #if HAZPTR_STATS -#define INC_HAZPTR_STATS(x) hazptr_stats().x() +#define INC_HAZPTR_STATS(x) hazptr_stats_.x() #else #define INC_HAZPTR_STATS(x) #endif @@ -91,65 +90,97 @@ class hazptr_mb { static void heavy(); }; -/** hazptr_tc +/** + * TLS structures + */ + +/** TLS life state */ + +enum hazptr_tls_state { TLS_ALIVE, TLS_UNINITIALIZED, TLS_DESTROYED }; + +/** hazptr_tc structures * Thread caching of hazptr_rec-s that belong to the default domain. */ -class hazptr_tc_entry { - friend class hazptr_tc; - hazptr_rec* hprec_{nullptr}; +struct hazptr_tc_entry { + hazptr_rec* hprec_; - public: void fill(hazptr_rec* hprec); hazptr_rec* get(); void evict(); }; -class hazptr_tc { - hazptr_tc_entry tc_[HAZPTR_TC_SIZE]; - int count_{0}; +static_assert( + std::is_trivial::value, + "hazptr_tc_entry must be trivial" + " to avoid a branch to check initialization"); + +struct hazptr_tc { + hazptr_tc_entry entry_[HAZPTR_TC_SIZE]; + int count_; public: - hazptr_tc(); - ~hazptr_tc(); hazptr_rec* get(); bool put(hazptr_rec* hprec); }; -hazptr_tc& hazptr_tc(); +static_assert( + std::is_trivial::value, + "hazptr_tc must be trivial to avoid a branch to check initialization"); + +void hazptr_tc_init(); +void hazptr_tc_shutdown(); +hazptr_rec* hazptr_tc_try_get(); +bool hazptr_tc_try_put(hazptr_rec* hprec); -/** hazptr_priv +/** hazptr_priv structures * Thread private lists of retired objects that belong to the default domain. */ -class hazptr_priv { - hazptr_domain* domain_{&default_hazptr_domain()}; - hazptr_obj* head_{nullptr}; - hazptr_obj* tail_{nullptr}; - int rcount_{0}; - bool active_{true}; +struct hazptr_priv { + hazptr_obj* head_; + hazptr_obj* tail_; + int rcount_; + bool active_; - public: - hazptr_priv(); - ~hazptr_priv(); void push(hazptr_obj* obj); - - private: void pushAllToDomain(); }; -hazptr_priv& hazptr_priv(); +static_assert( + std::is_trivial::value, + "hazptr_priv must be trivial to avoid a branch to check initialization"); + +void hazptr_priv_init(); +void hazptr_priv_shutdown(); +bool hazptr_priv_try_retire(hazptr_obj* obj); + +/** hazptr_tls_life */ + +struct hazptr_tls_life { + hazptr_tls_life(); + ~hazptr_tls_life(); +}; + +void tls_life_odr_use(); + +/** tls globals */ + +extern thread_local hazptr_tls_state tls_state_; +extern thread_local hazptr_tc tls_tc_data_; +extern thread_local hazptr_priv tls_priv_data_; +extern thread_local hazptr_tls_life tls_life_; // last /** - * public functions + * hazptr_domain */ -/** hazptr_domain */ - -constexpr hazptr_domain::hazptr_domain(memory_resource* mr) noexcept +inline constexpr hazptr_domain::hazptr_domain(memory_resource* mr) noexcept : mr_(mr) {} -/** hazptr_obj_base */ +/** + * hazptr_obj_base + */ template inline void hazptr_obj_base::retire(hazptr_domain& domain, D deleter) { @@ -162,18 +193,21 @@ inline void hazptr_obj_base::retire(hazptr_domain& domain, D deleter) { }; if (HAZPTR_PRIV && (HAZPTR_ONE_DOMAIN || (&domain == &default_hazptr_domain()))) { - hazptr_priv().push(this); - } else { - domain.objRetire(this); + if (hazptr_priv_try_retire(this)) { + return; + } } + domain.objRetire(this); } -/** hazptr_rec */ +/** + * hazptr_rec + */ class hazptr_rec { friend class hazptr_domain; friend class hazptr_holder; - friend class hazptr_tc_entry; + friend struct hazptr_tc_entry; FOLLY_ALIGN_TO_AVOID_FALSE_SHARING std::atomic hazptr_{nullptr}; @@ -188,16 +222,28 @@ class hazptr_rec { void release() noexcept; }; -/** hazptr_holder */ +/** + * hazptr_holder + */ FOLLY_ALWAYS_INLINE hazptr_holder::hazptr_holder(hazptr_domain& domain) { domain_ = &domain; + if (LIKELY( + HAZPTR_TC && + (HAZPTR_ONE_DOMAIN || &domain == &default_hazptr_domain()))) { + auto hprec = hazptr_tc_try_get(); + if (LIKELY(hprec != nullptr)) { + hazptr_ = hprec; + DEBUG_PRINT(this << " " << domain_ << " " << hazptr_); + return; + } + } hazptr_ = domain_->hazptrAcquire(); DEBUG_PRINT(this << " " << domain_ << " " << hazptr_); if (hazptr_ == nullptr) { std::bad_alloc e; throw e; } } -inline hazptr_holder::hazptr_holder(std::nullptr_t) { +FOLLY_ALWAYS_INLINE hazptr_holder::hazptr_holder(std::nullptr_t) { domain_ = nullptr; hazptr_ = nullptr; DEBUG_PRINT(this << " " << domain_ << " " << hazptr_); @@ -205,22 +251,30 @@ inline hazptr_holder::hazptr_holder(std::nullptr_t) { FOLLY_ALWAYS_INLINE hazptr_holder::~hazptr_holder() { DEBUG_PRINT(this); - if (domain_) { + if (LIKELY(hazptr_ != nullptr)) { hazptr_->clear(); + if (LIKELY( + HAZPTR_TC && + (HAZPTR_ONE_DOMAIN || domain_ == &default_hazptr_domain()))) { + if (LIKELY(hazptr_tc_try_put(hazptr_))) { + return; + } + } domain_->hazptrRelease(hazptr_); } } -inline hazptr_holder::hazptr_holder(hazptr_holder&& rhs) noexcept { +FOLLY_ALWAYS_INLINE hazptr_holder::hazptr_holder(hazptr_holder&& rhs) noexcept { domain_ = rhs.domain_; hazptr_ = rhs.hazptr_; rhs.domain_ = nullptr; rhs.hazptr_ = nullptr; } -inline hazptr_holder& hazptr_holder::operator=(hazptr_holder&& rhs) noexcept { +FOLLY_ALWAYS_INLINE +hazptr_holder& hazptr_holder::operator=(hazptr_holder&& rhs) noexcept { /* Self-move is a no-op. */ - if (this != &rhs) { + if (LIKELY(this != &rhs)) { this->~hazptr_holder(); new (this) hazptr_holder(std::move(rhs)); } @@ -243,7 +297,7 @@ FOLLY_ALWAYS_INLINE bool hazptr_holder::try_protect( reset(f(ptr)); /*** Full fence ***/ hazptr_mb::light(); T* p = src.load(std::memory_order_acquire); - if (p != ptr) { + if (UNLIKELY(p != ptr)) { ptr = p; reset(); return false; @@ -303,15 +357,14 @@ FOLLY_ALWAYS_INLINE void swap(hazptr_holder& lhs, hazptr_holder& rhs) noexcept { /** Definition of default_hazptr_domain() */ -inline hazptr_domain& default_hazptr_domain() { - static hazptr_domain d; - DEBUG_PRINT(&d); - return d; +FOLLY_ALWAYS_INLINE hazptr_domain& default_hazptr_domain() { + DEBUG_PRINT(&default_domain_); + return default_domain_; } /** hazptr_rec */ -inline void hazptr_rec::set(const void* p) noexcept { +FOLLY_ALWAYS_INLINE void hazptr_rec::set(const void* p) noexcept { DEBUG_PRINT(this << " " << p); hazptr_.store(p, std::memory_order_release); } @@ -322,7 +375,7 @@ inline const void* hazptr_rec::get() const noexcept { return p; } -inline void hazptr_rec::clear() noexcept { +FOLLY_ALWAYS_INLINE void hazptr_rec::clear() noexcept { DEBUG_PRINT(this); hazptr_.store(nullptr, std::memory_order_release); } @@ -369,7 +422,11 @@ inline hazptr_domain::~hazptr_domain() { retired = retired_.exchange(nullptr); } } - { /* free all hazptr_rec-s */ + /* Leak the data for the default domain to avoid destruction order + * issues with thread caches. + */ + if (this != &default_hazptr_domain()) { + /* free all hazptr_rec-s */ hazptr_rec* next; for (auto p = hazptrs_.load(std::memory_order_acquire); p; p = next) { next = p->next_; @@ -379,13 +436,7 @@ inline hazptr_domain::~hazptr_domain() { } } -FOLLY_ALWAYS_INLINE hazptr_rec* hazptr_domain::hazptrAcquire() { - if (HAZPTR_TC && (HAZPTR_ONE_DOMAIN || this == &default_hazptr_domain())) { - auto hprec = hazptr_tc().get(); - if (hprec) { - return hprec; - } - } +inline hazptr_rec* hazptr_domain::hazptrAcquire() { hazptr_rec* p; hazptr_rec* next; for (p = hazptrs_.load(std::memory_order_acquire); p; p = next) { @@ -395,6 +446,7 @@ FOLLY_ALWAYS_INLINE hazptr_rec* hazptr_domain::hazptrAcquire() { } } p = static_cast(mr_->allocate(sizeof(hazptr_rec))); + DEBUG_PRINT(this << " " << p << " " << sizeof(hazptr_rec)); if (p == nullptr) { return nullptr; } @@ -408,11 +460,7 @@ FOLLY_ALWAYS_INLINE hazptr_rec* hazptr_domain::hazptrAcquire() { return p; } -FOLLY_ALWAYS_INLINE void hazptr_domain::hazptrRelease(hazptr_rec* p) noexcept { - if (HAZPTR_TC && (HAZPTR_ONE_DOMAIN || this == &default_hazptr_domain()) && - hazptr_tc().put(p)) { - return; - } +inline void hazptr_domain::hazptrRelease(hazptr_rec* p) noexcept { DEBUG_PRINT(this << " " << p); p->release(); } @@ -506,6 +554,8 @@ class hazptr_stats { std::atomic seq_cst_{0}; }; +extern hazptr_stats hazptr_stats_; + inline hazptr_stats::~hazptr_stats() { DEBUG_PRINT(this << " light " << light_.load()); DEBUG_PRINT(this << " heavy " << heavy_.load()); @@ -530,15 +580,9 @@ inline void hazptr_stats::seq_cst() { } } -inline class hazptr_stats& hazptr_stats() { - static class hazptr_stats stats_; - DEBUG_PRINT(&stats_); - return stats_; -} - /** hazptr_mb */ -inline void hazptr_mb::light() { +FOLLY_ALWAYS_INLINE void hazptr_mb::light() { DEBUG_PRINT(""); if (HAZPTR_AMB) { folly::asymmetricLightBarrier(); @@ -560,41 +604,38 @@ inline void hazptr_mb::heavy() { } } -/** hazptr_tc - functions */ +/** + * TLS structures + */ + +/** + * hazptr_tc structures + */ + +/** hazptr_tc_entry */ -inline void hazptr_tc_entry::fill(hazptr_rec* hprec) { +FOLLY_ALWAYS_INLINE void hazptr_tc_entry::fill(hazptr_rec* hprec) { hprec_ = hprec; DEBUG_PRINT(this << " " << hprec); } -inline hazptr_rec* hazptr_tc_entry::get() { +FOLLY_ALWAYS_INLINE hazptr_rec* hazptr_tc_entry::get() { auto hprec = hprec_; - hprec_ = nullptr; DEBUG_PRINT(this << " " << hprec); return hprec; } inline void hazptr_tc_entry::evict() { auto hprec = hprec_; - hprec_ = nullptr; hprec->release(); DEBUG_PRINT(this << " " << hprec); } -inline hazptr_tc::hazptr_tc() { - DEBUG_PRINT(this); -} - -inline hazptr_tc::~hazptr_tc() { - DEBUG_PRINT(this); - for (int i = 0; i < count_; ++i) { - tc_[i].evict(); - } -} +/** hazptr_tc */ -inline hazptr_rec* hazptr_tc::get() { - if (count_ > 0) { - auto hprec = tc_[--count_].get(); +FOLLY_ALWAYS_INLINE hazptr_rec* hazptr_tc::get() { + if (LIKELY(count_ != 0)) { + auto hprec = entry_[--count_].get(); DEBUG_PRINT(this << " " << hprec); return hprec; } @@ -602,66 +643,147 @@ inline hazptr_rec* hazptr_tc::get() { return nullptr; } -inline bool hazptr_tc::put(hazptr_rec* hprec) { - if (count_ < HAZPTR_TC_SIZE) { - tc_[count_++].fill(hprec); +FOLLY_ALWAYS_INLINE bool hazptr_tc::put(hazptr_rec* hprec) { + if (LIKELY(count_ < HAZPTR_TC_SIZE)) { + entry_[count_++].fill(hprec); DEBUG_PRINT(this << " " << count_ - 1); return true; } return false; } -FOLLY_ALWAYS_INLINE class hazptr_tc& hazptr_tc() { - static thread_local class hazptr_tc tc; - DEBUG_PRINT(&tc); - return tc; +/** hazptr_tc free functions */ + +FOLLY_ALWAYS_INLINE hazptr_rec* hazptr_tc_try_get() { + DEBUG_PRINT(TLS_UNINITIALIZED << TLS_ALIVE << TLS_DESTROYED); + DEBUG_PRINT(tls_state_); + if (LIKELY(tls_state_ == TLS_ALIVE)) { + DEBUG_PRINT(tls_state_); + return tls_tc_data_.get(); + } else if (tls_state_ == TLS_UNINITIALIZED) { + tls_life_odr_use(); + return tls_tc_data_.get(); + } + return nullptr; } -/** hazptr_priv - functions */ +FOLLY_ALWAYS_INLINE bool hazptr_tc_try_put(hazptr_rec* hprec) { + DEBUG_PRINT(tls_state_); + if (LIKELY(tls_state_ == TLS_ALIVE)) { + DEBUG_PRINT(tls_state_); + return tls_tc_data_.put(hprec); + } + return false; +} -inline hazptr_priv::hazptr_priv() { - DEBUG_PRINT(this); +inline void hazptr_tc_init() { + DEBUG_PRINT(""); + auto& tc = tls_tc_data_; + DEBUG_PRINT(&tc); + tc.count_ = 0; + for (int i = 0; i < HAZPTR_TC_SIZE; ++i) { + tc.entry_[i].hprec_ = nullptr; + } } -inline hazptr_priv::~hazptr_priv() { - DEBUG_PRINT(this); - DCHECK(active_); - active_ = false; - if (tail_) { - pushAllToDomain(); +inline void hazptr_tc_shutdown() { + auto& tc = tls_tc_data_; + DEBUG_PRINT(&tc); + for (int i = 0; i < tc.count_; ++i) { + tc.entry_[i].evict(); } } +/** + * hazptr_priv + */ + inline void hazptr_priv::push(hazptr_obj* obj) { + auto& domain = default_hazptr_domain(); obj->next_ = nullptr; if (tail_) { tail_->next_ = obj; } else { if (!active_) { - default_hazptr_domain().objRetire(obj); + domain.objRetire(obj); return; } head_ = obj; } tail_ = obj; ++rcount_; - if (domain_->reachedThreshold(rcount_)) { + if (domain.reachedThreshold(rcount_)) { pushAllToDomain(); } } inline void hazptr_priv::pushAllToDomain() { - domain_->pushRetired(head_, tail_, rcount_); + auto& domain = default_hazptr_domain(); + domain.pushRetired(head_, tail_, rcount_); head_ = nullptr; tail_ = nullptr; rcount_ = 0; - domain_->tryBulkReclaim(); + domain.tryBulkReclaim(); +} + +inline void hazptr_priv_init() { + auto& priv = tls_priv_data_; + DEBUG_PRINT(&priv); + priv.head_ = nullptr; + priv.tail_ = nullptr; + priv.rcount_ = 0; + priv.active_ = true; } -inline class hazptr_priv& hazptr_priv() { - static thread_local class hazptr_priv priv; +inline void hazptr_priv_shutdown() { + auto& priv = tls_priv_data_; DEBUG_PRINT(&priv); - return priv; + DCHECK(priv.active_); + priv.active_ = false; + if (priv.tail_) { + priv.pushAllToDomain(); + } +} + +inline bool hazptr_priv_try_retire(hazptr_obj* obj) { + DEBUG_PRINT(tls_state_); + if (tls_state_ == TLS_ALIVE) { + DEBUG_PRINT(tls_state_); + tls_priv_data_.push(obj); + return true; + } else if (tls_state_ == TLS_UNINITIALIZED) { + DEBUG_PRINT(tls_state_); + tls_life_odr_use(); + tls_priv_data_.push(obj); + return true; + } + return false; +} + +/** hazptr_tls_life */ + +inline void tls_life_odr_use() { + DEBUG_PRINT(tls_state_); + CHECK(tls_state_ == TLS_UNINITIALIZED); + auto volatile tlsOdrUse = &tls_life_; + CHECK(tlsOdrUse != nullptr); + DEBUG_PRINT(tlsOdrUse); +} + +inline hazptr_tls_life::hazptr_tls_life() { + DEBUG_PRINT(this); + CHECK(tls_state_ == TLS_UNINITIALIZED); + hazptr_tc_init(); + hazptr_priv_init(); + tls_state_ = TLS_ALIVE; +} + +inline hazptr_tls_life::~hazptr_tls_life() { + DEBUG_PRINT(this); + CHECK(tls_state_ == TLS_ALIVE); + hazptr_tc_shutdown(); + hazptr_priv_shutdown(); + tls_state_ = TLS_DESTROYED; } } // namespace folly diff --git a/folly/experimental/hazptr/hazptr.cpp b/folly/experimental/hazptr/hazptr.cpp new file mode 100644 index 00000000..60870a8a --- /dev/null +++ b/folly/experimental/hazptr/hazptr.cpp @@ -0,0 +1,32 @@ +/* + * Copyright 2017 Facebook, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "hazptr.h" + +namespace folly { +namespace hazptr { + +FOLLY_STATIC_CTOR_PRIORITY_MAX hazptr_domain default_domain_; + +hazptr_stats hazptr_stats_; + +thread_local hazptr_tls_state tls_state_ = TLS_UNINITIALIZED; +thread_local hazptr_tc tls_tc_data_; +thread_local hazptr_priv tls_priv_data_; +thread_local hazptr_tls_life tls_life_; // last + +} // namespace hazptr +} // namespace folly diff --git a/folly/experimental/hazptr/hazptr.h b/folly/experimental/hazptr/hazptr.h index 301fdfab..456fa6c4 100644 --- a/folly/experimental/hazptr/hazptr.h +++ b/folly/experimental/hazptr/hazptr.h @@ -51,7 +51,7 @@ class hazptr_domain { friend class hazptr_holder; template friend class hazptr_obj_base; - friend class hazptr_priv; + friend struct hazptr_priv; memory_resource* mr_; std::atomic hazptrs_ = {nullptr}; @@ -71,12 +71,14 @@ class hazptr_domain { /** Get the default hazptr_domain */ hazptr_domain& default_hazptr_domain(); +extern hazptr_domain default_domain_; + /** Definition of hazptr_obj */ class hazptr_obj { friend class hazptr_domain; template friend class hazptr_obj_base; - friend class hazptr_priv; + friend struct hazptr_priv; void (*reclaim_)(hazptr_obj*); hazptr_obj* next_; diff --git a/folly/experimental/hazptr/memory_resource.cpp b/folly/experimental/hazptr/memory_resource.cpp new file mode 100644 index 00000000..4c8da83d --- /dev/null +++ b/folly/experimental/hazptr/memory_resource.cpp @@ -0,0 +1,65 @@ +/* + * Copyright 2017 Facebook, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "memory_resource.h" + +namespace folly { +namespace hazptr { + +memory_resource** default_mr_ptr() { + /* library-local */ static memory_resource* default_mr = + new_delete_resource(); + DEBUG_PRINT(&default_mr << " " << default_mr); + return &default_mr; +} + +memory_resource* get_default_resource() { + DEBUG_PRINT(""); + return *default_mr_ptr(); +} + +void set_default_resource(memory_resource* mr) { + DEBUG_PRINT(""); + *default_mr_ptr() = mr; +} + +memory_resource* new_delete_resource() { + class new_delete : public memory_resource { + public: + void* allocate( + const size_t bytes, + const size_t alignment = folly::max_align_v) override { + (void)alignment; + void* p = static_cast(new char[bytes]); + DEBUG_PRINT(this << " " << p << " " << bytes); + return p; + } + void deallocate( + void* p, + const size_t bytes, + const size_t alignment = folly::max_align_v) override { + (void)alignment; + (void)bytes; + DEBUG_PRINT(p << " " << bytes); + delete[] static_cast(p); + } + }; + static new_delete mr; + return &mr; +} + +} // namespace hazptr +} // namespace folly diff --git a/folly/experimental/hazptr/memory_resource.h b/folly/experimental/hazptr/memory_resource.h index d1869dfa..9123b8ce 100644 --- a/folly/experimental/hazptr/memory_resource.h +++ b/folly/experimental/hazptr/memory_resource.h @@ -22,6 +22,7 @@ /// std::pmr::memory_resource (C++17) as needed for developing a /// hazptr prototype. //////////////////////////////////////////////////////////////////////////////// + #include #include @@ -44,51 +45,5 @@ memory_resource* get_default_resource(); void set_default_resource(memory_resource*); memory_resource* new_delete_resource(); -//////////////////////////////////////////////////////////////////////////////// -/// Implementation -//////////////////////////////////////////////////////////////////////////////// - -inline memory_resource** default_mr_ptr() { - /* library-local */ static memory_resource* default_mr = - new_delete_resource(); - DEBUG_PRINT(&default_mr << " " << default_mr); - return &default_mr; -} - -inline memory_resource* get_default_resource() { - DEBUG_PRINT(""); - return *default_mr_ptr(); -} - -inline void set_default_resource(memory_resource* mr) { - DEBUG_PRINT(""); - *default_mr_ptr() = mr; -} - -inline memory_resource* new_delete_resource() { - class new_delete : public memory_resource { - public: - void* allocate( - const size_t bytes, - const size_t alignment = folly::max_align_v) override { - (void)alignment; - void* p = static_cast(new char[bytes]); - DEBUG_PRINT(this << " " << p << " " << bytes); - return p; - } - void deallocate( - void* p, - const size_t bytes, - const size_t alignment = folly::max_align_v) override { - (void)alignment; - (void)bytes; - DEBUG_PRINT(p << " " << bytes); - delete[] static_cast(p); - } - }; - static new_delete mr; - return &mr; -} - } // namespace folly } // namespace hazptr diff --git a/folly/experimental/hazptr/test/HazptrTest.cpp b/folly/experimental/hazptr/test/HazptrTest.cpp index 301aaa80..04cadd37 100644 --- a/folly/experimental/hazptr/test/HazptrTest.cpp +++ b/folly/experimental/hazptr/test/HazptrTest.cpp @@ -198,12 +198,11 @@ TEST_F(HazptrTest, LIFO) { TEST_F(HazptrTest, SWMRLIST) { using T = uint64_t; - hazptr_domain custom_domain; CHECK_GT(FLAGS_num_threads, 0); for (int i = 0; i < FLAGS_num_reps; ++i) { DEBUG_PRINT("========== start of rep scope"); - SWMRListSet s(custom_domain); + SWMRListSet s; std::vector threads(FLAGS_num_threads); for (int tid = 0; tid < FLAGS_num_threads; ++tid) { threads[tid] = std::thread([&s, tid]() { -- 2.34.1