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

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

Issue 2783393002: Revert of Assert sequence validity on non-thread-safe RefCount manipulations (2) (Closed)
Patch Set: 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/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"
20 #include "base/threading/thread_collision_warner.h" 19 #include "base/threading/thread_collision_warner.h"
21 #include "build/build_config.h" 20 #include "build/build_config.h"
22 21
23 namespace base { 22 namespace base {
24 23
25 namespace subtle { 24 namespace subtle {
26 25
27 class BASE_EXPORT RefCountedBase { 26 class BASE_EXPORT RefCountedBase {
28 public: 27 public:
29 bool HasOneRef() const { return ref_count_ == 1; } 28 bool HasOneRef() const { return ref_count_ == 1; }
30 29
31 protected: 30 protected:
32 RefCountedBase() { 31 RefCountedBase() {}
33 #if DCHECK_IS_ON()
34 sequence_checker_.DetachFromSequence();
35 #endif
36 }
37 32
38 ~RefCountedBase() { 33 ~RefCountedBase() {
39 #if DCHECK_IS_ON() 34 #if DCHECK_IS_ON()
40 DCHECK(in_dtor_) << "RefCounted object deleted without calling Release()"; 35 DCHECK(in_dtor_) << "RefCounted object deleted without calling Release()";
41 #endif 36 #endif
42 } 37 }
43 38
44 void AddRef() const { 39 void AddRef() const {
45 // TODO(maruel): Add back once it doesn't assert 500 times/sec. 40 // TODO(maruel): Add back once it doesn't assert 500 times/sec.
46 // Current thread books the critical section "AddRelease" 41 // Current thread books the critical section "AddRelease"
47 // without release it. 42 // without release it.
48 // DFAKE_SCOPED_LOCK_THREAD_LOCKED(add_release_); 43 // DFAKE_SCOPED_LOCK_THREAD_LOCKED(add_release_);
49 #if DCHECK_IS_ON() 44 #if DCHECK_IS_ON()
50 DCHECK(!in_dtor_); 45 DCHECK(!in_dtor_);
51 if (ref_count_ >= 1) {
52 DCHECK(CalledOnValidSequence());
53 }
54 #endif 46 #endif
55 47
56 ++ref_count_; 48 ++ref_count_;
57 } 49 }
58 50
59 // Returns true if the object should self-delete. 51 // Returns true if the object should self-delete.
60 bool Release() const { 52 bool Release() const {
61 --ref_count_; 53 --ref_count_;
62 54
63 // 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.
64 // Current thread books the critical section "AddRelease" 56 // Current thread books the critical section "AddRelease"
65 // without release it. 57 // without release it.
66 // DFAKE_SCOPED_LOCK_THREAD_LOCKED(add_release_); 58 // DFAKE_SCOPED_LOCK_THREAD_LOCKED(add_release_);
67 59
68 #if DCHECK_IS_ON() 60 #if DCHECK_IS_ON()
69 DCHECK(!in_dtor_); 61 DCHECK(!in_dtor_);
70 if (ref_count_ == 0) 62 if (ref_count_ == 0)
71 in_dtor_ = true; 63 in_dtor_ = true;
72
73 if (ref_count_ >= 1)
74 DCHECK(CalledOnValidSequence());
75 if (ref_count_ == 1)
76 sequence_checker_.DetachFromSequence();
77 #endif 64 #endif
78 65
79 return ref_count_ == 0; 66 return ref_count_ == 0;
80 } 67 }
81 68
82 private: 69 private:
83 #if DCHECK_IS_ON()
84 bool CalledOnValidSequence() const;
85 #endif
86
87 mutable size_t ref_count_ = 0; 70 mutable size_t ref_count_ = 0;
88
89 #if DCHECK_IS_ON() 71 #if DCHECK_IS_ON()
90 mutable bool in_dtor_ = false; 72 mutable bool in_dtor_ = false;
91 mutable SequenceChecker sequence_checker_;
92 #endif 73 #endif
93 74
94 DFAKE_MUTEX(add_release_); 75 DFAKE_MUTEX(add_release_);
95 76
96 DISALLOW_COPY_AND_ASSIGN(RefCountedBase); 77 DISALLOW_COPY_AND_ASSIGN(RefCountedBase);
97 }; 78 };
98 79
99 class BASE_EXPORT RefCountedThreadSafeBase { 80 class BASE_EXPORT RefCountedThreadSafeBase {
100 public: 81 public:
101 bool HasOneRef() const; 82 bool HasOneRef() const;
(...skipping 11 matching lines...) Expand all
113 mutable AtomicRefCount ref_count_ = 0; 94 mutable AtomicRefCount ref_count_ = 0;
114 #if DCHECK_IS_ON() 95 #if DCHECK_IS_ON()
115 mutable bool in_dtor_ = false; 96 mutable bool in_dtor_ = false;
116 #endif 97 #endif
117 98
118 DISALLOW_COPY_AND_ASSIGN(RefCountedThreadSafeBase); 99 DISALLOW_COPY_AND_ASSIGN(RefCountedThreadSafeBase);
119 }; 100 };
120 101
121 } // namespace subtle 102 } // namespace subtle
122 103
123 // ScopedAllowCrossThreadRefCountAccess disables the check documented on
124 // RefCounted below for rare pre-existing use cases where thread-safety was
125 // guaranteed through other means (e.g. explicit sequencing of calls across
126 // execution sequences when bouncing between threads in order). New callers
127 // should refrain from using this (callsites handling thread-safety through
128 // locks should use RefCountedThreadSafe per the overhead of its atomics being
129 // negligible compared to locks anyways and callsites doing explicit sequencing
130 // should properly std::move() the ref to avoid hitting this check).
131 // TODO(tzik): Cleanup existing use cases and remove
132 // ScopedAllowCrossThreadRefCountAccess.
133 class BASE_EXPORT ScopedAllowCrossThreadRefCountAccess final {
134 public:
135 #if DCHECK_IS_ON()
136 ScopedAllowCrossThreadRefCountAccess();
137 ~ScopedAllowCrossThreadRefCountAccess();
138 #else
139 ScopedAllowCrossThreadRefCountAccess() {}
140 ~ScopedAllowCrossThreadRefCountAccess() {}
141 #endif
142 };
143
144 // 104 //
145 // A base class for reference counted classes. Otherwise, known as a cheap 105 // A base class for reference counted classes. Otherwise, known as a cheap
146 // knock-off of WebKit's RefCounted<T> class. To use this, just extend your 106 // knock-off of WebKit's RefCounted<T> class. To use this, just extend your
147 // class from it like so: 107 // class from it like so:
148 // 108 //
149 // class MyFoo : public base::RefCounted<MyFoo> { 109 // class MyFoo : public base::RefCounted<MyFoo> {
150 // ... 110 // ...
151 // private: 111 // private:
152 // friend class base::RefCounted<MyFoo>; 112 // friend class base::RefCounted<MyFoo>;
153 // ~MyFoo(); 113 // ~MyFoo();
154 // }; 114 // };
155 // 115 //
156 // You should always make your destructor non-public, to avoid any code deleting 116 // You should always make your destructor non-public, to avoid any code deleting
157 // the object accidently while there are references to it. 117 // the object accidently while there are references to it.
158 //
159 // 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
161 // 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
163 // on the same execution sequence as the previous ones.
164 template <class T> 118 template <class T>
165 class RefCounted : public subtle::RefCountedBase { 119 class RefCounted : public subtle::RefCountedBase {
166 public: 120 public:
167 RefCounted() = default; 121 RefCounted() = default;
168 122
169 void AddRef() const { 123 void AddRef() const {
170 subtle::RefCountedBase::AddRef(); 124 subtle::RefCountedBase::AddRef();
171 } 125 }
172 126
173 void Release() const { 127 void Release() const {
(...skipping 317 matching lines...) Expand 10 before | Expand all | Expand 10 after
491 bool operator!=(std::nullptr_t null, const scoped_refptr<T>& rhs) { 445 bool operator!=(std::nullptr_t null, const scoped_refptr<T>& rhs) {
492 return !operator==(null, rhs); 446 return !operator==(null, rhs);
493 } 447 }
494 448
495 template <typename T> 449 template <typename T>
496 std::ostream& operator<<(std::ostream& out, const scoped_refptr<T>& p) { 450 std::ostream& operator<<(std::ostream& out, const scoped_refptr<T>& p) {
497 return out << p.get(); 451 return out << p.get();
498 } 452 }
499 453
500 #endif // BASE_MEMORY_REF_COUNTED_H_ 454 #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