| 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" | |
| 20 #include "base/threading/thread_collision_warner.h" | 19 #include "base/threading/thread_collision_warner.h" |
| 21 #include "build/build_config.h" | 20 #include "build/build_config.h" |
| 22 | 21 |
| 23 namespace base { | 22 namespace base { |
| 24 | 23 |
| 25 namespace subtle { | 24 namespace subtle { |
| 26 | 25 |
| 27 class BASE_EXPORT RefCountedBase { | 26 class BASE_EXPORT RefCountedBase { |
| 28 public: | 27 public: |
| 29 bool HasOneRef() const { return ref_count_ == 1; } | 28 bool HasOneRef() const { return ref_count_ == 1; } |
| 30 | 29 |
| 31 protected: | 30 protected: |
| 32 RefCountedBase() { | 31 RefCountedBase() {} |
| 33 #if DCHECK_IS_ON() | |
| 34 sequence_checker_.DetachFromSequence(); | |
| 35 #endif | |
| 36 } | |
| 37 | 32 |
| 38 ~RefCountedBase() { | 33 ~RefCountedBase() { |
| 39 #if DCHECK_IS_ON() | 34 #if DCHECK_IS_ON() |
| 40 DCHECK(in_dtor_) << "RefCounted object deleted without calling Release()"; | 35 DCHECK(in_dtor_) << "RefCounted object deleted without calling Release()"; |
| 41 #endif | 36 #endif |
| 42 } | 37 } |
| 43 | 38 |
| 44 void AddRef() const { | 39 void AddRef() const { |
| 45 // TODO(maruel): Add back once it doesn't assert 500 times/sec. | 40 // TODO(maruel): Add back once it doesn't assert 500 times/sec. |
| 46 // Current thread books the critical section "AddRelease" | 41 // Current thread books the critical section "AddRelease" |
| 47 // without release it. | 42 // without release it. |
| 48 // DFAKE_SCOPED_LOCK_THREAD_LOCKED(add_release_); | 43 // DFAKE_SCOPED_LOCK_THREAD_LOCKED(add_release_); |
| 49 #if DCHECK_IS_ON() | 44 #if DCHECK_IS_ON() |
| 50 DCHECK(!in_dtor_); | 45 DCHECK(!in_dtor_); |
| 51 if (ref_count_ >= 1) { | |
| 52 DCHECK(CalledOnValidSequence()); | |
| 53 } | |
| 54 #endif | 46 #endif |
| 55 | 47 |
| 56 ++ref_count_; | 48 ++ref_count_; |
| 57 } | 49 } |
| 58 | 50 |
| 59 // Returns true if the object should self-delete. | 51 // Returns true if the object should self-delete. |
| 60 bool Release() const { | 52 bool Release() const { |
| 61 --ref_count_; | 53 --ref_count_; |
| 62 | 54 |
| 63 // TODO(maruel): Add back once it doesn't assert 500 times/sec. | 55 // TODO(maruel): Add back once it doesn't assert 500 times/sec. |
| 64 // Current thread books the critical section "AddRelease" | 56 // Current thread books the critical section "AddRelease" |
| 65 // without release it. | 57 // without release it. |
| 66 // DFAKE_SCOPED_LOCK_THREAD_LOCKED(add_release_); | 58 // DFAKE_SCOPED_LOCK_THREAD_LOCKED(add_release_); |
| 67 | 59 |
| 68 #if DCHECK_IS_ON() | 60 #if DCHECK_IS_ON() |
| 69 DCHECK(!in_dtor_); | 61 DCHECK(!in_dtor_); |
| 70 if (ref_count_ == 0) | 62 if (ref_count_ == 0) |
| 71 in_dtor_ = true; | 63 in_dtor_ = true; |
| 72 | |
| 73 if (ref_count_ >= 1) | |
| 74 DCHECK(CalledOnValidSequence()); | |
| 75 if (ref_count_ == 1) | |
| 76 sequence_checker_.DetachFromSequence(); | |
| 77 #endif | 64 #endif |
| 78 | 65 |
| 79 return ref_count_ == 0; | 66 return ref_count_ == 0; |
| 80 } | 67 } |
| 81 | 68 |
| 82 private: | 69 private: |
| 83 #if DCHECK_IS_ON() | |
| 84 bool CalledOnValidSequence() const; | |
| 85 #endif | |
| 86 | |
| 87 mutable size_t ref_count_ = 0; | 70 mutable size_t ref_count_ = 0; |
| 88 | |
| 89 #if DCHECK_IS_ON() | 71 #if DCHECK_IS_ON() |
| 90 mutable bool in_dtor_ = false; | 72 mutable bool in_dtor_ = false; |
| 91 mutable SequenceChecker sequence_checker_; | |
| 92 #endif | 73 #endif |
| 93 | 74 |
| 94 DFAKE_MUTEX(add_release_); | 75 DFAKE_MUTEX(add_release_); |
| 95 | 76 |
| 96 DISALLOW_COPY_AND_ASSIGN(RefCountedBase); | 77 DISALLOW_COPY_AND_ASSIGN(RefCountedBase); |
| 97 }; | 78 }; |
| 98 | 79 |
| 99 class BASE_EXPORT RefCountedThreadSafeBase { | 80 class BASE_EXPORT RefCountedThreadSafeBase { |
| 100 public: | 81 public: |
| 101 bool HasOneRef() const; | 82 bool HasOneRef() const; |
| (...skipping 11 matching lines...) Expand all Loading... |
| 113 mutable AtomicRefCount ref_count_ = 0; | 94 mutable AtomicRefCount ref_count_ = 0; |
| 114 #if DCHECK_IS_ON() | 95 #if DCHECK_IS_ON() |
| 115 mutable bool in_dtor_ = false; | 96 mutable bool in_dtor_ = false; |
| 116 #endif | 97 #endif |
| 117 | 98 |
| 118 DISALLOW_COPY_AND_ASSIGN(RefCountedThreadSafeBase); | 99 DISALLOW_COPY_AND_ASSIGN(RefCountedThreadSafeBase); |
| 119 }; | 100 }; |
| 120 | 101 |
| 121 } // namespace subtle | 102 } // namespace subtle |
| 122 | 103 |
| 123 // ScopedAllowCrossThreadRefCountAccess disables the check documented on | |
| 124 // RefCounted below for rare pre-existing use cases where thread-safety was | |
| 125 // guaranteed through other means (e.g. explicit sequencing of calls across | |
| 126 // execution sequences when bouncing between threads in order). New callers | |
| 127 // should refrain from using this (callsites handling thread-safety through | |
| 128 // locks should use RefCountedThreadSafe per the overhead of its atomics being | |
| 129 // negligible compared to locks anyways and callsites doing explicit sequencing | |
| 130 // should properly std::move() the ref to avoid hitting this check). | |
| 131 // TODO(tzik): Cleanup existing use cases and remove | |
| 132 // ScopedAllowCrossThreadRefCountAccess. | |
| 133 class BASE_EXPORT ScopedAllowCrossThreadRefCountAccess final { | |
| 134 public: | |
| 135 #if DCHECK_IS_ON() | |
| 136 ScopedAllowCrossThreadRefCountAccess(); | |
| 137 ~ScopedAllowCrossThreadRefCountAccess(); | |
| 138 #else | |
| 139 ScopedAllowCrossThreadRefCountAccess() {} | |
| 140 ~ScopedAllowCrossThreadRefCountAccess() {} | |
| 141 #endif | |
| 142 }; | |
| 143 | |
| 144 // | 104 // |
| 145 // A base class for reference counted classes. Otherwise, known as a cheap | 105 // A base class for reference counted classes. Otherwise, known as a cheap |
| 146 // knock-off of WebKit's RefCounted<T> class. To use this, just extend your | 106 // knock-off of WebKit's RefCounted<T> class. To use this, just extend your |
| 147 // class from it like so: | 107 // class from it like so: |
| 148 // | 108 // |
| 149 // class MyFoo : public base::RefCounted<MyFoo> { | 109 // class MyFoo : public base::RefCounted<MyFoo> { |
| 150 // ... | 110 // ... |
| 151 // private: | 111 // private: |
| 152 // friend class base::RefCounted<MyFoo>; | 112 // friend class base::RefCounted<MyFoo>; |
| 153 // ~MyFoo(); | 113 // ~MyFoo(); |
| 154 // }; | 114 // }; |
| 155 // | 115 // |
| 156 // You should always make your destructor non-public, to avoid any code deleting | 116 // You should always make your destructor non-public, to avoid any code deleting |
| 157 // the object accidently while there are references to it. | 117 // the object accidently while there are references to it. |
| 158 // | |
| 159 // 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 | |
| 161 // 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 | |
| 163 // on the same execution sequence as the previous ones. | |
| 164 template <class T> | 118 template <class T> |
| 165 class RefCounted : public subtle::RefCountedBase { | 119 class RefCounted : public subtle::RefCountedBase { |
| 166 public: | 120 public: |
| 167 RefCounted() = default; | 121 RefCounted() = default; |
| 168 | 122 |
| 169 void AddRef() const { | 123 void AddRef() const { |
| 170 subtle::RefCountedBase::AddRef(); | 124 subtle::RefCountedBase::AddRef(); |
| 171 } | 125 } |
| 172 | 126 |
| 173 void Release() const { | 127 void Release() const { |
| (...skipping 317 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 491 bool operator!=(std::nullptr_t null, const scoped_refptr<T>& rhs) { | 445 bool operator!=(std::nullptr_t null, const scoped_refptr<T>& rhs) { |
| 492 return !operator==(null, rhs); | 446 return !operator==(null, rhs); |
| 493 } | 447 } |
| 494 | 448 |
| 495 template <typename T> | 449 template <typename T> |
| 496 std::ostream& operator<<(std::ostream& out, const scoped_refptr<T>& p) { | 450 std::ostream& operator<<(std::ostream& out, const scoped_refptr<T>& p) { |
| 497 return out << p.get(); | 451 return out << p.get(); |
| 498 } | 452 } |
| 499 | 453 |
| 500 #endif // BASE_MEMORY_REF_COUNTED_H_ | 454 #endif // BASE_MEMORY_REF_COUNTED_H_ |
| OLD | NEW |