WeakPtr.h 8.6 KB

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