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 enum StartRefCountFromZeroTag { kStartRefCountFromZeroTag }; | |
34 enum StartRefCountFromOneTag { kStartRefCountFromOneTag }; | |
35 | |
26 class BASE_EXPORT RefCountedBase { | 36 class BASE_EXPORT RefCountedBase { |
27 public: | 37 public: |
28 bool HasOneRef() const { return ref_count_ == 1; } | 38 bool HasOneRef() const { return ref_count_ == 1; } |
29 | 39 |
30 protected: | 40 protected: |
31 RefCountedBase() {} | 41 explicit RefCountedBase(StartRefCountFromZeroTag) {} |
42 explicit RefCountedBase(StartRefCountFromOneTag) : ref_count_(1) { | |
43 #if DCHECK_IS_ON() | |
44 needs_adopt_ref_ = true; | |
45 #endif | |
46 } | |
32 | 47 |
33 ~RefCountedBase() { | 48 ~RefCountedBase() { |
34 #if DCHECK_IS_ON() | 49 #if DCHECK_IS_ON() |
35 DCHECK(in_dtor_) << "RefCounted object deleted without calling Release()"; | 50 DCHECK(in_dtor_) << "RefCounted object deleted without calling Release()"; |
36 #endif | 51 #endif |
37 } | 52 } |
38 | 53 |
39 void AddRef() const { | 54 void AddRef() const { |
40 // 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. |
41 // Current thread books the critical section "AddRelease" | 56 // Current thread books the critical section "AddRelease" |
42 // without release it. | 57 // without release it. |
43 // DFAKE_SCOPED_LOCK_THREAD_LOCKED(add_release_); | 58 // DFAKE_SCOPED_LOCK_THREAD_LOCKED(add_release_); |
44 #if DCHECK_IS_ON() | 59 #if DCHECK_IS_ON() |
45 DCHECK(!in_dtor_); | 60 DCHECK(!in_dtor_); |
61 DCHECK(!needs_adopt_ref_) | |
62 << "This RefCounted object is created with non-zero reference count." | |
63 << " The first reference to such a object has to be made by AdoptRef or" | |
64 << " MakeShared."; | |
46 #endif | 65 #endif |
47 | 66 |
48 ++ref_count_; | 67 ++ref_count_; |
49 } | 68 } |
50 | 69 |
51 // Returns true if the object should self-delete. | 70 // Returns true if the object should self-delete. |
52 bool Release() const { | 71 bool Release() const { |
53 --ref_count_; | 72 --ref_count_; |
54 | 73 |
55 // TODO(maruel): Add back once it doesn't assert 500 times/sec. | 74 // TODO(maruel): Add back once it doesn't assert 500 times/sec. |
56 // Current thread books the critical section "AddRelease" | 75 // Current thread books the critical section "AddRelease" |
57 // without release it. | 76 // without release it. |
58 // DFAKE_SCOPED_LOCK_THREAD_LOCKED(add_release_); | 77 // DFAKE_SCOPED_LOCK_THREAD_LOCKED(add_release_); |
59 | 78 |
60 #if DCHECK_IS_ON() | 79 #if DCHECK_IS_ON() |
61 DCHECK(!in_dtor_); | 80 DCHECK(!in_dtor_); |
62 if (ref_count_ == 0) | 81 if (ref_count_ == 0) |
63 in_dtor_ = true; | 82 in_dtor_ = true; |
64 #endif | 83 #endif |
65 | 84 |
66 return ref_count_ == 0; | 85 return ref_count_ == 0; |
67 } | 86 } |
68 | 87 |
69 private: | 88 private: |
89 template <typename U> | |
90 friend scoped_refptr<U> base::AdoptRef(U*); | |
91 | |
92 void Adopted() const { | |
93 #if DCHECK_IS_ON() | |
94 DCHECK(needs_adopt_ref_); | |
95 needs_adopt_ref_ = false; | |
96 #endif | |
97 } | |
98 | |
70 mutable size_t ref_count_ = 0; | 99 mutable size_t ref_count_ = 0; |
100 | |
71 #if DCHECK_IS_ON() | 101 #if DCHECK_IS_ON() |
102 mutable bool needs_adopt_ref_ = false; | |
72 mutable bool in_dtor_ = false; | 103 mutable bool in_dtor_ = false; |
73 #endif | 104 #endif |
74 | 105 |
75 DFAKE_MUTEX(add_release_); | 106 DFAKE_MUTEX(add_release_); |
76 | 107 |
77 DISALLOW_COPY_AND_ASSIGN(RefCountedBase); | 108 DISALLOW_COPY_AND_ASSIGN(RefCountedBase); |
78 }; | 109 }; |
79 | 110 |
80 class BASE_EXPORT RefCountedThreadSafeBase { | 111 class BASE_EXPORT RefCountedThreadSafeBase { |
81 public: | 112 public: |
82 bool HasOneRef() const; | 113 bool HasOneRef() const; |
83 | 114 |
84 protected: | 115 protected: |
85 RefCountedThreadSafeBase(); | 116 explicit RefCountedThreadSafeBase(StartRefCountFromZeroTag) {} |
117 explicit RefCountedThreadSafeBase(StartRefCountFromOneTag) : ref_count_(1) { | |
118 #if DCHECK_IS_ON() | |
119 needs_adopt_ref_ = true; | |
120 #endif | |
121 } | |
122 | |
86 ~RefCountedThreadSafeBase(); | 123 ~RefCountedThreadSafeBase(); |
87 | 124 |
88 void AddRef() const; | 125 void AddRef() const; |
89 | 126 |
90 // Returns true if the object should self-delete. | 127 // Returns true if the object should self-delete. |
91 bool Release() const; | 128 bool Release() const; |
92 | 129 |
93 private: | 130 private: |
131 template <typename U> | |
132 friend scoped_refptr<U> base::AdoptRef(U*); | |
133 | |
134 void Adopted() const { | |
135 #if DCHECK_IS_ON() | |
136 DCHECK(needs_adopt_ref_); | |
137 needs_adopt_ref_ = false; | |
138 #endif | |
139 } | |
140 | |
94 mutable AtomicRefCount ref_count_ = 0; | 141 mutable AtomicRefCount ref_count_ = 0; |
95 #if DCHECK_IS_ON() | 142 #if DCHECK_IS_ON() |
143 mutable bool needs_adopt_ref_ = false; | |
96 mutable bool in_dtor_ = false; | 144 mutable bool in_dtor_ = false; |
97 #endif | 145 #endif |
98 | 146 |
99 DISALLOW_COPY_AND_ASSIGN(RefCountedThreadSafeBase); | 147 DISALLOW_COPY_AND_ASSIGN(RefCountedThreadSafeBase); |
100 }; | 148 }; |
101 | 149 |
102 } // namespace subtle | 150 } // namespace subtle |
103 | 151 |
104 // | 152 // |
105 // A base class for reference counted classes. Otherwise, known as a cheap | 153 // A base class for reference counted classes. Otherwise, known as a cheap |
106 // knock-off of WebKit's RefCounted<T> class. To use this, just extend your | 154 // knock-off of WebKit's RefCounted<T> class. To use this, just extend your |
107 // class from it like so: | 155 // class from it like so: |
108 // | 156 // |
109 // class MyFoo : public base::RefCounted<MyFoo> { | 157 // class MyFoo : public base::RefCounted<MyFoo> { |
110 // ... | 158 // ... |
111 // private: | 159 // private: |
112 // friend class base::RefCounted<MyFoo>; | 160 // friend class base::RefCounted<MyFoo>; |
113 // ~MyFoo(); | 161 // ~MyFoo(); |
114 // }; | 162 // }; |
115 // | 163 // |
116 // You should always make your destructor non-public, to avoid any code deleting | 164 // You should always make your destructor non-public, to avoid any code deleting |
117 // the object accidently while there are references to it. | 165 // the object accidently while there are references to it. |
166 // | |
167 // The reference count starts from zero by default, and we intended to migrate | |
168 // to start-from-one ref count. Put MAKE_REF_COUNT_START_FROM_ONE to the | |
169 // ref counted class to opt-in. | |
170 // | |
171 // If an object has start-from-one ref count, the first scoped_refptr need to be | |
172 // created by base::AdoptRef() or base::MakeShared(). We can use | |
173 // base::MakeShared() to create create both type of ref counted object. | |
174 // | |
175 // The motivations to use start-from-one ref count are: | |
176 // - Start-from-one ref count doesn't need the ref count increment for the | |
177 // first reference. | |
178 // - It can detect an invalid object acquisition for a being-deleted object | |
179 // that has zero ref count. That tends to happen on custom deleter that | |
180 // delays the deletion. | |
181 // TODO(tzik): Implement invalid acquisition detection. | |
182 // - Behavior parity to Blink's WTF::RefCounted, whose count starts from one. | |
183 // And start-from-one ref count is a step to merge WTF::RefCounted into | |
184 // base::RefCounted. | |
185 // | |
186 #define MAKE_REF_COUNT_START_FROM_ONE \ | |
dcheng
2017/04/03 00:07:28
Two nits
1) Make this a function-style macro, so t
tzik
2017/04/03 03:48:23
Done. Updated its name to REQUIRE_ADOPTION_FOR_REF
| |
187 static constexpr ::base::subtle::StartRefCountFromOneTag \ | |
188 kRefCountPreference = ::base::subtle::kStartRefCountFromOneTag | |
189 | |
118 template <class T> | 190 template <class T> |
119 class RefCounted : public subtle::RefCountedBase { | 191 class RefCounted : public subtle::RefCountedBase { |
120 public: | 192 public: |
121 RefCounted() = default; | 193 static constexpr subtle::StartRefCountFromZeroTag kRefCountPreference = |
194 subtle::kStartRefCountFromZeroTag; | |
195 | |
196 RefCounted() : subtle::RefCountedBase(T::kRefCountPreference) {} | |
122 | 197 |
123 void AddRef() const { | 198 void AddRef() const { |
124 subtle::RefCountedBase::AddRef(); | 199 subtle::RefCountedBase::AddRef(); |
125 } | 200 } |
126 | 201 |
127 void Release() const { | 202 void Release() const { |
128 if (subtle::RefCountedBase::Release()) { | 203 if (subtle::RefCountedBase::Release()) { |
129 delete static_cast<const T*>(this); | 204 delete static_cast<const T*>(this); |
130 } | 205 } |
131 } | 206 } |
132 | 207 |
133 protected: | 208 protected: |
134 ~RefCounted() = default; | 209 ~RefCounted() = default; |
135 | 210 |
136 private: | 211 private: |
137 DISALLOW_COPY_AND_ASSIGN(RefCounted<T>); | 212 DISALLOW_COPY_AND_ASSIGN(RefCounted); |
138 }; | 213 }; |
139 | 214 |
140 // Forward declaration. | 215 // Forward declaration. |
141 template <class T, typename Traits> class RefCountedThreadSafe; | 216 template <class T, typename Traits> class RefCountedThreadSafe; |
142 | 217 |
143 // Default traits for RefCountedThreadSafe<T>. Deletes the object when its ref | 218 // Default traits for RefCountedThreadSafe<T>. Deletes the object when its ref |
144 // count reaches 0. Overload to delete it on a different thread etc. | 219 // count reaches 0. Overload to delete it on a different thread etc. |
145 template<typename T> | 220 template<typename T> |
146 struct DefaultRefCountedThreadSafeTraits { | 221 struct DefaultRefCountedThreadSafeTraits { |
147 static void Destruct(const T* x) { | 222 static void Destruct(const T* x) { |
(...skipping 10 matching lines...) Expand all Loading... | |
158 // | 233 // |
159 // class MyFoo : public base::RefCountedThreadSafe<MyFoo> { | 234 // class MyFoo : public base::RefCountedThreadSafe<MyFoo> { |
160 // ... | 235 // ... |
161 // }; | 236 // }; |
162 // | 237 // |
163 // If you're using the default trait, then you should add compile time | 238 // If you're using the default trait, then you should add compile time |
164 // asserts that no one else is deleting your object. i.e. | 239 // asserts that no one else is deleting your object. i.e. |
165 // private: | 240 // private: |
166 // friend class base::RefCountedThreadSafe<MyFoo>; | 241 // friend class base::RefCountedThreadSafe<MyFoo>; |
167 // ~MyFoo(); | 242 // ~MyFoo(); |
243 // | |
244 // We can use MAKE_REF_COUNT_START_FROM_ONE with RefCountedThreadSafe too. | |
245 // See the comment above the RefCounted definition for details. | |
168 template <class T, typename Traits = DefaultRefCountedThreadSafeTraits<T> > | 246 template <class T, typename Traits = DefaultRefCountedThreadSafeTraits<T> > |
169 class RefCountedThreadSafe : public subtle::RefCountedThreadSafeBase { | 247 class RefCountedThreadSafe : public subtle::RefCountedThreadSafeBase { |
170 public: | 248 public: |
171 RefCountedThreadSafe() = default; | 249 static constexpr subtle::StartRefCountFromZeroTag kRefCountPreference = |
250 subtle::kStartRefCountFromZeroTag; | |
251 | |
252 explicit RefCountedThreadSafe() | |
253 : subtle::RefCountedThreadSafeBase(T::kRefCountPreference) {} | |
172 | 254 |
173 void AddRef() const { | 255 void AddRef() const { |
174 subtle::RefCountedThreadSafeBase::AddRef(); | 256 subtle::RefCountedThreadSafeBase::AddRef(); |
175 } | 257 } |
176 | 258 |
177 void Release() const { | 259 void Release() const { |
178 if (subtle::RefCountedThreadSafeBase::Release()) { | 260 if (subtle::RefCountedThreadSafeBase::Release()) { |
179 Traits::Destruct(static_cast<const T*>(this)); | 261 Traits::Destruct(static_cast<const T*>(this)); |
180 } | 262 } |
181 } | 263 } |
(...skipping 19 matching lines...) Expand all Loading... | |
201 RefCountedData() : data() {} | 283 RefCountedData() : data() {} |
202 RefCountedData(const T& in_value) : data(in_value) {} | 284 RefCountedData(const T& in_value) : data(in_value) {} |
203 | 285 |
204 T data; | 286 T data; |
205 | 287 |
206 private: | 288 private: |
207 friend class base::RefCountedThreadSafe<base::RefCountedData<T> >; | 289 friend class base::RefCountedThreadSafe<base::RefCountedData<T> >; |
208 ~RefCountedData() = default; | 290 ~RefCountedData() = default; |
209 }; | 291 }; |
210 | 292 |
293 // Creates a scoped_refptr from a raw pointer without incrementing the reference | |
294 // count. Use this only for a newly created object whose reference count starts | |
295 // from 1 instead of 0. | |
296 template <typename T> | |
297 scoped_refptr<T> AdoptRef(T* obj) { | |
298 using Tag = typename std::decay<decltype(T::kRefCountPreference)>::type; | |
299 static_assert(std::is_same<subtle::StartRefCountFromOneTag, Tag>::value, | |
300 "Use AdoptRef only for the reference count starts from one."); | |
301 | |
302 DCHECK(obj); | |
303 DCHECK(obj->HasOneRef()); | |
304 obj->Adopted(); | |
305 return scoped_refptr<T>(obj, subtle::kAdoptRefTag); | |
306 } | |
307 | |
308 namespace subtle { | |
309 | |
310 template <typename T> | |
311 scoped_refptr<T> AdoptRefIfNeeded(T* obj, StartRefCountFromZeroTag) { | |
312 return scoped_refptr<T>(obj); | |
313 } | |
314 | |
315 template <typename T> | |
316 scoped_refptr<T> AdoptRefIfNeeded(T* obj, StartRefCountFromOneTag) { | |
317 return AdoptRef(obj); | |
318 } | |
319 | |
320 } // namespace subtle | |
321 | |
322 // Constructs an instance of T, which is a ref counted type, and wraps the | |
323 // object into a scoped_refptr. | |
324 template <typename T, typename... Args> | |
325 scoped_refptr<T> MakeShared(Args&&... args) { | |
326 T* obj = new T(std::forward<Args>(args)...); | |
327 return subtle::AdoptRefIfNeeded(obj, T::kRefCountPreference); | |
328 } | |
329 | |
211 } // namespace base | 330 } // namespace base |
212 | 331 |
213 // | 332 // |
214 // A smart pointer class for reference counted objects. Use this class instead | 333 // A smart pointer class for reference counted objects. Use this class instead |
215 // of calling AddRef and Release manually on a reference counted object to | 334 // of calling AddRef and Release manually on a reference counted object to |
216 // avoid common memory leaks caused by forgetting to Release an object | 335 // avoid common memory leaks caused by forgetting to Release an object |
217 // reference. Sample usage: | 336 // reference. Sample usage: |
218 // | 337 // |
219 // class MyFoo : public RefCounted<MyFoo> { | 338 // class MyFoo : public RefCounted<MyFoo> { |
220 // ... | 339 // ... |
(...skipping 147 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
368 | 487 |
369 template <typename U> | 488 template <typename U> |
370 bool operator<(const scoped_refptr<U>& rhs) const { | 489 bool operator<(const scoped_refptr<U>& rhs) const { |
371 return ptr_ < rhs.get(); | 490 return ptr_ < rhs.get(); |
372 } | 491 } |
373 | 492 |
374 protected: | 493 protected: |
375 T* ptr_ = nullptr; | 494 T* ptr_ = nullptr; |
376 | 495 |
377 private: | 496 private: |
497 template <typename U> | |
498 friend scoped_refptr<U> base::AdoptRef(U*); | |
499 | |
500 scoped_refptr(T* p, base::subtle::AdoptRefTag) : ptr_(p) {} | |
501 | |
378 // Friend required for move constructors that set r.ptr_ to null. | 502 // Friend required for move constructors that set r.ptr_ to null. |
379 template <typename U> | 503 template <typename U> |
380 friend class scoped_refptr; | 504 friend class scoped_refptr; |
381 | 505 |
382 // Non-inline helpers to allow: | 506 // Non-inline helpers to allow: |
383 // class Opaque; | 507 // class Opaque; |
384 // extern template class scoped_refptr<Opaque>; | 508 // extern template class scoped_refptr<Opaque>; |
385 // Otherwise the compiler will complain that Opaque is an incomplete type. | 509 // Otherwise the compiler will complain that Opaque is an incomplete type. |
386 static void AddRef(T* ptr); | 510 static void AddRef(T* ptr); |
387 static void Release(T* ptr); | 511 static void Release(T* ptr); |
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
445 bool operator!=(std::nullptr_t null, const scoped_refptr<T>& rhs) { | 569 bool operator!=(std::nullptr_t null, const scoped_refptr<T>& rhs) { |
446 return !operator==(null, rhs); | 570 return !operator==(null, rhs); |
447 } | 571 } |
448 | 572 |
449 template <typename T> | 573 template <typename T> |
450 std::ostream& operator<<(std::ostream& out, const scoped_refptr<T>& p) { | 574 std::ostream& operator<<(std::ostream& out, const scoped_refptr<T>& p) { |
451 return out << p.get(); | 575 return out << p.get(); |
452 } | 576 } |
453 | 577 |
454 #endif // BASE_MEMORY_REF_COUNTED_H_ | 578 #endif // BASE_MEMORY_REF_COUNTED_H_ |
OLD | NEW |