Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(27)

Side by Side Diff: base/memory/ref_counted.h

Issue 2723423002: Start BindStateBase ref count from 1 instead of 0 (Closed)
Patch Set: +MAKE_REF_COUNT_START_FROM_ONE. +document Created 3 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « base/callback_internal.cc ('k') | base/memory/ref_counted.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
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
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_
OLDNEW
« no previous file with comments | « base/callback_internal.cc ('k') | base/memory/ref_counted.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698