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 BASE_MEMORY_REF_COUNTED_H_ 6 #define BASE_MEMORY_REF_COUNTED_H_ 7 8 #include <stddef.h> 9 10 #include <limits> 11 #include <utility> 12 13 #include "base/atomic_ref_count.h" 14 #include "base/base_export.h" 15 #include "base/check.h" 16 #include "base/check_op.h" 17 #include "base/compiler_specific.h" 18 #include "base/dcheck_is_on.h" 19 #include "base/memory/scoped_refptr.h" 20 #include "base/sequence_checker.h" 21 #include "base/template_util.h" 22 #include "base/threading/thread_collision_warner.h" 23 #include "build/build_config.h" 24 #include "third_party/abseil-cpp/absl/utility/utility.h" 25 26 namespace base { 27 namespace subtle { 28 29 class BASE_EXPORT RefCountedBase { 30 public: 31 RefCountedBase(const RefCountedBase&) = delete; 32 RefCountedBase& operator=(const RefCountedBase&) = delete; 33 HasOneRef()34 bool HasOneRef() const { return ref_count_ == 1; } HasAtLeastOneRef()35 bool HasAtLeastOneRef() const { return ref_count_ >= 1; } 36 37 protected: RefCountedBase(StartRefCountFromZeroTag)38 explicit RefCountedBase(StartRefCountFromZeroTag) { 39 #if DCHECK_IS_ON() 40 sequence_checker_.DetachFromSequence(); 41 #endif 42 } 43 RefCountedBase(StartRefCountFromOneTag)44 explicit RefCountedBase(StartRefCountFromOneTag) : ref_count_(1) { 45 #if DCHECK_IS_ON() 46 needs_adopt_ref_ = true; 47 sequence_checker_.DetachFromSequence(); 48 #endif 49 } 50 ~RefCountedBase()51 ~RefCountedBase() { 52 #if DCHECK_IS_ON() 53 // RefCounted object deleted without calling Release() 54 DCHECK(in_dtor_); 55 #endif 56 } 57 AddRef()58 void AddRef() const { 59 #if DCHECK_IS_ON() 60 DCHECK(!in_dtor_); 61 // This RefCounted object is created with non-zero reference count. 62 // The first reference to such a object has to be made by AdoptRef or 63 // MakeRefCounted. 64 DCHECK(!needs_adopt_ref_); 65 if (ref_count_ >= 1) { 66 DCHECK(CalledOnValidSequence()); 67 } 68 #endif 69 70 AddRefImpl(); 71 } 72 73 // Returns true if the object should self-delete. Release()74 bool Release() const { 75 ReleaseImpl(); 76 77 #if DCHECK_IS_ON() 78 DCHECK(!in_dtor_); 79 if (ref_count_ == 0) 80 in_dtor_ = true; 81 82 if (ref_count_ >= 1) 83 DCHECK(CalledOnValidSequence()); 84 if (ref_count_ == 1) 85 sequence_checker_.DetachFromSequence(); 86 #endif 87 88 return ref_count_ == 0; 89 } 90 91 // Returns true if it is safe to read or write the object, from a thread 92 // safety standpoint. Should be DCHECK'd from the methods of RefCounted 93 // classes if there is a danger of objects being shared across threads. 94 // 95 // This produces fewer false positives than adding a separate SequenceChecker 96 // into the subclass, because it automatically detaches from the sequence when 97 // the reference count is 1 (and never fails if there is only one reference). 98 // 99 // This means unlike a separate SequenceChecker, it will permit a singly 100 // referenced object to be passed between threads (not holding a reference on 101 // the sending thread), but will trap if the sending thread holds onto a 102 // reference, or if the object is accessed from multiple threads 103 // simultaneously. IsOnValidSequence()104 bool IsOnValidSequence() const { 105 #if DCHECK_IS_ON() 106 return ref_count_ <= 1 || CalledOnValidSequence(); 107 #else 108 return true; 109 #endif 110 } 111 112 private: 113 template <typename U> 114 friend scoped_refptr<U> base::AdoptRef(U*); 115 116 friend class RefCountedOverflowTest; 117 Adopted()118 void Adopted() const { 119 #if DCHECK_IS_ON() 120 DCHECK(needs_adopt_ref_); 121 needs_adopt_ref_ = false; 122 #endif 123 } 124 125 #if defined(ARCH_CPU_64_BITS) 126 void AddRefImpl() const; 127 void ReleaseImpl() const; 128 #else AddRefImpl()129 void AddRefImpl() const { ++ref_count_; } ReleaseImpl()130 void ReleaseImpl() const { --ref_count_; } 131 #endif 132 133 #if DCHECK_IS_ON() 134 bool CalledOnValidSequence() const; 135 #endif 136 137 mutable uint32_t ref_count_ = 0; 138 static_assert(std::is_unsigned_v<decltype(ref_count_)>, 139 "ref_count_ must be an unsigned type."); 140 141 #if DCHECK_IS_ON() 142 mutable bool needs_adopt_ref_ = false; 143 mutable bool in_dtor_ = false; 144 mutable SequenceChecker sequence_checker_; 145 #endif 146 147 DFAKE_MUTEX(add_release_); 148 }; 149 150 class BASE_EXPORT RefCountedThreadSafeBase { 151 public: 152 RefCountedThreadSafeBase(const RefCountedThreadSafeBase&) = delete; 153 RefCountedThreadSafeBase& operator=(const RefCountedThreadSafeBase&) = delete; 154 155 bool HasOneRef() const; 156 bool HasAtLeastOneRef() const; 157 158 protected: RefCountedThreadSafeBase(StartRefCountFromZeroTag)159 explicit constexpr RefCountedThreadSafeBase(StartRefCountFromZeroTag) {} RefCountedThreadSafeBase(StartRefCountFromOneTag)160 explicit constexpr RefCountedThreadSafeBase(StartRefCountFromOneTag) 161 : ref_count_(1) { 162 #if DCHECK_IS_ON() 163 needs_adopt_ref_ = true; 164 #endif 165 } 166 167 #if DCHECK_IS_ON() 168 ~RefCountedThreadSafeBase(); 169 #else 170 ~RefCountedThreadSafeBase() = default; 171 #endif 172 173 // Release and AddRef are suitable for inlining on X86 because they generate 174 // very small code sequences. 175 // 176 // ARM64 devices supporting ARMv8.1-A atomic instructions generate very little 177 // code, e.g. fetch_add() with acquire ordering is a single instruction (ldadd), 178 // vs LL/SC in previous ARM architectures. Inline it there as well. 179 // 180 // On other platforms (e.g. ARM), it causes a size regression and is probably 181 // not worth it. 182 #if defined(ARCH_CPU_X86_FAMILY) || defined(__ARM_FEATURE_ATOMICS) 183 // Returns true if the object should self-delete. Release()184 bool Release() const { return ReleaseImpl(); } AddRef()185 void AddRef() const { AddRefImpl(); } AddRefWithCheck()186 void AddRefWithCheck() const { AddRefWithCheckImpl(); } 187 #else 188 // Returns true if the object should self-delete. 189 bool Release() const; 190 void AddRef() const; 191 void AddRefWithCheck() const; 192 #endif 193 194 private: 195 template <typename U> 196 friend scoped_refptr<U> base::AdoptRef(U*); 197 198 friend class RefCountedOverflowTest; 199 Adopted()200 void Adopted() const { 201 #if DCHECK_IS_ON() 202 DCHECK(needs_adopt_ref_); 203 needs_adopt_ref_ = false; 204 #endif 205 } 206 AddRefImpl()207 ALWAYS_INLINE void AddRefImpl() const { 208 #if DCHECK_IS_ON() 209 DCHECK(!in_dtor_); 210 // This RefCounted object is created with non-zero reference count. 211 // The first reference to such a object has to be made by AdoptRef or 212 // MakeRefCounted. 213 DCHECK(!needs_adopt_ref_); 214 #endif 215 CHECK_NE(ref_count_.Increment(), std::numeric_limits<int>::max()); 216 } 217 AddRefWithCheckImpl()218 ALWAYS_INLINE void AddRefWithCheckImpl() const { 219 #if DCHECK_IS_ON() 220 DCHECK(!in_dtor_); 221 // This RefCounted object is created with non-zero reference count. 222 // The first reference to such a object has to be made by AdoptRef or 223 // MakeRefCounted. 224 DCHECK(!needs_adopt_ref_); 225 #endif 226 int pre_increment_count = ref_count_.Increment(); 227 CHECK_GT(pre_increment_count, 0); 228 CHECK_NE(pre_increment_count, std::numeric_limits<int>::max()); 229 } 230 ReleaseImpl()231 ALWAYS_INLINE bool ReleaseImpl() const { 232 #if DCHECK_IS_ON() 233 DCHECK(!in_dtor_); 234 DCHECK(!ref_count_.IsZero()); 235 #endif 236 if (!ref_count_.Decrement()) { 237 #if DCHECK_IS_ON() 238 in_dtor_ = true; 239 #endif 240 return true; 241 } 242 return false; 243 } 244 245 mutable AtomicRefCount ref_count_{0}; 246 #if DCHECK_IS_ON() 247 mutable bool needs_adopt_ref_ = false; 248 mutable bool in_dtor_ = false; 249 #endif 250 }; 251 252 } // namespace subtle 253 254 // ScopedAllowCrossThreadRefCountAccess disables the check documented on 255 // RefCounted below for rare pre-existing use cases where thread-safety was 256 // guaranteed through other means (e.g. explicit sequencing of calls across 257 // execution sequences when bouncing between threads in order). New callers 258 // should refrain from using this (callsites handling thread-safety through 259 // locks should use RefCountedThreadSafe per the overhead of its atomics being 260 // negligible compared to locks anyways and callsites doing explicit sequencing 261 // should properly std::move() the ref to avoid hitting this check). 262 // TODO(tzik): Cleanup existing use cases and remove 263 // ScopedAllowCrossThreadRefCountAccess. 264 class BASE_EXPORT ScopedAllowCrossThreadRefCountAccess final { 265 public: 266 #if DCHECK_IS_ON() 267 ScopedAllowCrossThreadRefCountAccess(); 268 ~ScopedAllowCrossThreadRefCountAccess(); 269 #else 270 ScopedAllowCrossThreadRefCountAccess() {} 271 ~ScopedAllowCrossThreadRefCountAccess() {} 272 #endif 273 }; 274 275 // 276 // A base class for reference counted classes. Otherwise, known as a cheap 277 // knock-off of WebKit's RefCounted<T> class. To use this, just extend your 278 // class from it like so: 279 // 280 // class MyFoo : public base::RefCounted<MyFoo> { 281 // ... 282 // private: 283 // friend class base::RefCounted<MyFoo>; 284 // ~MyFoo(); 285 // }; 286 // 287 // Usage Notes: 288 // 1. You should always make your destructor non-public, to avoid any code 289 // deleting the object accidentally while there are references to it. 290 // 2. You should always make the ref-counted base class a friend of your class, 291 // so that it can access the destructor. 292 // 293 // The ref count manipulation to RefCounted is NOT thread safe and has DCHECKs 294 // to trap unsafe cross thread usage. A subclass instance of RefCounted can be 295 // passed to another execution sequence only when its ref count is 1. If the ref 296 // count is more than 1, the RefCounted class verifies the ref updates are made 297 // on the same execution sequence as the previous ones. The subclass can also 298 // manually call IsOnValidSequence to trap other non-thread-safe accesses; see 299 // the documentation for that method. 300 // 301 // 302 // The reference count starts from zero by default, and we intended to migrate 303 // to start-from-one ref count. Put REQUIRE_ADOPTION_FOR_REFCOUNTED_TYPE() to 304 // the ref counted class to opt-in. 305 // 306 // If an object has start-from-one ref count, the first scoped_refptr need to be 307 // created by base::AdoptRef() or base::MakeRefCounted(). We can use 308 // base::MakeRefCounted() to create create both type of ref counted object. 309 // 310 // The motivations to use start-from-one ref count are: 311 // - Start-from-one ref count doesn't need the ref count increment for the 312 // first reference. 313 // - It can detect an invalid object acquisition for a being-deleted object 314 // that has zero ref count. That tends to happen on custom deleter that 315 // delays the deletion. 316 // TODO(tzik): Implement invalid acquisition detection. 317 // - Behavior parity to Blink's WTF::RefCounted, whose count starts from one. 318 // And start-from-one ref count is a step to merge WTF::RefCounted into 319 // base::RefCounted. 320 // 321 #define REQUIRE_ADOPTION_FOR_REFCOUNTED_TYPE() \ 322 using RefCountPreferenceTag = ::base::subtle::StartRefCountFromOneTag 323 324 template <class T, typename Traits> 325 class RefCounted; 326 327 template <typename T> 328 struct DefaultRefCountedTraits { DestructDefaultRefCountedTraits329 static void Destruct(const T* x) { 330 RefCounted<T, DefaultRefCountedTraits>::DeleteInternal(x); 331 } 332 }; 333 334 template <class T, typename Traits = DefaultRefCountedTraits<T>> 335 class RefCounted : public subtle::RefCountedBase { 336 public: 337 using RefCountPreferenceTag = subtle::StartRefCountFromZeroTag; 338 RefCounted()339 RefCounted() : subtle::RefCountedBase(subtle::GetRefCountPreference<T>()) {} 340 341 RefCounted(const RefCounted&) = delete; 342 RefCounted& operator=(const RefCounted&) = delete; 343 AddRef()344 void AddRef() const { 345 subtle::RefCountedBase::AddRef(); 346 } 347 Release()348 void Release() const { 349 if (subtle::RefCountedBase::Release()) { 350 // Prune the code paths which the static analyzer may take to simulate 351 // object destruction. Use-after-free errors aren't possible given the 352 // lifetime guarantees of the refcounting system. 353 ANALYZER_SKIP_THIS_PATH(); 354 355 Traits::Destruct(static_cast<const T*>(this)); 356 } 357 } 358 359 protected: 360 ~RefCounted() = default; 361 362 private: 363 friend struct DefaultRefCountedTraits<T>; 364 template <typename U> 365 static void DeleteInternal(const U* x) { 366 delete x; 367 } 368 }; 369 370 // Forward declaration. 371 template <class T, typename Traits> class RefCountedThreadSafe; 372 373 // Default traits for RefCountedThreadSafe<T>. Deletes the object when its ref 374 // count reaches 0. Overload to delete it on a different thread etc. 375 template<typename T> 376 struct DefaultRefCountedThreadSafeTraits { 377 static void Destruct(const T* x) { 378 // Delete through RefCountedThreadSafe to make child classes only need to be 379 // friend with RefCountedThreadSafe instead of this struct, which is an 380 // implementation detail. 381 RefCountedThreadSafe<T, 382 DefaultRefCountedThreadSafeTraits>::DeleteInternal(x); 383 } 384 }; 385 386 // 387 // A thread-safe variant of RefCounted<T> 388 // 389 // class MyFoo : public base::RefCountedThreadSafe<MyFoo> { 390 // ... 391 // }; 392 // 393 // If you're using the default trait, then you should add compile time 394 // asserts that no one else is deleting your object. i.e. 395 // private: 396 // friend class base::RefCountedThreadSafe<MyFoo>; 397 // ~MyFoo(); 398 // 399 // We can use REQUIRE_ADOPTION_FOR_REFCOUNTED_TYPE() with RefCountedThreadSafe 400 // too. See the comment above the RefCounted definition for details. 401 template <class T, typename Traits = DefaultRefCountedThreadSafeTraits<T> > 402 class RefCountedThreadSafe : public subtle::RefCountedThreadSafeBase { 403 public: 404 using RefCountPreferenceTag = subtle::StartRefCountFromZeroTag; 405 406 explicit RefCountedThreadSafe() 407 : subtle::RefCountedThreadSafeBase(subtle::GetRefCountPreference<T>()) {} 408 409 RefCountedThreadSafe(const RefCountedThreadSafe&) = delete; 410 RefCountedThreadSafe& operator=(const RefCountedThreadSafe&) = delete; 411 412 void AddRef() const { AddRefImpl(subtle::GetRefCountPreference<T>()); } 413 414 void Release() const { 415 if (subtle::RefCountedThreadSafeBase::Release()) { 416 ANALYZER_SKIP_THIS_PATH(); 417 Traits::Destruct(static_cast<const T*>(this)); 418 } 419 } 420 421 protected: 422 ~RefCountedThreadSafe() = default; 423 424 private: 425 friend struct DefaultRefCountedThreadSafeTraits<T>; 426 template <typename U> 427 static void DeleteInternal(const U* x) { 428 delete x; 429 } 430 431 void AddRefImpl(subtle::StartRefCountFromZeroTag) const { 432 subtle::RefCountedThreadSafeBase::AddRef(); 433 } 434 435 void AddRefImpl(subtle::StartRefCountFromOneTag) const { 436 subtle::RefCountedThreadSafeBase::AddRefWithCheck(); 437 } 438 }; 439 440 // 441 // A thread-safe wrapper for some piece of data so we can place other 442 // things in scoped_refptrs<>. 443 // 444 template<typename T> 445 class RefCountedData 446 : public base::RefCountedThreadSafe< base::RefCountedData<T> > { 447 public: 448 RefCountedData() : data() {} 449 RefCountedData(const T& in_value) : data(in_value) {} 450 RefCountedData(T&& in_value) : data(std::move(in_value)) {} 451 template <typename... Args> 452 explicit RefCountedData(std::in_place_t, Args&&... args) 453 : data(std::forward<Args>(args)...) {} 454 455 T data; 456 457 private: 458 friend class base::RefCountedThreadSafe<base::RefCountedData<T> >; 459 ~RefCountedData() = default; 460 }; 461 462 template <typename T> 463 bool operator==(const RefCountedData<T>& lhs, const RefCountedData<T>& rhs) { 464 return lhs.data == rhs.data; 465 } 466 467 template <typename T> 468 bool operator!=(const RefCountedData<T>& lhs, const RefCountedData<T>& rhs) { 469 return !(lhs == rhs); 470 } 471 472 } // namespace base 473 474 #endif // BASE_MEMORY_REF_COUNTED_H_ 475