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

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

Issue 2723423002: Start BindStateBase ref count from 1 instead of 0 (Closed)
Patch Set: s/MAKE_REF_COUNT_START_FROM_ONE/REQUIRE_ADOPTION_FOR_REFCOUNTED_TYPE()/ 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/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
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
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
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
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
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
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_
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