tor-browser

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

GenericRefCounted.h (3778B)


      1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
      2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
      3 /* This Source Code Form is subject to the terms of the Mozilla Public
      4 * License, v. 2.0. If a copy of the MPL was not distributed with this
      5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      6 
      7 // This header provides virtual, non-templated alternatives to MFBT's
      8 // RefCounted<T>. It intentionally uses MFBT coding style with the intention of
      9 // moving there should there be other use cases for it.
     10 
     11 #ifndef MOZILLA_GENERICREFCOUNTED_H_
     12 #define MOZILLA_GENERICREFCOUNTED_H_
     13 
     14 #include <type_traits>
     15 
     16 #include "mozilla/RefPtr.h"
     17 #include "mozilla/RefCounted.h"
     18 
     19 namespace mozilla {
     20 
     21 /**
     22 * Common base class for GenericRefCounted and GenericAtomicRefCounted.
     23 *
     24 * Having this shared base class, common to both the atomic and non-atomic
     25 * cases, allows to have RefPtr's that don't care about whether the
     26 * objects they're managing have atomic refcounts or not.
     27 */
     28 class GenericRefCountedBase {
     29 protected:
     30  virtual ~GenericRefCountedBase() = default;
     31 
     32 public:
     33  // AddRef() and Release() method names are for compatibility with nsRefPtr.
     34  virtual void AddRef() = 0;
     35 
     36  virtual void Release() = 0;
     37 
     38  // ref() and deref() method names are for compatibility with wtf::RefPtr.
     39  // No virtual keywords here: if a subclass wants to override the refcounting
     40  // mechanism, it is welcome to do so by overriding AddRef() and Release().
     41  void ref() { AddRef(); }
     42  void deref() { Release(); }
     43 
     44 #ifdef MOZ_REFCOUNTED_LEAK_CHECKING
     45  virtual const char* typeName() const = 0;
     46  virtual size_t typeSize() const = 0;
     47 #endif
     48 };
     49 
     50 namespace detail {
     51 
     52 template <RefCountAtomicity Atomicity>
     53 class GenericRefCounted : public GenericRefCountedBase {
     54 protected:
     55  GenericRefCounted() : refCnt(0) {}
     56 
     57  virtual ~GenericRefCounted() { MOZ_ASSERT(refCnt == detail::DEAD); }
     58 
     59 public:
     60  virtual void AddRef() override {
     61    // Note: this method must be thread safe for GenericAtomicRefCounted.
     62    MOZ_ASSERT(int32_t(refCnt) >= 0);
     63    MozRefCountType cnt = ++refCnt;
     64    detail::RefCountLogger::logAddRef(this, cnt);
     65  }
     66 
     67  virtual void Release() override {
     68    // Note: this method must be thread safe for GenericAtomicRefCounted.
     69    MOZ_ASSERT(int32_t(refCnt) > 0);
     70    detail::RefCountLogger::ReleaseLogger logger{this};
     71    MozRefCountType cnt = --refCnt;
     72    // Note: it's not safe to touch |this| after decrementing the refcount,
     73    // except for below.
     74    logger.logRelease(cnt);
     75    if (0 == cnt) {
     76      // Because we have atomically decremented the refcount above, only
     77      // one thread can get a 0 count here, so as long as we can assume that
     78      // everything else in the system is accessing this object through
     79      // RefPtrs, it's safe to access |this| here.
     80 #ifdef DEBUG
     81      refCnt = detail::DEAD;
     82 #endif
     83      delete this;
     84    }
     85  }
     86 
     87  MozRefCountType refCount() const { return refCnt; }
     88  bool hasOneRef() const {
     89    MOZ_ASSERT(refCnt > 0);
     90    return refCnt == 1;
     91  }
     92 
     93 private:
     94  std::conditional_t<Atomicity == AtomicRefCount, Atomic<MozRefCountType>,
     95                     MozRefCountType>
     96      refCnt;
     97 };
     98 
     99 }  // namespace detail
    100 
    101 /**
    102 * This reference-counting base class is virtual instead of
    103 * being templated, which is useful in cases where one needs
    104 * genericity at binary code level, but comes at the cost
    105 * of a moderate performance and size overhead, like anything virtual.
    106 */
    107 class GenericRefCounted
    108    : public detail::GenericRefCounted<detail::NonAtomicRefCount> {};
    109 
    110 /**
    111 * GenericAtomicRefCounted is like GenericRefCounted, with an atomically updated
    112 * reference counter.
    113 */
    114 class GenericAtomicRefCounted
    115    : public detail::GenericRefCounted<detail::AtomicRefCount> {};
    116 
    117 }  // namespace mozilla
    118 
    119 #endif