PMDK C++ bindings  1.13.0-git23.gf49772ac
This is the C++ bindings documentation for PMDK's libpmemobj.
common.hpp
Go to the documentation of this file.
1 // SPDX-License-Identifier: BSD-3-Clause
2 /* Copyright 2016-2021, Intel Corporation */
3 
9 #ifndef LIBPMEMOBJ_CPP_COMMON_HPP
10 #define LIBPMEMOBJ_CPP_COMMON_HPP
11 
13 #include <libpmemobj/tx_base.h>
14 #include <string>
15 #include <typeinfo>
16 
17 #if _MSC_VER
18 #include <intrin.h>
19 #include <windows.h>
20 #endif
21 
22 #if defined(__GNUC__) || defined(__clang__)
23 #define POBJ_CPP_DEPRECATED __attribute__((deprecated))
24 #elif defined(_MSC_VER)
25 #define POBJ_CPP_DEPRECATED __declspec(deprecated)
26 #else
27 #define POBJ_CPP_DEPRECATED
28 #endif
29 
30 #if LIBPMEMOBJ_CPP_VG_ENABLED
31 #undef LIBPMEMOBJ_CPP_VG_PMEMCHECK_ENABLED
32 #undef LIBPMEMOBJ_CPP_VG_MEMCHECK_ENABLED
33 #undef LIBPMEMOBJ_CPP_VG_HELGRIND_ENABLED
34 #undef LIBPMEMOBJ_CPP_VG_DRD_ENABLED
35 
36 #define LIBPMEMOBJ_CPP_VG_PMEMCHECK_ENABLED 1
37 #define LIBPMEMOBJ_CPP_VG_MEMCHECK_ENABLED 1
38 #define LIBPMEMOBJ_CPP_VG_HELGRIND_ENABLED 1
39 #define LIBPMEMOBJ_CPP_VG_DRD_ENABLED 1
40 #endif
41 
42 #if LIBPMEMOBJ_CPP_VG_PMEMCHECK_ENABLED || \
43  LIBPMEMOBJ_CPP_VG_MEMCHECK_ENABLED || \
44  LIBPMEMOBJ_CPP_VG_HELGRIND_ENABLED || LIBPMEMOBJ_CPP_VG_DRD_ENABLED
45 #define LIBPMEMOBJ_CPP_ANY_VG_TOOL_ENABLED 1
46 #endif
47 
48 #if LIBPMEMOBJ_CPP_ANY_VG_TOOL_ENABLED
49 #include <valgrind.h>
50 #endif
51 
52 #if LIBPMEMOBJ_CPP_VG_PMEMCHECK_ENABLED
53 #include <pmemcheck.h>
54 #endif
55 
56 #if LIBPMEMOBJ_CPP_VG_MEMCHECK_ENABLED
57 #include <memcheck.h>
58 #endif
59 
60 #if LIBPMEMOBJ_CPP_VG_HELGRIND_ENABLED
61 #include <helgrind.h>
62 #endif
63 
64 #if LIBPMEMOBJ_CPP_VG_DRD_ENABLED
65 #include <drd.h>
66 #endif
67 
68 #if LIBPMEMOBJ_CPP_VG_HELGRIND_ENABLED
69 
70 #define LIBPMEMOBJ_CPP_ANNOTATE_HAPPENS_BEFORE(order, ptr) \
71  if (order == std::memory_order_release || \
72  order == std::memory_order_acq_rel || \
73  order == std::memory_order_seq_cst) { \
74  ANNOTATE_HAPPENS_BEFORE(ptr); \
75  }
76 
77 #define LIBPMEMOBJ_CPP_ANNOTATE_HAPPENS_AFTER(order, ptr) \
78  if (order == std::memory_order_consume || \
79  order == std::memory_order_acquire || \
80  order == std::memory_order_acq_rel || \
81  order == std::memory_order_seq_cst) { \
82  ANNOTATE_HAPPENS_AFTER(ptr); \
83  }
84 #else
85 
86 #define LIBPMEMOBJ_CPP_ANNOTATE_HAPPENS_BEFORE(order, ptr)
87 #define LIBPMEMOBJ_CPP_ANNOTATE_HAPPENS_AFTER(order, ptr)
88 
89 #endif
90 
91 /*
92  * Workaround for missing "is_trivially_copyable" in gcc < 5.0.
93  * Be aware of a difference between __has_trivial_copy and is_trivially_copyable
94  * e.g. for deleted copy constructors __has_trivial_copy(A) returns 1 in clang
95  * and 0 in gcc. It means that for gcc < 5 LIBPMEMOBJ_CPP_IS_TRIVIALLY_COPYABLE
96  * is more restrictive than is_trivially_copyable.
97  */
98 #if !defined(LIBPMEMOBJ_CPP_USE_HAS_TRIVIAL_COPY)
99 #if !defined(__clang__) && defined(__GNUG__) && __GNUC__ < 5
100 #define LIBPMEMOBJ_CPP_USE_HAS_TRIVIAL_COPY 1
101 #else
102 #define LIBPMEMOBJ_CPP_USE_HAS_TRIVIAL_COPY 0
103 #endif
104 #endif
105 
106 #if LIBPMEMOBJ_CPP_USE_HAS_TRIVIAL_COPY
107 #define LIBPMEMOBJ_CPP_IS_TRIVIALLY_COPYABLE(T) __has_trivial_copy(T)
108 #else
109 #define LIBPMEMOBJ_CPP_IS_TRIVIALLY_COPYABLE(T) \
110  std::is_trivially_copyable<T>::value
111 #endif
112 
119 namespace pmem
120 {
127 namespace obj
128 {
129 template <typename T>
130 class persistent_ptr;
131 
139 namespace experimental
140 {
141 }
142 }
143 
150 namespace detail
151 {
152 
153 #if defined(__x86_64) || defined(_M_X64) || defined(__aarch64__) || \
154  defined(__riscv)
155 static constexpr size_t CACHELINE_SIZE = 64ULL;
156 #elif defined(__PPC64__)
157 static constexpr size_t CACHELINE_SIZE = 128ULL;
158 #else
159 #error unable to recognize architecture at compile time
160 #endif
161 
162 /*
163  * Conditionally add 'count' objects to a transaction.
164  *
165  * Adds count objects starting from `that` to the transaction if '*that' is
166  * within a pmemobj pool and there is an active transaction.
167  * Does nothing otherwise.
168  *
169  * @param[in] that pointer to the first object being added to the transaction.
170  * @param[in] count number of elements to be added to the transaction.
171  * @param[in] flags is a bitmask of values which are described in libpmemobj
172  * manpage (pmemobj_tx_xadd_range method)
173  */
174 template <typename T>
175 inline void
176 conditional_add_to_tx(const T *that, std::size_t count = 1, uint64_t flags = 0)
177 {
178  if (count == 0)
179  return;
180 
181  if (pmemobj_tx_stage() != TX_STAGE_WORK)
182  return;
183 
184  /* 'that' is not in any open pool */
185  if (!pmemobj_pool_by_ptr(that))
186  return;
187 
188  if (pmemobj_tx_xadd_range_direct(that, sizeof(*that) * count, flags)) {
189  if (errno == ENOMEM)
191  "Could not add object(s) to the transaction.")
192  .with_pmemobj_errormsg();
193  else
195  "Could not add object(s) to the transaction.")
196  .with_pmemobj_errormsg();
197  }
198 }
199 
200 /*
201  * Return type number for given type.
202  */
203 template <typename T>
204 uint64_t
205 type_num()
206 {
207  return typeid(T).hash_code();
208 }
209 
213 inline uint64_t
214 next_pow_2(uint64_t v)
215 {
216  v--;
217  v |= v >> 1;
218  v |= v >> 2;
219  v |= v >> 4;
220  v |= v >> 8;
221  v |= v >> 16;
222  v |= v >> 32;
223  ++v;
224  return v + (v == 0);
225 }
226 
230 inline uint64_t
231 next_pow_2(uint32_t v)
232 {
233  v--;
234  v |= v >> 1;
235  v |= v >> 2;
236  v |= v >> 4;
237  v |= v >> 8;
238  v |= v >> 16;
239  ++v;
240  return v + (v == 0);
241 }
242 
243 #if _MSC_VER
244 static inline int
245 Log2(uint64_t x)
246 {
247  unsigned long j;
248  _BitScanReverse64(&j, x);
249  return static_cast<int>(j);
250 }
251 #elif __GNUC__ || __clang__
252 static inline int
253 Log2(uint64_t x)
254 {
255  // __builtin_clz builtin count _number_ of leading zeroes
256  return 8 * int(sizeof(x)) - __builtin_clzll(x) - 1;
257 }
258 #else
259 static inline int
260 Log2(uint64_t x)
261 {
262  x |= (x >> 1);
263  x |= (x >> 2);
264  x |= (x >> 4);
265  x |= (x >> 8);
266  x |= (x >> 16);
267  x |= (x >> 32);
268 
269  static const int table[64] = {
270  0, 58, 1, 59, 47, 53, 2, 60, 39, 48, 27, 54, 33, 42, 3, 61,
271  51, 37, 40, 49, 18, 28, 20, 55, 30, 34, 11, 43, 14, 22, 4, 62,
272  57, 46, 52, 38, 26, 32, 41, 50, 36, 17, 19, 29, 10, 13, 21, 56,
273  45, 25, 31, 35, 16, 9, 12, 44, 24, 15, 8, 23, 7, 6, 5, 63};
274 
275  return table[(x * 0x03f6eaf2cd271461) >> 58];
276 }
277 #endif
278 
279 #ifndef _MSC_VER
280 
282 static inline uint8_t
283 mssb_index64(unsigned long long value)
284 {
285  return ((uint8_t)(63 - __builtin_clzll(value)));
286 }
287 
289 static inline uint8_t
290 mssb_index(unsigned int value)
291 {
292  return ((uint8_t)(31 - __builtin_clz(value)));
293 }
294 
295 #else
296 
297 static __inline uint8_t
298 mssb_index(unsigned long value)
299 {
300  unsigned long ret;
301  _BitScanReverse(&ret, value);
302  return (uint8_t)ret;
303 }
304 
305 static __inline uint8_t
306 mssb_index64(uint64_t value)
307 {
308  unsigned long ret;
309  _BitScanReverse64(&ret, value);
310  return (uint8_t)ret;
311 }
312 
313 #endif
314 
315 static constexpr size_t
316 align_up(size_t size, size_t align)
317 {
318  return ((size) + (align)-1) & ~((align)-1);
319 }
320 
321 static constexpr size_t
322 align_down(size_t size, size_t align)
323 {
324  return (size) & ~((align)-1);
325 }
326 
327 } /* namespace detail */
328 
329 } /* namespace pmem */
330 
331 #endif /* LIBPMEMOBJ_CPP_COMMON_HPP */
Custom transaction error class.
Definition: pexceptions.hpp:81
Custom out of memory error class.
Definition: pexceptions.hpp:138
uint64_t next_pow_2(uint64_t v)
Round up to the next lowest power of 2.
Definition: common.hpp:214
Persistent memory namespace.
Definition: allocation_flag.hpp:15
Custom exceptions.