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 * 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.
25 * // To have a class C support weak pointers, inherit from
27 * class C : public SupportsWeakPtr
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;
43 * // Test a weak pointer for validity before using it.
49 * // Destroying the underlying object clears weak pointers to it.
52 * MOZ_ASSERT(!weak, "Deleting |ptr| clears weak pointers to it.");
53 * MOZ_ASSERT(!other, "Deleting |ptr| clears all weak pointers to it.");
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.
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
61 * Note that multiple base classes inheriting from SupportsWeakPtr is not
62 * currently supported. We could support it if needed though.
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.
71 #ifndef mozilla_WeakPtr_h
72 #define mozilla_WeakPtr_h
74 #include "mozilla/ArrayUtils.h"
75 #include "mozilla/Assertions.h"
76 #include "mozilla/Attributes.h"
77 #include "mozilla/Maybe.h"
78 #include "mozilla/RefCounted.h"
79 #include "mozilla/RefPtr.h"
82 #include <type_traits>
84 #if defined(MOZILLA_INTERNAL_API)
85 // For thread safety checking.
86 # include "nsISupportsImpl.h"
87 // For main thread destructor behavior.
88 # include "nsProxyRelease.h"
91 #if defined(MOZILLA_INTERNAL_API) && \
92 defined(MOZ_THREAD_SAFETY_OWNERSHIP_CHECKS_SUPPORTED)
94 // Weak referencing is not implemented as thread safe. When a WeakPtr
95 // is created or dereferenced on thread A but the real object is just
96 // being Released() on thread B, there is a possibility of a race
97 // when the proxy object (detail::WeakReference) is notified about
98 // the real object destruction just between when thread A is storing
99 // the object pointer locally and is about to add a reference to it.
101 // Hence, a non-null weak proxy object is considered to have a single
102 // "owning thread". It means that each query for a weak reference,
103 // its dereference, and destruction of the real object must all happen
104 // on a single thread. The following macros implement assertions for
105 // checking these conditions.
107 // We re-use XPCOM's nsAutoOwningEventTarget checks when they are available.
108 // This has the advantage that it works with cooperative thread pools.
110 # define MOZ_WEAKPTR_DECLARE_THREAD_SAFETY_CHECK \
111 /* Will be none if mPtr = nullptr. */ \
112 Maybe<nsAutoOwningEventTarget> _owningThread;
113 # define MOZ_WEAKPTR_INIT_THREAD_SAFETY_CHECK() \
116 _owningThread.emplace(); \
119 # define MOZ_WEAKPTR_ASSERT_THREAD_SAFETY() \
121 MOZ_DIAGNOSTIC_ASSERT( \
122 !_owningThread || _owningThread->IsCurrentThread(), \
123 "WeakPtr accessed from multiple threads"); \
125 # define MOZ_WEAKPTR_ASSERT_THREAD_SAFETY_DELEGATED(that) \
126 (that)->AssertThreadSafety();
127 # define MOZ_WEAKPTR_ASSERT_THREAD_SAFETY_DELEGATED_IF(that) \
130 (that)->AssertThreadSafety(); \
134 # define MOZ_WEAKPTR_THREAD_SAFETY_CHECKING 1
138 # define MOZ_WEAKPTR_DECLARE_THREAD_SAFETY_CHECK
139 # define MOZ_WEAKPTR_INIT_THREAD_SAFETY_CHECK() \
142 # define MOZ_WEAKPTR_ASSERT_THREAD_SAFETY() \
145 # define MOZ_WEAKPTR_ASSERT_THREAD_SAFETY_DELEGATED(that) \
148 # define MOZ_WEAKPTR_ASSERT_THREAD_SAFETY_DELEGATED_IF(that) \
158 enum class WeakPtrDestructorBehavior
{
160 #ifdef MOZILLA_INTERNAL_API
165 } // namespace detail
167 template <typename T
, detail::WeakPtrDestructorBehavior
=
168 detail::WeakPtrDestructorBehavior::Normal
>
170 class SupportsWeakPtr
;
174 // This can live beyond the lifetime of the class derived from
176 class WeakReference
: public ::mozilla::RefCounted
<WeakReference
> {
178 explicit WeakReference(const SupportsWeakPtr
* p
)
179 : mPtr(const_cast<SupportsWeakPtr
*>(p
)) {
180 MOZ_WEAKPTR_INIT_THREAD_SAFETY_CHECK();
183 SupportsWeakPtr
* get() const {
184 MOZ_WEAKPTR_ASSERT_THREAD_SAFETY();
188 #ifdef MOZ_REFCOUNTED_LEAK_CHECKING
189 const char* typeName() const { return "WeakReference"; }
190 size_t typeSize() const { return sizeof(*this); }
193 #ifdef MOZ_WEAKPTR_THREAD_SAFETY_CHECKING
194 void AssertThreadSafety() { MOZ_WEAKPTR_ASSERT_THREAD_SAFETY(); }
198 friend class mozilla::SupportsWeakPtr
;
201 MOZ_WEAKPTR_ASSERT_THREAD_SAFETY();
205 SupportsWeakPtr
* MOZ_NON_OWNING_REF mPtr
;
206 MOZ_WEAKPTR_DECLARE_THREAD_SAFETY_CHECK
209 } // namespace detail
211 class SupportsWeakPtr
{
212 using WeakReference
= detail::WeakReference
;
215 ~SupportsWeakPtr() { DetachWeakPtr(); }
218 void DetachWeakPtr() {
219 if (mSelfReferencingWeakReference
) {
220 mSelfReferencingWeakReference
->detach();
225 WeakReference
* SelfReferencingWeakReference() const {
226 if (!mSelfReferencingWeakReference
) {
227 mSelfReferencingWeakReference
= new WeakReference(this);
229 MOZ_WEAKPTR_ASSERT_THREAD_SAFETY_DELEGATED(mSelfReferencingWeakReference
);
231 return mSelfReferencingWeakReference
.get();
234 template <typename U
, detail::WeakPtrDestructorBehavior
>
235 friend class WeakPtr
;
237 mutable RefPtr
<WeakReference
> mSelfReferencingWeakReference
;
240 template <typename T
, detail::WeakPtrDestructorBehavior Destruct
>
242 using WeakReference
= detail::WeakReference
;
245 WeakPtr
& operator=(const WeakPtr
& aOther
) {
246 // We must make sure the reference we have now is safe to be dereferenced
247 // before we throw it away... (this can be called from a ctor)
248 MOZ_WEAKPTR_ASSERT_THREAD_SAFETY_DELEGATED_IF(mRef
);
249 // ...and make sure the new reference is used on a single thread as well.
250 MOZ_WEAKPTR_ASSERT_THREAD_SAFETY_DELEGATED(aOther
.mRef
);
256 WeakPtr(const WeakPtr
& aOther
) {
257 // The thread safety check is performed inside of the operator= method.
261 WeakPtr
& operator=(decltype(nullptr)) {
262 // We must make sure the reference we have now is safe to be dereferenced
263 // before we throw it away.
264 MOZ_WEAKPTR_ASSERT_THREAD_SAFETY_DELEGATED_IF(mRef
);
265 if (!mRef
|| mRef
->get()) {
266 // Ensure that mRef is dereferenceable in the uninitialized state.
267 mRef
= new WeakReference(nullptr);
272 WeakPtr
& operator=(const T
* aOther
) {
273 // We must make sure the reference we have now is safe to be dereferenced
274 // before we throw it away.
275 MOZ_WEAKPTR_ASSERT_THREAD_SAFETY_DELEGATED_IF(mRef
);
277 mRef
= aOther
->SelfReferencingWeakReference();
278 } else if (!mRef
|| mRef
->get()) {
279 // Ensure that mRef is dereferenceable in the uninitialized state.
280 mRef
= new WeakReference(nullptr);
282 // The thread safety check happens inside SelfReferencingWeakPtr
283 // or is initialized in the WeakReference constructor.
287 MOZ_IMPLICIT
WeakPtr(T
* aOther
) {
289 #ifdef MOZILLA_INTERNAL_API
290 if (Destruct
== detail::WeakPtrDestructorBehavior::ProxyToMainThread
) {
291 MOZ_ASSERT(NS_IsMainThread(),
292 "MainThreadWeakPtr makes no sense on non-main threads");
297 explicit WeakPtr(const RefPtr
<T
>& aOther
) : WeakPtr(aOther
.get()) {}
299 // Ensure that mRef is dereferenceable in the uninitialized state.
300 WeakPtr() : mRef(new WeakReference(nullptr)) {}
302 explicit operator bool() const { return mRef
->get(); }
303 T
* get() const { return static_cast<T
*>(mRef
->get()); }
304 operator T
*() const { return get(); }
305 T
& operator*() const { return *get(); }
306 T
* operator->() const MOZ_NO_ADDREF_RELEASE_ON_RETURN
{ return get(); }
308 #ifdef MOZILLA_INTERNAL_API
310 if (Destruct
== detail::WeakPtrDestructorBehavior::ProxyToMainThread
) {
311 NS_ReleaseOnMainThread("WeakPtr::mRef", mRef
.forget());
313 MOZ_WEAKPTR_ASSERT_THREAD_SAFETY_DELEGATED(mRef
);
319 friend class SupportsWeakPtr
;
321 explicit WeakPtr(const RefPtr
<WeakReference
>& aOther
) : mRef(aOther
) {}
323 RefPtr
<WeakReference
> mRef
;
326 #ifdef MOZILLA_INTERNAL_API
328 template <typename T
>
329 using MainThreadWeakPtr
=
330 WeakPtr
<T
, detail::WeakPtrDestructorBehavior::ProxyToMainThread
>;
334 #define NS_IMPL_CYCLE_COLLECTION_UNLINK_WEAK_PTR tmp->DetachWeakPtr();
336 #define NS_IMPL_CYCLE_COLLECTION_WEAK_PTR(class_, ...) \
337 NS_IMPL_CYCLE_COLLECTION_CLASS(class_) \
338 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(class_) \
339 NS_IMPL_CYCLE_COLLECTION_UNLINK(__VA_ARGS__) \
340 NS_IMPL_CYCLE_COLLECTION_UNLINK_WEAK_PTR \
341 NS_IMPL_CYCLE_COLLECTION_UNLINK_END \
342 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(class_) \
343 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(__VA_ARGS__) \
344 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
346 #define NS_IMPL_CYCLE_COLLECTION_WEAK_PTR_INHERITED(class_, super_, ...) \
347 NS_IMPL_CYCLE_COLLECTION_CLASS(class_) \
348 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(class_, super_) \
349 NS_IMPL_CYCLE_COLLECTION_UNLINK(__VA_ARGS__) \
350 NS_IMPL_CYCLE_COLLECTION_UNLINK_WEAK_PTR \
351 NS_IMPL_CYCLE_COLLECTION_UNLINK_END \
352 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(class_, super_) \
353 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(__VA_ARGS__) \
354 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
356 } // namespace mozilla
358 #endif /* mozilla_WeakPtr_h */