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
)
152 void Run() override
{
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");
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
{
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));
195 DFAKE_SCOPED_LOCK(push_pop_
);
200 DFAKE_MUTEX(push_pop_
);
202 DISALLOW_COPY_AND_ASSIGN(NonThreadSafeQueue
);
205 class QueueUser
: public base::DelegateSimpleThread::Delegate
{
207 explicit QueueUser(NonThreadSafeQueue
& queue
)
210 void Run() override
{
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");
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
{
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));
253 DFAKE_SCOPED_LOCK(push_pop_
);
258 DFAKE_MUTEX(push_pop_
);
260 DISALLOW_COPY_AND_ASSIGN(NonThreadSafeQueue
);
263 // This time the QueueUser class protects the non thread safe queue with
265 class QueueUser
: public base::DelegateSimpleThread::Delegate
{
267 QueueUser(NonThreadSafeQueue
& queue
, base::Lock
& lock
)
271 void Run() override
{
273 base::AutoLock
auto_lock(lock_
);
277 base::AutoLock
auto_lock(lock_
);
282 NonThreadSafeQueue
& queue_
;
286 AssertReporter
* local_reporter
= new AssertReporter();
288 NonThreadSafeQueue
queue(local_reporter
);
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");
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
{
312 explicit NonThreadSafeQueue(base::AsserterBase
* asserter
)
313 : push_pop_(asserter
) {
317 DFAKE_SCOPED_RECURSIVE_LOCK(push_pop_
);
319 base::PlatformThread::Sleep(base::TimeDelta::FromSeconds(2));
323 DFAKE_SCOPED_RECURSIVE_LOCK(push_pop_
);
328 DFAKE_SCOPED_RECURSIVE_LOCK(push_pop_
);
332 DFAKE_MUTEX(push_pop_
);
334 DISALLOW_COPY_AND_ASSIGN(NonThreadSafeQueue
);
337 // This time the QueueUser class protects the non thread safe queue with
339 class QueueUser
: public base::DelegateSimpleThread::Delegate
{
341 QueueUser(NonThreadSafeQueue
& queue
, base::Lock
& lock
)
345 void Run() override
{
347 base::AutoLock
auto_lock(lock_
);
351 base::AutoLock
auto_lock(lock_
);
355 base::AutoLock
auto_lock(lock_
);
360 NonThreadSafeQueue
& queue_
;
364 AssertReporter
* local_reporter
= new AssertReporter();
366 NonThreadSafeQueue
queue(local_reporter
);
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");
382 EXPECT_FALSE(local_reporter
->fail_state());