tor-browser

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

AtomicRefCountedWithFinalize.h (5306B)


      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 #ifndef MOZILLA_ATOMICREFCOUNTEDWITHFINALIZE_H_
      8 #define MOZILLA_ATOMICREFCOUNTEDWITHFINALIZE_H_
      9 
     10 #include "mozilla/RefPtr.h"
     11 #include "MainThreadUtils.h"
     12 #include "base/message_loop.h"
     13 #include "base/task.h"
     14 #include "mozilla/gfx/Logging.h"
     15 
     16 #define ADDREF_MANUALLY(obj) \
     17  (obj)->AddRefManually(__FUNCTION__, __FILE__, __LINE__)
     18 #define RELEASE_MANUALLY(obj) \
     19  (obj)->ReleaseManually(__FUNCTION__, __FILE__, __LINE__)
     20 
     21 namespace mozilla {
     22 
     23 template <class U>
     24 class StaticRefPtr;
     25 
     26 namespace gl {
     27 template <typename T>
     28 class RefSet;
     29 
     30 template <typename T>
     31 class RefQueue;
     32 }  // namespace gl
     33 
     34 template <typename T>
     35 class AtomicRefCountedWithFinalize {
     36 protected:
     37  explicit AtomicRefCountedWithFinalize(const char* aName)
     38      : mRecycleCallback(nullptr),
     39        mClosure(nullptr),
     40        mRefCount(0)
     41 #ifdef DEBUG
     42        ,
     43        mSpew(false),
     44        mManualAddRefs(0),
     45        mManualReleases(0)
     46 #endif
     47 #ifdef NS_BUILD_REFCNT_LOGGING
     48        ,
     49        mName(aName)
     50 #endif
     51  {
     52  }
     53 
     54  ~AtomicRefCountedWithFinalize() {
     55    if (mRefCount >= 0) {
     56      gfxCriticalError() << "Deleting referenced object? " << mRefCount;
     57    }
     58  }
     59 
     60 public:
     61  // Mark user classes that are considered flawless.
     62  template <class U>
     63  friend class ::mozilla::StaticRefPtr;
     64 
     65  template <class U>
     66  friend struct mozilla::RefPtrTraits;
     67 
     68  template <typename U>
     69  friend class ::mozilla::gl::RefSet;
     70 
     71  template <typename U>
     72  friend class ::mozilla::gl::RefQueue;
     73 
     74  // friend class mozilla::gl::SurfaceFactory;
     75 
     76  void AddRefManually(const char* funcName, const char* fileName,
     77                      uint32_t lineNum) {
     78 #ifdef DEBUG
     79    uint32_t count = ++mManualAddRefs;
     80    if (mSpew) {
     81      printf_stderr("AddRefManually() #%u in %s at %s:%u\n", count, funcName,
     82                    fileName, lineNum);
     83    }
     84 #else
     85    (void)funcName;
     86    (void)fileName;
     87    (void)lineNum;
     88 #endif
     89    AddRef();
     90  }
     91 
     92  void ReleaseManually(const char* funcName, const char* fileName,
     93                       uint32_t lineNum) {
     94 #ifdef DEBUG
     95    uint32_t count = ++mManualReleases;
     96    if (mSpew) {
     97      printf_stderr("ReleaseManually() #%u in %s at %s:%u\n", count, funcName,
     98                    fileName, lineNum);
     99    }
    100 #else
    101    (void)funcName;
    102    (void)fileName;
    103    (void)lineNum;
    104 #endif
    105    Release();
    106  }
    107 
    108 private:
    109  void AddRef() {
    110    MOZ_ASSERT(mRefCount >= 0, "AddRef() during/after Finalize()/dtor.");
    111 #ifdef NS_BUILD_REFCNT_LOGGING
    112    int currCount = ++mRefCount;
    113    NS_LOG_ADDREF(this, currCount, mName, sizeof(*this));
    114 #else
    115    ++mRefCount;
    116 #endif
    117  }
    118 
    119  void Release() {
    120    MOZ_ASSERT(mRefCount > 0, "Release() during/after Finalize()/dtor.");
    121    // Read mRecycleCallback early so that it does not get set to
    122    // deleted memory, if the object is goes away.  See bug 994903.
    123    // This saves us in the case where there is no callback, so that
    124    // we can do the "else if" below.
    125    RecycleCallback recycleCallback = mRecycleCallback;
    126    int currCount = --mRefCount;
    127    if (currCount < 0) {
    128      gfxCriticalError() << "Invalid reference count release" << currCount;
    129      ++mRefCount;
    130      return;
    131    }
    132 #ifdef NS_BUILD_REFCNT_LOGGING
    133    NS_LOG_RELEASE(this, currCount, mName);
    134 #endif
    135 
    136    if (0 == currCount) {
    137      mRefCount = detail::DEAD;
    138      MOZ_ASSERT(IsDead());
    139 
    140      // Recycle listeners must call ClearRecycleCallback
    141      // before releasing their strong reference.
    142      if (mRecycleCallback) {
    143        gfxCriticalError() << "About to release with valid callback";
    144        mRecycleCallback = nullptr;
    145      }
    146 
    147      MOZ_ASSERT(mManualAddRefs == mManualReleases);
    148 
    149      T* derived = static_cast<T*>(this);
    150      derived->Finalize();
    151      delete derived;
    152    } else if (1 == currCount && recycleCallback) {
    153      // There is nothing enforcing this in the code, except how the callers
    154      // are being careful to never let the reference count go down if there
    155      // is a callback.
    156      MOZ_ASSERT(!IsDead());
    157      T* derived = static_cast<T*>(this);
    158      recycleCallback(derived, mClosure);
    159    }
    160  }
    161 
    162 public:
    163  typedef void (*RecycleCallback)(T* aObject, void* aClosure);
    164  /**
    165   * Set a callback responsible for recycling this object
    166   * before it is finalized.
    167   */
    168  void SetRecycleCallback(RecycleCallback aCallback, void* aClosure) {
    169    MOZ_ASSERT(!IsDead());
    170    mRecycleCallback = aCallback;
    171    mClosure = aClosure;
    172  }
    173  void ClearRecycleCallback() {
    174    MOZ_ASSERT(!IsDead());
    175    SetRecycleCallback(nullptr, nullptr);
    176  }
    177 
    178  bool HasRecycleCallback() const {
    179    MOZ_ASSERT(!IsDead());
    180    return !!mRecycleCallback;
    181  }
    182 
    183  bool IsDead() const { return mRefCount < 0; }
    184 
    185  bool HasOneRef() const { return mRefCount == 1; }
    186 
    187 private:
    188  RecycleCallback mRecycleCallback;
    189  void* mClosure;
    190  Atomic<int> mRefCount;
    191 #ifdef DEBUG
    192 public:
    193  bool mSpew;
    194 
    195 private:
    196  Atomic<uint32_t> mManualAddRefs;
    197  Atomic<uint32_t> mManualReleases;
    198 #endif
    199 #ifdef NS_BUILD_REFCNT_LOGGING
    200  const char* mName;
    201 #endif
    202 };
    203 
    204 }  // namespace mozilla
    205 
    206 #endif