1 // Copyright (c) 2014 Marshall A. Greenblatt. Portions copyright (c) 2012
2 // Google Inc. All rights reserved.
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions are
8 // * Redistributions of source code must retain the above copyright
9 // notice, this list of conditions and the following disclaimer.
10 // * Redistributions in binary form must reproduce the above
11 // copyright notice, this list of conditions and the following disclaimer
12 // in the documentation and/or other materials provided with the
14 // * Neither the name of Google Inc. nor the name Chromium Embedded
15 // Framework nor the names of its contributors may be used to endorse
16 // or promote products derived from this software without specific prior
17 // written permission.
19 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 #ifndef CEF_INCLUDE_BASE_CEF_THREAD_COLLISION_WARNER_H_
32 #define CEF_INCLUDE_BASE_CEF_THREAD_COLLISION_WARNER_H_
35 #if defined(BASE_THREADING_THREAD_COLLISION_WARNER_H_)
36 // Do nothing if the Chromium header has already been included.
37 // This can happen in cases where Chromium code is used directly by the
38 // client application. When using Chromium code directly always include
39 // the Chromium header first to avoid type conflicts.
40 #elif defined(BUILDING_CEF_SHARED)
41 // When building CEF include the Chromium header directly.
42 #include "base/threading/thread_collision_warner.h"
43 #else // !BUILDING_CEF_SHARED
44 // The following is substantially similar to the Chromium implementation.
45 // If the Chromium implementation diverges the below implementation should be
50 #include "include/base/cef_atomicops.h"
51 #include "include/base/cef_basictypes.h"
52 #include "include/base/cef_build.h"
53 #include "include/base/cef_macros.h"
55 // A helper class alongside macros to be used to verify assumptions about thread
58 // Example: Queue implementation non thread-safe but still usable if clients
59 // are synchronized somehow.
61 // In this case the macro DFAKE_SCOPED_LOCK has to be
62 // used, it checks that if a thread is inside the push/pop then
63 // noone else is still inside the pop/push
65 // class NonThreadSafeQueue {
68 // void push(int) { DFAKE_SCOPED_LOCK(push_pop_); ... }
69 // int pop() { DFAKE_SCOPED_LOCK(push_pop_); ... }
72 // DFAKE_MUTEX(push_pop_);
76 // Example: Queue implementation non thread-safe but still usable if clients
77 // are synchronized somehow, it calls a method to "protect" from
78 // a "protected" method
80 // In this case the macro DFAKE_SCOPED_RECURSIVE_LOCK
81 // has to be used, it checks that if a thread is inside the push/pop
82 // then noone else is still inside the pop/push
84 // class NonThreadSafeQueue {
87 // DFAKE_SCOPED_LOCK(push_pop_);
91 // DFAKE_SCOPED_RECURSIVE_LOCK(push_pop_);
95 // void bar() { DFAKE_SCOPED_RECURSIVE_LOCK(push_pop_); ... }
98 // DFAKE_MUTEX(push_pop_);
102 // Example: Queue implementation not usable even if clients are synchronized,
103 // so only one thread in the class life cycle can use the two members
106 // In this case the macro DFAKE_SCOPED_LOCK_THREAD_LOCKED pins the
108 // critical section the first time a thread enters push or pop, from
109 // that time on only that thread is allowed to execute push or pop.
111 // class NonThreadSafeQueue {
114 // void push(int) { DFAKE_SCOPED_LOCK_THREAD_LOCKED(push_pop_); ... }
115 // int pop() { DFAKE_SCOPED_LOCK_THREAD_LOCKED(push_pop_); ... }
118 // DFAKE_MUTEX(push_pop_);
122 // Example: Class that has to be contructed/destroyed on same thread, it has
123 // a "shareable" method (with external synchronization) and a not
124 // shareable method (even with external synchronization).
126 // In this case 3 Critical sections have to be defined
128 // class ExoticClass {
130 // ExoticClass() { DFAKE_SCOPED_LOCK_THREAD_LOCKED(ctor_dtor_); ... }
131 // ~ExoticClass() { DFAKE_SCOPED_LOCK_THREAD_LOCKED(ctor_dtor_); ... }
133 // void Shareable() { DFAKE_SCOPED_LOCK(shareable_section_); ... }
134 // void NotShareable() { DFAKE_SCOPED_LOCK_THREAD_LOCKED(ctor_dtor_); ... }
137 // DFAKE_MUTEX(ctor_dtor_);
138 // DFAKE_MUTEX(shareable_section_);
144 // Defines a class member that acts like a mutex. It is used only as a
145 // verification tool.
146 #define DFAKE_MUTEX(obj) \
147 mutable base::ThreadCollisionWarner obj
148 // Asserts the call is never called simultaneously in two threads. Used at
149 // member function scope.
150 #define DFAKE_SCOPED_LOCK(obj) \
151 base::ThreadCollisionWarner::ScopedCheck s_check_##obj(&obj)
152 // Asserts the call is never called simultaneously in two threads. Used at
153 // member function scope. Same as DFAKE_SCOPED_LOCK but allows recursive locks.
154 #define DFAKE_SCOPED_RECURSIVE_LOCK(obj) \
155 base::ThreadCollisionWarner::ScopedRecursiveCheck sr_check_##obj(&obj)
156 // Asserts the code is always executed in the same thread.
157 #define DFAKE_SCOPED_LOCK_THREAD_LOCKED(obj) \
158 base::ThreadCollisionWarner::Check check_##obj(&obj)
162 #define DFAKE_MUTEX(obj) typedef void InternalFakeMutexType##obj
163 #define DFAKE_SCOPED_LOCK(obj) ((void)0)
164 #define DFAKE_SCOPED_RECURSIVE_LOCK(obj) ((void)0)
165 #define DFAKE_SCOPED_LOCK_THREAD_LOCKED(obj) ((void)0)
171 // The class ThreadCollisionWarner uses an Asserter to notify the collision
172 // AsserterBase is the interfaces and DCheckAsserter is the default asserter
173 // used. During the unit tests is used another class that doesn't "DCHECK"
174 // in case of collision (check thread_collision_warner_unittests.cc)
175 struct AsserterBase {
176 virtual ~AsserterBase() {}
177 virtual void warn() = 0;
180 struct DCheckAsserter : public AsserterBase {
181 virtual ~DCheckAsserter() {}
182 virtual void warn() OVERRIDE;
185 class ThreadCollisionWarner {
187 // The parameter asserter is there only for test purpose
188 explicit ThreadCollisionWarner(AsserterBase* asserter = new DCheckAsserter())
189 : valid_thread_id_(0),
191 asserter_(asserter) {}
193 ~ThreadCollisionWarner() {
197 // This class is meant to be used through the macro
198 // DFAKE_SCOPED_LOCK_THREAD_LOCKED
199 // it doesn't leave the critical section, as opposed to ScopedCheck,
200 // because the critical section being pinned is allowed to be used only
204 explicit Check(ThreadCollisionWarner* warner)
206 warner_->EnterSelf();
212 ThreadCollisionWarner* warner_;
214 DISALLOW_COPY_AND_ASSIGN(Check);
217 // This class is meant to be used through the macro
221 explicit ScopedCheck(ThreadCollisionWarner* warner)
231 ThreadCollisionWarner* warner_;
233 DISALLOW_COPY_AND_ASSIGN(ScopedCheck);
236 // This class is meant to be used through the macro
237 // DFAKE_SCOPED_RECURSIVE_LOCK
238 class ScopedRecursiveCheck {
240 explicit ScopedRecursiveCheck(ThreadCollisionWarner* warner)
242 warner_->EnterSelf();
245 ~ScopedRecursiveCheck() {
250 ThreadCollisionWarner* warner_;
252 DISALLOW_COPY_AND_ASSIGN(ScopedRecursiveCheck);
256 // This method stores the current thread identifier and does a DCHECK
257 // if a another thread has already done it, it is safe if same thread
258 // calls this multiple time (recursion allowed).
261 // Same as EnterSelf but recursion is not allowed.
264 // Removes the thread_id stored in order to allow other threads to
265 // call EnterSelf or Enter.
268 // This stores the thread id that is inside the critical section, if the
269 // value is 0 then no thread is inside.
270 volatile subtle::Atomic32 valid_thread_id_;
272 // Counter to trace how many time a critical section was "pinned"
273 // (when allowed) in order to unpin it when counter_ reaches 0.
274 volatile subtle::Atomic32 counter_;
276 // Here only for class unit tests purpose, during the test I need to not
277 // DCHECK but notify the collision with something else.
278 AsserterBase* asserter_;
280 DISALLOW_COPY_AND_ASSIGN(ThreadCollisionWarner);
285 #endif // !BUILDING_CEF_SHARED
287 #endif // CEF_INCLUDE_BASE_CEF_THREAD_COLLISION_WARNER_H_