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)
19 // Would cause a memory leak otherwise.
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
28 // In Debug, we expect the AsserterBase::warn() to happen.
29 #define EXPECT_NDEBUG_FALSE_DEBUG_TRUE EXPECT_TRUE
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
39 class AssertReporter
: public base::AsserterBase
{
44 void warn() override
{ failed_
= true; }
46 ~AssertReporter() override
{}
48 bool fail_state() const { return failed_
; }
49 void reset() { failed_
= false; }
57 TEST(ThreadCollisionTest
, BookCriticalSection
) {
58 AssertReporter
* local_reporter
= new AssertReporter();
60 base::ThreadCollisionWarner
warner(local_reporter
);
61 EXPECT_FALSE(local_reporter
->fail_state());
64 DFAKE_SCOPED_LOCK_THREAD_LOCKED(warner
);
65 EXPECT_FALSE(local_reporter
->fail_state());
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());
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());
88 // Check that section is not pinned
90 DFAKE_SCOPED_LOCK(warner
);
91 EXPECT_FALSE(local_reporter
->fail_state());
95 TEST(ThreadCollisionTest
, ScopedBookCriticalSection
) {
96 AssertReporter
* local_reporter
= new AssertReporter();
98 base::ThreadCollisionWarner
warner(local_reporter
);
99 EXPECT_FALSE(local_reporter
->fail_state());
102 DFAKE_SCOPED_LOCK(warner
);
103 EXPECT_FALSE(local_reporter
->fail_state());
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();
120 DFAKE_SCOPED_LOCK(warner
);
121 EXPECT_FALSE(local_reporter
->fail_state());
125 TEST(ThreadCollisionTest
, MTBookCriticalSectionTest
) {
126 class NonThreadSafeQueue
{
128 explicit NonThreadSafeQueue(base::AsserterBase
* asserter
)
129 : push_pop_(asserter
) {
132 void push(int value
) {
133 DFAKE_SCOPED_LOCK_THREAD_LOCKED(push_pop_
);
137 DFAKE_SCOPED_LOCK_THREAD_LOCKED(push_pop_
);
142 DFAKE_MUTEX(push_pop_
);
144 DISALLOW_COPY_AND_ASSIGN(NonThreadSafeQueue
);
147 class QueueUser
: public base::DelegateSimpleThread::Delegate
{
149 explicit QueueUser(NonThreadSafeQueue
* queue
) : queue_(queue
) {}
151 void Run() override
{
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");
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
{
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));
194 DFAKE_SCOPED_LOCK(push_pop_
);
199 DFAKE_MUTEX(push_pop_
);
201 DISALLOW_COPY_AND_ASSIGN(NonThreadSafeQueue
);
204 class QueueUser
: public base::DelegateSimpleThread::Delegate
{
206 explicit QueueUser(NonThreadSafeQueue
* queue
) : queue_(queue
) {}
208 void Run() override
{
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");
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
{
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));
251 DFAKE_SCOPED_LOCK(push_pop_
);
256 DFAKE_MUTEX(push_pop_
);
258 DISALLOW_COPY_AND_ASSIGN(NonThreadSafeQueue
);
261 // This time the QueueUser class protects the non thread safe queue with
263 class QueueUser
: public base::DelegateSimpleThread::Delegate
{
265 QueueUser(NonThreadSafeQueue
* queue
, base::Lock
* lock
)
266 : queue_(queue
), lock_(lock
) {}
268 void Run() override
{
270 base::AutoLock
auto_lock(*lock_
);
274 base::AutoLock
auto_lock(*lock_
);
279 NonThreadSafeQueue
* queue_
;
283 AssertReporter
* local_reporter
= new AssertReporter();
285 NonThreadSafeQueue
queue(local_reporter
);
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");
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
{
309 explicit NonThreadSafeQueue(base::AsserterBase
* asserter
)
310 : push_pop_(asserter
) {
314 DFAKE_SCOPED_RECURSIVE_LOCK(push_pop_
);
316 base::PlatformThread::Sleep(base::TimeDelta::FromSeconds(2));
320 DFAKE_SCOPED_RECURSIVE_LOCK(push_pop_
);
325 DFAKE_SCOPED_RECURSIVE_LOCK(push_pop_
);
329 DFAKE_MUTEX(push_pop_
);
331 DISALLOW_COPY_AND_ASSIGN(NonThreadSafeQueue
);
334 // This time the QueueUser class protects the non thread safe queue with
336 class QueueUser
: public base::DelegateSimpleThread::Delegate
{
338 QueueUser(NonThreadSafeQueue
* queue
, base::Lock
* lock
)
339 : queue_(queue
), lock_(lock
) {}
341 void Run() override
{
343 base::AutoLock
auto_lock(*lock_
);
347 base::AutoLock
auto_lock(*lock_
);
351 base::AutoLock
auto_lock(*lock_
);
356 NonThreadSafeQueue
* queue_
;
360 AssertReporter
* local_reporter
= new AssertReporter();
362 NonThreadSafeQueue
queue(local_reporter
);
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");
378 EXPECT_FALSE(local_reporter
->fail_state());