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 virtual void warn() OVERRIDE
{
48 virtual ~AssertReporter() {}
50 bool fail_state() const { return failed_
; }
51 void reset() { failed_
= false; }
59 TEST(ThreadCollisionTest
, BookCriticalSection
) {
60 AssertReporter
* local_reporter
= new AssertReporter();
62 base::ThreadCollisionWarner
warner(local_reporter
);
63 EXPECT_FALSE(local_reporter
->fail_state());
66 DFAKE_SCOPED_LOCK_THREAD_LOCKED(warner
);
67 EXPECT_FALSE(local_reporter
->fail_state());
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());
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());
90 // Check that section is not pinned
92 DFAKE_SCOPED_LOCK(warner
);
93 EXPECT_FALSE(local_reporter
->fail_state());
97 TEST(ThreadCollisionTest
, ScopedBookCriticalSection
) {
98 AssertReporter
* local_reporter
= new AssertReporter();
100 base::ThreadCollisionWarner
warner(local_reporter
);
101 EXPECT_FALSE(local_reporter
->fail_state());
104 DFAKE_SCOPED_LOCK(warner
);
105 EXPECT_FALSE(local_reporter
->fail_state());
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();
122 DFAKE_SCOPED_LOCK(warner
);
123 EXPECT_FALSE(local_reporter
->fail_state());
127 TEST(ThreadCollisionTest
, MTBookCriticalSectionTest
) {
128 class NonThreadSafeQueue
{
130 explicit NonThreadSafeQueue(base::AsserterBase
* asserter
)
131 : push_pop_(asserter
) {
134 void push(int value
) {
135 DFAKE_SCOPED_LOCK_THREAD_LOCKED(push_pop_
);
139 DFAKE_SCOPED_LOCK_THREAD_LOCKED(push_pop_
);
144 DFAKE_MUTEX(push_pop_
);
146 DISALLOW_COPY_AND_ASSIGN(NonThreadSafeQueue
);
149 class QueueUser
: public base::DelegateSimpleThread::Delegate
{
151 explicit QueueUser(NonThreadSafeQueue
& queue
)
154 virtual void Run() OVERRIDE
{
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");
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
{
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));
197 DFAKE_SCOPED_LOCK(push_pop_
);
202 DFAKE_MUTEX(push_pop_
);
204 DISALLOW_COPY_AND_ASSIGN(NonThreadSafeQueue
);
207 class QueueUser
: public base::DelegateSimpleThread::Delegate
{
209 explicit QueueUser(NonThreadSafeQueue
& queue
)
212 virtual void Run() OVERRIDE
{
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");
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
{
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));
255 DFAKE_SCOPED_LOCK(push_pop_
);
260 DFAKE_MUTEX(push_pop_
);
262 DISALLOW_COPY_AND_ASSIGN(NonThreadSafeQueue
);
265 // This time the QueueUser class protects the non thread safe queue with
267 class QueueUser
: public base::DelegateSimpleThread::Delegate
{
269 QueueUser(NonThreadSafeQueue
& queue
, base::Lock
& lock
)
273 virtual void Run() OVERRIDE
{
275 base::AutoLock
auto_lock(lock_
);
279 base::AutoLock
auto_lock(lock_
);
284 NonThreadSafeQueue
& queue_
;
288 AssertReporter
* local_reporter
= new AssertReporter();
290 NonThreadSafeQueue
queue(local_reporter
);
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");
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
{
314 explicit NonThreadSafeQueue(base::AsserterBase
* asserter
)
315 : push_pop_(asserter
) {
319 DFAKE_SCOPED_RECURSIVE_LOCK(push_pop_
);
321 base::PlatformThread::Sleep(base::TimeDelta::FromSeconds(2));
325 DFAKE_SCOPED_RECURSIVE_LOCK(push_pop_
);
330 DFAKE_SCOPED_RECURSIVE_LOCK(push_pop_
);
334 DFAKE_MUTEX(push_pop_
);
336 DISALLOW_COPY_AND_ASSIGN(NonThreadSafeQueue
);
339 // This time the QueueUser class protects the non thread safe queue with
341 class QueueUser
: public base::DelegateSimpleThread::Delegate
{
343 QueueUser(NonThreadSafeQueue
& queue
, base::Lock
& lock
)
347 virtual void Run() OVERRIDE
{
349 base::AutoLock
auto_lock(lock_
);
353 base::AutoLock
auto_lock(lock_
);
357 base::AutoLock
auto_lock(lock_
);
362 NonThreadSafeQueue
& queue_
;
366 AssertReporter
* local_reporter
= new AssertReporter();
368 NonThreadSafeQueue
queue(local_reporter
);
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");
384 EXPECT_FALSE(local_reporter
->fail_state());