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