Chromium Code Reviews| 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/threading/thread_collision_warner.h" | 19 #include "base/threading/thread_collision_warner.h" |
| 20 #include "build/build_config.h" | 20 #include "build/build_config.h" |
| 21 | 21 |
| 22 template <class T> | |
| 23 class scoped_refptr; | |
| 24 | |
| 22 namespace base { | 25 namespace base { |
| 23 | 26 |
| 27 template <typename T> | |
| 28 scoped_refptr<T> AdoptRef(T* t); | |
| 29 | |
| 24 namespace subtle { | 30 namespace subtle { |
| 25 | 31 |
| 32 enum AdoptRefTag { kAdoptRefTag }; | |
| 33 | |
| 26 class BASE_EXPORT RefCountedBase { | 34 class BASE_EXPORT RefCountedBase { |
| 27 public: | 35 public: |
| 28 bool HasOneRef() const { return ref_count_ == 1; } | 36 bool HasOneRef() const { return ref_count_ == 1; } |
| 29 | 37 |
| 30 protected: | 38 protected: |
| 31 RefCountedBase() | 39 explicit RefCountedBase(size_t initial_ref_count = 0) |
|
dcheng
2017/03/30 04:26:15
I think I would prefer that we have a default ctor
| |
| 32 : ref_count_(0) | 40 : ref_count_(initial_ref_count) { |
| 33 #if DCHECK_IS_ON() | 41 #if DCHECK_IS_ON() |
| 34 , in_dtor_(false) | 42 DCHECK(initial_ref_count == 0 || initial_ref_count == 1); |
| 43 needs_adopt_ref_ = ref_count_ == 1; | |
| 35 #endif | 44 #endif |
| 36 { | |
| 37 } | 45 } |
| 38 | 46 |
| 39 ~RefCountedBase() { | 47 ~RefCountedBase() { |
| 40 #if DCHECK_IS_ON() | 48 #if DCHECK_IS_ON() |
| 41 DCHECK(in_dtor_) << "RefCounted object deleted without calling Release()"; | 49 DCHECK(in_dtor_) << "RefCounted object deleted without calling Release()"; |
| 42 #endif | 50 #endif |
| 43 } | 51 } |
| 44 | 52 |
| 45 | |
| 46 void AddRef() const { | 53 void AddRef() const { |
| 47 // TODO(maruel): Add back once it doesn't assert 500 times/sec. | 54 // TODO(maruel): Add back once it doesn't assert 500 times/sec. |
| 48 // Current thread books the critical section "AddRelease" | 55 // Current thread books the critical section "AddRelease" |
| 49 // without release it. | 56 // without release it. |
| 50 // DFAKE_SCOPED_LOCK_THREAD_LOCKED(add_release_); | 57 // DFAKE_SCOPED_LOCK_THREAD_LOCKED(add_release_); |
| 51 #if DCHECK_IS_ON() | 58 #if DCHECK_IS_ON() |
| 52 DCHECK(!in_dtor_); | 59 DCHECK(!in_dtor_); |
| 60 DCHECK(!needs_adopt_ref_) | |
| 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 << " MakeShared."; | |
| 53 #endif | 64 #endif |
| 65 | |
| 54 ++ref_count_; | 66 ++ref_count_; |
| 55 } | 67 } |
| 56 | 68 |
| 57 // Returns true if the object should self-delete. | 69 // Returns true if the object should self-delete. |
| 58 bool Release() const { | 70 bool Release() const { |
| 71 --ref_count_; | |
| 72 | |
| 59 // TODO(maruel): Add back once it doesn't assert 500 times/sec. | 73 // TODO(maruel): Add back once it doesn't assert 500 times/sec. |
| 60 // Current thread books the critical section "AddRelease" | 74 // Current thread books the critical section "AddRelease" |
| 61 // without release it. | 75 // without release it. |
| 62 // DFAKE_SCOPED_LOCK_THREAD_LOCKED(add_release_); | 76 // DFAKE_SCOPED_LOCK_THREAD_LOCKED(add_release_); |
| 77 | |
| 63 #if DCHECK_IS_ON() | 78 #if DCHECK_IS_ON() |
| 64 DCHECK(!in_dtor_); | 79 DCHECK(!in_dtor_); |
| 65 #endif | 80 if (ref_count_ == 0) |
| 66 if (--ref_count_ == 0) { | |
| 67 #if DCHECK_IS_ON() | |
| 68 in_dtor_ = true; | 81 in_dtor_ = true; |
| 69 #endif | 82 #endif |
| 70 return true; | 83 |
| 71 } | 84 return ref_count_ == 0; |
|
dcheng
2017/03/30 04:26:15
What is the purpose / necessity for these changes?
tzik
2017/03/30 13:16:27
Oops, this is a contamination from another CL: htt
| |
| 72 return false; | |
| 73 } | 85 } |
| 74 | 86 |
| 75 private: | 87 private: |
| 88 template <typename U> | |
| 89 friend scoped_refptr<U> base::AdoptRef(U*); | |
| 90 | |
| 91 void Adopted() const { | |
| 92 #if DCHECK_IS_ON() | |
| 93 DCHECK(needs_adopt_ref_); | |
| 94 needs_adopt_ref_ = false; | |
| 95 #endif | |
| 96 } | |
| 97 | |
| 76 mutable size_t ref_count_; | 98 mutable size_t ref_count_; |
| 99 | |
| 77 #if DCHECK_IS_ON() | 100 #if DCHECK_IS_ON() |
| 78 mutable bool in_dtor_; | 101 mutable bool needs_adopt_ref_; |
| 102 mutable bool in_dtor_ = false; | |
| 79 #endif | 103 #endif |
| 80 | 104 |
| 81 DFAKE_MUTEX(add_release_); | 105 DFAKE_MUTEX(add_release_); |
| 82 | 106 |
| 83 DISALLOW_COPY_AND_ASSIGN(RefCountedBase); | 107 DISALLOW_COPY_AND_ASSIGN(RefCountedBase); |
| 84 }; | 108 }; |
| 85 | 109 |
| 86 class BASE_EXPORT RefCountedThreadSafeBase { | 110 class BASE_EXPORT RefCountedThreadSafeBase { |
| 87 public: | 111 public: |
| 88 bool HasOneRef() const; | 112 bool HasOneRef() const; |
| 89 | 113 |
| 90 protected: | 114 protected: |
| 91 RefCountedThreadSafeBase(); | 115 explicit RefCountedThreadSafeBase(AtomicRefCount initial_ref_count = 0) |
| 116 : ref_count_(initial_ref_count) { | |
| 117 #if DCHECK_IS_ON() | |
| 118 needs_adopt_ref_ = initial_ref_count == 1; | |
| 119 #endif | |
| 120 } | |
| 121 | |
| 92 ~RefCountedThreadSafeBase(); | 122 ~RefCountedThreadSafeBase(); |
| 93 | 123 |
| 94 void AddRef() const; | 124 void AddRef() const; |
| 95 | 125 |
| 96 // Returns true if the object should self-delete. | 126 // Returns true if the object should self-delete. |
| 97 bool Release() const; | 127 bool Release() const; |
| 98 | 128 |
| 99 private: | 129 private: |
| 100 mutable AtomicRefCount ref_count_ = 0; | 130 template <typename U> |
| 131 friend scoped_refptr<U> base::AdoptRef(U*); | |
| 132 | |
| 133 void Adopted() const { | |
| 101 #if DCHECK_IS_ON() | 134 #if DCHECK_IS_ON() |
| 135 DCHECK(needs_adopt_ref_); | |
| 136 needs_adopt_ref_ = false; | |
| 137 #endif | |
| 138 } | |
| 139 | |
| 140 mutable AtomicRefCount ref_count_; | |
| 141 #if DCHECK_IS_ON() | |
| 142 mutable bool needs_adopt_ref_; | |
| 102 mutable bool in_dtor_ = false; | 143 mutable bool in_dtor_ = false; |
| 103 #endif | 144 #endif |
| 104 | 145 |
| 105 DISALLOW_COPY_AND_ASSIGN(RefCountedThreadSafeBase); | 146 DISALLOW_COPY_AND_ASSIGN(RefCountedThreadSafeBase); |
| 106 }; | 147 }; |
| 107 | 148 |
| 108 } // namespace subtle | 149 } // namespace subtle |
| 109 | 150 |
| 110 // | 151 // |
| 111 // A base class for reference counted classes. Otherwise, known as a cheap | 152 // A base class for reference counted classes. Otherwise, known as a cheap |
| 112 // knock-off of WebKit's RefCounted<T> class. To use this, just extend your | 153 // knock-off of WebKit's RefCounted<T> class. To use this, just extend your |
| 113 // class from it like so: | 154 // class from it like so: |
| 114 // | 155 // |
| 115 // class MyFoo : public base::RefCounted<MyFoo> { | 156 // class MyFoo : public base::RefCounted<MyFoo> { |
| 116 // ... | 157 // ... |
| 117 // private: | 158 // private: |
| 118 // friend class base::RefCounted<MyFoo>; | 159 // friend class base::RefCounted<MyFoo>; |
| 119 // ~MyFoo(); | 160 // ~MyFoo(); |
| 120 // }; | 161 // }; |
| 121 // | 162 // |
| 122 // You should always make your destructor non-public, to avoid any code deleting | 163 // You should always make your destructor non-public, to avoid any code deleting |
| 123 // the object accidently while there are references to it. | 164 // the object accidently while there are references to it. |
| 124 template <class T> | 165 template <class T> |
| 125 class RefCounted : public subtle::RefCountedBase { | 166 class RefCounted : public subtle::RefCountedBase { |
| 126 public: | 167 public: |
| 127 RefCounted() = default; | 168 explicit RefCounted(size_t initial_ref_count = 0) |
| 169 : subtle::RefCountedBase(initial_ref_count) {} | |
| 128 | 170 |
| 129 void AddRef() const { | 171 void AddRef() const { |
| 130 subtle::RefCountedBase::AddRef(); | 172 subtle::RefCountedBase::AddRef(); |
| 131 } | 173 } |
| 132 | 174 |
| 133 void Release() const { | 175 void Release() const { |
| 134 if (subtle::RefCountedBase::Release()) { | 176 if (subtle::RefCountedBase::Release()) { |
| 135 delete static_cast<const T*>(this); | 177 delete static_cast<const T*>(this); |
| 136 } | 178 } |
| 137 } | 179 } |
| (...skipping 29 matching lines...) Expand all Loading... | |
| 167 // }; | 209 // }; |
| 168 // | 210 // |
| 169 // If you're using the default trait, then you should add compile time | 211 // If you're using the default trait, then you should add compile time |
| 170 // asserts that no one else is deleting your object. i.e. | 212 // asserts that no one else is deleting your object. i.e. |
| 171 // private: | 213 // private: |
| 172 // friend class base::RefCountedThreadSafe<MyFoo>; | 214 // friend class base::RefCountedThreadSafe<MyFoo>; |
| 173 // ~MyFoo(); | 215 // ~MyFoo(); |
| 174 template <class T, typename Traits = DefaultRefCountedThreadSafeTraits<T> > | 216 template <class T, typename Traits = DefaultRefCountedThreadSafeTraits<T> > |
| 175 class RefCountedThreadSafe : public subtle::RefCountedThreadSafeBase { | 217 class RefCountedThreadSafe : public subtle::RefCountedThreadSafeBase { |
| 176 public: | 218 public: |
| 177 RefCountedThreadSafe() = default; | 219 explicit RefCountedThreadSafe(AtomicRefCount initial_ref_count = 0) |
| 220 : subtle::RefCountedThreadSafeBase(initial_ref_count) {} | |
| 178 | 221 |
| 179 void AddRef() const { | 222 void AddRef() const { |
| 180 subtle::RefCountedThreadSafeBase::AddRef(); | 223 subtle::RefCountedThreadSafeBase::AddRef(); |
| 181 } | 224 } |
| 182 | 225 |
| 183 void Release() const { | 226 void Release() const { |
| 184 if (subtle::RefCountedThreadSafeBase::Release()) { | 227 if (subtle::RefCountedThreadSafeBase::Release()) { |
| 185 Traits::Destruct(static_cast<const T*>(this)); | 228 Traits::Destruct(static_cast<const T*>(this)); |
| 186 } | 229 } |
| 187 } | 230 } |
| (...skipping 19 matching lines...) Expand all Loading... | |
| 207 RefCountedData() : data() {} | 250 RefCountedData() : data() {} |
| 208 RefCountedData(const T& in_value) : data(in_value) {} | 251 RefCountedData(const T& in_value) : data(in_value) {} |
| 209 | 252 |
| 210 T data; | 253 T data; |
| 211 | 254 |
| 212 private: | 255 private: |
| 213 friend class base::RefCountedThreadSafe<base::RefCountedData<T> >; | 256 friend class base::RefCountedThreadSafe<base::RefCountedData<T> >; |
| 214 ~RefCountedData() = default; | 257 ~RefCountedData() = default; |
| 215 }; | 258 }; |
| 216 | 259 |
| 260 // Creates a scoped_refptr from a raw pointer without incrementing the reference | |
| 261 // count. Use this only for a newly created object whose reference count starts | |
| 262 // from 1 instead of 0. | |
| 263 template <typename T> | |
| 264 scoped_refptr<T> AdoptRef(T* t) { | |
| 265 DCHECK(!t || t->HasOneRef()); | |
|
dcheng
2017/03/30 04:26:16
Hmm... why would we want to handle a null |t| here
tzik
2017/03/30 13:16:27
OK, updated to force nun-null.
| |
| 266 if (t) | |
| 267 t->Adopted(); | |
| 268 return scoped_refptr<T>(t, subtle::kAdoptRefTag); | |
| 269 } | |
| 270 | |
| 271 // Constructs an instance of T, which is a ref counted type, and wraps the | |
| 272 // object into a scoped_refptr. | |
| 273 template <typename T, typename... Args> | |
| 274 scoped_refptr<T> MakeShared(Args&&... args) { | |
| 275 T* obj = new T(std::forward<Args>(args)...); | |
| 276 if (obj->HasOneRef()) | |
| 277 return AdoptRef(obj); | |
| 278 return scoped_refptr<T>(obj); | |
|
dcheng
2017/03/30 04:26:16
Not sure if it's possible, but it would be nice if
tzik
2017/03/30 13:16:27
Trying that.
| |
| 279 } | |
| 280 | |
| 217 } // namespace base | 281 } // namespace base |
| 218 | 282 |
| 219 // | 283 // |
| 220 // A smart pointer class for reference counted objects. Use this class instead | 284 // A smart pointer class for reference counted objects. Use this class instead |
| 221 // of calling AddRef and Release manually on a reference counted object to | 285 // of calling AddRef and Release manually on a reference counted object to |
| 222 // avoid common memory leaks caused by forgetting to Release an object | 286 // avoid common memory leaks caused by forgetting to Release an object |
| 223 // reference. Sample usage: | 287 // reference. Sample usage: |
| 224 // | 288 // |
| 225 // class MyFoo : public RefCounted<MyFoo> { | 289 // class MyFoo : public RefCounted<MyFoo> { |
| 226 // ... | 290 // ... |
| (...skipping 147 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 374 | 438 |
| 375 template <typename U> | 439 template <typename U> |
| 376 bool operator<(const scoped_refptr<U>& rhs) const { | 440 bool operator<(const scoped_refptr<U>& rhs) const { |
| 377 return ptr_ < rhs.get(); | 441 return ptr_ < rhs.get(); |
| 378 } | 442 } |
| 379 | 443 |
| 380 protected: | 444 protected: |
| 381 T* ptr_ = nullptr; | 445 T* ptr_ = nullptr; |
| 382 | 446 |
| 383 private: | 447 private: |
| 448 template <typename U> | |
| 449 friend scoped_refptr<U> base::AdoptRef(U*); | |
| 450 | |
| 451 scoped_refptr(T* p, base::subtle::AdoptRefTag) : ptr_(p) {} | |
| 452 | |
| 384 // Friend required for move constructors that set r.ptr_ to null. | 453 // Friend required for move constructors that set r.ptr_ to null. |
| 385 template <typename U> | 454 template <typename U> |
| 386 friend class scoped_refptr; | 455 friend class scoped_refptr; |
| 387 | 456 |
| 388 // Non-inline helpers to allow: | 457 // Non-inline helpers to allow: |
| 389 // class Opaque; | 458 // class Opaque; |
| 390 // extern template class scoped_refptr<Opaque>; | 459 // extern template class scoped_refptr<Opaque>; |
| 391 // Otherwise the compiler will complain that Opaque is an incomplete type. | 460 // Otherwise the compiler will complain that Opaque is an incomplete type. |
| 392 static void AddRef(T* ptr); | 461 static void AddRef(T* ptr); |
| 393 static void Release(T* ptr); | 462 static void Release(T* ptr); |
| (...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 451 bool operator!=(std::nullptr_t null, const scoped_refptr<T>& rhs) { | 520 bool operator!=(std::nullptr_t null, const scoped_refptr<T>& rhs) { |
| 452 return !operator==(null, rhs); | 521 return !operator==(null, rhs); |
| 453 } | 522 } |
| 454 | 523 |
| 455 template <typename T> | 524 template <typename T> |
| 456 std::ostream& operator<<(std::ostream& out, const scoped_refptr<T>& p) { | 525 std::ostream& operator<<(std::ostream& out, const scoped_refptr<T>& p) { |
| 457 return out << p.get(); | 526 return out << p.get(); |
| 458 } | 527 } |
| 459 | 528 |
| 460 #endif // BASE_MEMORY_REF_COUNTED_H_ | 529 #endif // BASE_MEMORY_REF_COUNTED_H_ |
| OLD | NEW |