xenium
retire_list.hpp
1 //
2 // Copyright (c) 2018-2020 Manuel Pöter.
3 // Licensed under the MIT License. See LICENSE file in the project root for full license information.
4 //
5 
6 #pragma once
7 
8 #include <xenium/detail/port.hpp>
9 #include <xenium/reclamation/detail/deletable_object.hpp>
10 
11 namespace xenium::reclamation::detail {
12 template <class Node = deletable_object>
13 struct retired_nodes {
14  Node* first;
15  Node* last;
16 };
17 
18 template <class Node = deletable_object>
19 struct retire_list {
20  retire_list() {
21  _nodes.first = nullptr;
22  _nodes.last = nullptr;
23  }
24 
25  ~retire_list() { assert(_nodes.first == nullptr); }
26 
27  void push(Node* node) {
28  node->next = _nodes.first;
29  _nodes.first = node;
30  if (_nodes.last == nullptr) {
31  _nodes.last = node;
32  }
33  }
34 
35  retired_nodes<Node> steal() {
36  auto result = _nodes;
37  _nodes.first = nullptr;
38  _nodes.last = nullptr;
39  return result;
40  };
41 
42  [[nodiscard]] bool empty() const { return _nodes.first == nullptr; }
43 
44 private:
45  retired_nodes<Node> _nodes;
46 };
47 
48 template <class Node = deletable_object>
49 struct counting_retire_list {
50  void push(Node* node) {
51  list.push(node);
52  ++counter;
53  }
54 
55  retired_nodes<Node> steal() {
56  counter = 0;
57  return list.steal();
58  };
59 
60  [[nodiscard]] bool empty() const { return list.empty(); }
61  [[nodiscard]] std::size_t size() const { return counter; }
62 
63 private:
64  retire_list<Node> list;
65  std::size_t counter;
66 };
67 
68 template <class Node = deletable_object>
69 struct orphan_list {
70  void add(retired_nodes<Node> nodes) {
71  assert(nodes.first != nullptr);
72  auto* h = head.load(std::memory_order_relaxed);
73  do {
74  nodes.last->next = h;
75  // (1) - this releas-CAS synchronizes-with the acquire-exchange (2)
76  } while (!head.compare_exchange_weak(h, nodes.first, std::memory_order_release, std::memory_order_relaxed));
77  }
78 
79  XENIUM_FORCEINLINE Node* adopt() {
80  if (head.load(std::memory_order_relaxed) == nullptr) {
81  return nullptr;
82  }
83 
84  // (2) - this acquire-exchange synchronizes-with the release-CAS (1)
85  return head.exchange(nullptr, std::memory_order_acquire);
86  };
87 
88 private:
89  std::atomic<Node*> head;
90 };
91 } // namespace xenium::reclamation::detail