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/base_export.h" 14 #include "base/compiler_specific.h" 15 #include "base/logging.h" 16 #include "base/macros.h" 17 #include "base/memory/scoped_refptr.h" 18 #include "base/sequence_checker.h" 19 #include "base/threading/thread_collision_warner.h" 20 #include "build/build_config.h" 21 22 namespace base { 23 namespace subtle { 24 25 class BASE_EXPORT RefCountedBase { 26 public: HasOneRef()27 bool HasOneRef() const { return ref_count_ == 1; } 28 29 protected: RefCountedBase(StartRefCountFromZeroTag)30 explicit RefCountedBase(StartRefCountFromZeroTag) { 31 #if DCHECK_IS_ON() 32 sequence_checker_.DetachFromSequence(); 33 #endif 34 } 35 RefCountedBase(StartRefCountFromOneTag)36 explicit RefCountedBase(StartRefCountFromOneTag) : ref_count_(1) { 37 #if DCHECK_IS_ON() 38 needs_adopt_ref_ = true; 39 sequence_checker_.DetachFromSequence(); 40 #endif 41 } 42 ~RefCountedBase()43 ~RefCountedBase() { 44 #if DCHECK_IS_ON() 45 DCHECK(in_dtor_) << "RefCounted object deleted without calling Release()"; 46 #endif 47 } 48 AddRef()49 void AddRef() const { 50 // TODO(maruel): Add back once it doesn't assert 500 times/sec. 51 // Current thread books the critical section "AddRelease" 52 // without release it. 53 // DFAKE_SCOPED_LOCK_THREAD_LOCKED(add_release_); 54 #if DCHECK_IS_ON() 55 DCHECK(!in_dtor_); 56 DCHECK(!needs_adopt_ref_) 57 << "This RefCounted object is created with non-zero reference count." 58 << " The first reference to such a object has to be made by AdoptRef or" 59 << " MakeRefCounted."; 60 if (ref_count_ >= 1) { 61 DCHECK(CalledOnValidSequence()); 62 } 63 #endif 64 65 AddRefImpl(); 66 } 67 68 // Returns true if the object should self-delete. Release()69 bool Release() const { 70 --ref_count_; 71 72 // TODO(maruel): Add back once it doesn't assert 500 times/sec. 73 // Current thread books the critical section "AddRelease" 74 // without release it. 75 // DFAKE_SCOPED_LOCK_THREAD_LOCKED(add_release_); 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 Adopted()116 void Adopted() const { 117 #if DCHECK_IS_ON() 118 DCHECK(needs_adopt_ref_); 119 needs_adopt_ref_ = false; 120 #endif 121 } 122 123 #if defined(ARCH_CPU_64_BIT) 124 void AddRefImpl() const; 125 #else AddRefImpl()126 void AddRefImpl() const { ++ref_count_; } 127 #endif 128 129 #if DCHECK_IS_ON() 130 bool CalledOnValidSequence() const; 131 #endif 132 133 mutable uint32_t ref_count_ = 0; 134 135 #if DCHECK_IS_ON() 136 mutable bool needs_adopt_ref_ = false; 137 mutable bool in_dtor_ = false; 138 mutable SequenceChecker sequence_checker_; 139 #endif 140 141 DFAKE_MUTEX(add_release_); 142 143 DISALLOW_COPY_AND_ASSIGN(RefCountedBase); 144 }; 145 146 class BASE_EXPORT RefCountedThreadSafeBase { 147 public: 148 bool HasOneRef() const; 149 150 protected: RefCountedThreadSafeBase(StartRefCountFromZeroTag)151 explicit constexpr RefCountedThreadSafeBase(StartRefCountFromZeroTag) {} RefCountedThreadSafeBase(StartRefCountFromOneTag)152 explicit constexpr RefCountedThreadSafeBase(StartRefCountFromOneTag) 153 : ref_count_(1) { 154 #if DCHECK_IS_ON() 155 needs_adopt_ref_ = true; 156 #endif 157 } 158 159 #if DCHECK_IS_ON() 160 ~RefCountedThreadSafeBase(); 161 #else 162 ~RefCountedThreadSafeBase() = default; 163 #endif 164 165 // Release and AddRef are suitable for inlining on X86 because they generate 166 // very small code sequences. On other platforms (ARM), it causes a size 167 // regression and is probably not worth it. 168 #if defined(ARCH_CPU_X86_FAMILY) 169 // Returns true if the object should self-delete. Release()170 bool Release() const { return ReleaseImpl(); } AddRef()171 void AddRef() const { AddRefImpl(); } 172 #else 173 // Returns true if the object should self-delete. 174 bool Release() const; 175 void AddRef() const; 176 #endif 177 178 private: 179 template <typename U> 180 friend scoped_refptr<U> base::AdoptRef(U*); 181 Adopted()182 void Adopted() const { 183 #if DCHECK_IS_ON() 184 DCHECK(needs_adopt_ref_); 185 needs_adopt_ref_ = false; 186 #endif 187 } 188 AddRefImpl()189 ALWAYS_INLINE void AddRefImpl() const { 190 #if DCHECK_IS_ON() 191 DCHECK(!in_dtor_); 192 DCHECK(!needs_adopt_ref_) 193 << "This RefCounted object is created with non-zero reference count." 194 << " The first reference to such a object has to be made by AdoptRef or" 195 << " MakeRefCounted."; 196 #endif 197 ref_count_.Increment(); 198 } 199 ReleaseImpl()200 ALWAYS_INLINE bool ReleaseImpl() const { 201 #if DCHECK_IS_ON() 202 DCHECK(!in_dtor_); 203 DCHECK(!ref_count_.IsZero()); 204 #endif 205 if (!ref_count_.Decrement()) { 206 #if DCHECK_IS_ON() 207 in_dtor_ = true; 208 #endif 209 return true; 210 } 211 return false; 212 } 213 214 mutable AtomicRefCount ref_count_{0}; 215 #if DCHECK_IS_ON() 216 mutable bool needs_adopt_ref_ = false; 217 mutable bool in_dtor_ = false; 218 #endif 219 220 DISALLOW_COPY_AND_ASSIGN(RefCountedThreadSafeBase); 221 }; 222 223 } // namespace subtle 224 225 // ScopedAllowCrossThreadRefCountAccess disables the check documented on 226 // RefCounted below for rare pre-existing use cases where thread-safety was 227 // guaranteed through other means (e.g. explicit sequencing of calls across 228 // execution sequences when bouncing between threads in order). New callers 229 // should refrain from using this (callsites handling thread-safety through 230 // locks should use RefCountedThreadSafe per the overhead of its atomics being 231 // negligible compared to locks anyways and callsites doing explicit sequencing 232 // should properly std::move() the ref to avoid hitting this check). 233 // TODO(tzik): Cleanup existing use cases and remove 234 // ScopedAllowCrossThreadRefCountAccess. 235 class BASE_EXPORT ScopedAllowCrossThreadRefCountAccess final { 236 public: 237 #if DCHECK_IS_ON() 238 ScopedAllowCrossThreadRefCountAccess(); 239 ~ScopedAllowCrossThreadRefCountAccess(); 240 #else 241 ScopedAllowCrossThreadRefCountAccess() {} 242 ~ScopedAllowCrossThreadRefCountAccess() {} 243 #endif 244 }; 245 246 // 247 // A base class for reference counted classes. Otherwise, known as a cheap 248 // knock-off of WebKit's RefCounted<T> class. To use this, just extend your 249 // class from it like so: 250 // 251 // class MyFoo : public base::RefCounted<MyFoo> { 252 // ... 253 // private: 254 // friend class base::RefCounted<MyFoo>; 255 // ~MyFoo(); 256 // }; 257 // 258 // You should always make your destructor non-public, to avoid any code deleting 259 // the object accidently while there are references to it. 260 // 261 // 262 // The ref count manipulation to RefCounted is NOT thread safe and has DCHECKs 263 // to trap unsafe cross thread usage. A subclass instance of RefCounted can be 264 // passed to another execution sequence only when its ref count is 1. If the ref 265 // count is more than 1, the RefCounted class verifies the ref updates are made 266 // on the same execution sequence as the previous ones. The subclass can also 267 // manually call IsOnValidSequence to trap other non-thread-safe accesses; see 268 // the documentation for that method. 269 // 270 // 271 // The reference count starts from zero by default, and we intended to migrate 272 // to start-from-one ref count. Put REQUIRE_ADOPTION_FOR_REFCOUNTED_TYPE() to 273 // the ref counted class to opt-in. 274 // 275 // If an object has start-from-one ref count, the first scoped_refptr need to be 276 // created by base::AdoptRef() or base::MakeRefCounted(). We can use 277 // base::MakeRefCounted() to create create both type of ref counted object. 278 // 279 // The motivations to use start-from-one ref count are: 280 // - Start-from-one ref count doesn't need the ref count increment for the 281 // first reference. 282 // - It can detect an invalid object acquisition for a being-deleted object 283 // that has zero ref count. That tends to happen on custom deleter that 284 // delays the deletion. 285 // TODO(tzik): Implement invalid acquisition detection. 286 // - Behavior parity to Blink's WTF::RefCounted, whose count starts from one. 287 // And start-from-one ref count is a step to merge WTF::RefCounted into 288 // base::RefCounted. 289 // 290 #define REQUIRE_ADOPTION_FOR_REFCOUNTED_TYPE() \ 291 static constexpr ::base::subtle::StartRefCountFromOneTag \ 292 kRefCountPreference = ::base::subtle::kStartRefCountFromOneTag 293 294 template <class T, typename Traits> 295 class RefCounted; 296 297 template <typename T> 298 struct DefaultRefCountedTraits { DestructDefaultRefCountedTraits299 static void Destruct(const T* x) { 300 RefCounted<T, DefaultRefCountedTraits>::DeleteInternal(x); 301 } 302 }; 303 304 template <class T, typename Traits = DefaultRefCountedTraits<T>> 305 class RefCounted : public subtle::RefCountedBase { 306 public: 307 static constexpr subtle::StartRefCountFromZeroTag kRefCountPreference = 308 subtle::kStartRefCountFromZeroTag; 309 RefCounted()310 RefCounted() : subtle::RefCountedBase(T::kRefCountPreference) {} 311 AddRef()312 void AddRef() const { 313 subtle::RefCountedBase::AddRef(); 314 } 315 Release()316 void Release() const { 317 if (subtle::RefCountedBase::Release()) { 318 // Prune the code paths which the static analyzer may take to simulate 319 // object destruction. Use-after-free errors aren't possible given the 320 // lifetime guarantees of the refcounting system. 321 ANALYZER_SKIP_THIS_PATH(); 322 323 Traits::Destruct(static_cast<const T*>(this)); 324 } 325 } 326 327 protected: 328 ~RefCounted() = default; 329 330 private: 331 friend struct DefaultRefCountedTraits<T>; 332 template <typename U> 333 static void DeleteInternal(const U* x) { 334 delete x; 335 } 336 337 DISALLOW_COPY_AND_ASSIGN(RefCounted); 338 }; 339 340 // Forward declaration. 341 template <class T, typename Traits> class RefCountedThreadSafe; 342 343 // Default traits for RefCountedThreadSafe<T>. Deletes the object when its ref 344 // count reaches 0. Overload to delete it on a different thread etc. 345 template<typename T> 346 struct DefaultRefCountedThreadSafeTraits { 347 static void Destruct(const T* x) { 348 // Delete through RefCountedThreadSafe to make child classes only need to be 349 // friend with RefCountedThreadSafe instead of this struct, which is an 350 // implementation detail. 351 RefCountedThreadSafe<T, 352 DefaultRefCountedThreadSafeTraits>::DeleteInternal(x); 353 } 354 }; 355 356 // 357 // A thread-safe variant of RefCounted<T> 358 // 359 // class MyFoo : public base::RefCountedThreadSafe<MyFoo> { 360 // ... 361 // }; 362 // 363 // If you're using the default trait, then you should add compile time 364 // asserts that no one else is deleting your object. i.e. 365 // private: 366 // friend class base::RefCountedThreadSafe<MyFoo>; 367 // ~MyFoo(); 368 // 369 // We can use REQUIRE_ADOPTION_FOR_REFCOUNTED_TYPE() with RefCountedThreadSafe 370 // too. See the comment above the RefCounted definition for details. 371 template <class T, typename Traits = DefaultRefCountedThreadSafeTraits<T> > 372 class RefCountedThreadSafe : public subtle::RefCountedThreadSafeBase { 373 public: 374 static constexpr subtle::StartRefCountFromZeroTag kRefCountPreference = 375 subtle::kStartRefCountFromZeroTag; 376 377 explicit RefCountedThreadSafe() 378 : subtle::RefCountedThreadSafeBase(T::kRefCountPreference) {} 379 380 void AddRef() const { 381 subtle::RefCountedThreadSafeBase::AddRef(); 382 } 383 384 void Release() const { 385 if (subtle::RefCountedThreadSafeBase::Release()) { 386 ANALYZER_SKIP_THIS_PATH(); 387 Traits::Destruct(static_cast<const T*>(this)); 388 } 389 } 390 391 protected: 392 ~RefCountedThreadSafe() = default; 393 394 private: 395 friend struct DefaultRefCountedThreadSafeTraits<T>; 396 template <typename U> 397 static void DeleteInternal(const U* x) { 398 delete x; 399 } 400 401 DISALLOW_COPY_AND_ASSIGN(RefCountedThreadSafe); 402 }; 403 404 // 405 // A thread-safe wrapper for some piece of data so we can place other 406 // things in scoped_refptrs<>. 407 // 408 template<typename T> 409 class RefCountedData 410 : public base::RefCountedThreadSafe< base::RefCountedData<T> > { 411 public: 412 RefCountedData() : data() {} 413 RefCountedData(const T& in_value) : data(in_value) {} 414 RefCountedData(T&& in_value) : data(std::move(in_value)) {} 415 416 T data; 417 418 private: 419 friend class base::RefCountedThreadSafe<base::RefCountedData<T> >; 420 ~RefCountedData() = default; 421 }; 422 423 } // namespace base 424 425 #endif // BASE_MEMORY_REF_COUNTED_H_ 426