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