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/. */
7 /* Weak pointer functionality, implemented as a mixin for use with any class. */
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
17 * PLEASE NOTE: This weak pointer implementation is not thread-safe.
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.
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.
29 * // To have a class C support weak pointers, inherit from
30 * // SupportsWeakPtr<C>.
31 * class C : public SupportsWeakPtr<C>
34 * MOZ_DECLARE_WEAKREFERENCE_TYPENAME(C)
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;
48 * // Test a weak pointer for validity before using it.
54 * // Destroying the underlying object clears weak pointers to it.
57 * MOZ_ASSERT(!weak, "Deleting |ptr| clears weak pointers to it.");
58 * MOZ_ASSERT(!other, "Deleting |ptr| clears all weak pointers to it.");
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.
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
67 #ifndef mozilla_WeakPtr_h
68 #define mozilla_WeakPtr_h
70 #include "mozilla/ArrayUtils.h"
71 #include "mozilla/Assertions.h"
72 #include "mozilla/Attributes.h"
73 #include "mozilla/Maybe.h"
74 #include "mozilla/RefCounted.h"
75 #include "mozilla/RefPtr.h"
76 #include "mozilla/TypeTraits.h"
80 #if defined(MOZILLA_INTERNAL_API)
81 // For thread safety checking.
82 # include "nsISupportsImpl.h"
85 #if defined(MOZILLA_INTERNAL_API) && \
86 defined(MOZ_THREAD_SAFETY_OWNERSHIP_CHECKS_SUPPORTED)
88 // Weak referencing is not implemeted as thread safe. When a WeakPtr
89 // is created or dereferenced on thread A but the real object is just
90 // being Released() on thread B, there is a possibility of a race
91 // when the proxy object (detail::WeakReference) is notified about
92 // the real object destruction just between when thread A is storing
93 // the object pointer locally and is about to add a reference to it.
95 // Hence, a non-null weak proxy object is considered to have a single
96 // "owning thread". It means that each query for a weak reference,
97 // its dereference, and destruction of the real object must all happen
98 // on a single thread. The following macros implement assertions for
99 // checking these conditions.
101 // We re-use XPCOM's nsAutoOwningThread checks when they are available. This has
102 // the advantage that it works with cooperative thread pools.
104 # define MOZ_WEAKPTR_DECLARE_THREAD_SAFETY_CHECK \
105 /* Will be none if mPtr = nullptr. */ \
106 Maybe<nsAutoOwningThread> _owningThread;
107 # define MOZ_WEAKPTR_INIT_THREAD_SAFETY_CHECK() \
110 _owningThread.emplace(); \
113 # define MOZ_WEAKPTR_ASSERT_THREAD_SAFETY() \
115 if (_owningThread.isSome() && !_owningThread.ref().IsCurrentThread()) { \
116 WeakPtrTraits<T>::AssertSafeToAccessFromNonOwningThread(); \
119 # define MOZ_WEAKPTR_ASSERT_THREAD_SAFETY_DELEGATED(that) \
120 (that)->AssertThreadSafety();
122 # define MOZ_WEAKPTR_THREAD_SAFETY_CHECKING 1
126 # define MOZ_WEAKPTR_DECLARE_THREAD_SAFETY_CHECK
127 # define MOZ_WEAKPTR_INIT_THREAD_SAFETY_CHECK() \
130 # define MOZ_WEAKPTR_ASSERT_THREAD_SAFETY() \
133 # define MOZ_WEAKPTR_ASSERT_THREAD_SAFETY_DELEGATED(that) \
141 template <typename T
>
143 template <typename T
>
144 class SupportsWeakPtr
;
146 #ifdef MOZ_REFCOUNTED_LEAK_CHECKING
147 # define MOZ_DECLARE_WEAKREFERENCE_TYPENAME(T) \
148 static const char* weakReferenceTypeName() { \
149 return "WeakReference<" #T ">"; \
152 # define MOZ_DECLARE_WEAKREFERENCE_TYPENAME(T)
156 struct WeakPtrTraits
{
157 static void AssertSafeToAccessFromNonOwningThread() {
158 MOZ_DIAGNOSTIC_ASSERT(false, "WeakPtr accessed from multiple threads");
164 // This can live beyond the lifetime of the class derived from
167 class WeakReference
: public ::mozilla::RefCounted
<WeakReference
<T
> > {
169 explicit WeakReference(T
* p
) : mPtr(p
) {
170 MOZ_WEAKPTR_INIT_THREAD_SAFETY_CHECK();
174 MOZ_WEAKPTR_ASSERT_THREAD_SAFETY();
178 #ifdef MOZ_REFCOUNTED_LEAK_CHECKING
179 const char* typeName() const {
180 // The first time this is called mPtr is null, so don't
181 // invoke any methods on mPtr.
182 return T::weakReferenceTypeName();
184 size_t typeSize() const { return sizeof(*this); }
187 #ifdef MOZ_WEAKPTR_THREAD_SAFETY_CHECKING
188 void AssertThreadSafety() { MOZ_WEAKPTR_ASSERT_THREAD_SAFETY(); }
192 friend class mozilla::SupportsWeakPtr
<T
>;
195 MOZ_WEAKPTR_ASSERT_THREAD_SAFETY();
199 T
* MOZ_NON_OWNING_REF mPtr
;
200 MOZ_WEAKPTR_DECLARE_THREAD_SAFETY_CHECK
203 } // namespace detail
205 template <typename T
>
206 class SupportsWeakPtr
{
209 static_assert(IsBaseOf
<SupportsWeakPtr
<T
>, T
>::value
,
210 "T must derive from SupportsWeakPtr<T>");
211 if (mSelfReferencingWeakPtr
) {
212 mSelfReferencingWeakPtr
.mRef
->detach();
217 const WeakPtr
<T
>& SelfReferencingWeakPtr() {
218 if (!mSelfReferencingWeakPtr
) {
219 mSelfReferencingWeakPtr
.mRef
=
220 new detail::WeakReference
<T
>(static_cast<T
*>(this));
222 MOZ_WEAKPTR_ASSERT_THREAD_SAFETY_DELEGATED(mSelfReferencingWeakPtr
.mRef
);
224 return mSelfReferencingWeakPtr
;
227 const WeakPtr
<const T
>& SelfReferencingWeakPtr() const {
228 const WeakPtr
<T
>& p
=
229 const_cast<SupportsWeakPtr
*>(this)->SelfReferencingWeakPtr();
230 return reinterpret_cast<const WeakPtr
<const T
>&>(p
);
233 friend class WeakPtr
<T
>;
234 friend class WeakPtr
<const T
>;
236 WeakPtr
<T
> mSelfReferencingWeakPtr
;
239 template <typename T
>
241 typedef detail::WeakReference
<T
> WeakReference
;
244 WeakPtr
& operator=(const WeakPtr
& aOther
) {
246 MOZ_WEAKPTR_ASSERT_THREAD_SAFETY_DELEGATED(mRef
);
250 WeakPtr(const WeakPtr
& aOther
) {
251 // The thread safety check is performed inside of the operator= method.
255 WeakPtr
& operator=(T
* aOther
) {
257 *this = aOther
->SelfReferencingWeakPtr();
258 } else if (!mRef
|| mRef
->get()) {
259 // Ensure that mRef is dereferenceable in the uninitialized state.
260 mRef
= new WeakReference(nullptr);
262 // The thread safety check happens inside SelfReferencingWeakPtr
263 // or is initialized in the WeakReference constructor.
267 MOZ_IMPLICIT
WeakPtr(T
* aOther
) {
269 MOZ_WEAKPTR_ASSERT_THREAD_SAFETY_DELEGATED(mRef
);
272 // Ensure that mRef is dereferenceable in the uninitialized state.
273 WeakPtr() : mRef(new WeakReference(nullptr)) {}
275 operator T
*() const { return mRef
->get(); }
276 T
& operator*() const { return *mRef
->get(); }
278 T
* operator->() const MOZ_NO_ADDREF_RELEASE_ON_RETURN
{ return mRef
->get(); }
280 T
* get() const { return mRef
->get(); }
282 ~WeakPtr() { MOZ_WEAKPTR_ASSERT_THREAD_SAFETY_DELEGATED(mRef
); }
285 friend class SupportsWeakPtr
<T
>;
287 explicit WeakPtr(const RefPtr
<WeakReference
>& aOther
) : mRef(aOther
) {}
289 RefPtr
<WeakReference
> mRef
;
292 } // namespace mozilla
294 #endif /* mozilla_WeakPtr_h */