1 // Copyright 2012 The Chromium Authors 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #ifndef PARTITION_ALLOC_PARTITION_ALLOC_BASE_MEMORY_REF_COUNTED_H_ 6 #define PARTITION_ALLOC_PARTITION_ALLOC_BASE_MEMORY_REF_COUNTED_H_ 7 8 #include "build/build_config.h" 9 #include "partition_alloc/partition_alloc_base/atomic_ref_count.h" 10 #include "partition_alloc/partition_alloc_base/check.h" 11 #include "partition_alloc/partition_alloc_base/compiler_specific.h" 12 #include "partition_alloc/partition_alloc_base/component_export.h" 13 #include "partition_alloc/partition_alloc_base/debug/debugging_buildflags.h" 14 #include "partition_alloc/partition_alloc_base/memory/scoped_refptr.h" 15 16 namespace partition_alloc::internal::base { 17 namespace subtle { 18 PA_COMPONENT_EXPORT(PARTITION_ALLOC_BASE)19class PA_COMPONENT_EXPORT(PARTITION_ALLOC_BASE) RefCountedThreadSafeBase { 20 public: 21 RefCountedThreadSafeBase(const RefCountedThreadSafeBase&) = delete; 22 RefCountedThreadSafeBase& operator=(const RefCountedThreadSafeBase&) = delete; 23 24 bool HasOneRef() const; 25 bool HasAtLeastOneRef() const; 26 27 protected: 28 explicit constexpr RefCountedThreadSafeBase(StartRefCountFromZeroTag) {} 29 explicit constexpr RefCountedThreadSafeBase(StartRefCountFromOneTag) 30 : ref_count_(1) { 31 #if BUILDFLAG(PA_DCHECK_IS_ON) 32 needs_adopt_ref_ = true; 33 #endif 34 } 35 36 #if BUILDFLAG(PA_DCHECK_IS_ON) 37 ~RefCountedThreadSafeBase(); 38 #else 39 ~RefCountedThreadSafeBase() = default; 40 #endif 41 42 // Release and AddRef are suitable for inlining on X86 because they generate 43 // very small code sequences. On other platforms (ARM), it causes a size 44 // regression and is probably not worth it. 45 #if defined(ARCH_CPU_X86_FAMILY) 46 // Returns true if the object should self-delete. 47 bool Release() const { return ReleaseImpl(); } 48 void AddRef() const { AddRefImpl(); } 49 void AddRefWithCheck() const { AddRefWithCheckImpl(); } 50 #else 51 // Returns true if the object should self-delete. 52 bool Release() const; 53 void AddRef() const; 54 void AddRefWithCheck() const; 55 #endif 56 57 private: 58 template <typename U> 59 friend scoped_refptr<U> AdoptRef(U*); 60 61 void Adopted() const { 62 #if BUILDFLAG(PA_DCHECK_IS_ON) 63 PA_BASE_DCHECK(needs_adopt_ref_); 64 needs_adopt_ref_ = false; 65 #endif 66 } 67 68 PA_ALWAYS_INLINE void AddRefImpl() const { 69 #if BUILDFLAG(PA_DCHECK_IS_ON) 70 PA_BASE_DCHECK(!in_dtor_); 71 // This RefCounted object is created with non-zero reference count. 72 // The first reference to such a object has to be made by AdoptRef or 73 // MakeRefCounted. 74 PA_BASE_DCHECK(!needs_adopt_ref_); 75 #endif 76 ref_count_.Increment(); 77 } 78 79 PA_ALWAYS_INLINE void AddRefWithCheckImpl() const { 80 #if BUILDFLAG(PA_DCHECK_IS_ON) 81 PA_BASE_DCHECK(!in_dtor_); 82 // This RefCounted object is created with non-zero reference count. 83 // The first reference to such a object has to be made by AdoptRef or 84 // MakeRefCounted. 85 PA_BASE_DCHECK(!needs_adopt_ref_); 86 #endif 87 PA_BASE_CHECK(ref_count_.Increment() > 0); 88 } 89 90 PA_ALWAYS_INLINE bool ReleaseImpl() const { 91 #if BUILDFLAG(PA_DCHECK_IS_ON) 92 PA_BASE_DCHECK(!in_dtor_); 93 PA_BASE_DCHECK(!ref_count_.IsZero()); 94 #endif 95 if (!ref_count_.Decrement()) { 96 #if BUILDFLAG(PA_DCHECK_IS_ON) 97 in_dtor_ = true; 98 #endif 99 return true; 100 } 101 return false; 102 } 103 104 mutable AtomicRefCount ref_count_{0}; 105 #if BUILDFLAG(PA_DCHECK_IS_ON) 106 mutable bool needs_adopt_ref_ = false; 107 mutable bool in_dtor_ = false; 108 #endif 109 }; 110 111 } // namespace subtle 112 113 // Forward declaration. 114 template <class T, typename Traits> 115 class RefCountedThreadSafe; 116 117 // Default traits for RefCountedThreadSafe<T>. Deletes the object when its ref 118 // count reaches 0. Overload to delete it on a different thread etc. 119 template <typename T> 120 struct DefaultRefCountedThreadSafeTraits { DestructDefaultRefCountedThreadSafeTraits121 static void Destruct(const T* x) { 122 // Delete through RefCountedThreadSafe to make child classes only need to be 123 // friend with RefCountedThreadSafe instead of this struct, which is an 124 // implementation detail. 125 RefCountedThreadSafe<T, DefaultRefCountedThreadSafeTraits>::DeleteInternal( 126 x); 127 } 128 }; 129 130 // 131 // A thread-safe variant of RefCounted<T> 132 // 133 // class MyFoo : public base::RefCountedThreadSafe<MyFoo> { 134 // ... 135 // }; 136 // 137 // If you're using the default trait, then you should add compile time 138 // asserts that no one else is deleting your object. i.e. 139 // private: 140 // friend class base::RefCountedThreadSafe<MyFoo>; 141 // ~MyFoo(); 142 // 143 // We can use REQUIRE_ADOPTION_FOR_REFCOUNTED_TYPE() with RefCountedThreadSafe 144 // too. See the comment above the RefCounted definition for details. 145 template <class T, typename Traits = DefaultRefCountedThreadSafeTraits<T>> 146 class RefCountedThreadSafe : public subtle::RefCountedThreadSafeBase { 147 public: 148 static constexpr subtle::StartRefCountFromZeroTag kRefCountPreference = 149 subtle::kStartRefCountFromZeroTag; 150 RefCountedThreadSafe()151 explicit RefCountedThreadSafe() 152 : subtle::RefCountedThreadSafeBase(T::kRefCountPreference) {} 153 154 RefCountedThreadSafe(const RefCountedThreadSafe&) = delete; 155 RefCountedThreadSafe& operator=(const RefCountedThreadSafe&) = delete; 156 AddRef()157 void AddRef() const { AddRefImpl(T::kRefCountPreference); } 158 Release()159 void Release() const { 160 if (subtle::RefCountedThreadSafeBase::Release()) { 161 PA_ANALYZER_SKIP_THIS_PATH(); 162 Traits::Destruct(static_cast<const T*>(this)); 163 } 164 } 165 166 protected: 167 ~RefCountedThreadSafe() = default; 168 169 private: 170 friend struct DefaultRefCountedThreadSafeTraits<T>; 171 template <typename U> 172 static void DeleteInternal(const U* x) { 173 delete x; 174 } 175 176 void AddRefImpl(subtle::StartRefCountFromZeroTag) const { 177 subtle::RefCountedThreadSafeBase::AddRef(); 178 } 179 180 void AddRefImpl(subtle::StartRefCountFromOneTag) const { 181 subtle::RefCountedThreadSafeBase::AddRefWithCheck(); 182 } 183 }; 184 185 } // namespace partition_alloc::internal::base 186 187 #endif // PARTITION_ALLOC_PARTITION_ALLOC_BASE_MEMORY_REF_COUNTED_H_ 188