Coverage Report

Created: 2018-09-25 14:53

/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