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

Side by Side Diff: base/thread_collision_warner.h

Issue 6258: This CL is due the thread I have made on chromium-dev:... (Closed) Base URL: http://src.chromium.org/svn/trunk/src/
Patch Set: '' Created 12 years, 1 month 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 | Annotate | Revision Log
« no previous file with comments | « base/stack_container.h ('k') | base/thread_collision_warner.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright (c) 2008 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #ifndef THREAD_COLLISION_WARNER_H_
6 #define THREAD_COLLISION_WARNER_H_
7
8 #include "base/atomicops.h"
9 #include "base/platform_thread.h"
10
11 #include <memory>
12
13 // A helper class used to mark/define critical section in a class and then
14 // install controls to check that those critical sections are not violated
15
16 // Example: Queue implementation non thread-safe but still usable if clients
17 // are synchronized somehow.
18 //
19 // In this case the macro D_SCOPED_BOOK_CRITICAL_SECTION has to be
20 // used, it checks that if a thread is inside the push/pop then
21 // noone else is still inside the pop/push
22 //
23 // class NonThreadSafeQueue {
24 // public:
25 // ...
26 // void push(int) { D_SCOPED_BOOK_CRITICAL_SECTION(push_pop_); ... }
27 // int pop() { D_SCOPED_BOOK_CRITICAL_SECTION(push_pop_); ... }
28 // ...
29 // private:
30 // D_DEFINE_CRITICAL_SECTION(push_pop_);
31 // };
32 //
33 //
34 //
35 // Example: Queue implementation non thread-safe but still usable if clients
36 // are synchronized somehow, it calls a method to "protect" from
37 // a "protected" method
38 //
39 // In this case the macro D_SCOPED_RECURSIVE_BOOK_CRITICAL_SECTION
40 // has to be used, it checks that if a thread is inside the push/pop
41 // then noone else is still inside the pop/push
42 //
43 // class NonThreadSafeQueue {
44 // public:
45 // ...
46 // void push(int) {
47 // D_SCOPED_RECURSIVE_BOOK_CRITICAL_SECTION(push_pop_);
48 // ...
49 // }
50 // int pop() {
51 // D_SCOPED_RECURSIVE_BOOK_CRITICAL_SECTION(push_pop_);
52 // bar();
53 // ...
54 // }
55 // void bar() { D_SCOPED_RECURSIVE_BOOK_CRITICAL_SECTION(push_pop_); ... }
56 // ...
57 // private:
58 // D_DEFINE_CRITICAL_SECTION(push_pop_);
59 // };
60 //
61 //
62 //
63 // Example: Queue implementation not usable even if clients are synchronized,
64 // so only one thread in the class life cycle can use the two members
65 // push/pop
66 //
67 // In this case the macro D_BOOK_CRITICAL_SECTION pins the specified
68 // critical section the first time a thread enters push or pop, from
69 // that time on only that thread is allowed to execute push or pop.
70 //
71 // class NonThreadSafeQueue {
72 // public:
73 // ...
74 // void push(int) { D_BOOK_CRITICAL_SECTION(push_pop_); ... }
75 // int pop() { D_BOOK_CRITICAL_SECTION(push_pop_); ... }
76 // ...
77 // private:
78 // D_DEFINE_CRITICAL_SECTION(push_pop_);
79 // };
80 //
81 //
82 //
83 // Example: Class that has to be contructed/destroyed on same thread, it has
84 // a "shareable" method (with external syncronization) and a not
85 // shareable method (even with external syncronization).
86 //
87 // In this case 3 Critical sections have to be defined
88 //
89 // class ExoticClass {
90 // public:
91 // ExoticClass() { D_BOOK_CRITICAL_SECTION(ctor_dtor_); ... }
92 // ~ExoticClass() { D_BOOK_CRITICAL_SECTION(ctor_dtor_); ... }
93 //
94 // void Sharable() { D_SCOPED_BOOK_CRITICAL_SECTION(sharable_section_); ... }
95 // void NotSharable() { D_BOOK_CRITICAL_SECTION(not_sharable_section_); ... }
96 // ...
97 // private:
98 // D_DEFINE_CRITICAL_SECTION(ctor_dtor_);
99 // D_DEFINE_CRITICAL_SECTION(sharable_section_);
100 // D_DEFINE_CRITICAL_SECTION(not_sharable_section_);
101 // };
102
103
104 #ifndef NDEBUG
105
106 #define D_DEFINE_CRITICAL_SECTION(obj) \
107 mutable base::ThreadCollisionWarner obj
108 #define D_SCOPED_BOOK_CRITICAL_SECTION(obj) \
109 base::ThreadCollisionWarner::ScopedCheck s_check_##obj(&obj)
110 #define D_SCOPED_RECURSIVE_BOOK_CRITICAL_SECTION(obj) \
111 base::ThreadCollisionWarner::ScopedRecursiveCheck sr_check_##obj(&obj)
112 #define D_BOOK_CRITICAL_SECTION(obj) \
113 base::ThreadCollisionWarner::Check check_##obj(&obj)
114
115 #else
116
117 #define D_DEFINE_CRITICAL_SECTION(obj)
118 #define D_SCOPED_BOOK_CRITICAL_SECTION(obj)
119 #define D_BOOK_CRITICAL_SECTION(obj)
120
121 #endif
122
123 namespace base {
124
125 // The class ThreadCollisionWarner uses an Asserter to notify the collision
126 // AsserterBase is the interfaces and DCheckAsserter is the default asserter
127 // used. During the unit tests is used another class that doesn't "DCHECK"
128 // in case of collision (check thread_collision_warner_unittests.cc)
129 struct AsserterBase {
130 virtual ~AsserterBase() {}
131 virtual void warn() = 0;
132 };
133
134 struct DCheckAsserter : AsserterBase {
135 virtual ~DCheckAsserter() {}
136 virtual void warn();
137 };
138
139 class ThreadCollisionWarner {
140 public:
141 // The parameter asserter is there only for test purpose
142 ThreadCollisionWarner(AsserterBase* asserter = new DCheckAsserter())
143 : valid_thread_id_(0),
144 counter_(0),
145 asserter_(asserter) {}
146
147 ~ThreadCollisionWarner() {
148 delete asserter_;
149 }
150
151 // This class is meant to be used through the macro D_BOOK_CRITICAL_SECTION
152 // it doesn't leave the critical section, as opposed to ScopedCheck,
153 // because the critical section being pinned is allowed to be used only
154 // from one thread
155 class Check {
156 public:
157 explicit Check(ThreadCollisionWarner* warner)
158 : warner_(warner) {
159 warner_->EnterSelf();
160 }
161
162 ~Check() {}
163
164 private:
165 ThreadCollisionWarner* warner_;
166
167 DISALLOW_COPY_AND_ASSIGN(Check);
168 };
169
170 // This class is meant to be used through the macro
171 // D_SCOPED_BOOK_CRITICAL_SECTION
172 class ScopedCheck {
173 public:
174 explicit ScopedCheck(ThreadCollisionWarner* warner)
175 : warner_(warner) {
176 warner_->Enter();
177 }
178
179 ~ScopedCheck() {
180 warner_->Leave();
181 }
182
183 private:
184 ThreadCollisionWarner* warner_;
185
186 DISALLOW_COPY_AND_ASSIGN(ScopedCheck);
187 };
188
189 // This class is meant to be used through the macro
190 // D_SCOPED_RECURSIVE_BOOK_CRITICAL_SECTION
191 class ScopedRecursiveCheck {
192 public:
193 explicit ScopedRecursiveCheck(ThreadCollisionWarner* warner)
194 : warner_(warner) {
195 warner_->EnterSelf();
196 }
197
198 ~ScopedRecursiveCheck() {
199 warner_->Leave();
200 }
201
202 private:
203 ThreadCollisionWarner* warner_;
204
205 DISALLOW_COPY_AND_ASSIGN(ScopedRecursiveCheck);
206 };
207
208 private:
209 // This method stores the current thread identifier and does a DCHECK
210 // if a another thread has already done it, it'is safe if same thread
211 // calls this multiple time (recursion allowed).
212 void EnterSelf();
213
214 // Same as EnterSelf but recursion is not allowed
215 void Enter();
216
217 // Removes the thread_id stored in order to allow other threads to
218 // call EnterSelf or Enter
219 void Leave();
220
221 // This stores the thread id that is inside the critical section, if the
222 // value is 0 then no thread is inside
223 volatile int valid_thread_id_;
224
225 // Counter to trace how many time a critical section was "pinned"
226 // (when allowed) in order to unpin it when counter_ reaches 0
227 volatile subtle::Atomic32 counter_;
228
229 // Here only for class unit tests purpose, during the test I need to not
230 // DCHECK but notify the collision with something else
231 AsserterBase* asserter_;
232
233 DISALLOW_COPY_AND_ASSIGN(ThreadCollisionWarner);
234 };
235
236 } // namespace base
237
238 #endif // THREAD_COLLISION_WARNER_H_
239
OLDNEW
« no previous file with comments | « base/stack_container.h ('k') | base/thread_collision_warner.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698