• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #ifndef BASE_MEMORY_REF_COUNTED_H_
6 #define BASE_MEMORY_REF_COUNTED_H_
7 
8 #include <stddef.h>
9 
10 #include <utility>
11 
12 #include "base/atomic_ref_count.h"
13 #include "base/compiler_specific.h"
14 #include "base/logging.h"
15 #include "base/memory/scoped_refptr.h"
16 #include "util/build_config.h"
17 
18 namespace base {
19 namespace subtle {
20 
21 class RefCountedBase {
22  public:
HasOneRef()23   bool HasOneRef() const { return ref_count_ == 1; }
24 
25  protected:
RefCountedBase(StartRefCountFromZeroTag)26   explicit RefCountedBase(StartRefCountFromZeroTag) {}
27 
RefCountedBase(StartRefCountFromOneTag)28   explicit RefCountedBase(StartRefCountFromOneTag) : ref_count_(1) {}
29 
~RefCountedBase()30   ~RefCountedBase() {}
31 
AddRef()32   void AddRef() const { AddRefImpl(); }
33 
34   // Returns true if the object should self-delete.
Release()35   bool Release() const {
36     --ref_count_;
37 
38     // TODO(maruel): Add back once it doesn't assert 500 times/sec.
39     // Current thread books the critical section "AddRelease"
40     // without release it.
41     // DFAKE_SCOPED_LOCK_THREAD_LOCKED(add_release_);
42 
43     return ref_count_ == 0;
44   }
45 
46   // Returns true if it is safe to read or write the object, from a thread
47   // safety standpoint. Should be DCHECK'd from the methods of RefCounted
48   // classes if there is a danger of objects being shared across threads.
49   //
50   // This produces fewer false positives than adding a separate SequenceChecker
51   // into the subclass, because it automatically detaches from the sequence when
52   // the reference count is 1 (and never fails if there is only one reference).
53   //
54   // This means unlike a separate SequenceChecker, it will permit a singly
55   // referenced object to be passed between threads (not holding a reference on
56   // the sending thread), but will trap if the sending thread holds onto a
57   // reference, or if the object is accessed from multiple threads
58   // simultaneously.
IsOnValidSequence()59   bool IsOnValidSequence() const { return true; }
60 
61  private:
62   template <typename U>
63   friend scoped_refptr<U> base::AdoptRef(U*);
64 
Adopted()65   void Adopted() const {}
66 
67 #if defined(ARCH_CPU_64_BIT)
68   void AddRefImpl() const;
69 #else
AddRefImpl()70   void AddRefImpl() const { ++ref_count_; }
71 #endif
72 
73   mutable uint32_t ref_count_ = 0;
74 
75   RefCountedBase(const RefCountedBase&) = delete;
76   RefCountedBase& operator=(const RefCountedBase&) = delete;
77 };
78 
79 class RefCountedThreadSafeBase {
80  public:
81   bool HasOneRef() const;
82 
83  protected:
RefCountedThreadSafeBase(StartRefCountFromZeroTag)84   explicit constexpr RefCountedThreadSafeBase(StartRefCountFromZeroTag) {}
RefCountedThreadSafeBase(StartRefCountFromOneTag)85   explicit constexpr RefCountedThreadSafeBase(StartRefCountFromOneTag)
86       : ref_count_(1) {}
87 
88   ~RefCountedThreadSafeBase() = default;
89 
90 // Release and AddRef are suitable for inlining on X86 because they generate
91 // very small code sequences. On other platforms (ARM), it causes a size
92 // regression and is probably not worth it.
93 #if defined(ARCH_CPU_X86_FAMILY)
94   // Returns true if the object should self-delete.
Release()95   bool Release() const { return ReleaseImpl(); }
AddRef()96   void AddRef() const { AddRefImpl(); }
97 #else
98   // Returns true if the object should self-delete.
99   bool Release() const;
100   void AddRef() const;
101 #endif
102 
103  private:
104   template <typename U>
105   friend scoped_refptr<U> base::AdoptRef(U*);
106 
Adopted()107   void Adopted() const {}
108 
AddRefImpl()109   ALWAYS_INLINE void AddRefImpl() const { ref_count_.Increment(); }
110 
ReleaseImpl()111   ALWAYS_INLINE bool ReleaseImpl() const {
112     if (!ref_count_.Decrement()) {
113       return true;
114     }
115     return false;
116   }
117 
118   mutable AtomicRefCount ref_count_{0};
119 
120   RefCountedThreadSafeBase(const RefCountedThreadSafeBase&) = delete;
121   RefCountedThreadSafeBase& operator=(const RefCountedThreadSafeBase&) = delete;
122 };
123 
124 }  // namespace subtle
125 
126 // ScopedAllowCrossThreadRefCountAccess disables the check documented on
127 // RefCounted below for rare pre-existing use cases where thread-safety was
128 // guaranteed through other means (e.g. explicit sequencing of calls across
129 // execution sequences when bouncing between threads in order). New callers
130 // should refrain from using this (callsites handling thread-safety through
131 // locks should use RefCountedThreadSafe per the overhead of its atomics being
132 // negligible compared to locks anyways and callsites doing explicit sequencing
133 // should properly std::move() the ref to avoid hitting this check).
134 // TODO(tzik): Cleanup existing use cases and remove
135 // ScopedAllowCrossThreadRefCountAccess.
136 class ScopedAllowCrossThreadRefCountAccess final {
137  public:
ScopedAllowCrossThreadRefCountAccess()138   ScopedAllowCrossThreadRefCountAccess() {}
~ScopedAllowCrossThreadRefCountAccess()139   ~ScopedAllowCrossThreadRefCountAccess() {}
140 };
141 
142 //
143 // A base class for reference counted classes.  Otherwise, known as a cheap
144 // knock-off of WebKit's RefCounted<T> class.  To use this, just extend your
145 // class from it like so:
146 //
147 //   class MyFoo : public base::RefCounted<MyFoo> {
148 //    ...
149 //    private:
150 //     friend class base::RefCounted<MyFoo>;
151 //     ~MyFoo();
152 //   };
153 //
154 // You should always make your destructor non-public, to avoid any code deleting
155 // the object accidentally while there are references to it.
156 //
157 //
158 // The ref count manipulation to RefCounted is NOT thread safe and has DCHECKs
159 // to trap unsafe cross thread usage. A subclass instance of RefCounted can be
160 // passed to another execution sequence only when its ref count is 1. If the ref
161 // count is more than 1, the RefCounted class verifies the ref updates are made
162 // on the same execution sequence as the previous ones. The subclass can also
163 // manually call IsOnValidSequence to trap other non-thread-safe accesses; see
164 // the documentation for that method.
165 //
166 //
167 // The reference count starts from zero by default, and we intended to migrate
168 // to start-from-one ref count. Put REQUIRE_ADOPTION_FOR_REFCOUNTED_TYPE() to
169 // the ref counted class to opt-in.
170 //
171 // If an object has start-from-one ref count, the first scoped_refptr need to be
172 // created by base::AdoptRef() or base::MakeRefCounted(). We can use
173 // base::MakeRefCounted() to create create both type of ref counted object.
174 //
175 // The motivations to use start-from-one ref count are:
176 //  - Start-from-one ref count doesn't need the ref count increment for the
177 //    first reference.
178 //  - It can detect an invalid object acquisition for a being-deleted object
179 //    that has zero ref count. That tends to happen on custom deleter that
180 //    delays the deletion.
181 //    TODO(tzik): Implement invalid acquisition detection.
182 //  - Behavior parity to Blink's WTF::RefCounted, whose count starts from one.
183 //    And start-from-one ref count is a step to merge WTF::RefCounted into
184 //    base::RefCounted.
185 //
186 #define REQUIRE_ADOPTION_FOR_REFCOUNTED_TYPE()             \
187   static constexpr ::base::subtle::StartRefCountFromOneTag \
188       kRefCountPreference = ::base::subtle::kStartRefCountFromOneTag
189 
190 template <class T, typename Traits>
191 class RefCounted;
192 
193 template <typename T>
194 struct DefaultRefCountedTraits {
DestructDefaultRefCountedTraits195   static void Destruct(const T* x) {
196     RefCounted<T, DefaultRefCountedTraits>::DeleteInternal(x);
197   }
198 };
199 
200 template <class T, typename Traits = DefaultRefCountedTraits<T>>
201 class RefCounted : public subtle::RefCountedBase {
202  public:
203   static constexpr subtle::StartRefCountFromZeroTag kRefCountPreference =
204       subtle::kStartRefCountFromZeroTag;
205 
RefCounted()206   RefCounted() : subtle::RefCountedBase(T::kRefCountPreference) {}
207 
AddRef()208   void AddRef() const { subtle::RefCountedBase::AddRef(); }
209 
Release()210   void Release() const {
211     if (subtle::RefCountedBase::Release()) {
212       // Prune the code paths which the static analyzer may take to simulate
213       // object destruction. Use-after-free errors aren't possible given the
214       // lifetime guarantees of the refcounting system.
215       ANALYZER_SKIP_THIS_PATH();
216 
217       Traits::Destruct(static_cast<const T*>(this));
218     }
219   }
220 
221  protected:
222   ~RefCounted() = default;
223 
224  private:
225   friend struct DefaultRefCountedTraits<T>;
226   template <typename U>
227   static void DeleteInternal(const U* x) {
228     delete x;
229   }
230 
231   RefCounted(const RefCounted&) = delete;
232   RefCounted& operator=(const RefCounted&) = delete;
233 };
234 
235 // Forward declaration.
236 template <class T, typename Traits>
237 class RefCountedThreadSafe;
238 
239 // Default traits for RefCountedThreadSafe<T>.  Deletes the object when its ref
240 // count reaches 0.  Overload to delete it on a different thread etc.
241 template <typename T>
242 struct DefaultRefCountedThreadSafeTraits {
243   static void Destruct(const T* x) {
244     // Delete through RefCountedThreadSafe to make child classes only need to be
245     // friend with RefCountedThreadSafe instead of this struct, which is an
246     // implementation detail.
247     RefCountedThreadSafe<T, DefaultRefCountedThreadSafeTraits>::DeleteInternal(
248         x);
249   }
250 };
251 
252 //
253 // A thread-safe variant of RefCounted<T>
254 //
255 //   class MyFoo : public base::RefCountedThreadSafe<MyFoo> {
256 //    ...
257 //   };
258 //
259 // If you're using the default trait, then you should add compile time
260 // asserts that no one else is deleting your object.  i.e.
261 //    private:
262 //     friend class base::RefCountedThreadSafe<MyFoo>;
263 //     ~MyFoo();
264 //
265 // We can use REQUIRE_ADOPTION_FOR_REFCOUNTED_TYPE() with RefCountedThreadSafe
266 // too. See the comment above the RefCounted definition for details.
267 template <class T, typename Traits = DefaultRefCountedThreadSafeTraits<T>>
268 class RefCountedThreadSafe : public subtle::RefCountedThreadSafeBase {
269  public:
270   static constexpr subtle::StartRefCountFromZeroTag kRefCountPreference =
271       subtle::kStartRefCountFromZeroTag;
272 
273   explicit RefCountedThreadSafe()
274       : subtle::RefCountedThreadSafeBase(T::kRefCountPreference) {}
275 
276   void AddRef() const { subtle::RefCountedThreadSafeBase::AddRef(); }
277 
278   void Release() const {
279     if (subtle::RefCountedThreadSafeBase::Release()) {
280       ANALYZER_SKIP_THIS_PATH();
281       Traits::Destruct(static_cast<const T*>(this));
282     }
283   }
284 
285  protected:
286   ~RefCountedThreadSafe() = default;
287 
288  private:
289   friend struct DefaultRefCountedThreadSafeTraits<T>;
290   template <typename U>
291   static void DeleteInternal(const U* x) {
292     delete x;
293   }
294 
295   RefCountedThreadSafe(const RefCountedThreadSafe&) = delete;
296   RefCountedThreadSafe& operator=(const RefCountedThreadSafe&) = delete;
297 };
298 
299 //
300 // A thread-safe wrapper for some piece of data so we can place other
301 // things in scoped_refptrs<>.
302 //
303 template <typename T>
304 class RefCountedData
305     : public base::RefCountedThreadSafe<base::RefCountedData<T>> {
306  public:
307   RefCountedData() : data() {}
308   RefCountedData(const T& in_value) : data(in_value) {}
309   RefCountedData(T&& in_value) : data(std::move(in_value)) {}
310 
311   T data;
312 
313  private:
314   friend class base::RefCountedThreadSafe<base::RefCountedData<T>>;
315   ~RefCountedData() = default;
316 };
317 
318 }  // namespace base
319 
320 #endif  // BASE_MEMORY_REF_COUNTED_H_
321