tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

ref_counted.h (14647B)


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