/work/obj-fuzz/dist/include/mozilla/ThreadSafeWeakPtr.h
Line | Count | Source (jump to first uncovered line) |
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 | | /* A thread-safe weak pointer */ |
8 | | |
9 | | /** |
10 | | * Derive from SupportsThreadSafeWeakPtr to allow thread-safe weak pointers to an |
11 | | * atomically refcounted derived class. These thread-safe weak pointers may be safely |
12 | | * accessed and converted to strong pointers on multiple threads. |
13 | | * |
14 | | * Note that SupportsThreadSafeWeakPtr necessarily already inherits from AtomicRefCounted, |
15 | | * so you should not separately inherit from AtomicRefCounted. |
16 | | * |
17 | | * ThreadSafeWeakPtr and its implementation is distinct from the normal WeakPtr which is |
18 | | * not thread-safe. The interface discipline and implementation details are different enough |
19 | | * that these two implementations are separated for now for efficiency reasons. If you don't |
20 | | * actually need to use weak pointers on multiple threads, you can just use WeakPtr instead. |
21 | | * |
22 | | * When deriving from SupportsThreadSafeWeakPtr, you should add |
23 | | * MOZ_DECLARE_THREADSAFEWEAKREFERENCE_TYPENAME(ClassName) and |
24 | | * MOZ_DECLARE_REFCOUNTED_TYPENAME(ClassName) to the public section of your class, |
25 | | * where ClassName is the name of your class. |
26 | | * |
27 | | * Example usage: |
28 | | * |
29 | | * class C : public SupportsThreadSafeWeakPtr<C> |
30 | | * { |
31 | | * public: |
32 | | * MOZ_DECLARE_THREADSAFEWEAKREFERENCE_TYPENAME(C) |
33 | | * MOZ_DECLARE_REFCOUNTED_TYPENAME(C) |
34 | | * void doStuff(); |
35 | | * }; |
36 | | * |
37 | | * ThreadSafeWeakPtr<C> weak; |
38 | | * { |
39 | | * RefPtr<C> strong = new C; |
40 | | * if (strong) { |
41 | | * strong->doStuff(); |
42 | | * } |
43 | | * // Make a new weak reference to the object from the strong reference. |
44 | | * weak = strong; |
45 | | * } |
46 | | * MOZ_ASSERT(!bool(weak), "Weak pointers are cleared after all strong references are released."); |
47 | | * |
48 | | * // Convert the weak reference to a strong reference for usage. |
49 | | * RefPtr<C> other(weak); |
50 | | * if (other) { |
51 | | * other->doStuff(); |
52 | | * } |
53 | | */ |
54 | | |
55 | | #ifndef mozilla_ThreadSafeWeakPtr_h |
56 | | #define mozilla_ThreadSafeWeakPtr_h |
57 | | |
58 | | #include "mozilla/Assertions.h" |
59 | | #include "mozilla/Atomics.h" |
60 | | #include "mozilla/RefCounted.h" |
61 | | #include "mozilla/RefPtr.h" |
62 | | #include "mozilla/TypeTraits.h" |
63 | | #include "mozilla/Unused.h" |
64 | | |
65 | | #include <limits> |
66 | | |
67 | | namespace mozilla { |
68 | | |
69 | | template<typename T> class ThreadSafeWeakPtr; |
70 | | template<typename T> class SupportsThreadSafeWeakPtr; |
71 | | |
72 | | #ifdef MOZ_REFCOUNTED_LEAK_CHECKING |
73 | | #define MOZ_DECLARE_THREADSAFEWEAKREFERENCE_TYPENAME(T) \ |
74 | | static const char* threadSafeWeakReferenceTypeName() { return "ThreadSafeWeakReference<" #T ">"; } |
75 | | #else |
76 | | #define MOZ_DECLARE_THREADSAFEWEAKREFERENCE_TYPENAME(T) |
77 | | #endif |
78 | | |
79 | | namespace detail { |
80 | | |
81 | | // A multiple reader, single writer spin-lock. |
82 | | // This lock maintains an atomic counter which is incremented every time the lock is acquired |
83 | | // reading. So long as the counter remains positive, it may be incremented for reading multiple |
84 | | // times. When acquiring the lock for writing, we must ensure the counter is 0 (no readers), |
85 | | // and if so, set it to a negative value to indicate that no new readers may take the lock. |
86 | | class ReadWriteSpinLock |
87 | | { |
88 | | // Only need a type large enough to represent the number of simultaneously accessing threads. |
89 | | typedef int32_t CounterType; |
90 | | |
91 | | public: |
92 | | // Try to increment the counter for reading, so long as it is positive. |
93 | | void readLock() |
94 | 0 | { |
95 | 0 | for (;;) |
96 | 0 | { |
97 | 0 | CounterType oldCounter = mCounter & std::numeric_limits<CounterType>::max(); |
98 | 0 | CounterType newCounter = oldCounter + 1; |
99 | 0 | if (mCounter.compareExchange(oldCounter, newCounter)) { |
100 | 0 | break; |
101 | 0 | } |
102 | 0 | } |
103 | 0 | } |
104 | | |
105 | | // Decrement the counter to remove a read lock. |
106 | | void readUnlock() |
107 | 0 | { |
108 | 0 | mCounter--; |
109 | 0 | } |
110 | | |
111 | | // Try to acquire the write lock, but only if there are no readers. |
112 | | // If successful, sets the counter to a negative value. |
113 | | bool tryWriteLock() |
114 | 0 | { |
115 | 0 | return mCounter.compareExchange(0, std::numeric_limits<CounterType>::min()); |
116 | 0 | } |
117 | | |
118 | | // Reset the counter to 0. |
119 | | void writeUnlock() |
120 | 0 | { |
121 | 0 | mCounter = 0; |
122 | 0 | } |
123 | | |
124 | | private: |
125 | | Atomic<CounterType> mCounter; |
126 | | }; |
127 | | |
128 | | // A shared weak reference that is used to track a SupportsThreadSafeWeakPtr object. |
129 | | // It guards access to that object via a read-write spinlock. |
130 | | template<typename T> |
131 | | class ThreadSafeWeakReference : public external::AtomicRefCounted<ThreadSafeWeakReference<T>> |
132 | | { |
133 | | public: |
134 | | typedef T ElementType; |
135 | | |
136 | | explicit ThreadSafeWeakReference(T* aPtr) |
137 | 0 | { |
138 | 0 | mPtr = aPtr; |
139 | 0 | } Unexecuted instantiation: mozilla::detail::ThreadSafeWeakReference<mozilla::gfx::UnscaledFont>::ThreadSafeWeakReference(mozilla::gfx::UnscaledFont*) Unexecuted instantiation: mozilla::detail::ThreadSafeWeakReference<mozilla::gfx::ScaledFont>::ThreadSafeWeakReference(mozilla::gfx::ScaledFont*) |
140 | | |
141 | | #ifdef MOZ_REFCOUNTED_LEAK_CHECKING |
142 | | const char* typeName() const |
143 | | { |
144 | | // The first time this is called mPtr is null, so don't |
145 | | // invoke any methods on mPtr. |
146 | | return T::threadSafeWeakReferenceTypeName(); |
147 | | } |
148 | | size_t typeSize() const { return sizeof(*this); } |
149 | | #endif |
150 | | |
151 | | private: |
152 | | friend class mozilla::SupportsThreadSafeWeakPtr<T>; |
153 | | template<typename U> friend class mozilla::ThreadSafeWeakPtr; |
154 | | |
155 | | // Does an unsafe read of the raw weak pointer. |
156 | | T* get() const |
157 | 0 | { |
158 | 0 | return mPtr; |
159 | 0 | } Unexecuted instantiation: mozilla::detail::ThreadSafeWeakReference<mozilla::gfx::UnscaledFont>::get() const Unexecuted instantiation: mozilla::detail::ThreadSafeWeakReference<mozilla::gfx::ScaledFont>::get() const |
160 | | |
161 | | // Creates a new RefPtr to the tracked object. |
162 | | // We need to acquire the read lock while we do this, as we need to atomically |
163 | | // both read the pointer and then increment the refcount on it within the scope |
164 | | // of the lock. This guards against the object being destroyed while in the middle |
165 | | // of creating the new RefPtr. |
166 | | already_AddRefed<T> getRefPtr() |
167 | 0 | { |
168 | 0 | mLock.readLock(); |
169 | 0 | RefPtr<T> result(get()); |
170 | 0 | mLock.readUnlock(); |
171 | 0 | return result.forget(); |
172 | 0 | } Unexecuted instantiation: mozilla::detail::ThreadSafeWeakReference<mozilla::gfx::ScaledFont>::getRefPtr() Unexecuted instantiation: mozilla::detail::ThreadSafeWeakReference<mozilla::gfx::UnscaledFont>::getRefPtr() |
173 | | |
174 | | // Try to detach the weak reference from the tracked object. |
175 | | // We need to acquire the write lock while we do this, to ensure that no |
176 | | // RefPtr is created to this while detaching. Once acquired, it is safe |
177 | | // to check the refcount and verify that this is the last reference to |
178 | | // the tracked object, so the weak reference can be safely detached. |
179 | | void tryDetach(const SupportsThreadSafeWeakPtr<T>* aOwner) |
180 | 0 | { |
181 | 0 | if (mLock.tryWriteLock()) { |
182 | 0 | if (aOwner->hasOneRef()) { |
183 | 0 | mPtr = nullptr; |
184 | 0 | } |
185 | 0 | mLock.writeUnlock(); |
186 | 0 | } |
187 | 0 | } Unexecuted instantiation: mozilla::detail::ThreadSafeWeakReference<mozilla::gfx::UnscaledFont>::tryDetach(mozilla::SupportsThreadSafeWeakPtr<mozilla::gfx::UnscaledFont> const*) Unexecuted instantiation: mozilla::detail::ThreadSafeWeakReference<mozilla::gfx::ScaledFont>::tryDetach(mozilla::SupportsThreadSafeWeakPtr<mozilla::gfx::ScaledFont> const*) |
188 | | |
189 | | ReadWriteSpinLock mLock; |
190 | | Atomic<T*> mPtr; |
191 | | }; |
192 | | |
193 | | } // namespace detail |
194 | | |
195 | | template<typename T> |
196 | | class SupportsThreadSafeWeakPtr : public external::AtomicRefCounted<T> |
197 | | { |
198 | | protected: |
199 | | typedef external::AtomicRefCounted<T> AtomicRefCounted; |
200 | | typedef detail::ThreadSafeWeakReference<T> ThreadSafeWeakReference; |
201 | | |
202 | | public: |
203 | | ~SupportsThreadSafeWeakPtr() |
204 | 0 | { |
205 | 0 | // Clean up the shared weak reference if one exists. |
206 | 0 | if (ThreadSafeWeakReference* ptr = mRef) { |
207 | 0 | ptr->Release(); |
208 | 0 | } |
209 | 0 | } Unexecuted instantiation: mozilla::SupportsThreadSafeWeakPtr<mozilla::gfx::UnscaledFont>::~SupportsThreadSafeWeakPtr() Unexecuted instantiation: mozilla::SupportsThreadSafeWeakPtr<mozilla::gfx::ScaledFont>::~SupportsThreadSafeWeakPtr() |
210 | | |
211 | | void Release() const |
212 | 0 | { |
213 | 0 | // If there is only one remaining reference to the object when trying to release, |
214 | 0 | // then attempt to detach it from its weak reference. New references could possibly |
215 | 0 | // be created to the object while this happens, so take care to do this atomically |
216 | 0 | // inside tryDetach. |
217 | 0 | if (AtomicRefCounted::hasOneRef()) { |
218 | 0 | if (ThreadSafeWeakReference* ptr = mRef) { |
219 | 0 | ptr->tryDetach(this); |
220 | 0 | } |
221 | 0 | } |
222 | 0 |
|
223 | 0 | // Once possibly detached, it is now safe to continue to decrement the refcount. |
224 | 0 | AtomicRefCounted::Release(); |
225 | 0 | } Unexecuted instantiation: mozilla::SupportsThreadSafeWeakPtr<mozilla::gfx::UnscaledFont>::Release() const Unexecuted instantiation: mozilla::SupportsThreadSafeWeakPtr<mozilla::gfx::ScaledFont>::Release() const |
226 | | |
227 | | private: |
228 | | template<typename U> friend class ThreadSafeWeakPtr; |
229 | | |
230 | | // Creates a shared weak reference for the object if one does not exist. Note that the |
231 | | // object may be of an actual derived type U, but the weak reference is created for the |
232 | | // supplied type T of SupportsThreadSafeWeakPtr<T>. |
233 | | already_AddRefed<ThreadSafeWeakReference> getThreadSafeWeakReference() |
234 | 0 | { |
235 | 0 | static_assert(IsBaseOf<SupportsThreadSafeWeakPtr<T>, T>::value, |
236 | 0 | "T must derive from SupportsThreadSafeWeakPtr<T>"); |
237 | 0 |
|
238 | 0 | if (!mRef) { |
239 | 0 | RefPtr<ThreadSafeWeakReference> ptr(new ThreadSafeWeakReference(static_cast<T*>(this))); |
240 | 0 | // Only set the new weak reference if one does not exist (== nullptr). |
241 | 0 | // If there is already a weak reference, just let this superflous weak reference get |
242 | 0 | // destroyed when it goes out of scope. |
243 | 0 | if (mRef.compareExchange(nullptr, ptr)) { |
244 | 0 | // If successful, forget the refcount so that the weak reference stays alive. |
245 | 0 | Unused << ptr.forget(); |
246 | 0 | } |
247 | 0 | } |
248 | 0 |
|
249 | 0 | // Create a new RefPtr to weak reference. |
250 | 0 | RefPtr<ThreadSafeWeakReference> ptr(mRef); |
251 | 0 | return ptr.forget(); |
252 | 0 | } Unexecuted instantiation: mozilla::SupportsThreadSafeWeakPtr<mozilla::gfx::UnscaledFont>::getThreadSafeWeakReference() Unexecuted instantiation: mozilla::SupportsThreadSafeWeakPtr<mozilla::gfx::ScaledFont>::getThreadSafeWeakReference() |
253 | | |
254 | | Atomic<ThreadSafeWeakReference*> mRef; |
255 | | }; |
256 | | |
257 | | // A thread-safe variant of a weak pointer |
258 | | template<typename T> |
259 | | class ThreadSafeWeakPtr |
260 | | { |
261 | | // Be careful to use the weak reference type T in the SupportsThreadSafeWeakPtr<T> definition. |
262 | | typedef typename T::ThreadSafeWeakReference ThreadSafeWeakReference; |
263 | | |
264 | | public: |
265 | | ThreadSafeWeakPtr() |
266 | 0 | {} |
267 | | |
268 | | ThreadSafeWeakPtr& operator=(const ThreadSafeWeakPtr& aOther) |
269 | | { |
270 | | mRef = aOther.mRef; |
271 | | return *this; |
272 | | } |
273 | | |
274 | | ThreadSafeWeakPtr(const ThreadSafeWeakPtr& aOther) |
275 | | : mRef(aOther.mRef) |
276 | | { |
277 | | } |
278 | | |
279 | | ThreadSafeWeakPtr& operator=(ThreadSafeWeakPtr&& aOther) |
280 | 0 | { |
281 | 0 | mRef = aOther.mRef.forget(); |
282 | 0 | return *this; |
283 | 0 | } |
284 | | |
285 | | ThreadSafeWeakPtr(ThreadSafeWeakPtr&& aOther) |
286 | | : mRef(aOther.mRef.forget()) |
287 | 0 | { |
288 | 0 | } |
289 | | |
290 | | ThreadSafeWeakPtr& operator=(const RefPtr<T>& aOther) |
291 | 0 | { |
292 | 0 | if (aOther) { |
293 | 0 | // Get the underlying shared weak reference to the object, creating one if necessary. |
294 | 0 | mRef = aOther->getThreadSafeWeakReference(); |
295 | 0 | } else { |
296 | 0 | mRef = nullptr; |
297 | 0 | } |
298 | 0 | return *this; |
299 | 0 | } Unexecuted instantiation: mozilla::ThreadSafeWeakPtr<mozilla::gfx::UnscaledFont>::operator=(RefPtr<mozilla::gfx::UnscaledFont> const&) Unexecuted instantiation: mozilla::ThreadSafeWeakPtr<mozilla::gfx::ScaledFont>::operator=(RefPtr<mozilla::gfx::ScaledFont> const&) Unexecuted instantiation: mozilla::ThreadSafeWeakPtr<mozilla::gfx::UnscaledFontFontconfig>::operator=(RefPtr<mozilla::gfx::UnscaledFontFontconfig> const&) |
300 | | |
301 | | explicit ThreadSafeWeakPtr(const RefPtr<T>& aOther) |
302 | 0 | { |
303 | 0 | *this = aOther; |
304 | 0 | } Unexecuted instantiation: mozilla::ThreadSafeWeakPtr<mozilla::gfx::UnscaledFont>::ThreadSafeWeakPtr(RefPtr<mozilla::gfx::UnscaledFont> const&) Unexecuted instantiation: mozilla::ThreadSafeWeakPtr<mozilla::gfx::ScaledFont>::ThreadSafeWeakPtr(RefPtr<mozilla::gfx::ScaledFont> const&) |
305 | | |
306 | | ThreadSafeWeakPtr& operator=(decltype(nullptr)) |
307 | | { |
308 | | mRef = nullptr; |
309 | | return *this; |
310 | | } |
311 | | |
312 | | explicit ThreadSafeWeakPtr(decltype(nullptr)) |
313 | | {} |
314 | | |
315 | | explicit operator bool() const |
316 | | { |
317 | | return !!get(); |
318 | | } |
319 | | |
320 | | bool operator==(const ThreadSafeWeakPtr& aOther) const |
321 | | { |
322 | | return get() == aOther.get(); |
323 | | } |
324 | | |
325 | | bool operator==(const RefPtr<T>& aOther) const |
326 | | { |
327 | | return get() == aOther.get(); |
328 | | } |
329 | | |
330 | | bool operator==(const T* aOther) const |
331 | 0 | { |
332 | 0 | return get() == aOther; |
333 | 0 | } Unexecuted instantiation: mozilla::ThreadSafeWeakPtr<mozilla::gfx::UnscaledFont>::operator==(mozilla::gfx::UnscaledFont const*) const Unexecuted instantiation: mozilla::ThreadSafeWeakPtr<mozilla::gfx::ScaledFont>::operator==(mozilla::gfx::ScaledFont const*) const |
334 | | |
335 | | template<typename U> |
336 | | bool operator!=(const U& aOther) const |
337 | | { |
338 | | return !(*this == aOther); |
339 | | } |
340 | | |
341 | | // Convert the weak pointer to a strong RefPtr. |
342 | | explicit operator RefPtr<T>() const |
343 | 0 | { |
344 | 0 | return getRefPtr(); |
345 | 0 | } Unexecuted instantiation: mozilla::ThreadSafeWeakPtr<mozilla::gfx::ScaledFont>::operator RefPtr<mozilla::gfx::ScaledFont>() const Unexecuted instantiation: mozilla::ThreadSafeWeakPtr<mozilla::gfx::UnscaledFont>::operator RefPtr<mozilla::gfx::UnscaledFont>() const Unexecuted instantiation: mozilla::ThreadSafeWeakPtr<mozilla::gfx::UnscaledFontFontconfig>::operator RefPtr<mozilla::gfx::UnscaledFontFontconfig>() const |
346 | | |
347 | | private: |
348 | | // Gets a new strong reference of the proper type T to the tracked object. |
349 | | already_AddRefed<T> getRefPtr() const |
350 | 0 | { |
351 | 0 | static_assert(IsBaseOf<typename ThreadSafeWeakReference::ElementType, T>::value, |
352 | 0 | "T must derive from ThreadSafeWeakReference::ElementType"); |
353 | 0 | return mRef ? mRef->getRefPtr().template downcast<T>() : nullptr; |
354 | 0 | } Unexecuted instantiation: mozilla::ThreadSafeWeakPtr<mozilla::gfx::ScaledFont>::getRefPtr() const Unexecuted instantiation: mozilla::ThreadSafeWeakPtr<mozilla::gfx::UnscaledFont>::getRefPtr() const Unexecuted instantiation: mozilla::ThreadSafeWeakPtr<mozilla::gfx::UnscaledFontFontconfig>::getRefPtr() const |
355 | | |
356 | | // Get a pointer to the tracked object, downcasting to the proper type T. |
357 | | // Note that this operation is unsafe as it may cause races if downwind |
358 | | // code depends on the value not to change after reading. |
359 | | T* get() const |
360 | 0 | { |
361 | 0 | static_assert(IsBaseOf<typename ThreadSafeWeakReference::ElementType, T>::value, |
362 | 0 | "T must derive from ThreadSafeWeakReference::ElementType"); |
363 | 0 | return mRef ? static_cast<T*>(mRef->get()) : nullptr; |
364 | 0 | } Unexecuted instantiation: mozilla::ThreadSafeWeakPtr<mozilla::gfx::UnscaledFont>::get() const Unexecuted instantiation: mozilla::ThreadSafeWeakPtr<mozilla::gfx::ScaledFont>::get() const |
365 | | |
366 | | // A shared weak reference to an object. Note that this may be null so as to save memory |
367 | | // (at the slight cost of an extra null check) if no object is being tracked. |
368 | | RefPtr<ThreadSafeWeakReference> mRef; |
369 | | }; |
370 | | |
371 | | } // namespace mozilla |
372 | | |
373 | | template<typename T> |
374 | | inline already_AddRefed<T> |
375 | | do_AddRef(const mozilla::ThreadSafeWeakPtr<T>& aObj) |
376 | 0 | { |
377 | 0 | RefPtr<T> ref(aObj); |
378 | 0 | return ref.forget(); |
379 | 0 | } Unexecuted instantiation: already_AddRefed<mozilla::gfx::ScaledFont> do_AddRef<mozilla::gfx::ScaledFont>(mozilla::ThreadSafeWeakPtr<mozilla::gfx::ScaledFont> const&) Unexecuted instantiation: already_AddRefed<mozilla::gfx::UnscaledFont> do_AddRef<mozilla::gfx::UnscaledFont>(mozilla::ThreadSafeWeakPtr<mozilla::gfx::UnscaledFont> const&) |
380 | | |
381 | | #endif /* mozilla_ThreadSafeWeakPtr_h */ |
382 | | |