Added llvm into exceptions as we can't add README.chromium into 3rd party repository
[chromium-blink-merge.git] / base / threading / thread_collision_warner_unittest.cc
blob26faff404f6593a89125707ed50490e66b54d717
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
3 // found in the LICENSE file.
5 #include "base/compiler_specific.h"
6 #include "base/memory/scoped_ptr.h"
7 #include "base/synchronization/lock.h"
8 #include "base/threading/platform_thread.h"
9 #include "base/threading/simple_thread.h"
10 #include "base/threading/thread_collision_warner.h"
11 #include "testing/gtest/include/gtest/gtest.h"
13 // '' : local class member function does not have a body
14 MSVC_PUSH_DISABLE_WARNING(4822)
17 #if defined(NDEBUG)
19 // Would cause a memory leak otherwise.
20 #undef DFAKE_MUTEX
21 #define DFAKE_MUTEX(obj) scoped_ptr<base::AsserterBase> obj
23 // In Release, we expect the AsserterBase::warn() to not happen.
24 #define EXPECT_NDEBUG_FALSE_DEBUG_TRUE EXPECT_FALSE
26 #else
28 // In Debug, we expect the AsserterBase::warn() to happen.
29 #define EXPECT_NDEBUG_FALSE_DEBUG_TRUE EXPECT_TRUE
31 #endif
34 namespace {
36 // This is the asserter used with ThreadCollisionWarner instead of the default
37 // DCheckAsserter. The method fail_state is used to know if a collision took
38 // place.
39 class AssertReporter : public base::AsserterBase {
40 public:
41 AssertReporter()
42 : failed_(false) {}
44 void warn() override { failed_ = true; }
46 ~AssertReporter() override {}
48 bool fail_state() const { return failed_; }
49 void reset() { failed_ = false; }
51 private:
52 bool failed_;
55 } // namespace
57 TEST(ThreadCollisionTest, BookCriticalSection) {
58 AssertReporter* local_reporter = new AssertReporter();
60 base::ThreadCollisionWarner warner(local_reporter);
61 EXPECT_FALSE(local_reporter->fail_state());
63 { // Pin section.
64 DFAKE_SCOPED_LOCK_THREAD_LOCKED(warner);
65 EXPECT_FALSE(local_reporter->fail_state());
66 { // Pin section.
67 DFAKE_SCOPED_LOCK_THREAD_LOCKED(warner);
68 EXPECT_FALSE(local_reporter->fail_state());
73 TEST(ThreadCollisionTest, ScopedRecursiveBookCriticalSection) {
74 AssertReporter* local_reporter = new AssertReporter();
76 base::ThreadCollisionWarner warner(local_reporter);
77 EXPECT_FALSE(local_reporter->fail_state());
79 { // Pin section.
80 DFAKE_SCOPED_RECURSIVE_LOCK(warner);
81 EXPECT_FALSE(local_reporter->fail_state());
82 { // Pin section again (allowed by DFAKE_SCOPED_RECURSIVE_LOCK)
83 DFAKE_SCOPED_RECURSIVE_LOCK(warner);
84 EXPECT_FALSE(local_reporter->fail_state());
85 } // Unpin section.
86 } // Unpin section.
88 // Check that section is not pinned
89 { // Pin section.
90 DFAKE_SCOPED_LOCK(warner);
91 EXPECT_FALSE(local_reporter->fail_state());
92 } // Unpin section.
95 TEST(ThreadCollisionTest, ScopedBookCriticalSection) {
96 AssertReporter* local_reporter = new AssertReporter();
98 base::ThreadCollisionWarner warner(local_reporter);
99 EXPECT_FALSE(local_reporter->fail_state());
101 { // Pin section.
102 DFAKE_SCOPED_LOCK(warner);
103 EXPECT_FALSE(local_reporter->fail_state());
104 } // Unpin section.
106 { // Pin section.
107 DFAKE_SCOPED_LOCK(warner);
108 EXPECT_FALSE(local_reporter->fail_state());
110 // Pin section again (not allowed by DFAKE_SCOPED_LOCK)
111 DFAKE_SCOPED_LOCK(warner);
112 EXPECT_NDEBUG_FALSE_DEBUG_TRUE(local_reporter->fail_state());
113 // Reset the status of warner for further tests.
114 local_reporter->reset();
115 } // Unpin section.
116 } // Unpin section.
119 // Pin section.
120 DFAKE_SCOPED_LOCK(warner);
121 EXPECT_FALSE(local_reporter->fail_state());
122 } // Unpin section.
125 TEST(ThreadCollisionTest, MTBookCriticalSectionTest) {
126 class NonThreadSafeQueue {
127 public:
128 explicit NonThreadSafeQueue(base::AsserterBase* asserter)
129 : push_pop_(asserter) {
132 void push(int value) {
133 DFAKE_SCOPED_LOCK_THREAD_LOCKED(push_pop_);
136 int pop() {
137 DFAKE_SCOPED_LOCK_THREAD_LOCKED(push_pop_);
138 return 0;
141 private:
142 DFAKE_MUTEX(push_pop_);
144 DISALLOW_COPY_AND_ASSIGN(NonThreadSafeQueue);
147 class QueueUser : public base::DelegateSimpleThread::Delegate {
148 public:
149 explicit QueueUser(NonThreadSafeQueue& queue)
150 : queue_(queue) {}
152 void Run() override {
153 queue_.push(0);
154 queue_.pop();
157 private:
158 NonThreadSafeQueue& queue_;
161 AssertReporter* local_reporter = new AssertReporter();
163 NonThreadSafeQueue queue(local_reporter);
165 QueueUser queue_user_a(queue);
166 QueueUser queue_user_b(queue);
168 base::DelegateSimpleThread thread_a(&queue_user_a, "queue_user_thread_a");
169 base::DelegateSimpleThread thread_b(&queue_user_b, "queue_user_thread_b");
171 thread_a.Start();
172 thread_b.Start();
174 thread_a.Join();
175 thread_b.Join();
177 EXPECT_NDEBUG_FALSE_DEBUG_TRUE(local_reporter->fail_state());
180 TEST(ThreadCollisionTest, MTScopedBookCriticalSectionTest) {
181 // Queue with a 5 seconds push execution time, hopefuly the two used threads
182 // in the test will enter the push at same time.
183 class NonThreadSafeQueue {
184 public:
185 explicit NonThreadSafeQueue(base::AsserterBase* asserter)
186 : push_pop_(asserter) {
189 void push(int value) {
190 DFAKE_SCOPED_LOCK(push_pop_);
191 base::PlatformThread::Sleep(base::TimeDelta::FromSeconds(5));
194 int pop() {
195 DFAKE_SCOPED_LOCK(push_pop_);
196 return 0;
199 private:
200 DFAKE_MUTEX(push_pop_);
202 DISALLOW_COPY_AND_ASSIGN(NonThreadSafeQueue);
205 class QueueUser : public base::DelegateSimpleThread::Delegate {
206 public:
207 explicit QueueUser(NonThreadSafeQueue& queue)
208 : queue_(queue) {}
210 void Run() override {
211 queue_.push(0);
212 queue_.pop();
215 private:
216 NonThreadSafeQueue& queue_;
219 AssertReporter* local_reporter = new AssertReporter();
221 NonThreadSafeQueue queue(local_reporter);
223 QueueUser queue_user_a(queue);
224 QueueUser queue_user_b(queue);
226 base::DelegateSimpleThread thread_a(&queue_user_a, "queue_user_thread_a");
227 base::DelegateSimpleThread thread_b(&queue_user_b, "queue_user_thread_b");
229 thread_a.Start();
230 thread_b.Start();
232 thread_a.Join();
233 thread_b.Join();
235 EXPECT_NDEBUG_FALSE_DEBUG_TRUE(local_reporter->fail_state());
238 TEST(ThreadCollisionTest, MTSynchedScopedBookCriticalSectionTest) {
239 // Queue with a 2 seconds push execution time, hopefuly the two used threads
240 // in the test will enter the push at same time.
241 class NonThreadSafeQueue {
242 public:
243 explicit NonThreadSafeQueue(base::AsserterBase* asserter)
244 : push_pop_(asserter) {
247 void push(int value) {
248 DFAKE_SCOPED_LOCK(push_pop_);
249 base::PlatformThread::Sleep(base::TimeDelta::FromSeconds(2));
252 int pop() {
253 DFAKE_SCOPED_LOCK(push_pop_);
254 return 0;
257 private:
258 DFAKE_MUTEX(push_pop_);
260 DISALLOW_COPY_AND_ASSIGN(NonThreadSafeQueue);
263 // This time the QueueUser class protects the non thread safe queue with
264 // a lock.
265 class QueueUser : public base::DelegateSimpleThread::Delegate {
266 public:
267 QueueUser(NonThreadSafeQueue& queue, base::Lock& lock)
268 : queue_(queue),
269 lock_(lock) {}
271 void Run() override {
273 base::AutoLock auto_lock(lock_);
274 queue_.push(0);
277 base::AutoLock auto_lock(lock_);
278 queue_.pop();
281 private:
282 NonThreadSafeQueue& queue_;
283 base::Lock& lock_;
286 AssertReporter* local_reporter = new AssertReporter();
288 NonThreadSafeQueue queue(local_reporter);
290 base::Lock lock;
292 QueueUser queue_user_a(queue, lock);
293 QueueUser queue_user_b(queue, lock);
295 base::DelegateSimpleThread thread_a(&queue_user_a, "queue_user_thread_a");
296 base::DelegateSimpleThread thread_b(&queue_user_b, "queue_user_thread_b");
298 thread_a.Start();
299 thread_b.Start();
301 thread_a.Join();
302 thread_b.Join();
304 EXPECT_FALSE(local_reporter->fail_state());
307 TEST(ThreadCollisionTest, MTSynchedScopedRecursiveBookCriticalSectionTest) {
308 // Queue with a 2 seconds push execution time, hopefuly the two used threads
309 // in the test will enter the push at same time.
310 class NonThreadSafeQueue {
311 public:
312 explicit NonThreadSafeQueue(base::AsserterBase* asserter)
313 : push_pop_(asserter) {
316 void push(int) {
317 DFAKE_SCOPED_RECURSIVE_LOCK(push_pop_);
318 bar();
319 base::PlatformThread::Sleep(base::TimeDelta::FromSeconds(2));
322 int pop() {
323 DFAKE_SCOPED_RECURSIVE_LOCK(push_pop_);
324 return 0;
327 void bar() {
328 DFAKE_SCOPED_RECURSIVE_LOCK(push_pop_);
331 private:
332 DFAKE_MUTEX(push_pop_);
334 DISALLOW_COPY_AND_ASSIGN(NonThreadSafeQueue);
337 // This time the QueueUser class protects the non thread safe queue with
338 // a lock.
339 class QueueUser : public base::DelegateSimpleThread::Delegate {
340 public:
341 QueueUser(NonThreadSafeQueue& queue, base::Lock& lock)
342 : queue_(queue),
343 lock_(lock) {}
345 void Run() override {
347 base::AutoLock auto_lock(lock_);
348 queue_.push(0);
351 base::AutoLock auto_lock(lock_);
352 queue_.bar();
355 base::AutoLock auto_lock(lock_);
356 queue_.pop();
359 private:
360 NonThreadSafeQueue& queue_;
361 base::Lock& lock_;
364 AssertReporter* local_reporter = new AssertReporter();
366 NonThreadSafeQueue queue(local_reporter);
368 base::Lock lock;
370 QueueUser queue_user_a(queue, lock);
371 QueueUser queue_user_b(queue, lock);
373 base::DelegateSimpleThread thread_a(&queue_user_a, "queue_user_thread_a");
374 base::DelegateSimpleThread thread_b(&queue_user_b, "queue_user_thread_b");
376 thread_a.Start();
377 thread_b.Start();
379 thread_a.Join();
380 thread_b.Join();
382 EXPECT_FALSE(local_reporter->fail_state());