PMDK C++ bindings  1.13.0-git107.g7e59f08f
This is the C++ bindings documentation for PMDK's libpmemobj.
atomic_persistent_aware_ptr.hpp
Go to the documentation of this file.
1 // SPDX-License-Identifier: BSD-3-Clause
2 /* Copyright 2021, Intel Corporation */
3 
9 #ifndef LIBPMEMOBJ_CPP_ATOMIC_PERSISTENT_AWARE_PTR_HPP
10 #define LIBPMEMOBJ_CPP_ATOMIC_PERSISTENT_AWARE_PTR_HPP
11 
18 #include <libpmemobj++/utils.hpp>
19 
20 #include <atomic>
21 
22 namespace pmem
23 {
24 namespace obj
25 {
26 namespace experimental
27 {
28 
42 template <typename T, typename ReadOptimized>
44 private:
46  std::atomic<std::ptrdiff_t>>;
48  std::atomic<std::ptrdiff_t>>;
49 
50  static constexpr uintptr_t IS_DIRTY = 1;
51 
52 public:
55  using difference_type = typename value_type::difference_type;
56 
57  constexpr atomic_persistent_aware_ptr() noexcept = default;
58 
69  {
70  store(value);
71  }
72 
77  delete;
78 
85  template <typename OPT = ReadOptimized>
86  typename std::enable_if<std::is_same<OPT, std::true_type>::value>::type
87  store(value_type desired,
88  std::memory_order order = std::memory_order_seq_cst) noexcept
89  {
90  auto dirty_desired = mark_dirty(desired);
91  ptr.store(dirty_desired, order);
92  pool_by_vptr(this).persist(&ptr, sizeof(ptr));
93  ptr.compare_exchange_strong(dirty_desired, clear_dirty(desired),
94  order);
95  /* Flushing is not necessary for correctness, it's enough that
96  * dirty_desired is persistent */
97 #if LIBPMEMOBJ_CPP_VG_PMEMCHECK_ENABLED
98  VALGRIND_PMC_DO_FLUSH(&ptr, sizeof(ptr));
99 #endif
100  }
101 
108  template <typename OPT = ReadOptimized>
109  typename std::enable_if<!std::is_same<OPT, std::true_type>::value>::type
110  store(value_type desired,
111  std::memory_order order = std::memory_order_seq_cst) noexcept
112  {
113  ptr.store(mark_dirty(desired), order);
114  }
115 
121  template <typename OPT = ReadOptimized>
122  typename std::enable_if<std::is_same<OPT, std::true_type>::value,
123  value_type>::type
124  load(std::memory_order order = std::memory_order_seq_cst) noexcept
125  {
126  /* This load relies on the store function to clear the dirty
127  * flag. For correctness though, it flushes the dirty ptr and
128  * returns the clear ptr for now. */
129  auto val = ptr.load(order);
130  if (is_dirty(val)) {
131  pool_by_vptr(this).persist(&ptr, sizeof(ptr));
132  }
133  return clear_dirty(val);
134  }
135 
141  template <typename OPT = ReadOptimized>
142  typename std::enable_if<!std::is_same<OPT, std::true_type>::value,
143  value_type>::type
144  load(std::memory_order order = std::memory_order_seq_cst) noexcept
145  {
146  /* It flushes the ptr with the dirty flag - clears the flag
147  * using CAS after flush. If CAS failed it simply returns the
148  * old clear ptr and relies on a later load to clear the dirty
149  * flag. */
150  auto val = ptr.load(order);
151  if (is_dirty(val)) {
152  pool_by_vptr(this).persist(&ptr, sizeof(ptr));
153  auto clear_val = clear_dirty(val);
154  ptr.compare_exchange_strong(val, clear_val, order);
155 #if LIBPMEMOBJ_CPP_VG_PMEMCHECK_ENABLED
156  VALGRIND_PMC_DO_FLUSH(&ptr, sizeof(ptr));
157 #endif
158  return clear_val;
159  }
160  return clear_dirty(val);
161  }
162 
163  bool
164  is_lock_free() const noexcept
165  {
166  return ptr.is_lock_free();
167  }
168 
169  /*
170  * Operators
171  */
172 
176  operator value_type() const noexcept
177  {
178  return load();
179  }
180 
187  value_type
188  operator=(value_type desired) noexcept
189  {
190  store(desired);
191  return desired;
192  }
193 
199 
200 private:
201  value_type
202  mark_dirty(value_type ptr) const
203  {
204  auto dirty_ptr =
205  reinterpret_cast<uintptr_t>(ptr.get()) | IS_DIRTY;
206  return value_type{reinterpret_cast<T *>(dirty_ptr)};
207  }
208 
209  value_type
210  clear_dirty(value_type ptr) const
211  {
212  auto clear_ptr =
213  reinterpret_cast<uintptr_t>(ptr.get()) & ~IS_DIRTY;
214  return value_type{reinterpret_cast<T *>(clear_ptr)};
215  }
216 
217  bool
218  is_dirty(value_type ptr) const
219  {
220  return reinterpret_cast<uintptr_t>(ptr.get()) & IS_DIRTY;
221  }
222 
223  std::atomic<self_relative_ptr<T>> ptr;
224 };
225 } // namespace experimental
226 } // namespace obj
227 } // namespace pmem
228 
229 #endif // LIBPMEMOBJ_CPP_ATOMIC_PERSISTENT_AWARE_PTR_HPP
Atomic backoff, for time delay.
Atomic specialization for self_relative_ptr.
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
void persist(const void *addr, size_t len) noexcept
Performs persist operation on a given chunk of memory.
Definition: pool.hpp:280
Commonly used functionality.
pool_base pool_by_vptr(const T *that)
Retrieve pool handle for the given pointer.
Definition: utils.hpp:32
Persistent memory namespace.
Definition: allocation_flag.hpp:15
Persistent self-relative smart pointer.
Base class for self_relative_ptr.
Atomic specialization of a persistent ptr (self_relative_ptr) that manages its persistence by itself.
Definition: atomic_persistent_aware_ptr.hpp:43
std::enable_if< std::is_same< OPT, std::true_type >::value, value_type >::type load(std::memory_order order=std::memory_order_seq_cst) noexcept
Read-optimized load.
Definition: atomic_persistent_aware_ptr.hpp:124
atomic_persistent_aware_ptr & operator=(const atomic_persistent_aware_ptr &)=delete
Deleted assignment operator.
std::enable_if<!std::is_same< OPT, std::true_type >::value, value_type >::type load(std::memory_order order=std::memory_order_seq_cst) noexcept
Write-optimized load flushes the data.
Definition: atomic_persistent_aware_ptr.hpp:144
std::enable_if<!std::is_same< OPT, std::true_type >::value >::type store(value_type desired, std::memory_order order=std::memory_order_seq_cst) noexcept
Write-optimized store relies on a consequent load to do the flush.
Definition: atomic_persistent_aware_ptr.hpp:110
std::enable_if< std::is_same< OPT, std::true_type >::value >::type store(value_type desired, std::memory_order order=std::memory_order_seq_cst) noexcept
Read-optimized store does the flush already in the store function.
Definition: atomic_persistent_aware_ptr.hpp:87
value_type operator=(value_type desired) noexcept
Assignment operator.
Definition: atomic_persistent_aware_ptr.hpp:188
atomic_persistent_aware_ptr(const atomic_persistent_aware_ptr &)=delete
Deleted copy constructor.
atomic_persistent_aware_ptr(value_type value)
Constructors.
Definition: atomic_persistent_aware_ptr.hpp:68
C++ pmemobj transactions.
Libpmemobj C++ utils.