Port Android relocation packer to chromium build
[chromium-blink-merge.git] / base / threading / thread_collision_warner_unittest.cc
blobd7ce79ec3787393adf29767035ca05759e42a7b1
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) : queue_(queue) {}
151 void Run() override {
152 queue_->push(0);
153 queue_->pop();
156 private:
157 NonThreadSafeQueue* queue_;
160 AssertReporter* local_reporter = new AssertReporter();
162 NonThreadSafeQueue queue(local_reporter);
164 QueueUser queue_user_a(&queue);
165 QueueUser queue_user_b(&queue);
167 base::DelegateSimpleThread thread_a(&queue_user_a, "queue_user_thread_a");
168 base::DelegateSimpleThread thread_b(&queue_user_b, "queue_user_thread_b");
170 thread_a.Start();
171 thread_b.Start();
173 thread_a.Join();
174 thread_b.Join();
176 EXPECT_NDEBUG_FALSE_DEBUG_TRUE(local_reporter->fail_state());
179 TEST(ThreadCollisionTest, MTScopedBookCriticalSectionTest) {
180 // Queue with a 5 seconds push execution time, hopefuly the two used threads
181 // in the test will enter the push at same time.
182 class NonThreadSafeQueue {
183 public:
184 explicit NonThreadSafeQueue(base::AsserterBase* asserter)
185 : push_pop_(asserter) {
188 void push(int value) {
189 DFAKE_SCOPED_LOCK(push_pop_);
190 base::PlatformThread::Sleep(base::TimeDelta::FromSeconds(5));
193 int pop() {
194 DFAKE_SCOPED_LOCK(push_pop_);
195 return 0;
198 private:
199 DFAKE_MUTEX(push_pop_);
201 DISALLOW_COPY_AND_ASSIGN(NonThreadSafeQueue);
204 class QueueUser : public base::DelegateSimpleThread::Delegate {
205 public:
206 explicit QueueUser(NonThreadSafeQueue* queue) : queue_(queue) {}
208 void Run() override {
209 queue_->push(0);
210 queue_->pop();
213 private:
214 NonThreadSafeQueue* queue_;
217 AssertReporter* local_reporter = new AssertReporter();
219 NonThreadSafeQueue queue(local_reporter);
221 QueueUser queue_user_a(&queue);
222 QueueUser queue_user_b(&queue);
224 base::DelegateSimpleThread thread_a(&queue_user_a, "queue_user_thread_a");
225 base::DelegateSimpleThread thread_b(&queue_user_b, "queue_user_thread_b");
227 thread_a.Start();
228 thread_b.Start();
230 thread_a.Join();
231 thread_b.Join();
233 EXPECT_NDEBUG_FALSE_DEBUG_TRUE(local_reporter->fail_state());
236 TEST(ThreadCollisionTest, MTSynchedScopedBookCriticalSectionTest) {
237 // Queue with a 2 seconds push execution time, hopefuly the two used threads
238 // in the test will enter the push at same time.
239 class NonThreadSafeQueue {
240 public:
241 explicit NonThreadSafeQueue(base::AsserterBase* asserter)
242 : push_pop_(asserter) {
245 void push(int value) {
246 DFAKE_SCOPED_LOCK(push_pop_);
247 base::PlatformThread::Sleep(base::TimeDelta::FromSeconds(2));
250 int pop() {
251 DFAKE_SCOPED_LOCK(push_pop_);
252 return 0;
255 private:
256 DFAKE_MUTEX(push_pop_);
258 DISALLOW_COPY_AND_ASSIGN(NonThreadSafeQueue);
261 // This time the QueueUser class protects the non thread safe queue with
262 // a lock.
263 class QueueUser : public base::DelegateSimpleThread::Delegate {
264 public:
265 QueueUser(NonThreadSafeQueue* queue, base::Lock* lock)
266 : queue_(queue), lock_(lock) {}
268 void Run() override {
270 base::AutoLock auto_lock(*lock_);
271 queue_->push(0);
274 base::AutoLock auto_lock(*lock_);
275 queue_->pop();
278 private:
279 NonThreadSafeQueue* queue_;
280 base::Lock* lock_;
283 AssertReporter* local_reporter = new AssertReporter();
285 NonThreadSafeQueue queue(local_reporter);
287 base::Lock lock;
289 QueueUser queue_user_a(&queue, &lock);
290 QueueUser queue_user_b(&queue, &lock);
292 base::DelegateSimpleThread thread_a(&queue_user_a, "queue_user_thread_a");
293 base::DelegateSimpleThread thread_b(&queue_user_b, "queue_user_thread_b");
295 thread_a.Start();
296 thread_b.Start();
298 thread_a.Join();
299 thread_b.Join();
301 EXPECT_FALSE(local_reporter->fail_state());
304 TEST(ThreadCollisionTest, MTSynchedScopedRecursiveBookCriticalSectionTest) {
305 // Queue with a 2 seconds push execution time, hopefuly the two used threads
306 // in the test will enter the push at same time.
307 class NonThreadSafeQueue {
308 public:
309 explicit NonThreadSafeQueue(base::AsserterBase* asserter)
310 : push_pop_(asserter) {
313 void push(int) {
314 DFAKE_SCOPED_RECURSIVE_LOCK(push_pop_);
315 bar();
316 base::PlatformThread::Sleep(base::TimeDelta::FromSeconds(2));
319 int pop() {
320 DFAKE_SCOPED_RECURSIVE_LOCK(push_pop_);
321 return 0;
324 void bar() {
325 DFAKE_SCOPED_RECURSIVE_LOCK(push_pop_);
328 private:
329 DFAKE_MUTEX(push_pop_);
331 DISALLOW_COPY_AND_ASSIGN(NonThreadSafeQueue);
334 // This time the QueueUser class protects the non thread safe queue with
335 // a lock.
336 class QueueUser : public base::DelegateSimpleThread::Delegate {
337 public:
338 QueueUser(NonThreadSafeQueue* queue, base::Lock* lock)
339 : queue_(queue), lock_(lock) {}
341 void Run() override {
343 base::AutoLock auto_lock(*lock_);
344 queue_->push(0);
347 base::AutoLock auto_lock(*lock_);
348 queue_->bar();
351 base::AutoLock auto_lock(*lock_);
352 queue_->pop();
355 private:
356 NonThreadSafeQueue* queue_;
357 base::Lock* lock_;
360 AssertReporter* local_reporter = new AssertReporter();
362 NonThreadSafeQueue queue(local_reporter);
364 base::Lock lock;
366 QueueUser queue_user_a(&queue, &lock);
367 QueueUser queue_user_b(&queue, &lock);
369 base::DelegateSimpleThread thread_a(&queue_user_a, "queue_user_thread_a");
370 base::DelegateSimpleThread thread_b(&queue_user_b, "queue_user_thread_b");
372 thread_a.Start();
373 thread_b.Start();
375 thread_a.Join();
376 thread_b.Join();
378 EXPECT_FALSE(local_reporter->fail_state());