123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283 |
- /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
- /* 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/. */
- /* Weak pointer functionality, implemented as a mixin for use with any class. */
- /**
- * SupportsWeakPtr lets you have a pointer to an object 'Foo' without affecting
- * its lifetime. It works by creating a single shared reference counted object
- * (WeakReference) that each WeakPtr will access 'Foo' through. This lets 'Foo'
- * clear the pointer in the WeakReference without having to know about all of
- * the WeakPtrs to it and allows the WeakReference to live beyond the lifetime
- * of 'Foo'.
- *
- * PLEASE NOTE: This weak pointer implementation is not thread-safe.
- *
- * Note that when deriving from SupportsWeakPtr you should add
- * MOZ_DECLARE_WEAKREFERENCE_TYPENAME(ClassName) to the public section of your
- * class, where ClassName is the name of your class.
- *
- * The overhead of WeakPtr is that accesses to 'Foo' becomes an additional
- * dereference, and an additional heap allocated pointer sized object shared
- * between all of the WeakPtrs.
- *
- * Example of usage:
- *
- * // To have a class C support weak pointers, inherit from
- * // SupportsWeakPtr<C>.
- * class C : public SupportsWeakPtr<C>
- * {
- * public:
- * MOZ_DECLARE_WEAKREFERENCE_TYPENAME(C)
- * int mNum;
- * void act();
- * };
- *
- * C* ptr = new C();
- *
- * // Get weak pointers to ptr. The first time a weak pointer
- * // is obtained, a reference counted WeakReference object is created that
- * // can live beyond the lifetime of 'ptr'. The WeakReference
- * // object will be notified of 'ptr's destruction.
- * WeakPtr<C> weak = ptr;
- * WeakPtr<C> other = ptr;
- *
- * // Test a weak pointer for validity before using it.
- * if (weak) {
- * weak->mNum = 17;
- * weak->act();
- * }
- *
- * // Destroying the underlying object clears weak pointers to it.
- * delete ptr;
- *
- * MOZ_ASSERT(!weak, "Deleting |ptr| clears weak pointers to it.");
- * MOZ_ASSERT(!other, "Deleting |ptr| clears all weak pointers to it.");
- *
- * WeakPtr is typesafe and may be used with any class. It is not required that
- * the class be reference-counted or allocated in any particular way.
- *
- * The API was loosely inspired by Chromium's weak_ptr.h:
- * http://src.chromium.org/svn/trunk/src/base/memory/weak_ptr.h
- */
- #ifndef mozilla_WeakPtr_h
- #define mozilla_WeakPtr_h
- #include "mozilla/ArrayUtils.h"
- #include "mozilla/Assertions.h"
- #include "mozilla/Attributes.h"
- #include "mozilla/RefCounted.h"
- #include "mozilla/RefPtr.h"
- #include "mozilla/TypeTraits.h"
- #include <string.h>
- // Weak referencing is not implemeted as thread safe. When a WeakPtr
- // is created or dereferenced on thread A but the real object is just
- // being Released() on thread B, there is a possibility of a race
- // when the proxy object (detail::WeakReference) is notified about
- // the real object destruction just between when thread A is storing
- // the object pointer locally and is about to add a reference to it.
- //
- // Hence, a non-null weak proxy object is considered to have a single
- // "owning thread". It means that each query for a weak reference,
- // its dereference, and destruction of the real object must all happen
- // on a single thread. The following macros implement assertions for
- // checking these conditions.
- //
- // We disable this on MinGW. MinGW has two threading models: win32
- // API based, which disables std::thread; and POSIX based which
- // enables it but requires an emulation library (winpthreads).
- // Rather than attempting to switch to pthread emulation at this point,
- // we are disabling the std::thread based assertion checking.
- //
- // In the future, to enable it we could
- // a. have libgcc/stdc++ support win32 threads natively
- // b. switch to POSIX-based threading in MinGW with pthread emulation
- // c. refactor it to not use std::thread
- #if !defined(__MINGW32__) && (defined(DEBUG) || (defined(NIGHTLY_BUILD) && !defined(MOZ_PROFILING)))
- #include <thread>
- #define MOZ_WEAKPTR_DECLARE_THREAD_SAFETY_CHECK \
- std::thread::id _owningThread; \
- bool _empty; // If it was initialized as a placeholder with mPtr = nullptr.
- #define MOZ_WEAKPTR_INIT_THREAD_SAFETY_CHECK() \
- do { \
- _owningThread = std::this_thread::get_id(); \
- _empty = !p; \
- } while (false)
- #define MOZ_WEAKPTR_ASSERT_THREAD_SAFETY() \
- MOZ_DIAGNOSTIC_ASSERT(_empty || _owningThread == std::this_thread::get_id(), \
- "WeakPtr used on multiple threads")
- #define MOZ_WEAKPTR_ASSERT_THREAD_SAFETY_DELEGATED(that) \
- (that)->AssertThreadSafety();
- #define MOZ_WEAKPTR_THREAD_SAFETY_CHECKING 1
- #else
- #define MOZ_WEAKPTR_DECLARE_THREAD_SAFETY_CHECK
- #define MOZ_WEAKPTR_INIT_THREAD_SAFETY_CHECK() do { } while (false)
- #define MOZ_WEAKPTR_ASSERT_THREAD_SAFETY() do { } while (false)
- #define MOZ_WEAKPTR_ASSERT_THREAD_SAFETY_DELEGATED(that) do { } while (false)
- #endif
- namespace mozilla {
- template <typename T> class WeakPtr;
- template <typename T> class SupportsWeakPtr;
- #ifdef MOZ_REFCOUNTED_LEAK_CHECKING
- #define MOZ_DECLARE_WEAKREFERENCE_TYPENAME(T) \
- static const char* weakReferenceTypeName() { return "WeakReference<" #T ">"; }
- #else
- #define MOZ_DECLARE_WEAKREFERENCE_TYPENAME(T)
- #endif
- namespace detail {
- // This can live beyond the lifetime of the class derived from
- // SupportsWeakPtr.
- template<class T>
- class WeakReference : public ::mozilla::RefCounted<WeakReference<T> >
- {
- public:
- explicit WeakReference(T* p) : mPtr(p)
- {
- MOZ_WEAKPTR_INIT_THREAD_SAFETY_CHECK();
- }
- T* get() const {
- MOZ_WEAKPTR_ASSERT_THREAD_SAFETY();
- return mPtr;
- }
- #ifdef MOZ_REFCOUNTED_LEAK_CHECKING
- const char* typeName() const
- {
- // The first time this is called mPtr is null, so don't
- // invoke any methods on mPtr.
- return T::weakReferenceTypeName();
- }
- size_t typeSize() const { return sizeof(*this); }
- #endif
- #ifdef MOZ_WEAKPTR_THREAD_SAFETY_CHECKING
- void AssertThreadSafety() { MOZ_WEAKPTR_ASSERT_THREAD_SAFETY(); }
- #endif
- private:
- friend class mozilla::SupportsWeakPtr<T>;
- void detach() {
- MOZ_WEAKPTR_ASSERT_THREAD_SAFETY();
- mPtr = nullptr;
- }
- T* MOZ_NON_OWNING_REF mPtr;
- MOZ_WEAKPTR_DECLARE_THREAD_SAFETY_CHECK
- };
- } // namespace detail
- template <typename T>
- class SupportsWeakPtr
- {
- protected:
- ~SupportsWeakPtr()
- {
- static_assert(IsBaseOf<SupportsWeakPtr<T>, T>::value,
- "T must derive from SupportsWeakPtr<T>");
- if (mSelfReferencingWeakPtr) {
- mSelfReferencingWeakPtr.mRef->detach();
- }
- }
- private:
- const WeakPtr<T>& SelfReferencingWeakPtr()
- {
- if (!mSelfReferencingWeakPtr) {
- mSelfReferencingWeakPtr.mRef = new detail::WeakReference<T>(static_cast<T*>(this));
- } else {
- MOZ_WEAKPTR_ASSERT_THREAD_SAFETY_DELEGATED(mSelfReferencingWeakPtr.mRef);
- }
- return mSelfReferencingWeakPtr;
- }
- const WeakPtr<const T>& SelfReferencingWeakPtr() const
- {
- const WeakPtr<T>& p = const_cast<SupportsWeakPtr*>(this)->SelfReferencingWeakPtr();
- return reinterpret_cast<const WeakPtr<const T>&>(p);
- }
- friend class WeakPtr<T>;
- friend class WeakPtr<const T>;
- WeakPtr<T> mSelfReferencingWeakPtr;
- };
- template <typename T>
- class WeakPtr
- {
- typedef detail::WeakReference<T> WeakReference;
- public:
- WeakPtr& operator=(const WeakPtr& aOther)
- {
- mRef = aOther.mRef;
- MOZ_WEAKPTR_ASSERT_THREAD_SAFETY_DELEGATED(mRef);
- return *this;
- }
- WeakPtr(const WeakPtr& aOther)
- {
- // The thread safety check is performed inside of the operator= method.
- *this = aOther;
- }
- WeakPtr& operator=(T* aOther)
- {
- if (aOther) {
- *this = aOther->SelfReferencingWeakPtr();
- } else if (!mRef || mRef->get()) {
- // Ensure that mRef is dereferenceable in the uninitialized state.
- mRef = new WeakReference(nullptr);
- }
- // The thread safety check happens inside SelfReferencingWeakPtr
- // or is initialized in the WeakReference constructor.
- return *this;
- }
- MOZ_IMPLICIT WeakPtr(T* aOther)
- {
- *this = aOther;
- MOZ_WEAKPTR_ASSERT_THREAD_SAFETY_DELEGATED(mRef);
- }
- // Ensure that mRef is dereferenceable in the uninitialized state.
- WeakPtr() : mRef(new WeakReference(nullptr)) {}
- operator T*() const { return mRef->get(); }
- T& operator*() const { return *mRef->get(); }
- T* operator->() const MOZ_NO_ADDREF_RELEASE_ON_RETURN { return mRef->get(); }
- T* get() const { return mRef->get(); }
- private:
- friend class SupportsWeakPtr<T>;
- explicit WeakPtr(const RefPtr<WeakReference>& aOther) : mRef(aOther) {}
- RefPtr<WeakReference> mRef;
- };
- } // namespace mozilla
- #endif /* mozilla_WeakPtr_h */
|