proxygen
HazptrObjLinked.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 
20 
21 #include <glog/logging.h>
22 
23 #include <atomic>
24 #include <stack>
25 
29 
30 namespace folly {
31 
43 template <typename T, template <typename> class Atom>
44 class hazptr_root {
45  Atom<T*> link_;
46 
47  public:
48  explicit hazptr_root(T* p = nullptr) noexcept : link_(p) {}
49 
51  auto p = link_.load(std::memory_order_relaxed);
52  if (p) {
53  p->unlink();
54  }
55  }
56 
57  const Atom<T*>& operator()() const noexcept {
58  return link_;
59  }
60 
61  Atom<T*>& operator()() noexcept {
62  return link_;
63  }
64 }; // hazptr_root
65 
90 template <template <typename> class Atom>
91 class hazptr_obj_linked : public hazptr_obj<Atom> {
92  using Count = uint32_t;
93 
94  static constexpr Count kRef = 1u;
95  static constexpr Count kLink = 1u << 16;
96  static constexpr Count kRefMask = kLink - 1u;
97  static constexpr Count kLinkMask = ~kRefMask;
98 
99  Atom<Count> count_{0};
100 
101  public:
103  count_inc(kLink);
104  }
105 
107  count_inc_safe(kLink);
108  }
109 
111  count_inc(kRef);
112  }
113 
115  count_inc_safe(kRef);
116  }
117 
118  private:
119  template <typename, template <typename> class, typename>
121 
123  return count_.load(std::memory_order_acquire);
124  }
125 
127  count_.store(val, std::memory_order_release);
128  }
129 
131  auto oldval = count_.fetch_add(add, std::memory_order_acq_rel);
132  DCHECK_LT(oldval & kLinkMask, kLinkMask);
133  DCHECK_LT(oldval & kRefMask, kRefMask);
134  }
135 
137  auto oldval = count();
138  count_set(oldval + add);
139  DCHECK_LT(oldval & kLinkMask, kLinkMask);
140  DCHECK_LT(oldval & kRefMask, kRefMask);
141  }
142 
143  bool count_cas(Count& oldval, Count newval) noexcept {
144  return count_.compare_exchange_weak(
145  oldval, newval, std::memory_order_acq_rel, std::memory_order_acquire);
146  }
147 
149  auto sub = kLink;
150  auto oldval = count();
151  while (true) {
152  DCHECK_GT(oldval & kLinkMask, 0u);
153  if (oldval == kLink) {
154  count_set(0u);
155  return true;
156  }
157  if (count_cas(oldval, oldval - sub)) {
158  return false;
159  }
160  }
161  }
162 
164  auto sub = kRef;
165  auto oldval = count();
166  while (true) {
167  if (oldval == 0u) {
168  if (kIsDebug) {
169  count_set(kRefMask);
170  }
171  return true;
172  }
173  DCHECK_GT(oldval & kRefMask, 0u);
174  if (count_cas(oldval, oldval - sub)) {
175  return false;
176  }
177  }
178  }
179 
181  auto oldval = count();
182  auto sub = kLink - kRef;
183  while (true) {
184  if (oldval == kLink) {
185  count_set(kRef);
186  return true;
187  }
188  if (count_cas(oldval, oldval - sub)) {
189  return (oldval & kLinkMask) == kLink;
190  }
191  }
192  }
193 }; // hazptr_obj_linked
194 
233 template <typename T, template <typename> class Atom, typename D>
234 class hazptr_obj_base_linked : public hazptr_obj_linked<Atom>,
235  public hazptr_deleter<T, D> {
236  using Stack = std::stack<hazptr_obj_base_linked<T, Atom, D>*>;
237 
238  public:
239  void retire() {
240  this->pre_retire_check(); // defined in hazptr_obj
241  set_reclaim();
242  this->push_to_retired(
243  default_hazptr_domain<Atom>()); // defined in hazptr_obj
244  }
245 
246  /* unlink: Retire object if last link is released. */
247  void unlink() {
248  if (this->release_link()) { // defined in hazptr_obj_linked
249  downgrade_retire_immutable_descendants();
250  retire();
251  }
252  }
253 
254  /* unlink_and_reclaim_unchecked: Reclaim object if the last link is
255  released, without checking hazard pointers. To be called only
256  when the object cannot possibly be protected by any hazard
257  pointers. */
259  if (this->release_link()) { // defined in hazptr_obj_linked
260  DCHECK_EQ(this->count(), 0u);
261  delete_self();
262  }
263  }
264 
265  private:
267  this->reclaim_ = [](hazptr_obj<Atom>* p, hazptr_obj_list<Atom>& l) {
268  auto obj = static_cast<hazptr_obj_base_linked<T, Atom, D>*>(p);
269  if (obj->release_ref()) { // defined in hazptr_obj_linked
271  obj->release_retire_mutable_children(l);
272  obj->delete_self();
273  }
274  };
275  }
276 
278  Stack s;
279  call_push_links(false, s);
280  while (!s.empty()) {
281  auto p = s.top();
282  s.pop();
283  if (p && p->downgrade_link()) {
284  p->call_push_links(false, s);
285  p->retire();
286  }
287  }
288  }
289 
291  Stack s;
292  call_push_links(false, s);
293  while (!s.empty()) {
294  auto p = s.top();
295  s.pop();
296  if (p && p->release_ref()) {
297  p->call_push_links(false, s);
298  p->delete_self();
299  }
300  }
301  }
302 
304  Stack s;
305  call_push_links(true, s);
306  while (!s.empty()) {
307  auto p = s.top();
308  s.pop();
309  if (p->release_link()) {
310  p->pre_retire_check(); // defined in hazptr_obj
311  p->set_reclaim();
312  l.push(p); // treated as if retired immediately
313  }
314  }
315  }
316 
317  void call_push_links(bool m, Stack& s) {
318  static_cast<T*>(this)->push_links(m, s); // to be defined in T
319  }
320 
321  void delete_self() {
322  this->delete_obj(static_cast<T*>(this)); // defined in hazptr_deleter
323  }
324 }; // hazptr_obj_base_linked
325 
326 } // namespace folly
Sub sub(Sink sink)
Definition: Parallel.h:104
Count count() const noexcept
constexpr auto kIsDebug
Definition: Portability.h:264
void acquire_link() noexcept
auto add
Definition: BaseTest.cpp:70
void push(hazptr_obj< Atom > *obj)
Definition: HazptrObj.h:160
bool count_cas(Count &oldval, Count newval) noexcept
void count_inc_safe(Count add) noexcept
double val
Definition: String.cpp:273
folly::std T
—— Concurrent Priority Queue Implementation ——
Definition: AtomicBitSet.h:29
requires E e noexcept(noexcept(s.error(std::move(e))))
void count_inc(Count add) noexcept
const Atom< T * > & operator()() const noexcept
void count_set(Count val) noexcept
bool downgrade_link() noexcept
#define D(name, bit)
Definition: CpuId.h:145
#define Atom
Atom< T * > & operator()() noexcept
static map< string, int > m
bool release_ref() noexcept
int * count
void acquire_ref_safe() noexcept
hazptr_root(T *p=nullptr) noexcept
std::stack< hazptr_obj_base_linked< NodeAuto< Atom >, Atom, D > * > Stack
static set< string > s
const
Definition: upload.py:398
void acquire_ref() noexcept
void release_retire_mutable_children(hazptr_obj_list< Atom > &l)
void acquire_link_safe() noexcept
void call_push_links(bool m, Stack &s)
bool release_link() noexcept