| Index: base/memory/ref_counted.h
|
| diff --git a/base/memory/ref_counted.h b/base/memory/ref_counted.h
|
| index e06939d438e7a0768bff062d3b7bf05cc4144efb..be493f632f74916d4d4e6e77a6b89d590dc251ed 100644
|
| --- a/base/memory/ref_counted.h
|
| +++ b/base/memory/ref_counted.h
|
| @@ -20,17 +20,34 @@
|
| #include "base/threading/thread_collision_warner.h"
|
| #include "build/build_config.h"
|
|
|
| +template <class T>
|
| +class scoped_refptr;
|
| +
|
| namespace base {
|
|
|
| +template <typename T>
|
| +scoped_refptr<T> AdoptRef(T* t);
|
| +
|
| namespace subtle {
|
|
|
| +enum AdoptRefTag { kAdoptRefTag };
|
| +enum StartRefCountFromZeroTag { kStartRefCountFromZeroTag };
|
| +enum StartRefCountFromOneTag { kStartRefCountFromOneTag };
|
| +
|
| class BASE_EXPORT RefCountedBase {
|
| public:
|
| bool HasOneRef() const { return ref_count_ == 1; }
|
|
|
| protected:
|
| - RefCountedBase() {
|
| + explicit RefCountedBase(StartRefCountFromZeroTag) {
|
| +#if DCHECK_IS_ON()
|
| + sequence_checker_.DetachFromSequence();
|
| +#endif
|
| + }
|
| +
|
| + explicit RefCountedBase(StartRefCountFromOneTag) : ref_count_(1) {
|
| #if DCHECK_IS_ON()
|
| + needs_adopt_ref_ = true;
|
| sequence_checker_.DetachFromSequence();
|
| #endif
|
| }
|
| @@ -48,6 +65,10 @@ class BASE_EXPORT RefCountedBase {
|
| // DFAKE_SCOPED_LOCK_THREAD_LOCKED(add_release_);
|
| #if DCHECK_IS_ON()
|
| DCHECK(!in_dtor_);
|
| + DCHECK(!needs_adopt_ref_)
|
| + << "This RefCounted object is created with non-zero reference count."
|
| + << " The first reference to such a object has to be made by AdoptRef or"
|
| + << " MakeShared.";
|
| if (ref_count_ >= 1) {
|
| DCHECK(CalledOnValidSequence());
|
| }
|
| @@ -80,6 +101,16 @@ class BASE_EXPORT RefCountedBase {
|
| }
|
|
|
| private:
|
| + template <typename U>
|
| + friend scoped_refptr<U> base::AdoptRef(U*);
|
| +
|
| + void Adopted() const {
|
| +#if DCHECK_IS_ON()
|
| + DCHECK(needs_adopt_ref_);
|
| + needs_adopt_ref_ = false;
|
| +#endif
|
| + }
|
| +
|
| #if DCHECK_IS_ON()
|
| bool CalledOnValidSequence() const;
|
| #endif
|
| @@ -87,6 +118,7 @@ class BASE_EXPORT RefCountedBase {
|
| mutable size_t ref_count_ = 0;
|
|
|
| #if DCHECK_IS_ON()
|
| + mutable bool needs_adopt_ref_ = false;
|
| mutable bool in_dtor_ = false;
|
| mutable SequenceChecker sequence_checker_;
|
| #endif
|
| @@ -101,7 +133,13 @@ class BASE_EXPORT RefCountedThreadSafeBase {
|
| bool HasOneRef() const;
|
|
|
| protected:
|
| - RefCountedThreadSafeBase();
|
| + explicit RefCountedThreadSafeBase(StartRefCountFromZeroTag) {}
|
| + explicit RefCountedThreadSafeBase(StartRefCountFromOneTag) : ref_count_(1) {
|
| +#if DCHECK_IS_ON()
|
| + needs_adopt_ref_ = true;
|
| +#endif
|
| + }
|
| +
|
| ~RefCountedThreadSafeBase();
|
|
|
| void AddRef() const;
|
| @@ -110,8 +148,19 @@ class BASE_EXPORT RefCountedThreadSafeBase {
|
| bool Release() const;
|
|
|
| private:
|
| + template <typename U>
|
| + friend scoped_refptr<U> base::AdoptRef(U*);
|
| +
|
| + void Adopted() const {
|
| +#if DCHECK_IS_ON()
|
| + DCHECK(needs_adopt_ref_);
|
| + needs_adopt_ref_ = false;
|
| +#endif
|
| + }
|
| +
|
| mutable AtomicRefCount ref_count_ = 0;
|
| #if DCHECK_IS_ON()
|
| + mutable bool needs_adopt_ref_ = false;
|
| mutable bool in_dtor_ = false;
|
| #endif
|
|
|
| @@ -156,15 +205,44 @@ class BASE_EXPORT ScopedAllowCrossThreadRefCountAccess final {
|
| // You should always make your destructor non-public, to avoid any code deleting
|
| // the object accidently while there are references to it.
|
| //
|
| +//
|
| // The ref count manipulation to RefCounted is NOT thread safe and has DCHECKs
|
| // to trap unsafe cross thread usage. A subclass instance of RefCounted can be
|
| // passed to another execution sequence only when its ref count is 1. If the ref
|
| // count is more than 1, the RefCounted class verifies the ref updates are made
|
| // on the same execution sequence as the previous ones.
|
| +//
|
| +//
|
| +// The reference count starts from zero by default, and we intended to migrate
|
| +// to start-from-one ref count. Put REQUIRE_ADOPTION_FOR_REFCOUNTED_TYPE() to
|
| +// the ref counted class to opt-in.
|
| +//
|
| +// If an object has start-from-one ref count, the first scoped_refptr need to be
|
| +// created by base::AdoptRef() or base::MakeShared(). We can use
|
| +// base::MakeShared() to create create both type of ref counted object.
|
| +//
|
| +// The motivations to use start-from-one ref count are:
|
| +// - Start-from-one ref count doesn't need the ref count increment for the
|
| +// first reference.
|
| +// - It can detect an invalid object acquisition for a being-deleted object
|
| +// that has zero ref count. That tends to happen on custom deleter that
|
| +// delays the deletion.
|
| +// TODO(tzik): Implement invalid acquisition detection.
|
| +// - Behavior parity to Blink's WTF::RefCounted, whose count starts from one.
|
| +// And start-from-one ref count is a step to merge WTF::RefCounted into
|
| +// base::RefCounted.
|
| +//
|
| +#define REQUIRE_ADOPTION_FOR_REFCOUNTED_TYPE() \
|
| + static constexpr ::base::subtle::StartRefCountFromOneTag \
|
| + kRefCountPreference = ::base::subtle::kStartRefCountFromOneTag
|
| +
|
| template <class T>
|
| class RefCounted : public subtle::RefCountedBase {
|
| public:
|
| - RefCounted() = default;
|
| + static constexpr subtle::StartRefCountFromZeroTag kRefCountPreference =
|
| + subtle::kStartRefCountFromZeroTag;
|
| +
|
| + RefCounted() : subtle::RefCountedBase(T::kRefCountPreference) {}
|
|
|
| void AddRef() const {
|
| subtle::RefCountedBase::AddRef();
|
| @@ -180,7 +258,7 @@ class RefCounted : public subtle::RefCountedBase {
|
| ~RefCounted() = default;
|
|
|
| private:
|
| - DISALLOW_COPY_AND_ASSIGN(RefCounted<T>);
|
| + DISALLOW_COPY_AND_ASSIGN(RefCounted);
|
| };
|
|
|
| // Forward declaration.
|
| @@ -211,10 +289,17 @@ struct DefaultRefCountedThreadSafeTraits {
|
| // private:
|
| // friend class base::RefCountedThreadSafe<MyFoo>;
|
| // ~MyFoo();
|
| +//
|
| +// We can use REQUIRE_ADOPTION_FOR_REFCOUNTED_TYPE() with RefCountedThreadSafe
|
| +// too. See the comment above the RefCounted definition for details.
|
| template <class T, typename Traits = DefaultRefCountedThreadSafeTraits<T> >
|
| class RefCountedThreadSafe : public subtle::RefCountedThreadSafeBase {
|
| public:
|
| - RefCountedThreadSafe() = default;
|
| + static constexpr subtle::StartRefCountFromZeroTag kRefCountPreference =
|
| + subtle::kStartRefCountFromZeroTag;
|
| +
|
| + explicit RefCountedThreadSafe()
|
| + : subtle::RefCountedThreadSafeBase(T::kRefCountPreference) {}
|
|
|
| void AddRef() const {
|
| subtle::RefCountedThreadSafeBase::AddRef();
|
| @@ -254,6 +339,43 @@ class RefCountedData
|
| ~RefCountedData() = default;
|
| };
|
|
|
| +// Creates a scoped_refptr from a raw pointer without incrementing the reference
|
| +// count. Use this only for a newly created object whose reference count starts
|
| +// from 1 instead of 0.
|
| +template <typename T>
|
| +scoped_refptr<T> AdoptRef(T* obj) {
|
| + using Tag = typename std::decay<decltype(T::kRefCountPreference)>::type;
|
| + static_assert(std::is_same<subtle::StartRefCountFromOneTag, Tag>::value,
|
| + "Use AdoptRef only for the reference count starts from one.");
|
| +
|
| + DCHECK(obj);
|
| + DCHECK(obj->HasOneRef());
|
| + obj->Adopted();
|
| + return scoped_refptr<T>(obj, subtle::kAdoptRefTag);
|
| +}
|
| +
|
| +namespace subtle {
|
| +
|
| +template <typename T>
|
| +scoped_refptr<T> AdoptRefIfNeeded(T* obj, StartRefCountFromZeroTag) {
|
| + return scoped_refptr<T>(obj);
|
| +}
|
| +
|
| +template <typename T>
|
| +scoped_refptr<T> AdoptRefIfNeeded(T* obj, StartRefCountFromOneTag) {
|
| + return AdoptRef(obj);
|
| +}
|
| +
|
| +} // namespace subtle
|
| +
|
| +// Constructs an instance of T, which is a ref counted type, and wraps the
|
| +// object into a scoped_refptr.
|
| +template <typename T, typename... Args>
|
| +scoped_refptr<T> MakeShared(Args&&... args) {
|
| + T* obj = new T(std::forward<Args>(args)...);
|
| + return subtle::AdoptRefIfNeeded(obj, T::kRefCountPreference);
|
| +}
|
| +
|
| } // namespace base
|
|
|
| //
|
| @@ -421,6 +543,11 @@ class scoped_refptr {
|
| T* ptr_ = nullptr;
|
|
|
| private:
|
| + template <typename U>
|
| + friend scoped_refptr<U> base::AdoptRef(U*);
|
| +
|
| + scoped_refptr(T* p, base::subtle::AdoptRefTag) : ptr_(p) {}
|
| +
|
| // Friend required for move constructors that set r.ptr_ to null.
|
| template <typename U>
|
| friend class scoped_refptr;
|
|
|