Line data Source code
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 :
7 : /* Weak pointer functionality, implemented as a mixin for use with any class. */
8 :
9 : /**
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
15 : * of 'Foo'.
16 : *
17 : * PLEASE NOTE: This weak pointer implementation is not thread-safe.
18 : *
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.
22 : *
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.
26 : *
27 : * Example of usage:
28 : *
29 : * // To have a class C support weak pointers, inherit from
30 : * // SupportsWeakPtr<C>.
31 : * class C : public SupportsWeakPtr<C>
32 : * {
33 : * public:
34 : * MOZ_DECLARE_WEAKREFERENCE_TYPENAME(C)
35 : * int mNum;
36 : * void act();
37 : * };
38 : *
39 : * C* ptr = new C();
40 : *
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;
47 : *
48 : * // Test a weak pointer for validity before using it.
49 : * if (weak) {
50 : * weak->mNum = 17;
51 : * weak->act();
52 : * }
53 : *
54 : * // Destroying the underlying object clears weak pointers to it.
55 : * delete ptr;
56 : *
57 : * MOZ_ASSERT(!weak, "Deleting |ptr| clears weak pointers to it.");
58 : * MOZ_ASSERT(!other, "Deleting |ptr| clears all weak pointers to it.");
59 : *
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.
62 : *
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
65 : */
66 :
67 : #ifndef mozilla_WeakPtr_h
68 : #define mozilla_WeakPtr_h
69 :
70 : #include "mozilla/ArrayUtils.h"
71 : #include "mozilla/Assertions.h"
72 : #include "mozilla/Attributes.h"
73 : #include "mozilla/RefCounted.h"
74 : #include "mozilla/RefPtr.h"
75 : #include "mozilla/TypeTraits.h"
76 :
77 : #include <string.h>
78 :
79 : // Weak referencing is not implemeted as thread safe. When a WeakPtr
80 : // is created or dereferenced on thread A but the real object is just
81 : // being Released() on thread B, there is a possibility of a race
82 : // when the proxy object (detail::WeakReference) is notified about
83 : // the real object destruction just between when thread A is storing
84 : // the object pointer locally and is about to add a reference to it.
85 : //
86 : // Hence, a non-null weak proxy object is considered to have a single
87 : // "owning thread". It means that each query for a weak reference,
88 : // its dereference, and destruction of the real object must all happen
89 : // on a single thread. The following macros implement assertions for
90 : // checking these conditions.
91 : //
92 : // We disable this on MinGW. MinGW has two threading models: win32
93 : // API based, which disables std::thread; and POSIX based which
94 : // enables it but requires an emulation library (winpthreads).
95 : // Rather than attempting to switch to pthread emulation at this point,
96 : // we are disabling the std::thread based assertion checking.
97 : //
98 : // In the future, to enable it we could
99 : // a. have libgcc/stdc++ support win32 threads natively
100 : // b. switch to POSIX-based threading in MinGW with pthread emulation
101 : // c. refactor it to not use std::thread
102 :
103 : #if !defined(__MINGW32__) && (defined(DEBUG) || (defined(NIGHTLY_BUILD) && !defined(MOZ_PROFILING)))
104 :
105 : #include <thread>
106 : #define MOZ_WEAKPTR_DECLARE_THREAD_SAFETY_CHECK \
107 : std::thread::id _owningThread; \
108 : bool _empty; // If it was initialized as a placeholder with mPtr = nullptr.
109 : #define MOZ_WEAKPTR_INIT_THREAD_SAFETY_CHECK() \
110 : do { \
111 : _owningThread = std::this_thread::get_id(); \
112 : _empty = !p; \
113 : } while (false)
114 : #define MOZ_WEAKPTR_ASSERT_THREAD_SAFETY() \
115 : do { \
116 : if (!(_empty || _owningThread == std::this_thread::get_id())) { \
117 : WeakPtrTraits<T>::AssertSafeToAccessFromNonOwningThread(); \
118 : } \
119 : } while (false)
120 : #define MOZ_WEAKPTR_ASSERT_THREAD_SAFETY_DELEGATED(that) \
121 : (that)->AssertThreadSafety();
122 :
123 : #define MOZ_WEAKPTR_THREAD_SAFETY_CHECKING 1
124 :
125 : #else
126 :
127 : #define MOZ_WEAKPTR_DECLARE_THREAD_SAFETY_CHECK
128 : #define MOZ_WEAKPTR_INIT_THREAD_SAFETY_CHECK() do { } while (false)
129 : #define MOZ_WEAKPTR_ASSERT_THREAD_SAFETY() do { } while (false)
130 : #define MOZ_WEAKPTR_ASSERT_THREAD_SAFETY_DELEGATED(that) do { } while (false)
131 :
132 : #endif
133 :
134 : namespace mozilla {
135 :
136 : template <typename T> class WeakPtr;
137 : template <typename T> class SupportsWeakPtr;
138 :
139 : #ifdef MOZ_REFCOUNTED_LEAK_CHECKING
140 : #define MOZ_DECLARE_WEAKREFERENCE_TYPENAME(T) \
141 : static const char* weakReferenceTypeName() { return "WeakReference<" #T ">"; }
142 : #else
143 : #define MOZ_DECLARE_WEAKREFERENCE_TYPENAME(T)
144 : #endif
145 :
146 : template<class T>
147 : struct WeakPtrTraits
148 : {
149 0 : static void AssertSafeToAccessFromNonOwningThread()
150 : {
151 0 : MOZ_DIAGNOSTIC_ASSERT(false, "WeakPtr accessed from multiple threads");
152 : }
153 : };
154 :
155 : namespace detail {
156 :
157 : // This can live beyond the lifetime of the class derived from
158 : // SupportsWeakPtr.
159 : template<class T>
160 938 : class WeakReference : public ::mozilla::RefCounted<WeakReference<T> >
161 : {
162 : public:
163 1877 : explicit WeakReference(T* p) : mPtr(p)
164 : {
165 1877 : MOZ_WEAKPTR_INIT_THREAD_SAFETY_CHECK();
166 1877 : }
167 :
168 16606 : T* get() const {
169 16606 : MOZ_WEAKPTR_ASSERT_THREAD_SAFETY();
170 16606 : return mPtr;
171 : }
172 :
173 : #ifdef MOZ_REFCOUNTED_LEAK_CHECKING
174 5458 : const char* typeName() const
175 : {
176 : // The first time this is called mPtr is null, so don't
177 : // invoke any methods on mPtr.
178 5458 : return T::weakReferenceTypeName();
179 : }
180 3308 : size_t typeSize() const { return sizeof(*this); }
181 : #endif
182 :
183 : #ifdef MOZ_WEAKPTR_THREAD_SAFETY_CHECKING
184 3943 : void AssertThreadSafety() { MOZ_WEAKPTR_ASSERT_THREAD_SAFETY(); }
185 : #endif
186 :
187 : private:
188 : friend class mozilla::SupportsWeakPtr<T>;
189 :
190 30 : void detach() {
191 30 : MOZ_WEAKPTR_ASSERT_THREAD_SAFETY();
192 30 : mPtr = nullptr;
193 30 : }
194 :
195 : T* MOZ_NON_OWNING_REF mPtr;
196 : MOZ_WEAKPTR_DECLARE_THREAD_SAFETY_CHECK
197 : };
198 :
199 : } // namespace detail
200 :
201 : template <typename T>
202 410 : class SupportsWeakPtr
203 : {
204 : protected:
205 34 : ~SupportsWeakPtr()
206 : {
207 : static_assert(IsBaseOf<SupportsWeakPtr<T>, T>::value,
208 : "T must derive from SupportsWeakPtr<T>");
209 34 : if (mSelfReferencingWeakPtr) {
210 30 : mSelfReferencingWeakPtr.mRef->detach();
211 : }
212 34 : }
213 :
214 : private:
215 1199 : const WeakPtr<T>& SelfReferencingWeakPtr()
216 : {
217 1199 : if (!mSelfReferencingWeakPtr) {
218 267 : mSelfReferencingWeakPtr.mRef = new detail::WeakReference<T>(static_cast<T*>(this));
219 : } else {
220 932 : MOZ_WEAKPTR_ASSERT_THREAD_SAFETY_DELEGATED(mSelfReferencingWeakPtr.mRef);
221 : }
222 1199 : return mSelfReferencingWeakPtr;
223 : }
224 :
225 0 : const WeakPtr<const T>& SelfReferencingWeakPtr() const
226 : {
227 0 : const WeakPtr<T>& p = const_cast<SupportsWeakPtr*>(this)->SelfReferencingWeakPtr();
228 0 : return reinterpret_cast<const WeakPtr<const T>&>(p);
229 : }
230 :
231 : friend class WeakPtr<T>;
232 : friend class WeakPtr<const T>;
233 :
234 : WeakPtr<T> mSelfReferencingWeakPtr;
235 : };
236 :
237 : template <typename T>
238 1555 : class WeakPtr
239 : {
240 : typedef detail::WeakReference<T> WeakReference;
241 :
242 : public:
243 1431 : WeakPtr& operator=(const WeakPtr& aOther)
244 : {
245 1431 : mRef = aOther.mRef;
246 1431 : MOZ_WEAKPTR_ASSERT_THREAD_SAFETY_DELEGATED(mRef);
247 1431 : return *this;
248 : }
249 :
250 6 : WeakPtr(const WeakPtr& aOther)
251 6 : {
252 : // The thread safety check is performed inside of the operator= method.
253 6 : *this = aOther;
254 6 : }
255 :
256 1704 : WeakPtr& operator=(T* aOther)
257 : {
258 1704 : if (aOther) {
259 1199 : *this = aOther->SelfReferencingWeakPtr();
260 505 : } else if (!mRef || mRef->get()) {
261 : // Ensure that mRef is dereferenceable in the uninitialized state.
262 483 : mRef = new WeakReference(nullptr);
263 : }
264 : // The thread safety check happens inside SelfReferencingWeakPtr
265 : // or is initialized in the WeakReference constructor.
266 1704 : return *this;
267 : }
268 :
269 1580 : MOZ_IMPLICIT WeakPtr(T* aOther)
270 1580 : {
271 1580 : *this = aOther;
272 1580 : MOZ_WEAKPTR_ASSERT_THREAD_SAFETY_DELEGATED(mRef);
273 1580 : }
274 :
275 : // Ensure that mRef is dereferenceable in the uninitialized state.
276 2254 : WeakPtr() : mRef(new WeakReference(nullptr)) {}
277 :
278 10244 : operator T*() const { return mRef->get(); }
279 : T& operator*() const { return *mRef->get(); }
280 :
281 5090 : T* operator->() const MOZ_NO_ADDREF_RELEASE_ON_RETURN { return mRef->get(); }
282 :
283 1244 : T* get() const { return mRef->get(); }
284 :
285 : private:
286 : friend class SupportsWeakPtr<T>;
287 :
288 : explicit WeakPtr(const RefPtr<WeakReference>& aOther) : mRef(aOther) {}
289 :
290 : RefPtr<WeakReference> mRef;
291 : };
292 :
293 : } // namespace mozilla
294 :
295 : #endif /* mozilla_WeakPtr_h */
|