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 /* A thread-safe weak pointer */
10 * Derive from SupportsThreadSafeWeakPtr to allow thread-safe weak pointers to
11 * an atomically refcounted derived class. These thread-safe weak pointers may
12 * be safely accessed and converted to strong pointers on multiple threads.
14 * Note that SupportsThreadSafeWeakPtr defines the same member functions as
15 * AtomicRefCounted, so you should not separately inherit from it.
17 * ThreadSafeWeakPtr and its implementation is distinct from the normal WeakPtr
18 * which is not thread-safe. The interface discipline and implementation details
19 * are different enough that these two implementations are separated for now for
20 * efficiency reasons. If you don't actually need to use weak pointers on
21 * multiple threads, you can just use WeakPtr instead.
23 * When deriving from SupportsThreadSafeWeakPtr, you should add
24 * MOZ_DECLARE_REFCOUNTED_TYPENAME(ClassName) to the public section of your
25 * class, where ClassName is the name of your class.
29 * class C : public SupportsThreadSafeWeakPtr<C>
32 * MOZ_DECLARE_REFCOUNTED_TYPENAME(C)
36 * ThreadSafeWeakPtr<C> weak;
38 * RefPtr<C> strong = new C;
42 * // Make a new weak reference to the object from the strong reference.
45 * MOZ_ASSERT(!bool(weak), "Weak pointers are cleared after all "
46 * "strong references are released.");
48 * // Convert the weak reference to a strong reference for usage.
49 * RefPtr<C> other(weak);
55 #ifndef mozilla_ThreadSafeWeakPtr_h
56 #define mozilla_ThreadSafeWeakPtr_h
58 #include "mozilla/Assertions.h"
59 #include "mozilla/RefCounted.h"
60 #include "mozilla/RefPtr.h"
65 class ThreadSafeWeakPtr
;
68 class SupportsThreadSafeWeakPtr
;
72 class SupportsThreadSafeWeakPtrBase
{};
74 // A shared weak reference that is used to track a SupportsThreadSafeWeakPtr
75 // object. This object owns the reference count for the tracked object, and can
76 // perform atomic refcount upgrades.
77 class ThreadSafeWeakReference
78 : public external::AtomicRefCounted
<ThreadSafeWeakReference
> {
80 explicit ThreadSafeWeakReference(SupportsThreadSafeWeakPtrBase
* aPtr
)
83 #ifdef MOZ_REFCOUNTED_LEAK_CHECKING
84 const char* typeName() const { return "ThreadSafeWeakReference"; }
85 size_t typeSize() const { return sizeof(*this); }
90 friend class mozilla::SupportsThreadSafeWeakPtr
;
92 friend class mozilla::ThreadSafeWeakPtr
;
94 // Number of strong references to the underlying data structure.
96 // Other than the initial strong `AddRef` call incrementing this value to 1,
97 // which must occur before any weak references are taken, once this value
98 // reaches `0` again it cannot be changed.
99 RC
<MozRefCountType
, AtomicRefCount
> mStrongCnt
{0};
101 // Raw pointer to the tracked object. It is never valid to read this value
102 // outside of `ThreadSafeWeakPtr::getRefPtr()`.
103 SupportsThreadSafeWeakPtrBase
* MOZ_NON_OWNING_REF mPtr
;
106 } // namespace detail
108 // For usage documentation for SupportsThreadSafeWeakPtr, see the header-level
111 // To understand the layout of SupportsThreadSafeWeakPtr, consider the following
112 // simplified declaration:
114 // class MyType: SupportsThreadSafeWeakPtr { uint32_t mMyData; ... }
116 // Which will result in the following layout:
118 // +--------------------+
119 // | MyType | <===============================================+
120 // +--------------------+ I
121 // | RefPtr mWeakRef o======> +-------------------------------------+ I
122 // | uint32_t mMyData | | ThreadSafeWeakReference | I
123 // +--------------------+ +-------------------------------------+ I
124 // | RC mRefCount | I
125 // | RC mStrongCount | I
126 // | SupportsThreadSafeWeakPtrBase* mPtr o====+
127 // +-------------------------------------+
129 // The mRefCount inherited from AtomicRefCounted<ThreadSafeWeakReference> is the
130 // weak count. This means MyType implicitly holds a weak reference, so if the
131 // weak count ever hits 0, we know all strong *and* weak references are gone,
132 // and it's safe to free the ThreadSafeWeakReference. MyType's AddRef and
133 // Release implementations otherwise only manipulate mStrongCount.
135 // It's necessary to keep the counts in a separate allocation because we need
136 // to be able to delete MyType while weak references still exist. This ensures
137 // that weak references can still access all the state necessary to check if
138 // they can be upgraded (mStrongCount).
139 template <typename T
>
140 class SupportsThreadSafeWeakPtr
: public detail::SupportsThreadSafeWeakPtrBase
{
142 using ThreadSafeWeakReference
= detail::ThreadSafeWeakReference
;
144 // The `this` pointer will not have subclasses initialized yet, but it will
145 // also not be read until a weak pointer is upgraded, which should be after
147 SupportsThreadSafeWeakPtr() : mWeakRef(new ThreadSafeWeakReference(this)) {
148 static_assert(std::is_base_of_v
<SupportsThreadSafeWeakPtr
, T
>,
149 "T must derive from SupportsThreadSafeWeakPtr");
153 // Compatibility with RefPtr
154 void AddRef() const {
155 auto& refCnt
= mWeakRef
->mStrongCnt
;
156 MOZ_ASSERT(int32_t(refCnt
) >= 0);
157 MozRefCountType cnt
= ++refCnt
;
158 detail::RefCountLogger::logAddRef(static_cast<const T
*>(this), cnt
);
161 void Release() const {
162 auto& refCnt
= mWeakRef
->mStrongCnt
;
163 MOZ_ASSERT(int32_t(refCnt
) > 0);
164 detail::RefCountLogger::ReleaseLogger
logger(static_cast<const T
*>(this));
165 MozRefCountType cnt
= --refCnt
;
166 logger
.logRelease(cnt
);
168 // Because we have atomically decremented the refcount above, only one
169 // thread can get a 0 count here. Thus, it is safe to access and destroy
171 // No other thread can acquire a strong reference to |this| anymore
172 // through our weak pointer, as upgrading a weak pointer always uses
173 // |IncrementIfNonzero|, meaning the refcount can't leave a zero reference
175 // NOTE: We can't update our refcount to the marker `DEAD` value here, as
176 // it may still be read by mWeakRef.
177 delete static_cast<const T
*>(this);
181 // Compatibility with wtf::RefPtr
182 void ref() { AddRef(); }
183 void deref() { Release(); }
184 MozRefCountType
refCount() const { return mWeakRef
->mStrongCnt
; }
187 template <typename U
>
188 friend class ThreadSafeWeakPtr
;
190 ThreadSafeWeakReference
* getThreadSafeWeakReference() const {
194 const RefPtr
<ThreadSafeWeakReference
> mWeakRef
;
197 // A thread-safe variant of a weak pointer
198 template <typename T
>
199 class ThreadSafeWeakPtr
{
200 using ThreadSafeWeakReference
= detail::ThreadSafeWeakReference
;
203 ThreadSafeWeakPtr() = default;
205 ThreadSafeWeakPtr
& operator=(const ThreadSafeWeakPtr
& aOther
) = default;
206 ThreadSafeWeakPtr(const ThreadSafeWeakPtr
& aOther
) = default;
208 ThreadSafeWeakPtr
& operator=(ThreadSafeWeakPtr
&& aOther
) = default;
209 ThreadSafeWeakPtr(ThreadSafeWeakPtr
&& aOther
) = default;
211 ThreadSafeWeakPtr
& operator=(const RefPtr
<T
>& aOther
) {
213 // Get the underlying shared weak reference to the object.
214 mRef
= aOther
->getThreadSafeWeakReference();
221 explicit ThreadSafeWeakPtr(const RefPtr
<T
>& aOther
) { *this = aOther
; }
223 ThreadSafeWeakPtr
& operator=(decltype(nullptr)) {
228 explicit ThreadSafeWeakPtr(decltype(nullptr)) {}
230 // Use the explicit `IsNull()` or `IsDead()` methods instead.
231 explicit operator bool() const = delete;
233 // Check if the ThreadSafeWeakPtr was created wrapping a null pointer.
234 bool IsNull() const { return !mRef
; }
236 // Check if the managed object is nullptr or has already been destroyed. Once
237 // IsDead returns true, this ThreadSafeWeakPtr can never be upgraded again
238 // (until it has been re-assigned), but a false return value does NOT imply
239 // that any future upgrade will be successful.
240 bool IsDead() const { return IsNull() || size_t(mRef
->mStrongCnt
) == 0; }
242 bool operator==(const ThreadSafeWeakPtr
& aOther
) const {
243 return mRef
== aOther
.mRef
;
246 bool operator==(const RefPtr
<T
>& aOther
) const {
247 return *this == aOther
.get();
250 bool operator==(const T
* aOther
) const {
254 return aOther
&& aOther
->getThreadSafeWeakReference() == mRef
;
257 template <typename U
>
258 bool operator!=(const U
& aOther
) const {
259 return !(*this == aOther
);
262 // Convert the weak pointer to a strong RefPtr.
263 explicit operator RefPtr
<T
>() const { return getRefPtr(); }
266 // Gets a new strong reference of the proper type T to the tracked object.
267 already_AddRefed
<T
> getRefPtr() const {
271 // Increment our strong reference count only if it is nonzero, meaning that
272 // the object is still alive.
273 MozRefCountType cnt
= mRef
->mStrongCnt
.IncrementIfNonzero();
278 RefPtr
<T
> ptr
= already_AddRefed
<T
>(static_cast<T
*>(mRef
->mPtr
));
279 detail::RefCountLogger::logAddRef(ptr
.get(), cnt
);
283 // A shared weak reference to an object. Note that this may be null so as to
284 // save memory (at the slight cost of an extra null check) if no object is
286 RefPtr
<ThreadSafeWeakReference
> mRef
;
289 } // namespace mozilla
291 template <typename T
>
292 inline already_AddRefed
<T
> do_AddRef(
293 const mozilla::ThreadSafeWeakPtr
<T
>& aObj
) {
298 #endif /* mozilla_ThreadSafeWeakPtr_h */