WeakPtr.h 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283
  1. /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
  2. /* This Source Code Form is subject to the terms of the Mozilla Public
  3. * License, v. 2.0. If a copy of the MPL was not distributed with this
  4. * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
  5. /* Weak pointer functionality, implemented as a mixin for use with any class. */
  6. /**
  7. * SupportsWeakPtr lets you have a pointer to an object 'Foo' without affecting
  8. * its lifetime. It works by creating a single shared reference counted object
  9. * (WeakReference) that each WeakPtr will access 'Foo' through. This lets 'Foo'
  10. * clear the pointer in the WeakReference without having to know about all of
  11. * the WeakPtrs to it and allows the WeakReference to live beyond the lifetime
  12. * of 'Foo'.
  13. *
  14. * PLEASE NOTE: This weak pointer implementation is not thread-safe.
  15. *
  16. * Note that when deriving from SupportsWeakPtr you should add
  17. * MOZ_DECLARE_WEAKREFERENCE_TYPENAME(ClassName) to the public section of your
  18. * class, where ClassName is the name of your class.
  19. *
  20. * The overhead of WeakPtr is that accesses to 'Foo' becomes an additional
  21. * dereference, and an additional heap allocated pointer sized object shared
  22. * between all of the WeakPtrs.
  23. *
  24. * Example of usage:
  25. *
  26. * // To have a class C support weak pointers, inherit from
  27. * // SupportsWeakPtr<C>.
  28. * class C : public SupportsWeakPtr<C>
  29. * {
  30. * public:
  31. * MOZ_DECLARE_WEAKREFERENCE_TYPENAME(C)
  32. * int mNum;
  33. * void act();
  34. * };
  35. *
  36. * C* ptr = new C();
  37. *
  38. * // Get weak pointers to ptr. The first time a weak pointer
  39. * // is obtained, a reference counted WeakReference object is created that
  40. * // can live beyond the lifetime of 'ptr'. The WeakReference
  41. * // object will be notified of 'ptr's destruction.
  42. * WeakPtr<C> weak = ptr;
  43. * WeakPtr<C> other = ptr;
  44. *
  45. * // Test a weak pointer for validity before using it.
  46. * if (weak) {
  47. * weak->mNum = 17;
  48. * weak->act();
  49. * }
  50. *
  51. * // Destroying the underlying object clears weak pointers to it.
  52. * delete ptr;
  53. *
  54. * MOZ_ASSERT(!weak, "Deleting |ptr| clears weak pointers to it.");
  55. * MOZ_ASSERT(!other, "Deleting |ptr| clears all weak pointers to it.");
  56. *
  57. * WeakPtr is typesafe and may be used with any class. It is not required that
  58. * the class be reference-counted or allocated in any particular way.
  59. *
  60. * The API was loosely inspired by Chromium's weak_ptr.h:
  61. * http://src.chromium.org/svn/trunk/src/base/memory/weak_ptr.h
  62. */
  63. #ifndef mozilla_WeakPtr_h
  64. #define mozilla_WeakPtr_h
  65. #include "mozilla/ArrayUtils.h"
  66. #include "mozilla/Assertions.h"
  67. #include "mozilla/Attributes.h"
  68. #include "mozilla/RefCounted.h"
  69. #include "mozilla/RefPtr.h"
  70. #include "mozilla/TypeTraits.h"
  71. #include <string.h>
  72. // Weak referencing is not implemeted as thread safe. When a WeakPtr
  73. // is created or dereferenced on thread A but the real object is just
  74. // being Released() on thread B, there is a possibility of a race
  75. // when the proxy object (detail::WeakReference) is notified about
  76. // the real object destruction just between when thread A is storing
  77. // the object pointer locally and is about to add a reference to it.
  78. //
  79. // Hence, a non-null weak proxy object is considered to have a single
  80. // "owning thread". It means that each query for a weak reference,
  81. // its dereference, and destruction of the real object must all happen
  82. // on a single thread. The following macros implement assertions for
  83. // checking these conditions.
  84. //
  85. // We disable this on MinGW. MinGW has two threading models: win32
  86. // API based, which disables std::thread; and POSIX based which
  87. // enables it but requires an emulation library (winpthreads).
  88. // Rather than attempting to switch to pthread emulation at this point,
  89. // we are disabling the std::thread based assertion checking.
  90. //
  91. // In the future, to enable it we could
  92. // a. have libgcc/stdc++ support win32 threads natively
  93. // b. switch to POSIX-based threading in MinGW with pthread emulation
  94. // c. refactor it to not use std::thread
  95. #if !defined(__MINGW32__) && (defined(DEBUG) || (defined(NIGHTLY_BUILD) && !defined(MOZ_PROFILING)))
  96. #include <thread>
  97. #define MOZ_WEAKPTR_DECLARE_THREAD_SAFETY_CHECK \
  98. std::thread::id _owningThread; \
  99. bool _empty; // If it was initialized as a placeholder with mPtr = nullptr.
  100. #define MOZ_WEAKPTR_INIT_THREAD_SAFETY_CHECK() \
  101. do { \
  102. _owningThread = std::this_thread::get_id(); \
  103. _empty = !p; \
  104. } while (false)
  105. #define MOZ_WEAKPTR_ASSERT_THREAD_SAFETY() \
  106. MOZ_DIAGNOSTIC_ASSERT(_empty || _owningThread == std::this_thread::get_id(), \
  107. "WeakPtr used on multiple threads")
  108. #define MOZ_WEAKPTR_ASSERT_THREAD_SAFETY_DELEGATED(that) \
  109. (that)->AssertThreadSafety();
  110. #define MOZ_WEAKPTR_THREAD_SAFETY_CHECKING 1
  111. #else
  112. #define MOZ_WEAKPTR_DECLARE_THREAD_SAFETY_CHECK
  113. #define MOZ_WEAKPTR_INIT_THREAD_SAFETY_CHECK() do { } while (false)
  114. #define MOZ_WEAKPTR_ASSERT_THREAD_SAFETY() do { } while (false)
  115. #define MOZ_WEAKPTR_ASSERT_THREAD_SAFETY_DELEGATED(that) do { } while (false)
  116. #endif
  117. namespace mozilla {
  118. template <typename T> class WeakPtr;
  119. template <typename T> class SupportsWeakPtr;
  120. #ifdef MOZ_REFCOUNTED_LEAK_CHECKING
  121. #define MOZ_DECLARE_WEAKREFERENCE_TYPENAME(T) \
  122. static const char* weakReferenceTypeName() { return "WeakReference<" #T ">"; }
  123. #else
  124. #define MOZ_DECLARE_WEAKREFERENCE_TYPENAME(T)
  125. #endif
  126. namespace detail {
  127. // This can live beyond the lifetime of the class derived from
  128. // SupportsWeakPtr.
  129. template<class T>
  130. class WeakReference : public ::mozilla::RefCounted<WeakReference<T> >
  131. {
  132. public:
  133. explicit WeakReference(T* p) : mPtr(p)
  134. {
  135. MOZ_WEAKPTR_INIT_THREAD_SAFETY_CHECK();
  136. }
  137. T* get() const {
  138. MOZ_WEAKPTR_ASSERT_THREAD_SAFETY();
  139. return mPtr;
  140. }
  141. #ifdef MOZ_REFCOUNTED_LEAK_CHECKING
  142. const char* typeName() const
  143. {
  144. // The first time this is called mPtr is null, so don't
  145. // invoke any methods on mPtr.
  146. return T::weakReferenceTypeName();
  147. }
  148. size_t typeSize() const { return sizeof(*this); }
  149. #endif
  150. #ifdef MOZ_WEAKPTR_THREAD_SAFETY_CHECKING
  151. void AssertThreadSafety() { MOZ_WEAKPTR_ASSERT_THREAD_SAFETY(); }
  152. #endif
  153. private:
  154. friend class mozilla::SupportsWeakPtr<T>;
  155. void detach() {
  156. MOZ_WEAKPTR_ASSERT_THREAD_SAFETY();
  157. mPtr = nullptr;
  158. }
  159. T* MOZ_NON_OWNING_REF mPtr;
  160. MOZ_WEAKPTR_DECLARE_THREAD_SAFETY_CHECK
  161. };
  162. } // namespace detail
  163. template <typename T>
  164. class SupportsWeakPtr
  165. {
  166. protected:
  167. ~SupportsWeakPtr()
  168. {
  169. static_assert(IsBaseOf<SupportsWeakPtr<T>, T>::value,
  170. "T must derive from SupportsWeakPtr<T>");
  171. if (mSelfReferencingWeakPtr) {
  172. mSelfReferencingWeakPtr.mRef->detach();
  173. }
  174. }
  175. private:
  176. const WeakPtr<T>& SelfReferencingWeakPtr()
  177. {
  178. if (!mSelfReferencingWeakPtr) {
  179. mSelfReferencingWeakPtr.mRef = new detail::WeakReference<T>(static_cast<T*>(this));
  180. } else {
  181. MOZ_WEAKPTR_ASSERT_THREAD_SAFETY_DELEGATED(mSelfReferencingWeakPtr.mRef);
  182. }
  183. return mSelfReferencingWeakPtr;
  184. }
  185. const WeakPtr<const T>& SelfReferencingWeakPtr() const
  186. {
  187. const WeakPtr<T>& p = const_cast<SupportsWeakPtr*>(this)->SelfReferencingWeakPtr();
  188. return reinterpret_cast<const WeakPtr<const T>&>(p);
  189. }
  190. friend class WeakPtr<T>;
  191. friend class WeakPtr<const T>;
  192. WeakPtr<T> mSelfReferencingWeakPtr;
  193. };
  194. template <typename T>
  195. class WeakPtr
  196. {
  197. typedef detail::WeakReference<T> WeakReference;
  198. public:
  199. WeakPtr& operator=(const WeakPtr& aOther)
  200. {
  201. mRef = aOther.mRef;
  202. MOZ_WEAKPTR_ASSERT_THREAD_SAFETY_DELEGATED(mRef);
  203. return *this;
  204. }
  205. WeakPtr(const WeakPtr& aOther)
  206. {
  207. // The thread safety check is performed inside of the operator= method.
  208. *this = aOther;
  209. }
  210. WeakPtr& operator=(T* aOther)
  211. {
  212. if (aOther) {
  213. *this = aOther->SelfReferencingWeakPtr();
  214. } else if (!mRef || mRef->get()) {
  215. // Ensure that mRef is dereferenceable in the uninitialized state.
  216. mRef = new WeakReference(nullptr);
  217. }
  218. // The thread safety check happens inside SelfReferencingWeakPtr
  219. // or is initialized in the WeakReference constructor.
  220. return *this;
  221. }
  222. MOZ_IMPLICIT WeakPtr(T* aOther)
  223. {
  224. *this = aOther;
  225. MOZ_WEAKPTR_ASSERT_THREAD_SAFETY_DELEGATED(mRef);
  226. }
  227. // Ensure that mRef is dereferenceable in the uninitialized state.
  228. WeakPtr() : mRef(new WeakReference(nullptr)) {}
  229. operator T*() const { return mRef->get(); }
  230. T& operator*() const { return *mRef->get(); }
  231. T* operator->() const MOZ_NO_ADDREF_RELEASE_ON_RETURN { return mRef->get(); }
  232. T* get() const { return mRef->get(); }
  233. private:
  234. friend class SupportsWeakPtr<T>;
  235. explicit WeakPtr(const RefPtr<WeakReference>& aOther) : mRef(aOther) {}
  236. RefPtr<WeakReference> mRef;
  237. };
  238. } // namespace mozilla
  239. #endif /* mozilla_WeakPtr_h */