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 |