6 #ifndef XENIUM_HAZARD_POINTER_HPP
7 #define XENIUM_HAZARD_POINTER_HPP
9 #include <xenium/reclamation/detail/allocation_tracker.hpp>
10 #include <xenium/reclamation/detail/concurrent_ptr.hpp>
11 #include <xenium/reclamation/detail/deletable_object.hpp>
12 #include <xenium/reclamation/detail/guard_ptr.hpp>
13 #include <xenium/reclamation/detail/thread_block_list.hpp>
15 #include <xenium/acquire_guard.hpp>
16 #include <xenium/parameter.hpp>
17 #include <xenium/policy.hpp>
22 namespace xenium::reclamation {
30 using std::runtime_error::runtime_error;
34 template <
class Strategy,
class Derived>
35 struct basic_hp_thread_control_block;
37 template <
size_t K_,
size_t A,
size_t B,
template <
class>
class ThreadControlBlock>
38 struct generic_hp_allocation_strategy {
39 static constexpr
size_t K = K_;
41 static size_t retired_nodes_threshold() {
return A * number_of_active_hazard_pointers() + B; }
43 static size_t number_of_active_hazard_pointers() {
return number_of_active_hps.load(std::memory_order_relaxed); }
45 using thread_control_block = ThreadControlBlock<generic_hp_allocation_strategy>;
48 friend thread_control_block;
49 friend basic_hp_thread_control_block<generic_hp_allocation_strategy, thread_control_block>;
51 inline static std::atomic<size_t> number_of_active_hps{0};
54 template <
class Strategy>
55 struct static_hp_thread_control_block;
57 template <
class Strategy>
58 struct dynamic_hp_thread_control_block;
61 namespace hp_allocation {
72 template <
size_t K = 2,
size_t A = 2,
size_t B = 100>
73 struct static_strategy : detail::generic_hp_allocation_strategy<K, A, B, detail::static_hp_thread_control_block> {};
96 template <
size_t K = 2,
size_t A = 2,
size_t B = 100>
97 struct dynamic_strategy : detail::generic_hp_allocation_strategy<K, A, B, detail::dynamic_hp_thread_control_block> {};
100 template <
class AllocationStrategy = hp_allocation::static_strategy<3>>
101 struct hazard_pointer_traits {
102 using allocation_strategy = AllocationStrategy;
104 template <
class... Policies>
127 template <
typename Traits = hazard_po
inter_traits<>>
129 using allocation_strategy =
typename Traits::allocation_strategy;
130 using thread_control_block =
typename allocation_strategy::thread_control_block;
131 friend detail::basic_hp_thread_control_block<allocation_strategy, thread_control_block>;
133 template <
class T,
class MarkedPtr>
147 template <
class... Policies>
150 template <
class T, std::
size_t N = 0,
class Deleter = std::default_delete<T>>
151 class enable_concurrent_ptr;
153 class region_guard {};
155 template <
class T, std::
size_t N = T::number_of_mark_bits>
163 inline static detail::thread_block_list<thread_control_block> global_thread_block_list;
164 inline static thread_local thread_data local_thread_data;
166 ALLOCATION_TRACKING_FUNCTIONS;
169 template <
typename Traits>
170 template <
class T, std::
size_t N,
class Deleter>
171 class hazard_pointer<Traits>::enable_concurrent_ptr :
172 private detail::deletable_object_impl<T, Deleter>,
173 private detail::tracked_object<hazard_pointer> {
175 static constexpr std::size_t number_of_mark_bits = N;
178 enable_concurrent_ptr() noexcept = default;
179 enable_concurrent_ptr(const enable_concurrent_ptr&) noexcept = default;
180 enable_concurrent_ptr(enable_concurrent_ptr&&) noexcept = default;
181 enable_concurrent_ptr& operator=(const enable_concurrent_ptr&) noexcept = default;
182 enable_concurrent_ptr& operator=(enable_concurrent_ptr&&) noexcept = default;
183 ~enable_concurrent_ptr() noexcept override = default;
186 friend detail::deletable_object_impl<T, Deleter>;
188 template <class, class>
189 friend class guard_ptr;
192 template <typename Traits>
193 template <class T, class MarkedPtr>
194 class hazard_pointer<Traits>::guard_ptr : public detail::guard_ptr<T, MarkedPtr, guard_ptr<T, MarkedPtr>> {
195 using base = detail::guard_ptr<T, MarkedPtr, guard_ptr>;
196 using Deleter =
typename T::Deleter;
199 guard_ptr() noexcept = default;
202 explicit guard_ptr(const MarkedPtr& p);
203 guard_ptr(const guard_ptr& p);
204 guard_ptr(guard_ptr&& p) noexcept;
206 guard_ptr& operator=(const guard_ptr& p);
207 guard_ptr& operator=(guard_ptr&& p) noexcept;
210 void acquire(const concurrent_ptr<T>& p, std::memory_order order = std::memory_order_seq_cst);
213 bool acquire_if_equal(const concurrent_ptr<T>& p,
214 const MarkedPtr& expected,
215 std::memory_order order = std::memory_order_seq_cst);
218 void reset() noexcept;
221 void reclaim(Deleter d = Deleter()) noexcept;
224 using enable_concurrent_ptr = hazard_pointer::enable_concurrent_ptr<T, MarkedPtr::number_of_mark_bits, Deleter>;
227 void do_swap(guard_ptr& g) noexcept;
229 typename thread_control_block::hazard_pointer* hp =
nullptr;
233 #define HAZARD_POINTER_IMPL
234 #include <xenium/reclamation/impl/hazard_pointer.hpp>
235 #undef HAZARD_POINTER_IMPL