tor-browser

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

WeakPtr.h (12332B)


      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 /* Weak pointer functionality, implemented as a mixin for use with any class. */
      8 
      9 /**
     10 * SupportsWeakPtr lets you have a pointer to an object 'Foo' without affecting
     11 * its lifetime. It works by creating a single shared reference counted object
     12 * (WeakReference) that each WeakPtr will access 'Foo' through. This lets 'Foo'
     13 * clear the pointer in the WeakReference without having to know about all of
     14 * the WeakPtrs to it and allows the WeakReference to live beyond the lifetime
     15 * of 'Foo'.
     16 *
     17 * PLEASE NOTE: This weak pointer implementation is not thread-safe.
     18 *
     19 * The overhead of WeakPtr is that accesses to 'Foo' becomes an additional
     20 * dereference, and an additional heap allocated pointer sized object shared
     21 * between all of the WeakPtrs.
     22 *
     23 * Example of usage:
     24 *
     25 *   // To have a class C support weak pointers, inherit from
     26 *   // SupportsWeakPtr
     27 *   class C : public SupportsWeakPtr
     28 *   {
     29 *   public:
     30 *     int mNum;
     31 *     void act();
     32 *   };
     33 *
     34 *   C* ptr = new C();
     35 *
     36 *   // Get weak pointers to ptr. The first time a weak pointer
     37 *   // is obtained, a reference counted WeakReference object is created that
     38 *   // can live beyond the lifetime of 'ptr'. The WeakReference
     39 *   // object will be notified of 'ptr's destruction.
     40 *   WeakPtr<C> weak = ptr;
     41 *   WeakPtr<C> other = ptr;
     42 *
     43 *   // Test a weak pointer for validity before using it.
     44 *   if (weak) {
     45 *     weak->mNum = 17;
     46 *     weak->act();
     47 *   }
     48 *
     49 *   // Destroying the underlying object clears weak pointers to it.
     50 *   delete ptr;
     51 *
     52 *   MOZ_ASSERT(!weak, "Deleting |ptr| clears weak pointers to it.");
     53 *   MOZ_ASSERT(!other, "Deleting |ptr| clears all weak pointers to it.");
     54 *
     55 * WeakPtr is typesafe and may be used with any class. It is not required that
     56 * the class be reference-counted or allocated in any particular way.
     57 *
     58 * The API was loosely inspired by Chromium's weak_ptr.h:
     59 * http://src.chromium.org/svn/trunk/src/base/memory/weak_ptr.h
     60 *
     61 * Note that multiple base classes inheriting from SupportsWeakPtr is not
     62 * currently supported. We could support it if needed though.
     63 *
     64 * For Gecko-internal usage there is also MainThreadWeakPtr<T>, a version of
     65 * WeakPtr that can be destroyed on any thread, but whose release gets proxied
     66 * to the main thread. This is a similar API to nsMainThreadPtrHandle, but
     67 * without keeping a strong reference to the main-thread object. Said WeakPtr
     68 * can't be accessed from any other thread that isn't the main thread.
     69 */
     70 
     71 #ifndef mozilla_WeakPtr_h
     72 #define mozilla_WeakPtr_h
     73 
     74 #include "mozilla/Assertions.h"
     75 #include "mozilla/Attributes.h"
     76 #include "mozilla/Maybe.h"
     77 #include "mozilla/RefCounted.h"
     78 #include "mozilla/RefPtr.h"
     79 
     80 #include <string.h>
     81 
     82 #if defined(MOZILLA_INTERNAL_API)
     83 // For thread safety checking.
     84 #  include "nsISupportsImpl.h"
     85 // For main thread destructor behavior.
     86 #  include "nsProxyRelease.h"
     87 #endif
     88 
     89 #if defined(MOZILLA_INTERNAL_API) && \
     90    defined(MOZ_THREAD_SAFETY_OWNERSHIP_CHECKS_SUPPORTED)
     91 
     92 // Weak referencing is not implemented as thread safe.  When a WeakPtr
     93 // is created or dereferenced on thread A but the real object is just
     94 // being Released() on thread B, there is a possibility of a race
     95 // when the proxy object (detail::WeakReference) is notified about
     96 // the real object destruction just between when thread A is storing
     97 // the object pointer locally and is about to add a reference to it.
     98 //
     99 // Hence, a non-null weak proxy object is considered to have a single
    100 // "owning thread".  It means that each query for a weak reference,
    101 // its dereference, and destruction of the real object must all happen
    102 // on a single thread.  The following macros implement assertions for
    103 // checking these conditions.
    104 //
    105 // We re-use XPCOM's nsAutoOwningEventTarget checks when they are available.
    106 // This has the advantage that it works with cooperative thread pools.
    107 
    108 #  define MOZ_WEAKPTR_DECLARE_THREAD_SAFETY_CHECK \
    109    /* Will be none if mPtr = nullptr. */         \
    110    Maybe<nsAutoOwningEventTarget> _owningThread;
    111 #  define MOZ_WEAKPTR_INIT_THREAD_SAFETY_CHECK() \
    112    do {                                         \
    113      if (p) {                                   \
    114        _owningThread.emplace();                 \
    115      }                                          \
    116    } while (false)
    117 #  define MOZ_WEAKPTR_ASSERT_THREAD_SAFETY()                  \
    118    do {                                                      \
    119      MOZ_DIAGNOSTIC_ASSERT(                                  \
    120          !_owningThread || _owningThread->IsCurrentThread(), \
    121          "WeakPtr accessed from multiple threads");          \
    122    } while (false)
    123 #  define MOZ_WEAKPTR_ASSERT_THREAD_SAFETY_DELEGATED(that) \
    124    (that)->AssertThreadSafety();
    125 #  define MOZ_WEAKPTR_ASSERT_THREAD_SAFETY_DELEGATED_IF(that) \
    126    do {                                                      \
    127      if (that) {                                             \
    128        (that)->AssertThreadSafety();                         \
    129      }                                                       \
    130    } while (false)
    131 
    132 #  define MOZ_WEAKPTR_THREAD_SAFETY_CHECKING 1
    133 
    134 #else
    135 
    136 #  define MOZ_WEAKPTR_DECLARE_THREAD_SAFETY_CHECK
    137 #  define MOZ_WEAKPTR_INIT_THREAD_SAFETY_CHECK() \
    138    do {                                         \
    139    } while (false)
    140 #  define MOZ_WEAKPTR_ASSERT_THREAD_SAFETY() \
    141    do {                                     \
    142    } while (false)
    143 #  define MOZ_WEAKPTR_ASSERT_THREAD_SAFETY_DELEGATED(that) \
    144    do {                                                   \
    145    } while (false)
    146 #  define MOZ_WEAKPTR_ASSERT_THREAD_SAFETY_DELEGATED_IF(that) \
    147    do {                                                      \
    148    } while (false)
    149 
    150 #endif
    151 
    152 namespace mozilla {
    153 
    154 namespace detail {
    155 
    156 enum class WeakPtrDestructorBehavior {
    157  Normal,
    158 #ifdef MOZILLA_INTERNAL_API
    159  ProxyToMainThread,
    160 #endif
    161 };
    162 
    163 }  // namespace detail
    164 
    165 template <typename T, detail::WeakPtrDestructorBehavior =
    166                          detail::WeakPtrDestructorBehavior::Normal>
    167 class WeakPtr;
    168 class SupportsWeakPtr;
    169 
    170 namespace detail {
    171 
    172 // This can live beyond the lifetime of the class derived from
    173 // SupportsWeakPtr.
    174 class WeakReference : public ::mozilla::RefCounted<WeakReference> {
    175 public:
    176  explicit WeakReference(const SupportsWeakPtr* p)
    177      : mPtr(const_cast<SupportsWeakPtr*>(p)) {
    178    MOZ_WEAKPTR_INIT_THREAD_SAFETY_CHECK();
    179  }
    180 
    181  SupportsWeakPtr* get() const {
    182    MOZ_WEAKPTR_ASSERT_THREAD_SAFETY();
    183    return mPtr;
    184  }
    185 
    186 #ifdef MOZ_REFCOUNTED_LEAK_CHECKING
    187  const char* typeName() const { return "WeakReference"; }
    188  size_t typeSize() const { return sizeof(*this); }
    189 #endif
    190 
    191 #ifdef MOZ_WEAKPTR_THREAD_SAFETY_CHECKING
    192  void AssertThreadSafety() { MOZ_WEAKPTR_ASSERT_THREAD_SAFETY(); }
    193 #endif
    194 
    195 private:
    196  friend class mozilla::SupportsWeakPtr;
    197 
    198  void detach() {
    199    MOZ_WEAKPTR_ASSERT_THREAD_SAFETY();
    200    mPtr = nullptr;
    201  }
    202 
    203  SupportsWeakPtr* MOZ_NON_OWNING_REF mPtr;
    204  MOZ_WEAKPTR_DECLARE_THREAD_SAFETY_CHECK
    205 };
    206 
    207 }  // namespace detail
    208 
    209 class SupportsWeakPtr {
    210  using WeakReference = detail::WeakReference;
    211 
    212 protected:
    213  ~SupportsWeakPtr() { DetachWeakPtr(); }
    214 
    215 protected:
    216  void DetachWeakPtr() {
    217    if (mSelfReferencingWeakReference) {
    218      mSelfReferencingWeakReference->detach();
    219    }
    220  }
    221 
    222 private:
    223  WeakReference* SelfReferencingWeakReference() const {
    224    if (!mSelfReferencingWeakReference) {
    225      mSelfReferencingWeakReference = new WeakReference(this);
    226    } else {
    227      MOZ_WEAKPTR_ASSERT_THREAD_SAFETY_DELEGATED(mSelfReferencingWeakReference);
    228    }
    229    return mSelfReferencingWeakReference.get();
    230  }
    231 
    232  template <typename U, detail::WeakPtrDestructorBehavior>
    233  friend class WeakPtr;
    234 
    235  mutable RefPtr<WeakReference> mSelfReferencingWeakReference;
    236 };
    237 
    238 template <typename T, detail::WeakPtrDestructorBehavior Destruct>
    239 class WeakPtr {
    240  using WeakReference = detail::WeakReference;
    241 
    242 public:
    243  WeakPtr& operator=(const WeakPtr& aOther) {
    244    // We must make sure the reference we have now is safe to be dereferenced
    245    // before we throw it away... (this can be called from a ctor)
    246    MOZ_WEAKPTR_ASSERT_THREAD_SAFETY_DELEGATED_IF(mRef);
    247    // ...and make sure the new reference is used on a single thread as well.
    248    MOZ_WEAKPTR_ASSERT_THREAD_SAFETY_DELEGATED(aOther.mRef);
    249 
    250    mRef = aOther.mRef;
    251    return *this;
    252  }
    253 
    254  WeakPtr(const WeakPtr& aOther) {
    255    // The thread safety check is performed inside of the operator= method.
    256    *this = aOther;
    257  }
    258 
    259  WeakPtr& operator=(decltype(nullptr)) {
    260    // We must make sure the reference we have now is safe to be dereferenced
    261    // before we throw it away.
    262    MOZ_WEAKPTR_ASSERT_THREAD_SAFETY_DELEGATED_IF(mRef);
    263    if (!mRef || mRef->get()) {
    264      // Ensure that mRef is dereferenceable in the uninitialized state.
    265      mRef = new WeakReference(nullptr);
    266    }
    267    return *this;
    268  }
    269 
    270  WeakPtr& operator=(const T* aOther) {
    271    // We must make sure the reference we have now is safe to be dereferenced
    272    // before we throw it away.
    273    MOZ_WEAKPTR_ASSERT_THREAD_SAFETY_DELEGATED_IF(mRef);
    274    if (aOther) {
    275      mRef = aOther->SelfReferencingWeakReference();
    276    } else if (!mRef || mRef->get()) {
    277      // Ensure that mRef is dereferenceable in the uninitialized state.
    278      mRef = new WeakReference(nullptr);
    279    }
    280    // The thread safety check happens inside SelfReferencingWeakPtr
    281    // or is initialized in the WeakReference constructor.
    282    return *this;
    283  }
    284 
    285  MOZ_IMPLICIT WeakPtr(T* aOther) {
    286    *this = aOther;
    287 #ifdef MOZILLA_INTERNAL_API
    288    if (Destruct == detail::WeakPtrDestructorBehavior::ProxyToMainThread) {
    289      MOZ_ASSERT(NS_IsMainThread(),
    290                 "MainThreadWeakPtr makes no sense on non-main threads");
    291    }
    292 #endif
    293  }
    294 
    295  explicit WeakPtr(const RefPtr<T>& aOther) : WeakPtr(aOther.get()) {}
    296 
    297  // Ensure that mRef is dereferenceable in the uninitialized state.
    298  WeakPtr() : mRef(new WeakReference(nullptr)) {}
    299 
    300  explicit operator bool() const { return mRef->get(); }
    301  T* get() const { return static_cast<T*>(mRef->get()); }
    302  operator T*() const { return get(); }
    303  T& operator*() const { return *get(); }
    304  T* operator->() const MOZ_NO_ADDREF_RELEASE_ON_RETURN { return get(); }
    305 
    306 #ifdef MOZILLA_INTERNAL_API
    307  ~WeakPtr() {
    308    if (Destruct == detail::WeakPtrDestructorBehavior::ProxyToMainThread) {
    309      NS_ReleaseOnMainThread("WeakPtr::mRef", mRef.forget());
    310    } else {
    311      MOZ_WEAKPTR_ASSERT_THREAD_SAFETY_DELEGATED(mRef);
    312    }
    313  }
    314 #endif
    315 
    316 private:
    317  friend class SupportsWeakPtr;
    318 
    319  explicit WeakPtr(const RefPtr<WeakReference>& aOther) : mRef(aOther) {}
    320 
    321  RefPtr<WeakReference> mRef;
    322 };
    323 
    324 #ifdef MOZILLA_INTERNAL_API
    325 
    326 template <typename T>
    327 using MainThreadWeakPtr =
    328    WeakPtr<T, detail::WeakPtrDestructorBehavior::ProxyToMainThread>;
    329 
    330 #endif
    331 
    332 #define NS_IMPL_CYCLE_COLLECTION_UNLINK_WEAK_PTR tmp->DetachWeakPtr();
    333 
    334 #define NS_IMPL_CYCLE_COLLECTION_WEAK_PTR(class_, ...) \
    335  NS_IMPL_CYCLE_COLLECTION_CLASS(class_)               \
    336  NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(class_)        \
    337    NS_IMPL_CYCLE_COLLECTION_UNLINK(__VA_ARGS__)       \
    338    NS_IMPL_CYCLE_COLLECTION_UNLINK_WEAK_PTR           \
    339  NS_IMPL_CYCLE_COLLECTION_UNLINK_END                  \
    340  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(class_)      \
    341    NS_IMPL_CYCLE_COLLECTION_TRAVERSE(__VA_ARGS__)     \
    342  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
    343 
    344 #define NS_IMPL_CYCLE_COLLECTION_WEAK_PTR_INHERITED(class_, super_, ...) \
    345  NS_IMPL_CYCLE_COLLECTION_CLASS(class_)                                 \
    346  NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(class_, super_)        \
    347    NS_IMPL_CYCLE_COLLECTION_UNLINK(__VA_ARGS__)                         \
    348    NS_IMPL_CYCLE_COLLECTION_UNLINK_WEAK_PTR                             \
    349  NS_IMPL_CYCLE_COLLECTION_UNLINK_END                                    \
    350  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(class_, super_)      \
    351    NS_IMPL_CYCLE_COLLECTION_TRAVERSE(__VA_ARGS__)                       \
    352  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
    353 
    354 }  // namespace mozilla
    355 
    356 #endif /* mozilla_WeakPtr_h */