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