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

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

Issue 2666423002: Assert sequence validity on non-thread-safe RefCount manipulations (2) (Closed)
Patch Set: per-instance opt-out Created 3 years, 9 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/at_exit.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/threading/thread_collision_warner.h" 20 #include "base/threading/thread_collision_warner.h"
20 #include "build/build_config.h" 21 #include "build/build_config.h"
21 22
22 namespace base { 23 namespace base {
23
24 namespace subtle { 24 namespace subtle {
25 25
26 class BASE_EXPORT RefCountedBase { 26 class BASE_EXPORT RefCountedBase {
27 public: 27 public:
28 bool HasOneRef() const { return ref_count_ == 1; } 28 bool HasOneRef() const { return ref_count_ == 1; }
29 29
30 protected: 30 void DisableSequenceConsistencyAssertions() {
31 RefCountedBase()
32 : ref_count_(0)
33 #if DCHECK_IS_ON() 31 #if DCHECK_IS_ON()
34 , in_dtor_(false) 32 sequence_consistency_assertion_enabled_ = false;
35 #endif 33 #endif
36 {
37 } 34 }
38 35
36 protected:
37 RefCountedBase() {
38 #if DCHECK_IS_ON()
39 sequence_checker_.DetachFromSequence();
40 #endif
41 }
39 ~RefCountedBase() { 42 ~RefCountedBase() {
40 #if DCHECK_IS_ON() 43 #if DCHECK_IS_ON()
41 DCHECK(in_dtor_) << "RefCounted object deleted without calling Release()"; 44 DCHECK(in_dtor_) << "RefCounted object deleted without calling Release()";
42 #endif 45 #endif
43 } 46 }
44 47
45
46 void AddRef() const { 48 void AddRef() const {
47 // TODO(maruel): Add back once it doesn't assert 500 times/sec. 49 // TODO(maruel): Add back once it doesn't assert 500 times/sec.
48 // Current thread books the critical section "AddRelease" 50 // Current thread books the critical section "AddRelease"
49 // without release it. 51 // without release it.
50 // DFAKE_SCOPED_LOCK_THREAD_LOCKED(add_release_); 52 // DFAKE_SCOPED_LOCK_THREAD_LOCKED(add_release_);
51 #if DCHECK_IS_ON() 53 #if DCHECK_IS_ON()
52 DCHECK(!in_dtor_); 54 DCHECK(!in_dtor_);
55 if (ref_count_ >= 1) {
56 DCHECK(!sequence_consistency_assertion_enabled_ ||
57 CalledOnValidSequence());
58 }
53 #endif 59 #endif
60
54 ++ref_count_; 61 ++ref_count_;
55 } 62 }
56 63
57 // Returns true if the object should self-delete. 64 // Returns true if the object should self-delete.
58 bool Release() const { 65 bool Release() const {
66 --ref_count_;
67
59 // TODO(maruel): Add back once it doesn't assert 500 times/sec. 68 // TODO(maruel): Add back once it doesn't assert 500 times/sec.
60 // Current thread books the critical section "AddRelease" 69 // Current thread books the critical section "AddRelease"
61 // without release it. 70 // without release it.
62 // DFAKE_SCOPED_LOCK_THREAD_LOCKED(add_release_); 71 // DFAKE_SCOPED_LOCK_THREAD_LOCKED(add_release_);
72
63 #if DCHECK_IS_ON() 73 #if DCHECK_IS_ON()
64 DCHECK(!in_dtor_); 74 DCHECK(!in_dtor_);
75 if (ref_count_ == 0)
76 in_dtor_ = true;
77
78 if (ref_count_ >= 1)
79 DCHECK(!sequence_consistency_assertion_enabled_ ||
80 CalledOnValidSequence());
81 if (ref_count_ == 1)
82 sequence_checker_.DetachFromSequence();
65 #endif 83 #endif
66 if (--ref_count_ == 0) { 84
67 #if DCHECK_IS_ON() 85 return ref_count_ == 0;
68 in_dtor_ = true;
69 #endif
70 return true;
71 }
72 return false;
73 } 86 }
74 87
75 private: 88 private:
76 mutable size_t ref_count_;
77 #if DCHECK_IS_ON() 89 #if DCHECK_IS_ON()
78 mutable bool in_dtor_; 90 bool CalledOnValidSequence() const;
91 #endif
92
93 mutable size_t ref_count_ = 0;
94
95 #if DCHECK_IS_ON()
96 mutable bool in_dtor_ = false;
97 mutable SequenceChecker sequence_checker_;
98 bool sequence_consistency_assertion_enabled_ = true;
79 #endif 99 #endif
80 100
81 DFAKE_MUTEX(add_release_); 101 DFAKE_MUTEX(add_release_);
82 102
83 DISALLOW_COPY_AND_ASSIGN(RefCountedBase); 103 DISALLOW_COPY_AND_ASSIGN(RefCountedBase);
84 }; 104 };
85 105
86 class BASE_EXPORT RefCountedThreadSafeBase { 106 class BASE_EXPORT RefCountedThreadSafeBase {
87 public: 107 public:
88 bool HasOneRef() const; 108 bool HasOneRef() const;
(...skipping 11 matching lines...) Expand all
100 mutable AtomicRefCount ref_count_ = 0; 120 mutable AtomicRefCount ref_count_ = 0;
101 #if DCHECK_IS_ON() 121 #if DCHECK_IS_ON()
102 mutable bool in_dtor_ = false; 122 mutable bool in_dtor_ = false;
103 #endif 123 #endif
104 124
105 DISALLOW_COPY_AND_ASSIGN(RefCountedThreadSafeBase); 125 DISALLOW_COPY_AND_ASSIGN(RefCountedThreadSafeBase);
106 }; 126 };
107 127
108 } // namespace subtle 128 } // namespace subtle
109 129
130 // See RefCounted class for documentation.
131 class BASE_EXPORT ScopedAllowCrossThreadRefCountAccess final {
132 public:
133 #if DCHECK_IS_ON()
134 ScopedAllowCrossThreadRefCountAccess();
135 ~ScopedAllowCrossThreadRefCountAccess();
136 #else
137 ScopedAllowCrossThreadRefCountAccess() {}
138 ~ScopedAllowCrossThreadRefCountAccess() {}
139 #endif
140 };
141
110 // 142 //
111 // A base class for reference counted classes. Otherwise, known as a cheap 143 // 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 144 // knock-off of WebKit's RefCounted<T> class. To use this, just extend your
113 // class from it like so: 145 // class from it like so:
114 // 146 //
115 // class MyFoo : public base::RefCounted<MyFoo> { 147 // class MyFoo : public base::RefCounted<MyFoo> {
116 // ... 148 // ...
117 // private: 149 // private:
118 // friend class base::RefCounted<MyFoo>; 150 // friend class base::RefCounted<MyFoo>;
119 // ~MyFoo(); 151 // ~MyFoo();
120 // }; 152 // };
121 // 153 //
122 // You should always make your destructor non-public, to avoid any code deleting 154 // You should always make your destructor non-public, to avoid any code deleting
123 // the object accidently while there are references to it. 155 // the object accidently while there are references to it.
156 //
157 // The ref count manipulation to RefCounted is NOT thread safe and has DCHECKs
158 // to trap unsafe cross thread usage. A subclass instance of RefCounted can be
159 // passed to another execution sequence only when its ref count is 1. If the ref
160 // count is more than 1, the RefCounted class verifies the ref updates are made
161 // on the same execution sequence as the previous ones.
162 // In rare cases where thread-safety is guaranteed through other means (e.g.
163 // locks or explicit sequencing of calls across execution sequences):
164 // ScopedAllowCrossThreadRefCountAccess can be used to explicitly indicate this
165 // and disable the aforementioned check.
yzshen1 2017/03/14 17:36:33 Nit: Please also mention DisableSequenceConsistenc
124 template <class T> 166 template <class T>
125 class RefCounted : public subtle::RefCountedBase { 167 class RefCounted : public subtle::RefCountedBase {
126 public: 168 public:
127 RefCounted() = default; 169 RefCounted() = default;
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 {
(...skipping 321 matching lines...) Expand 10 before | Expand all | Expand 10 after
455 bool operator!=(std::nullptr_t null, const scoped_refptr<T>& rhs) { 497 bool operator!=(std::nullptr_t null, const scoped_refptr<T>& rhs) {
456 return !operator==(null, rhs); 498 return !operator==(null, rhs);
457 } 499 }
458 500
459 template <typename T> 501 template <typename T>
460 std::ostream& operator<<(std::ostream& out, const scoped_refptr<T>& p) { 502 std::ostream& operator<<(std::ostream& out, const scoped_refptr<T>& p) {
461 return out << p.get(); 503 return out << p.get();
462 } 504 }
463 505
464 #endif // BASE_MEMORY_REF_COUNTED_H_ 506 #endif // BASE_MEMORY_REF_COUNTED_H_
OLDNEW
« no previous file with comments | « base/at_exit.cc ('k') | base/memory/ref_counted.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698