proxygen
AtomicSharedPtr-detail.h
Go to the documentation of this file.
1 /*
2  * Copyright 2017-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 #include <atomic>
18 #include <memory>
19 
20 #include <folly/lang/SafeAssert.h>
21 
22 namespace folly {
23 namespace detail {
24 
25 // This implementation is specific to libstdc++, now accepting
26 // diffs for other libraries.
27 
28 // Specifically, this adds support for two things:
29 // 1) incrementing/decrementing the shared count by more than 1 at a time
30 // 2) Getting the thing the shared_ptr points to, which may be different from
31 // the aliased pointer.
32 
34  public:
35  template <typename T, typename... Args>
36  static std::shared_ptr<T> make_ptr(Args&&... args) {
37  return std::make_shared<T>(std::forward<Args...>(args...));
38  }
39  typedef std::__shared_count<std::_S_atomic> shared_count;
40  typedef std::_Sp_counted_base<std::_S_atomic> counted_base;
41  template <typename T>
42  using CountedPtr = std::shared_ptr<T>;
43 
44  template <typename T>
45  static counted_base* get_counted_base(const std::shared_ptr<T>& bar);
46 
47  static void inc_shared_count(counted_base* base, long count);
48 
49  template <typename T>
50  static void release_shared(counted_base* base, long count);
51 
52  template <typename T>
53  static T* get_shared_ptr(counted_base* base);
54 
55  template <typename T>
56  static T* release_ptr(std::shared_ptr<T>& p);
57 
58  template <typename T>
59  static std::shared_ptr<T> get_shared_ptr_from_counted_base(
60  counted_base* base,
61  bool inc = true);
62 
63  private:
64  /* Accessors for private members using explicit template instantiation */
66  typedef shared_count std::__shared_ptr<const void, std::_S_atomic>::*type;
68  };
69 
70  struct access_base {
71  typedef counted_base* shared_count::*type;
72  friend type fieldPtr(access_base);
73  };
74 
76  typedef _Atomic_word counted_base::*type;
78  };
79 
81  typedef _Atomic_word counted_base::*type;
83  };
84 
86  typedef const void* std::_Sp_counted_ptr<const void*, std::_S_atomic>::*
87  type;
89  };
90 
92  typedef const void* std::__shared_ptr<const void, std::_S_atomic>::*type;
94  };
95 
96  struct access_refcount {
97  typedef shared_count std::__shared_ptr<const void, std::_S_atomic>::*type;
99  };
100 
101  template <typename Tag, typename Tag::type M>
102  struct Rob {
103  friend typename Tag::type fieldPtr(Tag) {
104  return M;
105  }
106  };
107 };
108 
109 template struct shared_ptr_internals::Rob<
111  &std::__shared_ptr<const void, std::_S_atomic>::_M_refcount>;
112 template struct shared_ptr_internals::Rob<
114  &shared_ptr_internals::shared_count::_M_pi>;
115 template struct shared_ptr_internals::Rob<
117  &shared_ptr_internals::counted_base::_M_use_count>;
118 template struct shared_ptr_internals::Rob<
120  &shared_ptr_internals::counted_base::_M_weak_count>;
121 template struct shared_ptr_internals::Rob<
123  &std::_Sp_counted_ptr<const void*, std::_S_atomic>::_M_ptr>;
124 template struct shared_ptr_internals::Rob<
126  &std::__shared_ptr<const void, std::_S_atomic>::_M_ptr>;
127 template struct shared_ptr_internals::Rob<
129  &std::__shared_ptr<const void, std::_S_atomic>::_M_refcount>;
130 
131 template <typename T>
133 shared_ptr_internals::get_counted_base(const std::shared_ptr<T>& bar) {
134  // reinterpret_pointer_cast<const void>
135  // Not quite C++ legal, but explicit template instantiation access to
136  // private members requires full type name (i.e. shared_ptr<const void>, not
137  // shared_ptr<T>)
138  const std::shared_ptr<const void>& ptr(
139  reinterpret_cast<const std::shared_ptr<const void>&>(bar));
140  return (ptr.*fieldPtr(access_shared_ptr{})).*fieldPtr(access_base{});
141 }
142 
144  counted_base* base,
145  long count) {
146  // Check that we don't exceed the maximum number of atomic_shared_ptrs.
147  // Consider setting EXTERNAL_COUNT lower if this CHECK is hit.
149  base->_M_get_use_count() + count < INT_MAX, "atomic_shared_ptr overflow");
150  __gnu_cxx::__atomic_add_dispatch(
151  &(base->*fieldPtr(access_use_count{})), count);
152 }
153 
154 template <typename T>
156  counted_base* base,
157  long count) {
158  // If count == 1, this is equivalent to base->_M_release()
159  if (__gnu_cxx::__exchange_and_add_dispatch(
160  &(base->*fieldPtr(access_use_count{})), -count) == count) {
161  base->_M_dispose();
162 
163  if (__gnu_cxx::__exchange_and_add_dispatch(
164  &(base->*fieldPtr(access_weak_count{})), -1) == 1) {
165  base->_M_destroy();
166  }
167  }
168 }
169 
170 template <typename T>
172  // See if this was a make_shared allocation
173  auto inplace = base->_M_get_deleter(typeid(std::_Sp_make_shared_tag));
174  if (inplace) {
175  return (T*)inplace;
176  }
177  // Could also be a _Sp_counted_deleter, but the layout is the same
178  using derived_type = std::_Sp_counted_ptr<const void*, std::_S_atomic>;
179  auto ptr = reinterpret_cast<derived_type*>(base);
180  return (T*)(ptr->*fieldPtr(access_counted_ptr_ptr{}));
181 }
182 
183 template <typename T>
184 inline T* shared_ptr_internals::release_ptr(std::shared_ptr<T>& p) {
185  auto res = p.get();
186  std::shared_ptr<const void>& ptr(
187  reinterpret_cast<std::shared_ptr<const void>&>(p));
188  ptr.*fieldPtr(access_shared_ptr_ptr{}) = nullptr;
189  (ptr.*fieldPtr(access_refcount{})).*fieldPtr(access_base{}) = nullptr;
190  return res;
191 }
192 
193 template <typename T>
194 inline std::shared_ptr<T>
196  counted_base* base,
197  bool inc) {
198  if (!base) {
199  return nullptr;
200  }
201  std::shared_ptr<const void> newp;
202  if (inc) {
203  inc_shared_count(base, 1);
204  }
206  get_shared_ptr<const void>(base); // _M_ptr
207  (newp.*fieldPtr(access_refcount{})).*fieldPtr(access_base{}) = base;
208  // reinterpret_pointer_cast<T>
209  auto res = reinterpret_cast<std::shared_ptr<T>*>(&newp);
210  return std::move(*res);
211 }
212 
213 } // namespace detail
214 } // namespace folly
static void release_shared(counted_base *base, long count)
void * ptr
std::_Sp_counted_base< std::_S_atomic > counted_base
PskType type
constexpr detail::Map< Move > move
Definition: Base-inl.h:2567
static counted_base * get_counted_base(const std::shared_ptr< T > &bar)
folly::std T
internal::ArgsMatcher< InnerMatcher > Args(const InnerMatcher &matcher)
—— Concurrent Priority Queue Implementation ——
Definition: AtomicBitSet.h:29
static std::shared_ptr< T > make_ptr(Args &&...args)
#define FOLLY_SAFE_CHECK(expr, msg)
Definition: SafeAssert.h:35
**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
std::__shared_count< std::_S_atomic > shared_count
int * count
static void inc_shared_count(counted_base *base, long count)
static T * get_shared_ptr(counted_base *base)
static std::shared_ptr< T > get_shared_ptr_from_counted_base(counted_base *base, bool inc=true)
static T * release_ptr(std::shared_ptr< T > &p)