| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #ifndef BASE_MEMORY_REF_COUNTED_H_ | 5 #ifndef BASE_MEMORY_REF_COUNTED_H_ |
| 6 #define BASE_MEMORY_REF_COUNTED_H_ | 6 #define BASE_MEMORY_REF_COUNTED_H_ |
| 7 | 7 |
| 8 #include <stddef.h> | 8 #include <stddef.h> |
| 9 | 9 |
| 10 #include <cassert> | 10 #include <cassert> |
| 11 #include <iosfwd> | 11 #include <iosfwd> |
| 12 #include <type_traits> | 12 #include <type_traits> |
| 13 | 13 |
| 14 #include "base/atomic_ref_count.h" | 14 #include "base/atomic_ref_count.h" |
| 15 #include "base/base_export.h" | 15 #include "base/base_export.h" |
| 16 #include "base/compiler_specific.h" | 16 #include "base/compiler_specific.h" |
| 17 #include "base/logging.h" | 17 #include "base/logging.h" |
| 18 #include "base/macros.h" | 18 #include "base/macros.h" |
| 19 #include "base/sequence_checker.h" | 19 #include "base/sequence_checker.h" |
| 20 #include "base/threading/thread_collision_warner.h" | 20 #include "base/threading/thread_collision_warner.h" |
| 21 #include "build/build_config.h" | 21 #include "build/build_config.h" |
| 22 | 22 |
| 23 template <class T> |
| 24 class scoped_refptr; |
| 25 |
| 23 namespace base { | 26 namespace base { |
| 24 | 27 |
| 28 template <typename T> |
| 29 scoped_refptr<T> AdoptRef(T* t); |
| 30 |
| 25 namespace subtle { | 31 namespace subtle { |
| 26 | 32 |
| 33 enum AdoptRefTag { kAdoptRefTag }; |
| 34 enum StartRefCountFromZeroTag { kStartRefCountFromZeroTag }; |
| 35 enum StartRefCountFromOneTag { kStartRefCountFromOneTag }; |
| 36 |
| 27 class BASE_EXPORT RefCountedBase { | 37 class BASE_EXPORT RefCountedBase { |
| 28 public: | 38 public: |
| 29 bool HasOneRef() const { return ref_count_ == 1; } | 39 bool HasOneRef() const { return ref_count_ == 1; } |
| 30 | 40 |
| 31 protected: | 41 protected: |
| 32 RefCountedBase() { | 42 explicit RefCountedBase(StartRefCountFromZeroTag) { |
| 33 #if DCHECK_IS_ON() | 43 #if DCHECK_IS_ON() |
| 34 sequence_checker_.DetachFromSequence(); | 44 sequence_checker_.DetachFromSequence(); |
| 35 #endif | 45 #endif |
| 36 } | 46 } |
| 47 |
| 48 explicit RefCountedBase(StartRefCountFromOneTag) : ref_count_(1) { |
| 49 #if DCHECK_IS_ON() |
| 50 needs_adopt_ref_ = true; |
| 51 sequence_checker_.DetachFromSequence(); |
| 52 #endif |
| 53 } |
| 37 | 54 |
| 38 ~RefCountedBase() { | 55 ~RefCountedBase() { |
| 39 #if DCHECK_IS_ON() | 56 #if DCHECK_IS_ON() |
| 40 DCHECK(in_dtor_) << "RefCounted object deleted without calling Release()"; | 57 DCHECK(in_dtor_) << "RefCounted object deleted without calling Release()"; |
| 41 #endif | 58 #endif |
| 42 } | 59 } |
| 43 | 60 |
| 44 void AddRef() const { | 61 void AddRef() const { |
| 45 // TODO(maruel): Add back once it doesn't assert 500 times/sec. | 62 // TODO(maruel): Add back once it doesn't assert 500 times/sec. |
| 46 // Current thread books the critical section "AddRelease" | 63 // Current thread books the critical section "AddRelease" |
| 47 // without release it. | 64 // without release it. |
| 48 // DFAKE_SCOPED_LOCK_THREAD_LOCKED(add_release_); | 65 // DFAKE_SCOPED_LOCK_THREAD_LOCKED(add_release_); |
| 49 #if DCHECK_IS_ON() | 66 #if DCHECK_IS_ON() |
| 50 DCHECK(!in_dtor_); | 67 DCHECK(!in_dtor_); |
| 68 DCHECK(!needs_adopt_ref_) |
| 69 << "This RefCounted object is created with non-zero reference count." |
| 70 << " The first reference to such a object has to be made by AdoptRef or" |
| 71 << " MakeShared."; |
| 51 if (ref_count_ >= 1) { | 72 if (ref_count_ >= 1) { |
| 52 DCHECK(CalledOnValidSequence()); | 73 DCHECK(CalledOnValidSequence()); |
| 53 } | 74 } |
| 54 #endif | 75 #endif |
| 55 | 76 |
| 56 ++ref_count_; | 77 ++ref_count_; |
| 57 } | 78 } |
| 58 | 79 |
| 59 // Returns true if the object should self-delete. | 80 // Returns true if the object should self-delete. |
| 60 bool Release() const { | 81 bool Release() const { |
| (...skipping 12 matching lines...) Expand all Loading... |
| 73 if (ref_count_ >= 1) | 94 if (ref_count_ >= 1) |
| 74 DCHECK(CalledOnValidSequence()); | 95 DCHECK(CalledOnValidSequence()); |
| 75 if (ref_count_ == 1) | 96 if (ref_count_ == 1) |
| 76 sequence_checker_.DetachFromSequence(); | 97 sequence_checker_.DetachFromSequence(); |
| 77 #endif | 98 #endif |
| 78 | 99 |
| 79 return ref_count_ == 0; | 100 return ref_count_ == 0; |
| 80 } | 101 } |
| 81 | 102 |
| 82 private: | 103 private: |
| 104 template <typename U> |
| 105 friend scoped_refptr<U> base::AdoptRef(U*); |
| 106 |
| 107 void Adopted() const { |
| 108 #if DCHECK_IS_ON() |
| 109 DCHECK(needs_adopt_ref_); |
| 110 needs_adopt_ref_ = false; |
| 111 #endif |
| 112 } |
| 113 |
| 83 #if DCHECK_IS_ON() | 114 #if DCHECK_IS_ON() |
| 84 bool CalledOnValidSequence() const; | 115 bool CalledOnValidSequence() const; |
| 85 #endif | 116 #endif |
| 86 | 117 |
| 87 mutable size_t ref_count_ = 0; | 118 mutable size_t ref_count_ = 0; |
| 88 | 119 |
| 89 #if DCHECK_IS_ON() | 120 #if DCHECK_IS_ON() |
| 121 mutable bool needs_adopt_ref_ = false; |
| 90 mutable bool in_dtor_ = false; | 122 mutable bool in_dtor_ = false; |
| 91 mutable SequenceChecker sequence_checker_; | 123 mutable SequenceChecker sequence_checker_; |
| 92 #endif | 124 #endif |
| 93 | 125 |
| 94 DFAKE_MUTEX(add_release_); | 126 DFAKE_MUTEX(add_release_); |
| 95 | 127 |
| 96 DISALLOW_COPY_AND_ASSIGN(RefCountedBase); | 128 DISALLOW_COPY_AND_ASSIGN(RefCountedBase); |
| 97 }; | 129 }; |
| 98 | 130 |
| 99 class BASE_EXPORT RefCountedThreadSafeBase { | 131 class BASE_EXPORT RefCountedThreadSafeBase { |
| 100 public: | 132 public: |
| 101 bool HasOneRef() const; | 133 bool HasOneRef() const; |
| 102 | 134 |
| 103 protected: | 135 protected: |
| 104 RefCountedThreadSafeBase(); | 136 explicit RefCountedThreadSafeBase(StartRefCountFromZeroTag) {} |
| 137 explicit RefCountedThreadSafeBase(StartRefCountFromOneTag) : ref_count_(1) { |
| 138 #if DCHECK_IS_ON() |
| 139 needs_adopt_ref_ = true; |
| 140 #endif |
| 141 } |
| 142 |
| 105 ~RefCountedThreadSafeBase(); | 143 ~RefCountedThreadSafeBase(); |
| 106 | 144 |
| 107 void AddRef() const; | 145 void AddRef() const; |
| 108 | 146 |
| 109 // Returns true if the object should self-delete. | 147 // Returns true if the object should self-delete. |
| 110 bool Release() const; | 148 bool Release() const; |
| 111 | 149 |
| 112 private: | 150 private: |
| 151 template <typename U> |
| 152 friend scoped_refptr<U> base::AdoptRef(U*); |
| 153 |
| 154 void Adopted() const { |
| 155 #if DCHECK_IS_ON() |
| 156 DCHECK(needs_adopt_ref_); |
| 157 needs_adopt_ref_ = false; |
| 158 #endif |
| 159 } |
| 160 |
| 113 mutable AtomicRefCount ref_count_ = 0; | 161 mutable AtomicRefCount ref_count_ = 0; |
| 114 #if DCHECK_IS_ON() | 162 #if DCHECK_IS_ON() |
| 163 mutable bool needs_adopt_ref_ = false; |
| 115 mutable bool in_dtor_ = false; | 164 mutable bool in_dtor_ = false; |
| 116 #endif | 165 #endif |
| 117 | 166 |
| 118 DISALLOW_COPY_AND_ASSIGN(RefCountedThreadSafeBase); | 167 DISALLOW_COPY_AND_ASSIGN(RefCountedThreadSafeBase); |
| 119 }; | 168 }; |
| 120 | 169 |
| 121 } // namespace subtle | 170 } // namespace subtle |
| 122 | 171 |
| 123 // ScopedAllowCrossThreadRefCountAccess disables the check documented on | 172 // ScopedAllowCrossThreadRefCountAccess disables the check documented on |
| 124 // RefCounted below for rare pre-existing use cases where thread-safety was | 173 // RefCounted below for rare pre-existing use cases where thread-safety was |
| (...skipping 24 matching lines...) Expand all Loading... |
| 149 // class MyFoo : public base::RefCounted<MyFoo> { | 198 // class MyFoo : public base::RefCounted<MyFoo> { |
| 150 // ... | 199 // ... |
| 151 // private: | 200 // private: |
| 152 // friend class base::RefCounted<MyFoo>; | 201 // friend class base::RefCounted<MyFoo>; |
| 153 // ~MyFoo(); | 202 // ~MyFoo(); |
| 154 // }; | 203 // }; |
| 155 // | 204 // |
| 156 // You should always make your destructor non-public, to avoid any code deleting | 205 // You should always make your destructor non-public, to avoid any code deleting |
| 157 // the object accidently while there are references to it. | 206 // the object accidently while there are references to it. |
| 158 // | 207 // |
| 208 // |
| 159 // The ref count manipulation to RefCounted is NOT thread safe and has DCHECKs | 209 // The ref count manipulation to RefCounted is NOT thread safe and has DCHECKs |
| 160 // to trap unsafe cross thread usage. A subclass instance of RefCounted can be | 210 // to trap unsafe cross thread usage. A subclass instance of RefCounted can be |
| 161 // passed to another execution sequence only when its ref count is 1. If the ref | 211 // passed to another execution sequence only when its ref count is 1. If the ref |
| 162 // count is more than 1, the RefCounted class verifies the ref updates are made | 212 // count is more than 1, the RefCounted class verifies the ref updates are made |
| 163 // on the same execution sequence as the previous ones. | 213 // on the same execution sequence as the previous ones. |
| 214 // |
| 215 // |
| 216 // The reference count starts from zero by default, and we intended to migrate |
| 217 // to start-from-one ref count. Put REQUIRE_ADOPTION_FOR_REFCOUNTED_TYPE() to |
| 218 // the ref counted class to opt-in. |
| 219 // |
| 220 // If an object has start-from-one ref count, the first scoped_refptr need to be |
| 221 // created by base::AdoptRef() or base::MakeShared(). We can use |
| 222 // base::MakeShared() to create create both type of ref counted object. |
| 223 // |
| 224 // The motivations to use start-from-one ref count are: |
| 225 // - Start-from-one ref count doesn't need the ref count increment for the |
| 226 // first reference. |
| 227 // - It can detect an invalid object acquisition for a being-deleted object |
| 228 // that has zero ref count. That tends to happen on custom deleter that |
| 229 // delays the deletion. |
| 230 // TODO(tzik): Implement invalid acquisition detection. |
| 231 // - Behavior parity to Blink's WTF::RefCounted, whose count starts from one. |
| 232 // And start-from-one ref count is a step to merge WTF::RefCounted into |
| 233 // base::RefCounted. |
| 234 // |
| 235 #define REQUIRE_ADOPTION_FOR_REFCOUNTED_TYPE() \ |
| 236 static constexpr ::base::subtle::StartRefCountFromOneTag \ |
| 237 kRefCountPreference = ::base::subtle::kStartRefCountFromOneTag |
| 238 |
| 164 template <class T> | 239 template <class T> |
| 165 class RefCounted : public subtle::RefCountedBase { | 240 class RefCounted : public subtle::RefCountedBase { |
| 166 public: | 241 public: |
| 167 RefCounted() = default; | 242 static constexpr subtle::StartRefCountFromZeroTag kRefCountPreference = |
| 243 subtle::kStartRefCountFromZeroTag; |
| 244 |
| 245 RefCounted() : subtle::RefCountedBase(T::kRefCountPreference) {} |
| 168 | 246 |
| 169 void AddRef() const { | 247 void AddRef() const { |
| 170 subtle::RefCountedBase::AddRef(); | 248 subtle::RefCountedBase::AddRef(); |
| 171 } | 249 } |
| 172 | 250 |
| 173 void Release() const { | 251 void Release() const { |
| 174 if (subtle::RefCountedBase::Release()) { | 252 if (subtle::RefCountedBase::Release()) { |
| 175 delete static_cast<const T*>(this); | 253 delete static_cast<const T*>(this); |
| 176 } | 254 } |
| 177 } | 255 } |
| 178 | 256 |
| 179 protected: | 257 protected: |
| 180 ~RefCounted() = default; | 258 ~RefCounted() = default; |
| 181 | 259 |
| 182 private: | 260 private: |
| 183 DISALLOW_COPY_AND_ASSIGN(RefCounted<T>); | 261 DISALLOW_COPY_AND_ASSIGN(RefCounted); |
| 184 }; | 262 }; |
| 185 | 263 |
| 186 // Forward declaration. | 264 // Forward declaration. |
| 187 template <class T, typename Traits> class RefCountedThreadSafe; | 265 template <class T, typename Traits> class RefCountedThreadSafe; |
| 188 | 266 |
| 189 // Default traits for RefCountedThreadSafe<T>. Deletes the object when its ref | 267 // Default traits for RefCountedThreadSafe<T>. Deletes the object when its ref |
| 190 // count reaches 0. Overload to delete it on a different thread etc. | 268 // count reaches 0. Overload to delete it on a different thread etc. |
| 191 template<typename T> | 269 template<typename T> |
| 192 struct DefaultRefCountedThreadSafeTraits { | 270 struct DefaultRefCountedThreadSafeTraits { |
| 193 static void Destruct(const T* x) { | 271 static void Destruct(const T* x) { |
| (...skipping 10 matching lines...) Expand all Loading... |
| 204 // | 282 // |
| 205 // class MyFoo : public base::RefCountedThreadSafe<MyFoo> { | 283 // class MyFoo : public base::RefCountedThreadSafe<MyFoo> { |
| 206 // ... | 284 // ... |
| 207 // }; | 285 // }; |
| 208 // | 286 // |
| 209 // If you're using the default trait, then you should add compile time | 287 // If you're using the default trait, then you should add compile time |
| 210 // asserts that no one else is deleting your object. i.e. | 288 // asserts that no one else is deleting your object. i.e. |
| 211 // private: | 289 // private: |
| 212 // friend class base::RefCountedThreadSafe<MyFoo>; | 290 // friend class base::RefCountedThreadSafe<MyFoo>; |
| 213 // ~MyFoo(); | 291 // ~MyFoo(); |
| 292 // |
| 293 // We can use REQUIRE_ADOPTION_FOR_REFCOUNTED_TYPE() with RefCountedThreadSafe |
| 294 // too. See the comment above the RefCounted definition for details. |
| 214 template <class T, typename Traits = DefaultRefCountedThreadSafeTraits<T> > | 295 template <class T, typename Traits = DefaultRefCountedThreadSafeTraits<T> > |
| 215 class RefCountedThreadSafe : public subtle::RefCountedThreadSafeBase { | 296 class RefCountedThreadSafe : public subtle::RefCountedThreadSafeBase { |
| 216 public: | 297 public: |
| 217 RefCountedThreadSafe() = default; | 298 static constexpr subtle::StartRefCountFromZeroTag kRefCountPreference = |
| 299 subtle::kStartRefCountFromZeroTag; |
| 300 |
| 301 explicit RefCountedThreadSafe() |
| 302 : subtle::RefCountedThreadSafeBase(T::kRefCountPreference) {} |
| 218 | 303 |
| 219 void AddRef() const { | 304 void AddRef() const { |
| 220 subtle::RefCountedThreadSafeBase::AddRef(); | 305 subtle::RefCountedThreadSafeBase::AddRef(); |
| 221 } | 306 } |
| 222 | 307 |
| 223 void Release() const { | 308 void Release() const { |
| 224 if (subtle::RefCountedThreadSafeBase::Release()) { | 309 if (subtle::RefCountedThreadSafeBase::Release()) { |
| 225 Traits::Destruct(static_cast<const T*>(this)); | 310 Traits::Destruct(static_cast<const T*>(this)); |
| 226 } | 311 } |
| 227 } | 312 } |
| (...skipping 19 matching lines...) Expand all Loading... |
| 247 RefCountedData() : data() {} | 332 RefCountedData() : data() {} |
| 248 RefCountedData(const T& in_value) : data(in_value) {} | 333 RefCountedData(const T& in_value) : data(in_value) {} |
| 249 | 334 |
| 250 T data; | 335 T data; |
| 251 | 336 |
| 252 private: | 337 private: |
| 253 friend class base::RefCountedThreadSafe<base::RefCountedData<T> >; | 338 friend class base::RefCountedThreadSafe<base::RefCountedData<T> >; |
| 254 ~RefCountedData() = default; | 339 ~RefCountedData() = default; |
| 255 }; | 340 }; |
| 256 | 341 |
| 342 // Creates a scoped_refptr from a raw pointer without incrementing the reference |
| 343 // count. Use this only for a newly created object whose reference count starts |
| 344 // from 1 instead of 0. |
| 345 template <typename T> |
| 346 scoped_refptr<T> AdoptRef(T* obj) { |
| 347 using Tag = typename std::decay<decltype(T::kRefCountPreference)>::type; |
| 348 static_assert(std::is_same<subtle::StartRefCountFromOneTag, Tag>::value, |
| 349 "Use AdoptRef only for the reference count starts from one."); |
| 350 |
| 351 DCHECK(obj); |
| 352 DCHECK(obj->HasOneRef()); |
| 353 obj->Adopted(); |
| 354 return scoped_refptr<T>(obj, subtle::kAdoptRefTag); |
| 355 } |
| 356 |
| 357 namespace subtle { |
| 358 |
| 359 template <typename T> |
| 360 scoped_refptr<T> AdoptRefIfNeeded(T* obj, StartRefCountFromZeroTag) { |
| 361 return scoped_refptr<T>(obj); |
| 362 } |
| 363 |
| 364 template <typename T> |
| 365 scoped_refptr<T> AdoptRefIfNeeded(T* obj, StartRefCountFromOneTag) { |
| 366 return AdoptRef(obj); |
| 367 } |
| 368 |
| 369 } // namespace subtle |
| 370 |
| 371 // Constructs an instance of T, which is a ref counted type, and wraps the |
| 372 // object into a scoped_refptr. |
| 373 template <typename T, typename... Args> |
| 374 scoped_refptr<T> MakeShared(Args&&... args) { |
| 375 T* obj = new T(std::forward<Args>(args)...); |
| 376 return subtle::AdoptRefIfNeeded(obj, T::kRefCountPreference); |
| 377 } |
| 378 |
| 257 } // namespace base | 379 } // namespace base |
| 258 | 380 |
| 259 // | 381 // |
| 260 // A smart pointer class for reference counted objects. Use this class instead | 382 // A smart pointer class for reference counted objects. Use this class instead |
| 261 // of calling AddRef and Release manually on a reference counted object to | 383 // of calling AddRef and Release manually on a reference counted object to |
| 262 // avoid common memory leaks caused by forgetting to Release an object | 384 // avoid common memory leaks caused by forgetting to Release an object |
| 263 // reference. Sample usage: | 385 // reference. Sample usage: |
| 264 // | 386 // |
| 265 // class MyFoo : public RefCounted<MyFoo> { | 387 // class MyFoo : public RefCounted<MyFoo> { |
| 266 // ... | 388 // ... |
| (...skipping 147 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 414 | 536 |
| 415 template <typename U> | 537 template <typename U> |
| 416 bool operator<(const scoped_refptr<U>& rhs) const { | 538 bool operator<(const scoped_refptr<U>& rhs) const { |
| 417 return ptr_ < rhs.get(); | 539 return ptr_ < rhs.get(); |
| 418 } | 540 } |
| 419 | 541 |
| 420 protected: | 542 protected: |
| 421 T* ptr_ = nullptr; | 543 T* ptr_ = nullptr; |
| 422 | 544 |
| 423 private: | 545 private: |
| 546 template <typename U> |
| 547 friend scoped_refptr<U> base::AdoptRef(U*); |
| 548 |
| 549 scoped_refptr(T* p, base::subtle::AdoptRefTag) : ptr_(p) {} |
| 550 |
| 424 // Friend required for move constructors that set r.ptr_ to null. | 551 // Friend required for move constructors that set r.ptr_ to null. |
| 425 template <typename U> | 552 template <typename U> |
| 426 friend class scoped_refptr; | 553 friend class scoped_refptr; |
| 427 | 554 |
| 428 // Non-inline helpers to allow: | 555 // Non-inline helpers to allow: |
| 429 // class Opaque; | 556 // class Opaque; |
| 430 // extern template class scoped_refptr<Opaque>; | 557 // extern template class scoped_refptr<Opaque>; |
| 431 // Otherwise the compiler will complain that Opaque is an incomplete type. | 558 // Otherwise the compiler will complain that Opaque is an incomplete type. |
| 432 static void AddRef(T* ptr); | 559 static void AddRef(T* ptr); |
| 433 static void Release(T* ptr); | 560 static void Release(T* ptr); |
| (...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 491 bool operator!=(std::nullptr_t null, const scoped_refptr<T>& rhs) { | 618 bool operator!=(std::nullptr_t null, const scoped_refptr<T>& rhs) { |
| 492 return !operator==(null, rhs); | 619 return !operator==(null, rhs); |
| 493 } | 620 } |
| 494 | 621 |
| 495 template <typename T> | 622 template <typename T> |
| 496 std::ostream& operator<<(std::ostream& out, const scoped_refptr<T>& p) { | 623 std::ostream& operator<<(std::ostream& out, const scoped_refptr<T>& p) { |
| 497 return out << p.get(); | 624 return out << p.get(); |
| 498 } | 625 } |
| 499 | 626 |
| 500 #endif // BASE_MEMORY_REF_COUNTED_H_ | 627 #endif // BASE_MEMORY_REF_COUNTED_H_ |
| OLD | NEW |