cycle_ptr
generation.h
1 #ifndef CYCLE_PTR_DETAIL_GENERATION_H
2 #define CYCLE_PTR_DETAIL_GENERATION_H
3 
4 #include <atomic>
5 #include <cassert>
6 #include <cstdint>
7 #include <utility>
8 #include <cycle_ptr/detail/color.h>
9 #include <cycle_ptr/detail/base_control.h>
10 #include <cycle_ptr/detail/intrusive_ptr.h>
11 
12 namespace cycle_ptr {
13 class gc_operation;
14 } /* namespace cycle_ptr */
15 
16 namespace cycle_ptr::detail {
17 
18 
19 class generation {
20  friend class cycle_ptr::gc_operation;
21 
22  friend auto intrusive_ptr_add_ref(generation* g)
23  noexcept
24  -> void {
25  assert(g != nullptr);
26 
27  [[maybe_unused]]
28  std::uintptr_t old = g->refs_.fetch_add(1u, std::memory_order_relaxed);
29  assert(old < UINTPTR_MAX);
30  }
31 
32  friend auto intrusive_ptr_release(generation* g)
33  noexcept
34  -> void {
35  assert(g != nullptr);
36 
37  std::uintptr_t old = g->refs_.fetch_sub(1u, std::memory_order_release);
38  assert(old > 0u);
39 
40  if (old == 1u) delete g;
41  }
42 
43  private:
45 
46  generation() = default;
47 
48  generation(std::uintmax_t seq)
49  : seq_(seq)
50  {}
51 
52  generation(const generation&) = delete;
53 
54 #ifndef NDEBUG
55  ~generation() noexcept {
56  assert(controls_.empty());
57  assert(refs_ == 0u);
58  }
59 #else
60  ~generation() noexcept = default;
61 #endif
62 
63  public:
64  static auto new_generation()
66  return intrusive_ptr<generation>(new generation(), true);
67  }
68 
69  static auto new_generation(std::uintmax_t seq)
71  return intrusive_ptr<generation>(new generation(seq), true);
72  }
73 
74  static auto order_invariant(const generation& origin, const generation& dest)
75  noexcept
76  -> bool {
77  return origin.seq() < (dest.seq() & ~moveable_seq);
78  }
79 
80  auto link(base_control& bc) noexcept
81  -> void {
82  std::lock_guard<std::shared_mutex> lck{ mtx_ };
83  controls_.push_back(bc);
84  }
85 
86  auto unlink(base_control& bc) noexcept
87  -> void {
88  std::lock_guard<std::shared_mutex> lck{ mtx_ };
89  controls_.erase(controls_.iterator_to(bc));
90  }
91 
92  private:
93  static constexpr std::uintmax_t moveable_seq = 0x1;
94 
95  static auto new_seq_() noexcept -> std::uintmax_t;
96 
97  public:
98  auto seq() const
99  noexcept
100  -> std::uintmax_t {
101  return seq_.load(std::memory_order_relaxed);
102  }
103 
104  auto gc() noexcept -> void;
105 
116  static auto fix_ordering(base_control& src, base_control& dst) noexcept
117  -> std::shared_lock<std::shared_mutex>;
118 
119  private:
134  auto gc_() noexcept -> void;
135 
147  auto gc_mark_() noexcept -> controls_list::iterator;
148 
155  auto gc_phase2_mark_(controls_list::iterator b) noexcept
156  -> controls_list::iterator;
157 
168  auto gc_sweep_(controls_list::iterator wavefront_end) noexcept
169  -> controls_list::iterator;
170 
177  auto gc_phase2_sweep_(controls_list::iterator wavefront_end) noexcept
178  -> controls_list::iterator;
179 
191  static auto merge_(
192  std::tuple<intrusive_ptr<generation>, bool> src_tpl,
193  std::tuple<intrusive_ptr<generation>, bool> dst_tpl) noexcept
194  -> std::tuple<intrusive_ptr<generation>, bool>;
195 
217  [[nodiscard]]
218  static auto merge0_(
219  std::tuple<generation*, bool> x,
220  std::tuple<generation*, bool> y,
221  [[maybe_unused]] const std::unique_lock<std::shared_mutex>& x_mtx_lck,
222  [[maybe_unused]] const std::unique_lock<std::shared_mutex>& x_merge_mtx_lck) noexcept
223  -> bool;
224 
225  public:
227  std::shared_mutex mtx_;
230  std::shared_mutex merge_mtx_;
231 
232  private:
234  controls_list controls_;
235 
236  public:
245  std::shared_mutex red_promotion_mtx_;
246 
247  private:
249  std::atomic<std::uintmax_t> seq_ = new_seq_();
251  std::atomic<std::uintptr_t> refs_{ 0u };
253  std::atomic_flag gc_flag_;
254 };
255 
256 
257 } /* namespace cycle_ptr::detail */
258 
259 #endif /* CYCLE_PTR_DETAIL_GENERATION_H */
Definition: generation.h:19
auto empty() const noexcept -> bool
Test if this list is empty.
Definition: llist.h:85
std::shared_mutex red_promotion_mtx_
Lock to control weak red-promotions.
Definition: generation.h:245
Intrusive pointer.
Definition: intrusive_ptr.h:21
auto erase(const_iterator b) -> iterator
Erase element from the list.
Definition: llist.h:716
GC operations for delayed collection.
Definition: util.h:24
static auto fix_ordering(base_control &src, base_control &dst) noexcept -> std::shared_lock< std::shared_mutex >
Ensure src and dst meet constraint, in order to create an edge between them.
std::shared_mutex mtx_
Mutex protecting controls_ and GC.
Definition: generation.h:227
auto push_back(T &v) noexcept -> void
Link element into the list, as the last item.
Definition: llist.h:251
std::shared_mutex merge_mtx_
Mutex protecting merges.
Definition: generation.h:230
Base class for all control blocks.
Definition: base_control.h:30
static auto iterator_to(T &elem) noexcept -> iterator
Create iterator to element.
Definition: llist.h:110