1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 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 BASE_MEMORY_REF_COUNTED_H_ 6 #define BASE_MEMORY_REF_COUNTED_H_ 7 8 #include <stddef.h> 9 10 #include <utility> 11 12 #include "base/atomic_ref_count.h" 13 #include "base/compiler_specific.h" 14 #include "base/logging.h" 15 #include "base/macros.h" 16 #include "base/memory/scoped_refptr.h" 17 #include "util/build_config.h" 18 19 namespace base { 20 namespace subtle { 21 22 class RefCountedBase { 23 public: HasOneRef()24 bool HasOneRef() const { return ref_count_ == 1; } 25 26 protected: RefCountedBase(StartRefCountFromZeroTag)27 explicit RefCountedBase(StartRefCountFromZeroTag) {} 28 RefCountedBase(StartRefCountFromOneTag)29 explicit RefCountedBase(StartRefCountFromOneTag) : ref_count_(1) {} 30 ~RefCountedBase()31 ~RefCountedBase() {} 32 AddRef()33 void AddRef() const { AddRefImpl(); } 34 35 // Returns true if the object should self-delete. Release()36 bool Release() const { 37 --ref_count_; 38 39 // TODO(maruel): Add back once it doesn't assert 500 times/sec. 40 // Current thread books the critical section "AddRelease" 41 // without release it. 42 // DFAKE_SCOPED_LOCK_THREAD_LOCKED(add_release_); 43 44 return ref_count_ == 0; 45 } 46 47 // Returns true if it is safe to read or write the object, from a thread 48 // safety standpoint. Should be DCHECK'd from the methods of RefCounted 49 // classes if there is a danger of objects being shared across threads. 50 // 51 // This produces fewer false positives than adding a separate SequenceChecker 52 // into the subclass, because it automatically detaches from the sequence when 53 // the reference count is 1 (and never fails if there is only one reference). 54 // 55 // This means unlike a separate SequenceChecker, it will permit a singly 56 // referenced object to be passed between threads (not holding a reference on 57 // the sending thread), but will trap if the sending thread holds onto a 58 // reference, or if the object is accessed from multiple threads 59 // simultaneously. IsOnValidSequence()60 bool IsOnValidSequence() const { return true; } 61 62 private: 63 template <typename U> 64 friend scoped_refptr<U> base::AdoptRef(U*); 65 Adopted()66 void Adopted() const {} 67 68 #if defined(ARCH_CPU_64_BIT) 69 void AddRefImpl() const; 70 #else AddRefImpl()71 void AddRefImpl() const { ++ref_count_; } 72 #endif 73 74 mutable uint32_t ref_count_ = 0; 75 76 DISALLOW_COPY_AND_ASSIGN(RefCountedBase); 77 }; 78 79 class RefCountedThreadSafeBase { 80 public: 81 bool HasOneRef() const; 82 83 protected: RefCountedThreadSafeBase(StartRefCountFromZeroTag)84 explicit constexpr RefCountedThreadSafeBase(StartRefCountFromZeroTag) {} RefCountedThreadSafeBase(StartRefCountFromOneTag)85 explicit constexpr RefCountedThreadSafeBase(StartRefCountFromOneTag) 86 : ref_count_(1) {} 87 88 ~RefCountedThreadSafeBase() = default; 89 90 // Release and AddRef are suitable for inlining on X86 because they generate 91 // very small code sequences. On other platforms (ARM), it causes a size 92 // regression and is probably not worth it. 93 #if defined(ARCH_CPU_X86_FAMILY) 94 // Returns true if the object should self-delete. Release()95 bool Release() const { return ReleaseImpl(); } AddRef()96 void AddRef() const { AddRefImpl(); } 97 #else 98 // Returns true if the object should self-delete. 99 bool Release() const; 100 void AddRef() const; 101 #endif 102 103 private: 104 template <typename U> 105 friend scoped_refptr<U> base::AdoptRef(U*); 106 Adopted()107 void Adopted() const {} 108 AddRefImpl()109 ALWAYS_INLINE void AddRefImpl() const { ref_count_.Increment(); } 110 ReleaseImpl()111 ALWAYS_INLINE bool ReleaseImpl() const { 112 if (!ref_count_.Decrement()) { 113 return true; 114 } 115 return false; 116 } 117 118 mutable AtomicRefCount ref_count_{0}; 119 120 DISALLOW_COPY_AND_ASSIGN(RefCountedThreadSafeBase); 121 }; 122 123 } // namespace subtle 124 125 // ScopedAllowCrossThreadRefCountAccess disables the check documented on 126 // RefCounted below for rare pre-existing use cases where thread-safety was 127 // guaranteed through other means (e.g. explicit sequencing of calls across 128 // execution sequences when bouncing between threads in order). New callers 129 // should refrain from using this (callsites handling thread-safety through 130 // locks should use RefCountedThreadSafe per the overhead of its atomics being 131 // negligible compared to locks anyways and callsites doing explicit sequencing 132 // should properly std::move() the ref to avoid hitting this check). 133 // TODO(tzik): Cleanup existing use cases and remove 134 // ScopedAllowCrossThreadRefCountAccess. 135 class ScopedAllowCrossThreadRefCountAccess final { 136 public: ScopedAllowCrossThreadRefCountAccess()137 ScopedAllowCrossThreadRefCountAccess() {} ~ScopedAllowCrossThreadRefCountAccess()138 ~ScopedAllowCrossThreadRefCountAccess() {} 139 }; 140 141 // 142 // A base class for reference counted classes. Otherwise, known as a cheap 143 // knock-off of WebKit's RefCounted<T> class. To use this, just extend your 144 // class from it like so: 145 // 146 // class MyFoo : public base::RefCounted<MyFoo> { 147 // ... 148 // private: 149 // friend class base::RefCounted<MyFoo>; 150 // ~MyFoo(); 151 // }; 152 // 153 // You should always make your destructor non-public, to avoid any code deleting 154 // the object accidently while there are references to it. 155 // 156 // 157 // The ref count manipulation to RefCounted is NOT thread safe and has DCHECKs 158 // to trap unsafe cross thread usage. A subclass instance of RefCounted can be 159 // passed to another execution sequence only when its ref count is 1. If the ref 160 // count is more than 1, the RefCounted class verifies the ref updates are made 161 // on the same execution sequence as the previous ones. The subclass can also 162 // manually call IsOnValidSequence to trap other non-thread-safe accesses; see 163 // the documentation for that method. 164 // 165 // 166 // The reference count starts from zero by default, and we intended to migrate 167 // to start-from-one ref count. Put REQUIRE_ADOPTION_FOR_REFCOUNTED_TYPE() to 168 // the ref counted class to opt-in. 169 // 170 // If an object has start-from-one ref count, the first scoped_refptr need to be 171 // created by base::AdoptRef() or base::MakeRefCounted(). We can use 172 // base::MakeRefCounted() to create create both type of ref counted object. 173 // 174 // The motivations to use start-from-one ref count are: 175 // - Start-from-one ref count doesn't need the ref count increment for the 176 // first reference. 177 // - It can detect an invalid object acquisition for a being-deleted object 178 // that has zero ref count. That tends to happen on custom deleter that 179 // delays the deletion. 180 // TODO(tzik): Implement invalid acquisition detection. 181 // - Behavior parity to Blink's WTF::RefCounted, whose count starts from one. 182 // And start-from-one ref count is a step to merge WTF::RefCounted into 183 // base::RefCounted. 184 // 185 #define REQUIRE_ADOPTION_FOR_REFCOUNTED_TYPE() \ 186 static constexpr ::base::subtle::StartRefCountFromOneTag \ 187 kRefCountPreference = ::base::subtle::kStartRefCountFromOneTag 188 189 template <class T, typename Traits> 190 class RefCounted; 191 192 template <typename T> 193 struct DefaultRefCountedTraits { DestructDefaultRefCountedTraits194 static void Destruct(const T* x) { 195 RefCounted<T, DefaultRefCountedTraits>::DeleteInternal(x); 196 } 197 }; 198 199 template <class T, typename Traits = DefaultRefCountedTraits<T>> 200 class RefCounted : public subtle::RefCountedBase { 201 public: 202 static constexpr subtle::StartRefCountFromZeroTag kRefCountPreference = 203 subtle::kStartRefCountFromZeroTag; 204 RefCounted()205 RefCounted() : subtle::RefCountedBase(T::kRefCountPreference) {} 206 AddRef()207 void AddRef() const { subtle::RefCountedBase::AddRef(); } 208 Release()209 void Release() const { 210 if (subtle::RefCountedBase::Release()) { 211 // Prune the code paths which the static analyzer may take to simulate 212 // object destruction. Use-after-free errors aren't possible given the 213 // lifetime guarantees of the refcounting system. 214 ANALYZER_SKIP_THIS_PATH(); 215 216 Traits::Destruct(static_cast<const T*>(this)); 217 } 218 } 219 220 protected: 221 ~RefCounted() = default; 222 223 private: 224 friend struct DefaultRefCountedTraits<T>; 225 template <typename U> 226 static void DeleteInternal(const U* x) { 227 delete x; 228 } 229 230 DISALLOW_COPY_AND_ASSIGN(RefCounted); 231 }; 232 233 // Forward declaration. 234 template <class T, typename Traits> 235 class RefCountedThreadSafe; 236 237 // Default traits for RefCountedThreadSafe<T>. Deletes the object when its ref 238 // count reaches 0. Overload to delete it on a different thread etc. 239 template <typename T> 240 struct DefaultRefCountedThreadSafeTraits { 241 static void Destruct(const T* x) { 242 // Delete through RefCountedThreadSafe to make child classes only need to be 243 // friend with RefCountedThreadSafe instead of this struct, which is an 244 // implementation detail. 245 RefCountedThreadSafe<T, DefaultRefCountedThreadSafeTraits>::DeleteInternal( 246 x); 247 } 248 }; 249 250 // 251 // A thread-safe variant of RefCounted<T> 252 // 253 // class MyFoo : public base::RefCountedThreadSafe<MyFoo> { 254 // ... 255 // }; 256 // 257 // If you're using the default trait, then you should add compile time 258 // asserts that no one else is deleting your object. i.e. 259 // private: 260 // friend class base::RefCountedThreadSafe<MyFoo>; 261 // ~MyFoo(); 262 // 263 // We can use REQUIRE_ADOPTION_FOR_REFCOUNTED_TYPE() with RefCountedThreadSafe 264 // too. See the comment above the RefCounted definition for details. 265 template <class T, typename Traits = DefaultRefCountedThreadSafeTraits<T>> 266 class RefCountedThreadSafe : public subtle::RefCountedThreadSafeBase { 267 public: 268 static constexpr subtle::StartRefCountFromZeroTag kRefCountPreference = 269 subtle::kStartRefCountFromZeroTag; 270 271 explicit RefCountedThreadSafe() 272 : subtle::RefCountedThreadSafeBase(T::kRefCountPreference) {} 273 274 void AddRef() const { subtle::RefCountedThreadSafeBase::AddRef(); } 275 276 void Release() const { 277 if (subtle::RefCountedThreadSafeBase::Release()) { 278 ANALYZER_SKIP_THIS_PATH(); 279 Traits::Destruct(static_cast<const T*>(this)); 280 } 281 } 282 283 protected: 284 ~RefCountedThreadSafe() = default; 285 286 private: 287 friend struct DefaultRefCountedThreadSafeTraits<T>; 288 template <typename U> 289 static void DeleteInternal(const U* x) { 290 delete x; 291 } 292 293 DISALLOW_COPY_AND_ASSIGN(RefCountedThreadSafe); 294 }; 295 296 // 297 // A thread-safe wrapper for some piece of data so we can place other 298 // things in scoped_refptrs<>. 299 // 300 template <typename T> 301 class RefCountedData 302 : public base::RefCountedThreadSafe<base::RefCountedData<T>> { 303 public: 304 RefCountedData() : data() {} 305 RefCountedData(const T& in_value) : data(in_value) {} 306 RefCountedData(T&& in_value) : data(std::move(in_value)) {} 307 308 T data; 309 310 private: 311 friend class base::RefCountedThreadSafe<base::RefCountedData<T>>; 312 ~RefCountedData() = default; 313 }; 314 315 } // namespace base 316 317 #endif // BASE_MEMORY_REF_COUNTED_H_ 318