/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* vim: set ts=8 sts=2 et sw=2 tw=80: */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/* A thread-safe weak pointer */
/** * Derive from SupportsThreadSafeWeakPtr to allow thread-safe weak pointers to * an atomically refcounted derived class. These thread-safe weak pointers may * be safely accessed and converted to strong pointers on multiple threads. * * Note that SupportsThreadSafeWeakPtr defines the same member functions as * AtomicRefCounted, so you should not separately inherit from it. * * ThreadSafeWeakPtr and its implementation is distinct from the normal WeakPtr * which is not thread-safe. The interface discipline and implementation details * are different enough that these two implementations are separated for now for * efficiency reasons. If you don't actually need to use weak pointers on * multiple threads, you can just use WeakPtr instead. * * When deriving from SupportsThreadSafeWeakPtr, you should add * MOZ_DECLARE_REFCOUNTED_TYPENAME(ClassName) to the public section of your * class, where ClassName is the name of your class. * * Example usage: * * class C : public SupportsThreadSafeWeakPtr<C> * { * public: * MOZ_DECLARE_REFCOUNTED_TYPENAME(C) * void doStuff(); * }; * * ThreadSafeWeakPtr<C> weak; * { * RefPtr<C> strong = new C; * if (strong) { * strong->doStuff(); * } * // Make a new weak reference to the object from the strong reference. * weak = strong; * } * MOZ_ASSERT(!bool(weak), "Weak pointers are cleared after all " * "strong references are released."); * * // Convert the weak reference to a strong reference for usage. * RefPtr<C> other(weak); * if (other) { * other->doStuff(); * }
*/
template <typename T> class SupportsThreadSafeWeakPtr;
namespace detail {
class SupportsThreadSafeWeakPtrBase {};
// A shared weak reference that is used to track a SupportsThreadSafeWeakPtr // object. This object owns the reference count for the tracked object, and can // perform atomic refcount upgrades. class ThreadSafeWeakReference
: public external::AtomicRefCounted<ThreadSafeWeakReference> { public: explicit ThreadSafeWeakReference(SupportsThreadSafeWeakPtrBase* aPtr)
: mPtr(aPtr) {}
// Number of strong references to the underlying data structure. // // Other than the initial strong `AddRef` call incrementing this value to 1, // which must occur before any weak references are taken, once this value // reaches `0` again it cannot be changed.
RC<MozRefCountType, AtomicRefCount> mStrongCnt{0};
// Raw pointer to the tracked object. It is never valid to read this value // outside of `ThreadSafeWeakPtr::getRefPtr()`.
SupportsThreadSafeWeakPtrBase* MOZ_NON_OWNING_REF mPtr;
};
} // namespace detail
// For usage documentation for SupportsThreadSafeWeakPtr, see the header-level // documentation. // // To understand the layout of SupportsThreadSafeWeakPtr, consider the following // simplified declaration: // // class MyType: SupportsThreadSafeWeakPtr { uint32_t mMyData; ... } // // Which will result in the following layout: // // +--------------------+ // | MyType | <===============================================+ // +--------------------+ I // | RefPtr mWeakRef o======> +-------------------------------------+ I // | uint32_t mMyData | | ThreadSafeWeakReference | I // +--------------------+ +-------------------------------------+ I // | RC mRefCount | I // | RC mStrongCount | I // | SupportsThreadSafeWeakPtrBase* mPtr o====+ // +-------------------------------------+ // // The mRefCount inherited from AtomicRefCounted<ThreadSafeWeakReference> is the // weak count. This means MyType implicitly holds a weak reference, so if the // weak count ever hits 0, we know all strong *and* weak references are gone, // and it's safe to free the ThreadSafeWeakReference. MyType's AddRef and // Release implementations otherwise only manipulate mStrongCount. // // It's necessary to keep the counts in a separate allocation because we need // to be able to delete MyType while weak references still exist. This ensures // that weak references can still access all the state necessary to check if // they can be upgraded (mStrongCount). template <typename T> class SupportsThreadSafeWeakPtr : public detail::SupportsThreadSafeWeakPtrBase { protected: using ThreadSafeWeakReference = detail::ThreadSafeWeakReference;
// The `this` pointer will not have subclasses initialized yet, but it will // also not be read until a weak pointer is upgraded, which should be after // this point.
SupportsThreadSafeWeakPtr() : mWeakRef(new ThreadSafeWeakReference(this)) {
static_assert(std::is_base_of_v<SupportsThreadSafeWeakPtr, T>, "T must derive from SupportsThreadSafeWeakPtr");
}
MozExternalRefCountType Release() const { auto& refCnt = mWeakRef->mStrongCnt;
MOZ_ASSERT(int32_t(refCnt) > 0);
detail::RefCountLogger::ReleaseLogger logger(static_cast<const T*>(this));
MozRefCountType cnt = --refCnt;
logger.logRelease(cnt); if (0 == cnt) { // Because we have atomically decremented the refcount above, only one // thread can get a 0 count here. Thus, it is safe to access and destroy // |this| here. // No other thread can acquire a strong reference to |this| anymore // through our weak pointer, as upgrading a weak pointer always uses // |IncrementIfNonzero|, meaning the refcount can't leave a zero reference // state. // NOTE: We can't update our refcount to the marker `DEAD` value here, as // it may still be read by mWeakRef. deletestatic_cast<const T*>(this);
} return cnt;
}
// A thread-safe variant of a weak pointer template <typename T> class ThreadSafeWeakPtr { using ThreadSafeWeakReference = detail::ThreadSafeWeakReference;
// Use the explicit `IsNull()` or `IsDead()` methods instead. explicitoperatorbool() const = delete;
// Check if the ThreadSafeWeakPtr was created wrapping a null pointer. bool IsNull() const { return !mRef; }
// Check if the managed object is nullptr or has already been destroyed. Once // IsDead returns true, this ThreadSafeWeakPtr can never be upgraded again // (until it has been re-assigned), but a false return value does NOT imply // that any future upgrade will be successful. bool IsDead() const { return IsNull() || size_t(mRef->mStrongCnt) == 0; }
// Convert the weak pointer to a strong RefPtr. explicitoperator RefPtr<T>() const { return getRefPtr(); }
private: // Gets a new strong reference of the proper type T to the tracked object.
already_AddRefed<T> getRefPtr() const { if (!mRef) { return nullptr;
} // Increment our strong reference count only if it is nonzero, meaning that // the object is still alive.
MozRefCountType cnt = mRef->mStrongCnt.IncrementIfNonzero(); if (cnt == 0) { return nullptr;
}
// A shared weak reference to an object. Note that this may be null so as to // save memory (at the slight cost of an extra null check) if no object is // being tracked.
RefPtr<ThreadSafeWeakReference> mRef;
};
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung ist noch experimentell.