LCOV - code coverage report
Current view: top level - mfbt - WeakPtr.h (source / functions) Hit Total Coverage
Test: output.info Lines: 49 54 90.7 %
Date: 2017-07-14 16:53:18 Functions: 210 669 31.4 %
Legend: Lines: hit not hit

          Line data    Source code
       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             :  * Note that when deriving from SupportsWeakPtr you should add
      20             :  * MOZ_DECLARE_WEAKREFERENCE_TYPENAME(ClassName) to the public section of your
      21             :  * class, where ClassName is the name of your class.
      22             :  *
      23             :  * The overhead of WeakPtr is that accesses to 'Foo' becomes an additional
      24             :  * dereference, and an additional heap allocated pointer sized object shared
      25             :  * between all of the WeakPtrs.
      26             :  *
      27             :  * Example of usage:
      28             :  *
      29             :  *   // To have a class C support weak pointers, inherit from
      30             :  *   // SupportsWeakPtr<C>.
      31             :  *   class C : public SupportsWeakPtr<C>
      32             :  *   {
      33             :  *   public:
      34             :  *     MOZ_DECLARE_WEAKREFERENCE_TYPENAME(C)
      35             :  *     int mNum;
      36             :  *     void act();
      37             :  *   };
      38             :  *
      39             :  *   C* ptr = new C();
      40             :  *
      41             :  *   // Get weak pointers to ptr. The first time a weak pointer
      42             :  *   // is obtained, a reference counted WeakReference object is created that
      43             :  *   // can live beyond the lifetime of 'ptr'. The WeakReference
      44             :  *   // object will be notified of 'ptr's destruction.
      45             :  *   WeakPtr<C> weak = ptr;
      46             :  *   WeakPtr<C> other = ptr;
      47             :  *
      48             :  *   // Test a weak pointer for validity before using it.
      49             :  *   if (weak) {
      50             :  *     weak->mNum = 17;
      51             :  *     weak->act();
      52             :  *   }
      53             :  *
      54             :  *   // Destroying the underlying object clears weak pointers to it.
      55             :  *   delete ptr;
      56             :  *
      57             :  *   MOZ_ASSERT(!weak, "Deleting |ptr| clears weak pointers to it.");
      58             :  *   MOZ_ASSERT(!other, "Deleting |ptr| clears all weak pointers to it.");
      59             :  *
      60             :  * WeakPtr is typesafe and may be used with any class. It is not required that
      61             :  * the class be reference-counted or allocated in any particular way.
      62             :  *
      63             :  * The API was loosely inspired by Chromium's weak_ptr.h:
      64             :  * http://src.chromium.org/svn/trunk/src/base/memory/weak_ptr.h
      65             :  */
      66             : 
      67             : #ifndef mozilla_WeakPtr_h
      68             : #define mozilla_WeakPtr_h
      69             : 
      70             : #include "mozilla/ArrayUtils.h"
      71             : #include "mozilla/Assertions.h"
      72             : #include "mozilla/Attributes.h"
      73             : #include "mozilla/RefCounted.h"
      74             : #include "mozilla/RefPtr.h"
      75             : #include "mozilla/TypeTraits.h"
      76             : 
      77             : #include <string.h>
      78             : 
      79             : // Weak referencing is not implemeted as thread safe.  When a WeakPtr
      80             : // is created or dereferenced on thread A but the real object is just
      81             : // being Released() on thread B, there is a possibility of a race
      82             : // when the proxy object (detail::WeakReference) is notified about
      83             : // the real object destruction just between when thread A is storing
      84             : // the object pointer locally and is about to add a reference to it.
      85             : //
      86             : // Hence, a non-null weak proxy object is considered to have a single
      87             : // "owning thread".  It means that each query for a weak reference,
      88             : // its dereference, and destruction of the real object must all happen
      89             : // on a single thread.  The following macros implement assertions for
      90             : // checking these conditions.
      91             : //
      92             : // We disable this on MinGW. MinGW has two threading models: win32
      93             : // API based, which disables std::thread; and POSIX based which
      94             : // enables it but requires an emulation library (winpthreads).
      95             : // Rather than attempting to switch to pthread emulation at this point,
      96             : // we are disabling the std::thread based assertion checking.
      97             : //
      98             : // In the future, to enable it we could
      99             : // a. have libgcc/stdc++ support win32 threads natively
     100             : // b. switch to POSIX-based threading in MinGW with pthread emulation
     101             : // c. refactor it to not use std::thread
     102             : 
     103             : #if !defined(__MINGW32__) && (defined(DEBUG) || (defined(NIGHTLY_BUILD) && !defined(MOZ_PROFILING)))
     104             : 
     105             : #include <thread>
     106             : #define MOZ_WEAKPTR_DECLARE_THREAD_SAFETY_CHECK \
     107             :   std::thread::id _owningThread; \
     108             :   bool _empty; // If it was initialized as a placeholder with mPtr = nullptr.
     109             : #define MOZ_WEAKPTR_INIT_THREAD_SAFETY_CHECK() \
     110             :   do { \
     111             :     _owningThread = std::this_thread::get_id(); \
     112             :     _empty = !p; \
     113             :   } while (false)
     114             : #define MOZ_WEAKPTR_ASSERT_THREAD_SAFETY() \
     115             :   do { \
     116             :     if (!(_empty || _owningThread == std::this_thread::get_id())) { \
     117             :       WeakPtrTraits<T>::AssertSafeToAccessFromNonOwningThread(); \
     118             :     } \
     119             :   } while (false)
     120             : #define MOZ_WEAKPTR_ASSERT_THREAD_SAFETY_DELEGATED(that) \
     121             :   (that)->AssertThreadSafety();
     122             : 
     123             : #define MOZ_WEAKPTR_THREAD_SAFETY_CHECKING 1
     124             : 
     125             : #else
     126             : 
     127             : #define MOZ_WEAKPTR_DECLARE_THREAD_SAFETY_CHECK
     128             : #define MOZ_WEAKPTR_INIT_THREAD_SAFETY_CHECK() do { } while (false)
     129             : #define MOZ_WEAKPTR_ASSERT_THREAD_SAFETY() do { } while (false)
     130             : #define MOZ_WEAKPTR_ASSERT_THREAD_SAFETY_DELEGATED(that) do { } while (false)
     131             : 
     132             : #endif
     133             : 
     134             : namespace mozilla {
     135             : 
     136             : template <typename T> class WeakPtr;
     137             : template <typename T> class SupportsWeakPtr;
     138             : 
     139             : #ifdef MOZ_REFCOUNTED_LEAK_CHECKING
     140             : #define MOZ_DECLARE_WEAKREFERENCE_TYPENAME(T) \
     141             :   static const char* weakReferenceTypeName() { return "WeakReference<" #T ">"; }
     142             : #else
     143             : #define MOZ_DECLARE_WEAKREFERENCE_TYPENAME(T)
     144             : #endif
     145             : 
     146             : template<class T>
     147             : struct WeakPtrTraits
     148             : {
     149           0 :   static void AssertSafeToAccessFromNonOwningThread()
     150             :   {
     151           0 :     MOZ_DIAGNOSTIC_ASSERT(false, "WeakPtr accessed from multiple threads");
     152             :   }
     153             : };
     154             : 
     155             : namespace detail {
     156             : 
     157             : // This can live beyond the lifetime of the class derived from
     158             : // SupportsWeakPtr.
     159             : template<class T>
     160         938 : class WeakReference : public ::mozilla::RefCounted<WeakReference<T> >
     161             : {
     162             : public:
     163        1877 :   explicit WeakReference(T* p) : mPtr(p)
     164             :   {
     165        1877 :     MOZ_WEAKPTR_INIT_THREAD_SAFETY_CHECK();
     166        1877 :   }
     167             : 
     168       16606 :   T* get() const {
     169       16606 :     MOZ_WEAKPTR_ASSERT_THREAD_SAFETY();
     170       16606 :     return mPtr;
     171             :   }
     172             : 
     173             : #ifdef MOZ_REFCOUNTED_LEAK_CHECKING
     174        5458 :   const char* typeName() const
     175             :   {
     176             :     // The first time this is called mPtr is null, so don't
     177             :     // invoke any methods on mPtr.
     178        5458 :     return T::weakReferenceTypeName();
     179             :   }
     180        3308 :   size_t typeSize() const { return sizeof(*this); }
     181             : #endif
     182             : 
     183             : #ifdef MOZ_WEAKPTR_THREAD_SAFETY_CHECKING
     184        3943 :   void AssertThreadSafety() { MOZ_WEAKPTR_ASSERT_THREAD_SAFETY(); }
     185             : #endif
     186             : 
     187             : private:
     188             :   friend class mozilla::SupportsWeakPtr<T>;
     189             : 
     190          30 :   void detach() {
     191          30 :     MOZ_WEAKPTR_ASSERT_THREAD_SAFETY();
     192          30 :     mPtr = nullptr;
     193          30 :   }
     194             : 
     195             :   T* MOZ_NON_OWNING_REF mPtr;
     196             :   MOZ_WEAKPTR_DECLARE_THREAD_SAFETY_CHECK
     197             : };
     198             : 
     199             : } // namespace detail
     200             : 
     201             : template <typename T>
     202         410 : class SupportsWeakPtr
     203             : {
     204             : protected:
     205          34 :   ~SupportsWeakPtr()
     206             :   {
     207             :     static_assert(IsBaseOf<SupportsWeakPtr<T>, T>::value,
     208             :                   "T must derive from SupportsWeakPtr<T>");
     209          34 :     if (mSelfReferencingWeakPtr) {
     210          30 :       mSelfReferencingWeakPtr.mRef->detach();
     211             :     }
     212          34 :   }
     213             : 
     214             : private:
     215        1199 :   const WeakPtr<T>& SelfReferencingWeakPtr()
     216             :   {
     217        1199 :     if (!mSelfReferencingWeakPtr) {
     218         267 :       mSelfReferencingWeakPtr.mRef = new detail::WeakReference<T>(static_cast<T*>(this));
     219             :     } else {
     220         932 :       MOZ_WEAKPTR_ASSERT_THREAD_SAFETY_DELEGATED(mSelfReferencingWeakPtr.mRef);
     221             :     }
     222        1199 :     return mSelfReferencingWeakPtr;
     223             :   }
     224             : 
     225           0 :   const WeakPtr<const T>& SelfReferencingWeakPtr() const
     226             :   {
     227           0 :     const WeakPtr<T>& p = const_cast<SupportsWeakPtr*>(this)->SelfReferencingWeakPtr();
     228           0 :     return reinterpret_cast<const WeakPtr<const T>&>(p);
     229             :   }
     230             : 
     231             :   friend class WeakPtr<T>;
     232             :   friend class WeakPtr<const T>;
     233             : 
     234             :   WeakPtr<T> mSelfReferencingWeakPtr;
     235             : };
     236             : 
     237             : template <typename T>
     238        1555 : class WeakPtr
     239             : {
     240             :   typedef detail::WeakReference<T> WeakReference;
     241             : 
     242             : public:
     243        1431 :   WeakPtr& operator=(const WeakPtr& aOther)
     244             :   {
     245        1431 :     mRef = aOther.mRef;
     246        1431 :     MOZ_WEAKPTR_ASSERT_THREAD_SAFETY_DELEGATED(mRef);
     247        1431 :     return *this;
     248             :   }
     249             : 
     250           6 :   WeakPtr(const WeakPtr& aOther)
     251           6 :   {
     252             :     // The thread safety check is performed inside of the operator= method.
     253           6 :     *this = aOther;
     254           6 :   }
     255             : 
     256        1704 :   WeakPtr& operator=(T* aOther)
     257             :   {
     258        1704 :     if (aOther) {
     259        1199 :       *this = aOther->SelfReferencingWeakPtr();
     260         505 :     } else if (!mRef || mRef->get()) {
     261             :       // Ensure that mRef is dereferenceable in the uninitialized state.
     262         483 :       mRef = new WeakReference(nullptr);
     263             :     }
     264             :     // The thread safety check happens inside SelfReferencingWeakPtr
     265             :     // or is initialized in the WeakReference constructor.
     266        1704 :     return *this;
     267             :   }
     268             : 
     269        1580 :   MOZ_IMPLICIT WeakPtr(T* aOther)
     270        1580 :   {
     271        1580 :     *this = aOther;
     272        1580 :     MOZ_WEAKPTR_ASSERT_THREAD_SAFETY_DELEGATED(mRef);
     273        1580 :   }
     274             : 
     275             :   // Ensure that mRef is dereferenceable in the uninitialized state.
     276        2254 :   WeakPtr() : mRef(new WeakReference(nullptr)) {}
     277             : 
     278       10244 :   operator T*() const { return mRef->get(); }
     279             :   T& operator*() const { return *mRef->get(); }
     280             : 
     281        5090 :   T* operator->() const MOZ_NO_ADDREF_RELEASE_ON_RETURN { return mRef->get(); }
     282             : 
     283        1244 :   T* get() const { return mRef->get(); }
     284             : 
     285             : private:
     286             :   friend class SupportsWeakPtr<T>;
     287             : 
     288             :   explicit WeakPtr(const RefPtr<WeakReference>& aOther) : mRef(aOther) {}
     289             : 
     290             :   RefPtr<WeakReference> mRef;
     291             : };
     292             : 
     293             : } // namespace mozilla
     294             : 
     295             : #endif /* mozilla_WeakPtr_h */

Generated by: LCOV version 1.13