Updating trunk VERSION from 2139.0 to 2140.0
[chromium-blink-merge.git] / base / threading / thread_collision_warner_unittest.cc
blob48710a7f3cc508fe91c6389fe9b1b54ae246596a
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 virtual void warn() OVERRIDE {
45 failed_ = true;
48 virtual ~AssertReporter() {}
50 bool fail_state() const { return failed_; }
51 void reset() { failed_ = false; }
53 private:
54 bool failed_;
57 } // namespace
59 TEST(ThreadCollisionTest, BookCriticalSection) {
60 AssertReporter* local_reporter = new AssertReporter();
62 base::ThreadCollisionWarner warner(local_reporter);
63 EXPECT_FALSE(local_reporter->fail_state());
65 { // Pin section.
66 DFAKE_SCOPED_LOCK_THREAD_LOCKED(warner);
67 EXPECT_FALSE(local_reporter->fail_state());
68 { // Pin section.
69 DFAKE_SCOPED_LOCK_THREAD_LOCKED(warner);
70 EXPECT_FALSE(local_reporter->fail_state());
75 TEST(ThreadCollisionTest, ScopedRecursiveBookCriticalSection) {
76 AssertReporter* local_reporter = new AssertReporter();
78 base::ThreadCollisionWarner warner(local_reporter);
79 EXPECT_FALSE(local_reporter->fail_state());
81 { // Pin section.
82 DFAKE_SCOPED_RECURSIVE_LOCK(warner);
83 EXPECT_FALSE(local_reporter->fail_state());
84 { // Pin section again (allowed by DFAKE_SCOPED_RECURSIVE_LOCK)
85 DFAKE_SCOPED_RECURSIVE_LOCK(warner);
86 EXPECT_FALSE(local_reporter->fail_state());
87 } // Unpin section.
88 } // Unpin section.
90 // Check that section is not pinned
91 { // Pin section.
92 DFAKE_SCOPED_LOCK(warner);
93 EXPECT_FALSE(local_reporter->fail_state());
94 } // Unpin section.
97 TEST(ThreadCollisionTest, ScopedBookCriticalSection) {
98 AssertReporter* local_reporter = new AssertReporter();
100 base::ThreadCollisionWarner warner(local_reporter);
101 EXPECT_FALSE(local_reporter->fail_state());
103 { // Pin section.
104 DFAKE_SCOPED_LOCK(warner);
105 EXPECT_FALSE(local_reporter->fail_state());
106 } // Unpin section.
108 { // Pin section.
109 DFAKE_SCOPED_LOCK(warner);
110 EXPECT_FALSE(local_reporter->fail_state());
112 // Pin section again (not allowed by DFAKE_SCOPED_LOCK)
113 DFAKE_SCOPED_LOCK(warner);
114 EXPECT_NDEBUG_FALSE_DEBUG_TRUE(local_reporter->fail_state());
115 // Reset the status of warner for further tests.
116 local_reporter->reset();
117 } // Unpin section.
118 } // Unpin section.
121 // Pin section.
122 DFAKE_SCOPED_LOCK(warner);
123 EXPECT_FALSE(local_reporter->fail_state());
124 } // Unpin section.
127 TEST(ThreadCollisionTest, MTBookCriticalSectionTest) {
128 class NonThreadSafeQueue {
129 public:
130 explicit NonThreadSafeQueue(base::AsserterBase* asserter)
131 : push_pop_(asserter) {
134 void push(int value) {
135 DFAKE_SCOPED_LOCK_THREAD_LOCKED(push_pop_);
138 int pop() {
139 DFAKE_SCOPED_LOCK_THREAD_LOCKED(push_pop_);
140 return 0;
143 private:
144 DFAKE_MUTEX(push_pop_);
146 DISALLOW_COPY_AND_ASSIGN(NonThreadSafeQueue);
149 class QueueUser : public base::DelegateSimpleThread::Delegate {
150 public:
151 explicit QueueUser(NonThreadSafeQueue& queue)
152 : queue_(queue) {}
154 virtual void Run() OVERRIDE {
155 queue_.push(0);
156 queue_.pop();
159 private:
160 NonThreadSafeQueue& queue_;
163 AssertReporter* local_reporter = new AssertReporter();
165 NonThreadSafeQueue queue(local_reporter);
167 QueueUser queue_user_a(queue);
168 QueueUser queue_user_b(queue);
170 base::DelegateSimpleThread thread_a(&queue_user_a, "queue_user_thread_a");
171 base::DelegateSimpleThread thread_b(&queue_user_b, "queue_user_thread_b");
173 thread_a.Start();
174 thread_b.Start();
176 thread_a.Join();
177 thread_b.Join();
179 EXPECT_NDEBUG_FALSE_DEBUG_TRUE(local_reporter->fail_state());
182 TEST(ThreadCollisionTest, MTScopedBookCriticalSectionTest) {
183 // Queue with a 5 seconds push execution time, hopefuly the two used threads
184 // in the test will enter the push at same time.
185 class NonThreadSafeQueue {
186 public:
187 explicit NonThreadSafeQueue(base::AsserterBase* asserter)
188 : push_pop_(asserter) {
191 void push(int value) {
192 DFAKE_SCOPED_LOCK(push_pop_);
193 base::PlatformThread::Sleep(base::TimeDelta::FromSeconds(5));
196 int pop() {
197 DFAKE_SCOPED_LOCK(push_pop_);
198 return 0;
201 private:
202 DFAKE_MUTEX(push_pop_);
204 DISALLOW_COPY_AND_ASSIGN(NonThreadSafeQueue);
207 class QueueUser : public base::DelegateSimpleThread::Delegate {
208 public:
209 explicit QueueUser(NonThreadSafeQueue& queue)
210 : queue_(queue) {}
212 virtual void Run() OVERRIDE {
213 queue_.push(0);
214 queue_.pop();
217 private:
218 NonThreadSafeQueue& queue_;
221 AssertReporter* local_reporter = new AssertReporter();
223 NonThreadSafeQueue queue(local_reporter);
225 QueueUser queue_user_a(queue);
226 QueueUser queue_user_b(queue);
228 base::DelegateSimpleThread thread_a(&queue_user_a, "queue_user_thread_a");
229 base::DelegateSimpleThread thread_b(&queue_user_b, "queue_user_thread_b");
231 thread_a.Start();
232 thread_b.Start();
234 thread_a.Join();
235 thread_b.Join();
237 EXPECT_NDEBUG_FALSE_DEBUG_TRUE(local_reporter->fail_state());
240 TEST(ThreadCollisionTest, MTSynchedScopedBookCriticalSectionTest) {
241 // Queue with a 2 seconds push execution time, hopefuly the two used threads
242 // in the test will enter the push at same time.
243 class NonThreadSafeQueue {
244 public:
245 explicit NonThreadSafeQueue(base::AsserterBase* asserter)
246 : push_pop_(asserter) {
249 void push(int value) {
250 DFAKE_SCOPED_LOCK(push_pop_);
251 base::PlatformThread::Sleep(base::TimeDelta::FromSeconds(2));
254 int pop() {
255 DFAKE_SCOPED_LOCK(push_pop_);
256 return 0;
259 private:
260 DFAKE_MUTEX(push_pop_);
262 DISALLOW_COPY_AND_ASSIGN(NonThreadSafeQueue);
265 // This time the QueueUser class protects the non thread safe queue with
266 // a lock.
267 class QueueUser : public base::DelegateSimpleThread::Delegate {
268 public:
269 QueueUser(NonThreadSafeQueue& queue, base::Lock& lock)
270 : queue_(queue),
271 lock_(lock) {}
273 virtual void Run() OVERRIDE {
275 base::AutoLock auto_lock(lock_);
276 queue_.push(0);
279 base::AutoLock auto_lock(lock_);
280 queue_.pop();
283 private:
284 NonThreadSafeQueue& queue_;
285 base::Lock& lock_;
288 AssertReporter* local_reporter = new AssertReporter();
290 NonThreadSafeQueue queue(local_reporter);
292 base::Lock lock;
294 QueueUser queue_user_a(queue, lock);
295 QueueUser queue_user_b(queue, lock);
297 base::DelegateSimpleThread thread_a(&queue_user_a, "queue_user_thread_a");
298 base::DelegateSimpleThread thread_b(&queue_user_b, "queue_user_thread_b");
300 thread_a.Start();
301 thread_b.Start();
303 thread_a.Join();
304 thread_b.Join();
306 EXPECT_FALSE(local_reporter->fail_state());
309 TEST(ThreadCollisionTest, MTSynchedScopedRecursiveBookCriticalSectionTest) {
310 // Queue with a 2 seconds push execution time, hopefuly the two used threads
311 // in the test will enter the push at same time.
312 class NonThreadSafeQueue {
313 public:
314 explicit NonThreadSafeQueue(base::AsserterBase* asserter)
315 : push_pop_(asserter) {
318 void push(int) {
319 DFAKE_SCOPED_RECURSIVE_LOCK(push_pop_);
320 bar();
321 base::PlatformThread::Sleep(base::TimeDelta::FromSeconds(2));
324 int pop() {
325 DFAKE_SCOPED_RECURSIVE_LOCK(push_pop_);
326 return 0;
329 void bar() {
330 DFAKE_SCOPED_RECURSIVE_LOCK(push_pop_);
333 private:
334 DFAKE_MUTEX(push_pop_);
336 DISALLOW_COPY_AND_ASSIGN(NonThreadSafeQueue);
339 // This time the QueueUser class protects the non thread safe queue with
340 // a lock.
341 class QueueUser : public base::DelegateSimpleThread::Delegate {
342 public:
343 QueueUser(NonThreadSafeQueue& queue, base::Lock& lock)
344 : queue_(queue),
345 lock_(lock) {}
347 virtual void Run() OVERRIDE {
349 base::AutoLock auto_lock(lock_);
350 queue_.push(0);
353 base::AutoLock auto_lock(lock_);
354 queue_.bar();
357 base::AutoLock auto_lock(lock_);
358 queue_.pop();
361 private:
362 NonThreadSafeQueue& queue_;
363 base::Lock& lock_;
366 AssertReporter* local_reporter = new AssertReporter();
368 NonThreadSafeQueue queue(local_reporter);
370 base::Lock lock;
372 QueueUser queue_user_a(queue, lock);
373 QueueUser queue_user_b(queue, lock);
375 base::DelegateSimpleThread thread_a(&queue_user_a, "queue_user_thread_a");
376 base::DelegateSimpleThread thread_b(&queue_user_b, "queue_user_thread_b");
378 thread_a.Start();
379 thread_b.Start();
381 thread_a.Join();
382 thread_b.Join();
384 EXPECT_FALSE(local_reporter->fail_state());