PMDK C++ bindings  1.13.0-git107.g7e59f08f
This is the C++ bindings documentation for PMDK's libpmemobj.
atomic_self_relative_ptr.hpp
Go to the documentation of this file.
1 // SPDX-License-Identifier: BSD-3-Clause
2 /* Copyright 2020-2021, Intel Corporation */
3 
9 #ifndef LIBPMEMOBJ_CPP_ATOMIC_SELF_RELATIVE_PTR_HPP
10 #define LIBPMEMOBJ_CPP_ATOMIC_SELF_RELATIVE_PTR_HPP
11 
16 
17 #include <atomic>
18 
19 namespace std
20 {
27 template <typename T>
28 struct atomic<pmem::obj::experimental::self_relative_ptr<T>> {
29 private:
31  std::atomic<std::ptrdiff_t>>;
33  std::atomic<std::ptrdiff_t>>;
34 
35 public:
36  using this_type = atomic;
38  using difference_type = typename value_type::difference_type;
39 
40  /*
41  * Constructors
42  */
43 
44  constexpr atomic() noexcept = default;
45  atomic(value_type value) : ptr()
46  {
47  store(value);
48  }
49  atomic(const atomic &) = delete;
50 
51  void
52  store(value_type desired,
53  std::memory_order order = std::memory_order_seq_cst) noexcept
54  {
55  auto offset = accessor::pointer_to_offset(ptr, desired.get());
56  LIBPMEMOBJ_CPP_ANNOTATE_HAPPENS_BEFORE(order, &ptr);
57  accessor::get_offset(ptr).store(offset, order);
58  }
59 
61  load(std::memory_order order = std::memory_order_seq_cst) const noexcept
62  {
63  auto offset = accessor::get_offset(ptr).load(order);
64  LIBPMEMOBJ_CPP_ANNOTATE_HAPPENS_AFTER(order, &ptr);
65  auto pointer = accessor::offset_to_pointer<T>(offset, ptr);
66  return value_type{pointer};
67  }
68 
70  exchange(value_type desired,
71  std::memory_order order = std::memory_order_seq_cst) noexcept
72  {
73  auto new_offset =
74  accessor::pointer_to_offset(ptr, desired.get());
75  auto old_offset =
76  accessor::get_offset(ptr).exchange(new_offset, order);
77  return value_type{
78  accessor::offset_to_pointer<T>(old_offset, ptr)};
79  }
80 
81  bool
82  compare_exchange_weak(value_type &expected, value_type desired,
83  std::memory_order success,
84  std::memory_order failure) noexcept
85  {
86  auto expected_offset =
87  accessor::pointer_to_offset(ptr, expected.get());
88  auto desired_offset =
89  accessor::pointer_to_offset(ptr, desired.get());
90 
91  bool result = accessor::get_offset(ptr).compare_exchange_weak(
92  expected_offset, desired_offset, success, failure);
93  if (!result) {
94  try {
95  expected = accessor::offset_to_pointer<T>(
96  expected_offset, ptr);
97  } catch (...) {
98  std::terminate();
99  }
100  }
101  return result;
102  }
103 
104  bool
105  compare_exchange_weak(
106  value_type &expected, value_type desired,
107  std::memory_order order = std::memory_order_seq_cst) noexcept
108  {
109  auto expected_offset =
110  accessor::pointer_to_offset(ptr, expected.get());
111  auto desired_offset =
112  accessor::pointer_to_offset(ptr, desired.get());
113 
114  bool result = accessor::get_offset(ptr).compare_exchange_weak(
115  expected_offset, desired_offset, order);
116  if (!result) {
117  try {
118  expected = accessor::offset_to_pointer<T>(
119  expected_offset, ptr);
120  } catch (...) {
121  std::terminate();
122  }
123  }
124  return result;
125  }
126 
127  bool
128  compare_exchange_strong(value_type &expected, value_type desired,
129  std::memory_order success,
130  std::memory_order failure) noexcept
131  {
132  auto expected_offset =
133  accessor::pointer_to_offset(ptr, expected.get());
134  auto desired_offset =
135  accessor::pointer_to_offset(ptr, desired.get());
136 
137  bool result = accessor::get_offset(ptr).compare_exchange_strong(
138  expected_offset, desired_offset, success, failure);
139  if (!result) {
140  try {
141  expected = accessor::offset_to_pointer<T>(
142  expected_offset, ptr);
143  } catch (...) {
144  std::terminate();
145  }
146  }
147  return result;
148  }
149 
150  bool
151  compare_exchange_strong(
152  value_type &expected, value_type desired,
153  std::memory_order order = std::memory_order_seq_cst) noexcept
154  {
155  auto expected_offset =
156  accessor::pointer_to_offset(ptr, expected.get());
157  auto desired_offset =
158  accessor::pointer_to_offset(ptr, desired.get());
159 
160  bool result = accessor::get_offset(ptr).compare_exchange_strong(
161  expected_offset, desired_offset, order);
162  if (!result) {
163  try {
164  expected = accessor::offset_to_pointer<T>(
165  expected_offset, ptr);
166  } catch (...) {
167  std::terminate();
168  }
169  }
170  return result;
171  }
172 
173  value_type
174  fetch_add(difference_type val,
175  std::memory_order order = std::memory_order_seq_cst) noexcept
176  {
177  auto offset = accessor::get_offset(ptr).fetch_add(
178  val * static_cast<difference_type>(sizeof(T)), order);
179  return value_type{accessor::offset_to_pointer<T>(offset, ptr)};
180  }
181 
182  value_type
183  fetch_sub(difference_type val,
184  std::memory_order order = std::memory_order_seq_cst) noexcept
185  {
186  auto offset = accessor::get_offset(ptr).fetch_sub(
187  val * static_cast<difference_type>(sizeof(T)), order);
188  return value_type{accessor::offset_to_pointer<T>(offset, ptr)};
189  }
190 
191  bool
192  is_lock_free() const noexcept
193  {
194  return accessor::get_offset(ptr).is_lock_free();
195  }
196 
197  /*
198  * Operators
199  */
200 
201  operator value_type() const noexcept
202  {
203  return load();
204  }
205 
206  atomic &operator=(const atomic &) = delete;
207  atomic &operator=(const atomic &) volatile = delete;
208 
209  value_type
210  operator=(value_type desired) noexcept
211  {
212  store(desired);
213  return desired;
214  }
215 
216  value_type
217  operator++() noexcept
218  {
219  try {
220  return this->fetch_add(1) + 1;
221  } catch (...) {
222  /* This should never happen during normal program
223  * execution */
224  std::terminate();
225  }
226  }
227 
228  value_type
229  operator++(int) noexcept
230  {
231  return this->fetch_add(1);
232  }
233 
234  value_type
235  operator--() noexcept
236  {
237  try {
238  return this->fetch_sub(1) - 1;
239  } catch (...) {
240  /* This should never happen during normal program
241  * execution */
242  std::terminate();
243  }
244  }
245 
246  value_type
247  operator--(int) noexcept
248  {
249  return this->fetch_sub(1);
250  }
251 
252  value_type
253  operator+=(difference_type diff) noexcept
254  {
255  try {
256  return this->fetch_add(diff) + diff;
257  } catch (...) {
258  /* This should never happen during normal program
259  * execution */
260  std::terminate();
261  }
262  }
263 
264  value_type
265  operator-=(difference_type diff) noexcept
266  {
267  try {
268  return this->fetch_sub(diff) - diff;
269  } catch (...) {
270  /* This should never happen during normal program
271  * execution */
272  std::terminate();
273  }
274  }
275 
276 private:
277  ptr_type ptr;
278 };
279 
280 } /* namespace std */
281 
282 namespace pmem
283 {
284 
285 namespace detail
286 {
287 
294 template <typename T>
295 struct can_do_snapshot<std::atomic<obj::experimental::self_relative_ptr<T>>> {
297  static constexpr bool value = sizeof(std::atomic<snapshot_type>) ==
298  sizeof(typename snapshot_type::offset_type);
299  static_assert(value,
300  "std::atomic<self_relative_ptr> should be the same size");
301 };
302 
303 } /* namespace detail */
304 
305 } /* namespace pmem */
306 
307 #endif
Static class accessor to self_relative_ptr_base.
Definition: self_relative_ptr_base_impl.hpp:296
Persistent self-relative pointer class.
Definition: self_relative_ptr.hpp:82
element_type * get() const noexcept
Get the direct pointer.
Definition: self_relative_ptr.hpp:197
typename base_type::difference_type difference_type
The self_relative_ptr difference type.
Definition: self_relative_ptr.hpp:100
Commonly used functionality.
Persistent memory namespace.
Definition: allocation_flag.hpp:15
Persistent self-relative smart pointer.
Base class for self_relative_ptr.
A structure that checks if it is possible to snapshot the specified memory.
Definition: transaction.hpp:41
C++ pmemobj transactions.