Source code

Revision control

Other Tools

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:
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/Maybe.h"
74
#include "mozilla/RefCounted.h"
75
#include "mozilla/RefPtr.h"
76
#include "mozilla/TypeTraits.h"
77
78
#include <string.h>
79
80
#if defined(MOZILLA_INTERNAL_API)
81
// For thread safety checking.
82
# include "nsISupportsImpl.h"
83
#endif
84
85
#if defined(MOZILLA_INTERNAL_API) && \
86
defined(MOZ_THREAD_SAFETY_OWNERSHIP_CHECKS_SUPPORTED)
87
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.
94
//
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.
100
//
101
// We re-use XPCOM's nsAutoOwningThread checks when they are available. This has
102
// the advantage that it works with cooperative thread pools.
103
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() \
108
do { \
109
if (p) { \
110
_owningThread.emplace(); \
111
} \
112
} while (false)
113
# define MOZ_WEAKPTR_ASSERT_THREAD_SAFETY() \
114
do { \
115
if (_owningThread.isSome() && !_owningThread.ref().IsCurrentThread()) { \
116
WeakPtrTraits<T>::AssertSafeToAccessFromNonOwningThread(); \
117
} \
118
} while (false)
119
# define MOZ_WEAKPTR_ASSERT_THREAD_SAFETY_DELEGATED(that) \
120
(that)->AssertThreadSafety();
121
# define MOZ_WEAKPTR_ASSERT_THREAD_SAFETY_DELEGATED_IF(that) \
122
do { \
123
if (that) { \
124
(that)->AssertThreadSafety(); \
125
} \
126
} while (false)
127
128
# define MOZ_WEAKPTR_THREAD_SAFETY_CHECKING 1
129
130
#else
131
132
# define MOZ_WEAKPTR_DECLARE_THREAD_SAFETY_CHECK
133
# define MOZ_WEAKPTR_INIT_THREAD_SAFETY_CHECK() \
134
do { \
135
} while (false)
136
# define MOZ_WEAKPTR_ASSERT_THREAD_SAFETY() \
137
do { \
138
} while (false)
139
# define MOZ_WEAKPTR_ASSERT_THREAD_SAFETY_DELEGATED(that) \
140
do { \
141
} while (false)
142
# define MOZ_WEAKPTR_ASSERT_THREAD_SAFETY_DELEGATED_IF(that) \
143
do { \
144
} while (false)
145
146
#endif
147
148
namespace mozilla {
149
150
template <typename T>
151
class WeakPtr;
152
template <typename T>
153
class SupportsWeakPtr;
154
155
#ifdef MOZ_REFCOUNTED_LEAK_CHECKING
156
# define MOZ_DECLARE_WEAKREFERENCE_TYPENAME(T) \
157
static const char* weakReferenceTypeName() { \
158
return "WeakReference<" #T ">"; \
159
}
160
#else
161
# define MOZ_DECLARE_WEAKREFERENCE_TYPENAME(T)
162
#endif
163
164
template <class T>
165
struct WeakPtrTraits {
166
static void AssertSafeToAccessFromNonOwningThread() {
167
MOZ_DIAGNOSTIC_ASSERT(false, "WeakPtr accessed from multiple threads");
168
}
169
};
170
171
namespace detail {
172
173
// This can live beyond the lifetime of the class derived from
174
// SupportsWeakPtr.
175
template <class T>
176
class WeakReference : public ::mozilla::RefCounted<WeakReference<T>> {
177
public:
178
explicit WeakReference(T* p) : mPtr(p) {
179
MOZ_WEAKPTR_INIT_THREAD_SAFETY_CHECK();
180
}
181
182
T* get() const {
183
MOZ_WEAKPTR_ASSERT_THREAD_SAFETY();
184
return mPtr;
185
}
186
187
#ifdef MOZ_REFCOUNTED_LEAK_CHECKING
188
const char* typeName() const {
189
// The first time this is called mPtr is null, so don't
190
// invoke any methods on mPtr.
191
return T::weakReferenceTypeName();
192
}
193
size_t typeSize() const { return sizeof(*this); }
194
#endif
195
196
#ifdef MOZ_WEAKPTR_THREAD_SAFETY_CHECKING
197
void AssertThreadSafety() { MOZ_WEAKPTR_ASSERT_THREAD_SAFETY(); }
198
#endif
199
200
private:
201
friend class mozilla::SupportsWeakPtr<T>;
202
203
void detach() {
204
MOZ_WEAKPTR_ASSERT_THREAD_SAFETY();
205
mPtr = nullptr;
206
}
207
208
T* MOZ_NON_OWNING_REF mPtr;
209
MOZ_WEAKPTR_DECLARE_THREAD_SAFETY_CHECK
210
};
211
212
} // namespace detail
213
214
template <typename T>
215
class SupportsWeakPtr {
216
protected:
217
~SupportsWeakPtr() {
218
static_assert(std::is_base_of<SupportsWeakPtr<T>, T>::value,
219
"T must derive from SupportsWeakPtr<T>");
220
if (mSelfReferencingWeakPtr) {
221
mSelfReferencingWeakPtr.mRef->detach();
222
}
223
}
224
225
private:
226
const WeakPtr<T>& SelfReferencingWeakPtr() {
227
if (!mSelfReferencingWeakPtr) {
228
mSelfReferencingWeakPtr.mRef =
229
new detail::WeakReference<T>(static_cast<T*>(this));
230
} else {
231
MOZ_WEAKPTR_ASSERT_THREAD_SAFETY_DELEGATED(mSelfReferencingWeakPtr.mRef);
232
}
233
return mSelfReferencingWeakPtr;
234
}
235
236
const WeakPtr<const T>& SelfReferencingWeakPtr() const {
237
const WeakPtr<T>& p =
238
const_cast<SupportsWeakPtr*>(this)->SelfReferencingWeakPtr();
239
return reinterpret_cast<const WeakPtr<const T>&>(p);
240
}
241
242
friend class WeakPtr<T>;
243
friend class WeakPtr<const T>;
244
245
WeakPtr<T> mSelfReferencingWeakPtr;
246
};
247
248
template <typename T>
249
class WeakPtr {
250
typedef detail::WeakReference<T> WeakReference;
251
typedef typename RemoveConst<T>::Type NonConstT;
252
253
public:
254
WeakPtr& operator=(const WeakPtr& aOther) {
255
// We must make sure the reference we have now is safe to be dereferenced
256
// before we throw it away... (this can be called from a ctor)
257
MOZ_WEAKPTR_ASSERT_THREAD_SAFETY_DELEGATED_IF(mRef);
258
// ...and make sure the new reference is used on a single thread as well.
259
MOZ_WEAKPTR_ASSERT_THREAD_SAFETY_DELEGATED(aOther.mRef);
260
261
mRef = aOther.mRef;
262
return *this;
263
}
264
265
WeakPtr(const WeakPtr& aOther) {
266
// The thread safety check is performed inside of the operator= method.
267
*this = aOther;
268
}
269
270
WeakPtr& operator=(decltype(nullptr)) {
271
// We must make sure the reference we have now is safe to be dereferenced
272
// before we throw it away.
273
MOZ_WEAKPTR_ASSERT_THREAD_SAFETY_DELEGATED_IF(mRef);
274
if (!mRef || mRef->get()) {
275
// Ensure that mRef is dereferenceable in the uninitialized state.
276
mRef = new WeakReference(nullptr);
277
}
278
return *this;
279
}
280
281
WeakPtr& operator=(SupportsWeakPtr<NonConstT> const* aOther) {
282
// We must make sure the reference we have now is safe to be dereferenced
283
// before we throw it away.
284
MOZ_WEAKPTR_ASSERT_THREAD_SAFETY_DELEGATED_IF(mRef);
285
if (aOther) {
286
*this = aOther->SelfReferencingWeakPtr();
287
} else if (!mRef || mRef->get()) {
288
// Ensure that mRef is dereferenceable in the uninitialized state.
289
mRef = new WeakReference(nullptr);
290
}
291
// The thread safety check happens inside SelfReferencingWeakPtr
292
// or is initialized in the WeakReference constructor.
293
return *this;
294
}
295
296
WeakPtr& operator=(SupportsWeakPtr<NonConstT>* aOther) {
297
// We must make sure the reference we have now is safe to be dereferenced
298
// before we throw it away.
299
MOZ_WEAKPTR_ASSERT_THREAD_SAFETY_DELEGATED_IF(mRef);
300
if (aOther) {
301
*this = aOther->SelfReferencingWeakPtr();
302
} else if (!mRef || mRef->get()) {
303
// Ensure that mRef is dereferenceable in the uninitialized state.
304
mRef = new WeakReference(nullptr);
305
}
306
// The thread safety check happens inside SelfReferencingWeakPtr
307
// or is initialized in the WeakReference constructor.
308
return *this;
309
}
310
311
MOZ_IMPLICIT WeakPtr(T* aOther) { *this = aOther; }
312
313
// Ensure that mRef is dereferenceable in the uninitialized state.
314
WeakPtr() : mRef(new WeakReference(nullptr)) {}
315
316
operator T*() const { return mRef->get(); }
317
T& operator*() const { return *mRef->get(); }
318
319
T* operator->() const MOZ_NO_ADDREF_RELEASE_ON_RETURN { return mRef->get(); }
320
321
T* get() const { return mRef->get(); }
322
323
~WeakPtr() { MOZ_WEAKPTR_ASSERT_THREAD_SAFETY_DELEGATED(mRef); }
324
325
private:
326
friend class SupportsWeakPtr<T>;
327
328
explicit WeakPtr(const RefPtr<WeakReference>& aOther) : mRef(aOther) {}
329
330
RefPtr<WeakReference> mRef;
331
};
332
333
} // namespace mozilla
334
335
#endif /* mozilla_WeakPtr_h */