• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2012 The Chromium Authors
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/base_export.h"
14 #include "base/check.h"
15 #include "base/check_op.h"
16 #include "base/compiler_specific.h"
17 #include "base/dcheck_is_on.h"
18 // TODO(dcheng): Remove this separately.
19 #include "base/gtest_prod_util.h"
20 #include "base/memory/scoped_refptr.h"
21 #include "base/sequence_checker.h"
22 #include "base/template_util.h"
23 #include "base/threading/thread_collision_warner.h"
24 #include "build/build_config.h"
25 #include "third_party/abseil-cpp/absl/utility/utility.h"
26 
27 namespace base {
28 namespace subtle {
29 
30 class BASE_EXPORT RefCountedBase {
31  public:
32   RefCountedBase(const RefCountedBase&) = delete;
33   RefCountedBase& operator=(const RefCountedBase&) = delete;
34 
HasOneRef()35   bool HasOneRef() const { return ref_count_ == 1; }
HasAtLeastOneRef()36   bool HasAtLeastOneRef() const { return ref_count_ >= 1; }
37 
38  protected:
RefCountedBase(StartRefCountFromZeroTag)39   explicit RefCountedBase(StartRefCountFromZeroTag) {
40 #if DCHECK_IS_ON()
41     sequence_checker_.DetachFromSequence();
42 #endif
43   }
44 
RefCountedBase(StartRefCountFromOneTag)45   explicit RefCountedBase(StartRefCountFromOneTag) : ref_count_(1) {
46 #if DCHECK_IS_ON()
47     needs_adopt_ref_ = true;
48     sequence_checker_.DetachFromSequence();
49 #endif
50   }
51 
~RefCountedBase()52   ~RefCountedBase() {
53 #if DCHECK_IS_ON()
54     // RefCounted object deleted without calling Release()
55     DCHECK(in_dtor_);
56 #endif
57   }
58 
AddRef()59   void AddRef() const {
60 #if DCHECK_IS_ON()
61     DCHECK(!in_dtor_);
62     // This RefCounted object is created with non-zero reference count.
63     // The first reference to such a object has to be made by AdoptRef or
64     // MakeRefCounted.
65     DCHECK(!needs_adopt_ref_);
66     if (ref_count_ >= 1) {
67       DCHECK(CalledOnValidSequence());
68     }
69 #endif
70 
71     AddRefImpl();
72   }
73 
74   // Returns true if the object should self-delete.
Release()75   bool Release() const {
76     ReleaseImpl();
77 
78 #if DCHECK_IS_ON()
79     DCHECK(!in_dtor_);
80     if (ref_count_ == 0)
81       in_dtor_ = true;
82 
83     if (ref_count_ >= 1)
84       DCHECK(CalledOnValidSequence());
85     if (ref_count_ == 1)
86       sequence_checker_.DetachFromSequence();
87 #endif
88 
89     return ref_count_ == 0;
90   }
91 
92   // Returns true if it is safe to read or write the object, from a thread
93   // safety standpoint. Should be DCHECK'd from the methods of RefCounted
94   // classes if there is a danger of objects being shared across threads.
95   //
96   // This produces fewer false positives than adding a separate SequenceChecker
97   // into the subclass, because it automatically detaches from the sequence when
98   // the reference count is 1 (and never fails if there is only one reference).
99   //
100   // This means unlike a separate SequenceChecker, it will permit a singly
101   // referenced object to be passed between threads (not holding a reference on
102   // the sending thread), but will trap if the sending thread holds onto a
103   // reference, or if the object is accessed from multiple threads
104   // simultaneously.
IsOnValidSequence()105   bool IsOnValidSequence() const {
106 #if DCHECK_IS_ON()
107     return ref_count_ <= 1 || CalledOnValidSequence();
108 #else
109     return true;
110 #endif
111   }
112 
113  private:
114   template <typename U>
115   friend scoped_refptr<U> base::AdoptRef(U*);
116 
117   friend class RefCountedOverflowTest;
118 
Adopted()119   void Adopted() const {
120 #if DCHECK_IS_ON()
121     DCHECK(needs_adopt_ref_);
122     needs_adopt_ref_ = false;
123 #endif
124   }
125 
126 #if defined(ARCH_CPU_64_BITS)
127   void AddRefImpl() const;
128   void ReleaseImpl() const;
129 #else
AddRefImpl()130   void AddRefImpl() const { ++ref_count_; }
ReleaseImpl()131   void ReleaseImpl() const { --ref_count_; }
132 #endif
133 
134 #if DCHECK_IS_ON()
135   bool CalledOnValidSequence() const;
136 #endif
137 
138   mutable uint32_t ref_count_ = 0;
139   static_assert(std::is_unsigned<decltype(ref_count_)>::value,
140                 "ref_count_ must be an unsigned type.");
141 
142 #if DCHECK_IS_ON()
143   mutable bool needs_adopt_ref_ = false;
144   mutable bool in_dtor_ = false;
145   mutable SequenceChecker sequence_checker_;
146 #endif
147 
148   DFAKE_MUTEX(add_release_);
149 };
150 
151 class BASE_EXPORT RefCountedThreadSafeBase {
152  public:
153   RefCountedThreadSafeBase(const RefCountedThreadSafeBase&) = delete;
154   RefCountedThreadSafeBase& operator=(const RefCountedThreadSafeBase&) = delete;
155 
156   bool HasOneRef() const;
157   bool HasAtLeastOneRef() const;
158 
159  protected:
RefCountedThreadSafeBase(StartRefCountFromZeroTag)160   explicit constexpr RefCountedThreadSafeBase(StartRefCountFromZeroTag) {}
RefCountedThreadSafeBase(StartRefCountFromOneTag)161   explicit constexpr RefCountedThreadSafeBase(StartRefCountFromOneTag)
162       : ref_count_(1) {
163 #if DCHECK_IS_ON()
164     needs_adopt_ref_ = true;
165 #endif
166   }
167 
168 #if DCHECK_IS_ON()
169   ~RefCountedThreadSafeBase();
170 #else
171   ~RefCountedThreadSafeBase() = default;
172 #endif
173 
174 // Release and AddRef are suitable for inlining on X86 because they generate
175 // very small code sequences.
176 //
177 // ARM64 devices supporting ARMv8.1-A atomic instructions generate very little
178 // code, e.g. fetch_add() with acquire ordering is a single instruction (ldadd),
179 // vs LL/SC in previous ARM architectures. Inline it there as well.
180 //
181 // On other platforms (e.g. ARM), it causes a size regression and is probably
182 // not worth it.
183 #if defined(ARCH_CPU_X86_FAMILY) || defined(__ARM_FEATURE_ATOMICS)
184   // Returns true if the object should self-delete.
Release()185   bool Release() const { return ReleaseImpl(); }
AddRef()186   void AddRef() const { AddRefImpl(); }
AddRefWithCheck()187   void AddRefWithCheck() const { AddRefWithCheckImpl(); }
188 #else
189   // Returns true if the object should self-delete.
190   bool Release() const;
191   void AddRef() const;
192   void AddRefWithCheck() const;
193 #endif
194 
195  private:
196   template <typename U>
197   friend scoped_refptr<U> base::AdoptRef(U*);
198 
199   friend class RefCountedOverflowTest;
200 
Adopted()201   void Adopted() const {
202 #if DCHECK_IS_ON()
203     DCHECK(needs_adopt_ref_);
204     needs_adopt_ref_ = false;
205 #endif
206   }
207 
AddRefImpl()208   ALWAYS_INLINE void AddRefImpl() const {
209 #if DCHECK_IS_ON()
210     DCHECK(!in_dtor_);
211     // This RefCounted object is created with non-zero reference count.
212     // The first reference to such a object has to be made by AdoptRef or
213     // MakeRefCounted.
214     DCHECK(!needs_adopt_ref_);
215 #endif
216     CHECK_NE(ref_count_.Increment(), std::numeric_limits<int>::max());
217   }
218 
AddRefWithCheckImpl()219   ALWAYS_INLINE void AddRefWithCheckImpl() const {
220 #if DCHECK_IS_ON()
221     DCHECK(!in_dtor_);
222     // This RefCounted object is created with non-zero reference count.
223     // The first reference to such a object has to be made by AdoptRef or
224     // MakeRefCounted.
225     DCHECK(!needs_adopt_ref_);
226 #endif
227     int pre_increment_count = ref_count_.Increment();
228     CHECK_GT(pre_increment_count, 0);
229     CHECK_NE(pre_increment_count, std::numeric_limits<int>::max());
230   }
231 
ReleaseImpl()232   ALWAYS_INLINE bool ReleaseImpl() const {
233 #if DCHECK_IS_ON()
234     DCHECK(!in_dtor_);
235     DCHECK(!ref_count_.IsZero());
236 #endif
237     if (!ref_count_.Decrement()) {
238 #if DCHECK_IS_ON()
239       in_dtor_ = true;
240 #endif
241       return true;
242     }
243     return false;
244   }
245 
246   mutable AtomicRefCount ref_count_{0};
247 #if DCHECK_IS_ON()
248   mutable bool needs_adopt_ref_ = false;
249   mutable bool in_dtor_ = false;
250 #endif
251 };
252 
253 }  // namespace subtle
254 
255 // ScopedAllowCrossThreadRefCountAccess disables the check documented on
256 // RefCounted below for rare pre-existing use cases where thread-safety was
257 // guaranteed through other means (e.g. explicit sequencing of calls across
258 // execution sequences when bouncing between threads in order). New callers
259 // should refrain from using this (callsites handling thread-safety through
260 // locks should use RefCountedThreadSafe per the overhead of its atomics being
261 // negligible compared to locks anyways and callsites doing explicit sequencing
262 // should properly std::move() the ref to avoid hitting this check).
263 // TODO(tzik): Cleanup existing use cases and remove
264 // ScopedAllowCrossThreadRefCountAccess.
265 class BASE_EXPORT ScopedAllowCrossThreadRefCountAccess final {
266  public:
267 #if DCHECK_IS_ON()
268   ScopedAllowCrossThreadRefCountAccess();
269   ~ScopedAllowCrossThreadRefCountAccess();
270 #else
271   ScopedAllowCrossThreadRefCountAccess() {}
272   ~ScopedAllowCrossThreadRefCountAccess() {}
273 #endif
274 };
275 
276 //
277 // A base class for reference counted classes.  Otherwise, known as a cheap
278 // knock-off of WebKit's RefCounted<T> class.  To use this, just extend your
279 // class from it like so:
280 //
281 //   class MyFoo : public base::RefCounted<MyFoo> {
282 //    ...
283 //    private:
284 //     friend class base::RefCounted<MyFoo>;
285 //     ~MyFoo();
286 //   };
287 //
288 // Usage Notes:
289 // 1. You should always make your destructor non-public, to avoid any code
290 // deleting the object accidentally while there are references to it.
291 // 2. You should always make the ref-counted base class a friend of your class,
292 // so that it can access the destructor.
293 //
294 // The ref count manipulation to RefCounted is NOT thread safe and has DCHECKs
295 // to trap unsafe cross thread usage. A subclass instance of RefCounted can be
296 // passed to another execution sequence only when its ref count is 1. If the ref
297 // count is more than 1, the RefCounted class verifies the ref updates are made
298 // on the same execution sequence as the previous ones. The subclass can also
299 // manually call IsOnValidSequence to trap other non-thread-safe accesses; see
300 // the documentation for that method.
301 //
302 //
303 // The reference count starts from zero by default, and we intended to migrate
304 // to start-from-one ref count. Put REQUIRE_ADOPTION_FOR_REFCOUNTED_TYPE() to
305 // the ref counted class to opt-in.
306 //
307 // If an object has start-from-one ref count, the first scoped_refptr need to be
308 // created by base::AdoptRef() or base::MakeRefCounted(). We can use
309 // base::MakeRefCounted() to create create both type of ref counted object.
310 //
311 // The motivations to use start-from-one ref count are:
312 //  - Start-from-one ref count doesn't need the ref count increment for the
313 //    first reference.
314 //  - It can detect an invalid object acquisition for a being-deleted object
315 //    that has zero ref count. That tends to happen on custom deleter that
316 //    delays the deletion.
317 //    TODO(tzik): Implement invalid acquisition detection.
318 //  - Behavior parity to Blink's WTF::RefCounted, whose count starts from one.
319 //    And start-from-one ref count is a step to merge WTF::RefCounted into
320 //    base::RefCounted.
321 //
322 #define REQUIRE_ADOPTION_FOR_REFCOUNTED_TYPE() \
323   using RefCountPreferenceTag = ::base::subtle::StartRefCountFromOneTag
324 
325 template <class T, typename Traits>
326 class RefCounted;
327 
328 template <typename T>
329 struct DefaultRefCountedTraits {
DestructDefaultRefCountedTraits330   static void Destruct(const T* x) {
331     RefCounted<T, DefaultRefCountedTraits>::DeleteInternal(x);
332   }
333 };
334 
335 template <class T, typename Traits = DefaultRefCountedTraits<T>>
336 class RefCounted : public subtle::RefCountedBase {
337  public:
338   using RefCountPreferenceTag = subtle::StartRefCountFromZeroTag;
339 
RefCounted()340   RefCounted() : subtle::RefCountedBase(subtle::GetRefCountPreference<T>()) {}
341 
342   RefCounted(const RefCounted&) = delete;
343   RefCounted& operator=(const RefCounted&) = delete;
344 
AddRef()345   void AddRef() const {
346     subtle::RefCountedBase::AddRef();
347   }
348 
Release()349   void Release() const {
350     if (subtle::RefCountedBase::Release()) {
351       // Prune the code paths which the static analyzer may take to simulate
352       // object destruction. Use-after-free errors aren't possible given the
353       // lifetime guarantees of the refcounting system.
354       ANALYZER_SKIP_THIS_PATH();
355 
356       Traits::Destruct(static_cast<const T*>(this));
357     }
358   }
359 
360  protected:
361   ~RefCounted() = default;
362 
363  private:
364   friend struct DefaultRefCountedTraits<T>;
365   template <typename U>
366   static void DeleteInternal(const U* x) {
367     delete x;
368   }
369 };
370 
371 // Forward declaration.
372 template <class T, typename Traits> class RefCountedThreadSafe;
373 
374 // Default traits for RefCountedThreadSafe<T>.  Deletes the object when its ref
375 // count reaches 0.  Overload to delete it on a different thread etc.
376 template<typename T>
377 struct DefaultRefCountedThreadSafeTraits {
378   static void Destruct(const T* x) {
379     // Delete through RefCountedThreadSafe to make child classes only need to be
380     // friend with RefCountedThreadSafe instead of this struct, which is an
381     // implementation detail.
382     RefCountedThreadSafe<T,
383                          DefaultRefCountedThreadSafeTraits>::DeleteInternal(x);
384   }
385 };
386 
387 //
388 // A thread-safe variant of RefCounted<T>
389 //
390 //   class MyFoo : public base::RefCountedThreadSafe<MyFoo> {
391 //    ...
392 //   };
393 //
394 // If you're using the default trait, then you should add compile time
395 // asserts that no one else is deleting your object.  i.e.
396 //    private:
397 //     friend class base::RefCountedThreadSafe<MyFoo>;
398 //     ~MyFoo();
399 //
400 // We can use REQUIRE_ADOPTION_FOR_REFCOUNTED_TYPE() with RefCountedThreadSafe
401 // too. See the comment above the RefCounted definition for details.
402 template <class T, typename Traits = DefaultRefCountedThreadSafeTraits<T> >
403 class RefCountedThreadSafe : public subtle::RefCountedThreadSafeBase {
404  public:
405   using RefCountPreferenceTag = subtle::StartRefCountFromZeroTag;
406 
407   explicit RefCountedThreadSafe()
408       : subtle::RefCountedThreadSafeBase(subtle::GetRefCountPreference<T>()) {}
409 
410   RefCountedThreadSafe(const RefCountedThreadSafe&) = delete;
411   RefCountedThreadSafe& operator=(const RefCountedThreadSafe&) = delete;
412 
413   void AddRef() const { AddRefImpl(subtle::GetRefCountPreference<T>()); }
414 
415   void Release() const {
416     if (subtle::RefCountedThreadSafeBase::Release()) {
417       ANALYZER_SKIP_THIS_PATH();
418       Traits::Destruct(static_cast<const T*>(this));
419     }
420   }
421 
422  protected:
423   ~RefCountedThreadSafe() = default;
424 
425  private:
426   friend struct DefaultRefCountedThreadSafeTraits<T>;
427   template <typename U>
428   static void DeleteInternal(const U* x) {
429     delete x;
430   }
431 
432   void AddRefImpl(subtle::StartRefCountFromZeroTag) const {
433     subtle::RefCountedThreadSafeBase::AddRef();
434   }
435 
436   void AddRefImpl(subtle::StartRefCountFromOneTag) const {
437     subtle::RefCountedThreadSafeBase::AddRefWithCheck();
438   }
439 };
440 
441 //
442 // A thread-safe wrapper for some piece of data so we can place other
443 // things in scoped_refptrs<>.
444 //
445 template<typename T>
446 class RefCountedData
447     : public base::RefCountedThreadSafe< base::RefCountedData<T> > {
448  public:
449   RefCountedData() : data() {}
450   RefCountedData(const T& in_value) : data(in_value) {}
451   RefCountedData(T&& in_value) : data(std::move(in_value)) {}
452   template <typename... Args>
453   explicit RefCountedData(absl::in_place_t, Args&&... args)
454       : data(std::forward<Args>(args)...) {}
455 
456   T data;
457 
458  private:
459   friend class base::RefCountedThreadSafe<base::RefCountedData<T> >;
460   ~RefCountedData() = default;
461 };
462 
463 template <typename T>
464 bool operator==(const RefCountedData<T>& lhs, const RefCountedData<T>& rhs) {
465   return lhs.data == rhs.data;
466 }
467 
468 template <typename T>
469 bool operator!=(const RefCountedData<T>& lhs, const RefCountedData<T>& rhs) {
470   return !(lhs == rhs);
471 }
472 
473 }  // namespace base
474 
475 #endif  // BASE_MEMORY_REF_COUNTED_H_
476