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