6 #ifndef XENIUM_DETAIL_THREAD_BLOCK_LIST_HPP
7 #define XENIUM_DETAIL_THREAD_BLOCK_LIST_HPP
14 #pragma warning(disable: 4324) // structure was padded due to alignment specifier
17 namespace xenium {
namespace reclamation {
namespace detail {
19 template <
typename T,
typename DeletableObject = detail::deletable_
object>
20 class thread_block_list
22 enum class entry_state {
32 state(entry_state::active)
39 bool is_active(std::memory_order memory_order = std::memory_order_relaxed)
const {
40 return state.load(memory_order) == entry_state::active;
47 state.store(entry_state::free, std::memory_order_release);
51 assert(state.load(std::memory_order_relaxed) == entry_state::inactive);
52 state.store(entry_state::active, std::memory_order_release);
56 friend class thread_block_list;
58 bool try_adopt(entry_state initial_state)
60 if (state.load(std::memory_order_relaxed) == entry_state::free)
62 auto expected = entry_state::free;
64 return state.compare_exchange_strong(expected, initial_state, std::memory_order_acquire);
74 std::atomic<entry_state> state;
81 explicit iterator(T* ptr) : ptr(ptr) {}
83 using iterator_category = std::forward_iterator_tag;
85 using difference_type = std::ptrdiff_t;
91 void swap(iterator& other) noexcept
93 std::swap(ptr, other.ptr);
96 iterator& operator++ ()
98 assert(ptr !=
nullptr);
99 ptr = ptr->next_entry;
103 iterator operator++ (
int)
105 assert(ptr !=
nullptr);
107 ptr = ptr->next_entry;
111 bool operator == (
const iterator& rhs)
const
113 return ptr == rhs.ptr;
116 bool operator != (
const iterator& rhs)
const
118 return ptr != rhs.ptr;
121 T& operator* ()
const
123 assert(ptr !=
nullptr);
127 T* operator-> ()
const
129 assert(ptr !=
nullptr);
133 friend class thread_block_list;
138 return adopt_or_create_entry(entry_state::active);
141 T* acquire_inactive_entry()
143 return adopt_or_create_entry(entry_state::inactive);
146 void release_entry(T* entry)
154 return iterator{head.load(std::memory_order_acquire)};
157 iterator end() {
return iterator{}; }
159 void abandon_retired_nodes(DeletableObject* obj)
162 auto next = last->next;
169 auto h = abandoned_retired_nodes.load(std::memory_order_relaxed);
174 }
while (!abandoned_retired_nodes.compare_exchange_weak(h, obj,
175 std::memory_order_release, std::memory_order_relaxed));
178 DeletableObject* adopt_abandoned_retired_nodes()
180 if (abandoned_retired_nodes.load(std::memory_order_relaxed) ==
nullptr)
184 return abandoned_retired_nodes.exchange(
nullptr, std::memory_order_acquire);
188 void add_entry(T* node)
190 auto h = head.load(std::memory_order_relaxed);
193 node->next_entry = h;
195 }
while (!head.compare_exchange_weak(h, node, std::memory_order_release, std::memory_order_relaxed));
198 T* adopt_or_create_entry(entry_state initial_state)
200 static_assert(std::is_base_of<entry, T>::value,
"T must derive from entry.");
203 T* result = head.load(std::memory_order_acquire);
206 if (result->try_adopt(initial_state))
209 result = result->next_entry;
213 result->state.store(initial_state, std::memory_order_relaxed);
218 std::atomic<T*> head{
nullptr};
220 alignas(64) std::atomic<DeletableObject*> abandoned_retired_nodes{
nullptr};