proxygen
HazptrHolder.h
Go to the documentation of this file.
1 /*
2  * Copyright 2018-present Facebook, Inc.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 #pragma once
17 
22 
24 
25 namespace folly {
26 
30 
51 template <template <typename> class Atom>
52 class hazptr_holder {
54 
55  public:
58  hazptr_domain<Atom>& domain = default_hazptr_domain<Atom>()) {
59 #if FOLLY_HAZPTR_THR_LOCAL
60  if (LIKELY(&domain == &default_hazptr_domain<Atom>())) {
61  auto hprec = hazptr_tc_tls<Atom>().try_get();
62  if (LIKELY(hprec != nullptr)) {
63  hprec_ = hprec;
64  return;
65  }
66  }
67 #endif
68  hprec_ = domain.hprec_acquire();
69  }
70 
72  FOLLY_ALWAYS_INLINE explicit hazptr_holder(std::nullptr_t) noexcept
73  : hprec_(nullptr) {}
74 
77  hprec_ = rhs.hprec_;
78  rhs.hprec_ = nullptr;
79  }
80 
81  hazptr_holder(const hazptr_holder&) = delete;
82  hazptr_holder& operator=(const hazptr_holder&) = delete;
83 
86  if (LIKELY(hprec_ != nullptr)) {
87  hprec_->reset_hazptr();
88  auto domain = hprec_->domain();
89 #if FOLLY_HAZPTR_THR_LOCAL
90  if (LIKELY(domain == &default_hazptr_domain<Atom>())) {
91  if (LIKELY(hazptr_tc_tls<Atom>().try_put(hprec_))) {
92  return;
93  }
94  }
95 #endif
96  domain->hprec_release(hprec_);
97  }
98  }
99 
102  /* Self-move is a no-op. */
103  if (LIKELY(this != &rhs)) {
104  this->~hazptr_holder();
105  new (this) hazptr_holder(nullptr);
106  hprec_ = rhs.hprec_;
107  rhs.hprec_ = nullptr;
108  }
109  return *this;
110  }
111 
115  template <typename T>
116  FOLLY_ALWAYS_INLINE bool try_protect(T*& ptr, const Atom<T*>& src) noexcept {
117  return try_protect(ptr, src, [](T* t) { return t; });
118  }
119 
120  template <typename T, typename Func>
122  try_protect(T*& ptr, const Atom<T*>& src, Func f) noexcept {
123  /* Filtering the protected pointer through function Func is useful
124  for stealing bits of the pointer word */
125  auto p = ptr;
126  reset(f(p));
127  /*** Full fence ***/ folly::asymmetricLightBarrier();
128  ptr = src.load(std::memory_order_acquire);
129  if (UNLIKELY(p != ptr)) {
130  reset();
131  return false;
132  }
133  return true;
134  }
135 
137  template <typename T>
138  FOLLY_ALWAYS_INLINE T* get_protected(const Atom<T*>& src) noexcept {
139  return get_protected(src, [](T* t) { return t; });
140  }
141 
142  template <typename T, typename Func>
144  T* ptr = src.load(std::memory_order_relaxed);
145  while (!try_protect(ptr, src, f)) {
146  /* Keep trying */;
147  }
148  return ptr;
149  }
150 
152  template <typename T>
154  auto p = static_cast<hazptr_obj<Atom>*>(const_cast<T*>(ptr));
155  DCHECK(hprec_); // UB if *this is empty
156  hprec_->reset_hazptr(p);
157  }
158 
159  FOLLY_ALWAYS_INLINE void reset(std::nullptr_t = nullptr) noexcept {
160  DCHECK(hprec_); // UB if *this is empty
161  hprec_->reset_hazptr();
162  }
163 
164  /* Swap ownership of hazard pointers between hazptr_holder-s. */
165  /* Note: The owned hazard pointers remain unmodified during the swap
166  * and continue to protect the respective objects that they were
167  * protecting before the swap, if any. */
169  std::swap(this->hprec_, rhs.hprec_);
170  }
171 
174  return hprec_;
175  }
176 
179  hprec_ = hprec;
180  }
181 }; // hazptr_holder
182 
186 template <template <typename> class Atom>
188  hazptr_holder<Atom>& lhs,
190  lhs.swap(rhs);
191 }
192 
196 template <template <typename> class Atom>
197 using aligned_hazptr_holder = typename std::aligned_storage<
198  sizeof(hazptr_holder<Atom>),
200 
216 template <uint8_t M, template <typename> class Atom>
217 class hazptr_array {
218  static_assert(M > 0, "M must be a positive integer.");
219 
221  bool empty_{false};
222 
223  public:
226  auto h = reinterpret_cast<hazptr_holder<Atom>*>(&raw_);
227 #if FOLLY_HAZPTR_THR_LOCAL
228  static_assert(
230  "M must be within the thread cache capacity.");
231  auto& tc = hazptr_tc_tls<Atom>();
232  auto count = tc.count();
233  if (UNLIKELY(M > count)) {
234  tc.fill(M - count);
235  count = M;
236  }
237  uint8_t offset = count - M;
238  for (uint8_t i = 0; i < M; ++i) {
239  auto hprec = tc[offset + i].get();
240  DCHECK(hprec != nullptr);
241  new (&h[i]) hazptr_holder<Atom>(nullptr);
242  h[i].set_hprec(hprec);
243  }
244  tc.set_count(offset);
245 #else
246  for (uint8_t i = 0; i < M; ++i) {
247  new (&h[i]) hazptr_holder<Atom>;
248  }
249 #endif
250  }
251 
254  auto h = reinterpret_cast<hazptr_holder<Atom>*>(&raw_);
255  for (uint8_t i = 0; i < M; ++i) {
256  new (&h[i]) hazptr_holder<Atom>(nullptr);
257  }
258  empty_ = true;
259  }
260 
263  auto h = reinterpret_cast<hazptr_holder<Atom>*>(&raw_);
264  auto hother = reinterpret_cast<hazptr_holder<Atom>*>(&other.raw_);
265  for (uint8_t i = 0; i < M; ++i) {
266  new (&h[i]) hazptr_holder<Atom>(std::move(hother[i]));
267  }
268  empty_ = other.empty_;
269  other.empty_ = true;
270  }
271 
272  hazptr_array(const hazptr_array&) = delete;
273  hazptr_array& operator=(const hazptr_array&) = delete;
274 
277  if (empty_) {
278  return;
279  }
280  auto h = reinterpret_cast<hazptr_holder<Atom>*>(&raw_);
281 #if FOLLY_HAZPTR_THR_LOCAL
282  auto& tc = hazptr_tc_tls<Atom>();
283  auto count = tc.count();
284  auto cap = hazptr_tc<Atom>::capacity();
285  if (UNLIKELY((M + count) > cap)) {
286  tc.evict((M + count) - cap);
287  count = cap - M;
288  }
289  for (uint8_t i = 0; i < M; ++i) {
290  h[i].reset();
291  tc[count + i].fill(h[i].hprec());
292  new (&h[i]) hazptr_holder<Atom>(nullptr);
293  }
294  tc.set_count(count + M);
295 #else
296  for (uint8_t i = 0; i < M; ++i) {
297  h[i].~hazptr_holder();
298  }
299 #endif
300  }
301 
304  auto h = reinterpret_cast<hazptr_holder<Atom>*>(&raw_);
305  for (uint8_t i = 0; i < M; ++i) {
306  h[i] = std::move(other[i]);
307  }
308  empty_ = other.empty_;
309  other.empty_ = true;
310  return *this;
311  }
312 
315  auto h = reinterpret_cast<hazptr_holder<Atom>*>(&raw_);
316  DCHECK(i < M);
317  return h[i];
318  }
319 }; // hazptr_array
320 
334 template <uint8_t M, template <typename> class Atom>
335 class hazptr_local {
336  static_assert(M > 0, "M must be a positive integer.");
337 
339 
340  public:
343  auto h = reinterpret_cast<hazptr_holder<Atom>*>(&raw_);
344 #if FOLLY_HAZPTR_THR_LOCAL
345  static_assert(
347  "M must be <= hazptr_tc::capacity().");
348  auto& tc = hazptr_tc_tls<Atom>();
349  auto count = tc.count();
350  if (UNLIKELY(M > count)) {
351  tc.fill(M - count);
352  }
353  if (kIsDebug) {
354  DCHECK(!tc.local());
355  tc.set_local(true);
356  }
357  for (uint8_t i = 0; i < M; ++i) {
358  auto hprec = tc[i].get();
359  DCHECK(hprec != nullptr);
360  new (&h[i]) hazptr_holder<Atom>(nullptr);
361  h[i].set_hprec(hprec);
362  }
363 #else
364  for (uint8_t i = 0; i < M; ++i) {
365  new (&h[i]) hazptr_holder<Atom>;
366  }
367 #endif
368  }
369 
370  hazptr_local(const hazptr_local&) = delete;
371  hazptr_local& operator=(const hazptr_local&) = delete;
372  hazptr_local(hazptr_local&&) = delete;
373  hazptr_local& operator=(hazptr_local&&) = delete;
374 
377  auto h = reinterpret_cast<hazptr_holder<Atom>*>(&raw_);
378 #if FOLLY_HAZPTR_THR_LOCAL
379  if (kIsDebug) {
380  auto& tc = hazptr_tc_tls<Atom>();
381  DCHECK(tc.local());
382  tc.set_local(false);
383  }
384  for (uint8_t i = 0; i < M; ++i) {
385  h[i].reset();
386  }
387 #else
388  for (uint8_t i = 0; i < M; ++i) {
389  h[i].~hazptr_holder();
390  }
391 #endif
392  }
393 
396  auto h = reinterpret_cast<hazptr_holder<Atom>*>(&raw_);
397  DCHECK(i < M);
398  return h[i];
399  }
400 }; // hazptr_local
401 
402 } // namespace folly
void * ptr
*than *hazptr_holder h
Definition: Hazptr.h:116
auto f
FOLLY_ALWAYS_INLINE hazptr_holder & operator=(hazptr_holder &&rhs) noexcept
Definition: HazptrHolder.h:101
constexpr auto kIsDebug
Definition: Portability.h:264
FOLLY_ALWAYS_INLINE bool try_protect(T *&ptr, const Atom< T * > &src) noexcept
Definition: HazptrHolder.h:116
#define FOLLY_ALWAYS_INLINE
Definition: CPortability.h:151
FOLLY_ALWAYS_INLINE T * get_protected(const Atom< T * > &src) noexcept
Definition: HazptrHolder.h:138
PskType type
FOLLY_ALWAYS_INLINE hazptr_holder(hazptr_holder &&rhs) noexcept
Definition: HazptrHolder.h:76
FOLLY_ALWAYS_INLINE hazptr_array & operator=(hazptr_array &&other) noexcept
Definition: HazptrHolder.h:303
constexpr detail::Map< Move > move
Definition: Base-inl.h:2567
#define LIKELY(x)
Definition: Likely.h:47
folly::std T
FOLLY_ALWAYS_INLINE void reset(std::nullptr_t=nullptr) noexcept
Definition: HazptrHolder.h:159
—— Concurrent Priority Queue Implementation ——
Definition: AtomicBitSet.h:29
FOLLY_ALWAYS_INLINE hazptr_local()
Definition: HazptrHolder.h:342
requires E e noexcept(noexcept(s.error(std::move(e))))
hazptr_rec< Atom > * hprec_
Definition: HazptrHolder.h:53
FOLLY_PUSH_WARNING RHS rhs
Definition: Traits.h:649
FOLLY_ALWAYS_INLINE ~hazptr_local()
Definition: HazptrHolder.h:376
FOLLY_ALWAYS_INLINE hazptr_holder< Atom > & operator[](uint8_t i) noexcept
Definition: HazptrHolder.h:314
FOLLY_ALWAYS_INLINE hazptr_array(std::nullptr_t) noexcept
Definition: HazptrHolder.h:253
FOLLY_ALWAYS_INLINE ~hazptr_holder()
Definition: HazptrHolder.h:85
#define Atom
FOLLY_ALWAYS_INLINE T * get_protected(const Atom< T * > &src, Func f) noexcept
Definition: HazptrHolder.h:143
static bool tc
FOLLY_ALWAYS_INLINE bool try_protect(T *&ptr, const Atom< T * > &src, Func f) noexcept
Definition: HazptrHolder.h:122
FOLLY_ALWAYS_INLINE void set_hprec(hazptr_rec< Atom > *hprec) noexcept
Definition: HazptrHolder.h:178
FOLLY_ALWAYS_INLINE void asymmetricLightBarrier()
typename std::aligned_storage< sizeof(hazptr_holder< Atom >), alignof(hazptr_holder< Atom >)>::type aligned_hazptr_holder
Definition: HazptrHolder.h:199
FOLLY_ALWAYS_INLINE hazptr_holder(hazptr_domain< Atom > &domain=default_hazptr_domain< Atom >())
Definition: HazptrHolder.h:57
**Optimized Holders **The template hazptr_array< M > provides most of the functionality *of M hazptr_holder s but with faster construction destruction *for M
Definition: Hazptr.h:104
FOLLY_ALWAYS_INLINE hazptr_domain< Atom > * domain()
Definition: HazptrRec.h:77
int * count
FOLLY_ALWAYS_INLINE void swap(hazptr_holder< Atom > &lhs, hazptr_holder< Atom > &rhs) noexcept
Definition: HazptrHolder.h:187
const
Definition: upload.py:398
FOLLY_ALWAYS_INLINE void reset_hazptr(const void *p=nullptr) noexcept
Definition: HazptrRec.h:46
FOLLY_ALWAYS_INLINE hazptr_holder< Atom > & operator[](uint8_t i) noexcept
Definition: HazptrHolder.h:395
hazptr_holder & operator=(const hazptr_holder &)=delete
FOLLY_ALWAYS_INLINE hazptr_array()
Definition: HazptrHolder.h:225
FOLLY_ALWAYS_INLINE void reset(const T *ptr) noexcept
Definition: HazptrHolder.h:153
FOLLY_ALWAYS_INLINE hazptr_rec< Atom > * hprec() const noexcept
Definition: HazptrHolder.h:173
#define UNLIKELY(x)
Definition: Likely.h:48
FOLLY_ALWAYS_INLINE hazptr_holder(std::nullptr_t) noexcept
Definition: HazptrHolder.h:72
FOLLY_ALWAYS_INLINE ~hazptr_array()
Definition: HazptrHolder.h:276
FOLLY_ALWAYS_INLINE void swap(hazptr_holder< Atom > &rhs) noexcept
Definition: HazptrHolder.h:168
FOLLY_ALWAYS_INLINE hazptr_array(hazptr_array &&other) noexcept
Definition: HazptrHolder.h:262