]> git.sesse.net Git - casparcg/blob - dependencies64/cef/include/base/cef_thread_collision_warner.h
* Merged html producer and updated to latest CEF version (does not have satisfactory...
[casparcg] / dependencies64 / cef / include / base / cef_thread_collision_warner.h
1 // Copyright (c) 2014 Marshall A. Greenblatt. Portions copyright (c) 2012
2 // Google Inc. All rights reserved.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions are
6 // met:
7 //
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
13 // distribution.
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.
18 //
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.
30
31 #ifndef CEF_INCLUDE_BASE_CEF_THREAD_COLLISION_WARNER_H_
32 #define CEF_INCLUDE_BASE_CEF_THREAD_COLLISION_WARNER_H_
33 #pragma once
34
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
46 // updated to match.
47
48 #include <memory>
49
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"
54
55 // A helper class alongside macros to be used to verify assumptions about thread
56 // safety of a class.
57 //
58 // Example: Queue implementation non thread-safe but still usable if clients
59 //          are synchronized somehow.
60 //
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
64 //
65 // class NonThreadSafeQueue {
66 //  public:
67 //   ...
68 //   void push(int) { DFAKE_SCOPED_LOCK(push_pop_); ... }
69 //   int pop() { DFAKE_SCOPED_LOCK(push_pop_); ... }
70 //   ...
71 //  private:
72 //   DFAKE_MUTEX(push_pop_);
73 // };
74 //
75 //
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
79 //
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
83 //
84 // class NonThreadSafeQueue {
85 //  public:
86 //   void push(int) {
87 //     DFAKE_SCOPED_LOCK(push_pop_);
88 //     ...
89 //   }
90 //   int pop() {
91 //     DFAKE_SCOPED_RECURSIVE_LOCK(push_pop_);
92 //     bar();
93 //     ...
94 //   }
95 //   void bar() { DFAKE_SCOPED_RECURSIVE_LOCK(push_pop_); ... }
96 //   ...
97 //  private:
98 //   DFAKE_MUTEX(push_pop_);
99 // };
100 //
101 //
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
104 //          push/pop.
105 //
106 //          In this case the macro DFAKE_SCOPED_LOCK_THREAD_LOCKED pins the
107 //          specified
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.
110 //
111 // class NonThreadSafeQueue {
112 //  public:
113 //   ...
114 //   void push(int) { DFAKE_SCOPED_LOCK_THREAD_LOCKED(push_pop_); ... }
115 //   int pop() { DFAKE_SCOPED_LOCK_THREAD_LOCKED(push_pop_); ... }
116 //   ...
117 //  private:
118 //   DFAKE_MUTEX(push_pop_);
119 // };
120 //
121 //
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).
125 //
126 //          In this case 3 Critical sections have to be defined
127 //
128 // class ExoticClass {
129 //  public:
130 //   ExoticClass() { DFAKE_SCOPED_LOCK_THREAD_LOCKED(ctor_dtor_); ... }
131 //   ~ExoticClass() { DFAKE_SCOPED_LOCK_THREAD_LOCKED(ctor_dtor_); ... }
132 //
133 //   void Shareable() { DFAKE_SCOPED_LOCK(shareable_section_); ... }
134 //   void NotShareable() { DFAKE_SCOPED_LOCK_THREAD_LOCKED(ctor_dtor_); ... }
135 //   ...
136 //  private:
137 //   DFAKE_MUTEX(ctor_dtor_);
138 //   DFAKE_MUTEX(shareable_section_);
139 // };
140
141
142 #if !defined(NDEBUG)
143
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)
159
160 #else
161
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)
166
167 #endif
168
169 namespace base {
170
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;
178 };
179
180 struct DCheckAsserter : public AsserterBase {
181   virtual ~DCheckAsserter() {}
182   virtual void warn() OVERRIDE;
183 };
184
185 class ThreadCollisionWarner {
186  public:
187   // The parameter asserter is there only for test purpose
188   explicit ThreadCollisionWarner(AsserterBase* asserter = new DCheckAsserter())
189       : valid_thread_id_(0),
190         counter_(0),
191         asserter_(asserter) {}
192
193   ~ThreadCollisionWarner() {
194     delete asserter_;
195   }
196
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
201   // from one thread
202   class Check {
203    public:
204     explicit Check(ThreadCollisionWarner* warner)
205         : warner_(warner) {
206       warner_->EnterSelf();
207     }
208
209     ~Check() {}
210
211    private:
212     ThreadCollisionWarner* warner_;
213
214     DISALLOW_COPY_AND_ASSIGN(Check);
215   };
216
217   // This class is meant to be used through the macro
218   // DFAKE_SCOPED_LOCK
219   class ScopedCheck {
220    public:
221     explicit ScopedCheck(ThreadCollisionWarner* warner)
222         : warner_(warner) {
223       warner_->Enter();
224     }
225
226     ~ScopedCheck() {
227       warner_->Leave();
228     }
229
230    private:
231     ThreadCollisionWarner* warner_;
232
233     DISALLOW_COPY_AND_ASSIGN(ScopedCheck);
234   };
235
236   // This class is meant to be used through the macro
237   // DFAKE_SCOPED_RECURSIVE_LOCK
238   class ScopedRecursiveCheck {
239    public:
240     explicit ScopedRecursiveCheck(ThreadCollisionWarner* warner)
241         : warner_(warner) {
242       warner_->EnterSelf();
243     }
244
245     ~ScopedRecursiveCheck() {
246       warner_->Leave();
247     }
248
249    private:
250     ThreadCollisionWarner* warner_;
251
252     DISALLOW_COPY_AND_ASSIGN(ScopedRecursiveCheck);
253   };
254
255  private:
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).
259   void EnterSelf();
260
261   // Same as EnterSelf but recursion is not allowed.
262   void Enter();
263
264   // Removes the thread_id stored in order to allow other threads to
265   // call EnterSelf or Enter.
266   void Leave();
267
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_;
271
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_;
275
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_;
279
280   DISALLOW_COPY_AND_ASSIGN(ThreadCollisionWarner);
281 };
282
283 }  // namespace base
284
285 #endif  // !BUILDING_CEF_SHARED
286
287 #endif  // CEF_INCLUDE_BASE_CEF_THREAD_COLLISION_WARNER_H_