blob: 48710a7f3cc508fe91c6389fe9b1b54ae246596a [file] [log] [blame]
[email protected]44106182012-04-06 03:53:021// Copyright (c) 2012 The Chromium Authors. All rights reserved.
[email protected]2d4537d52008-12-17 02:25:442// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "base/compiler_specific.h"
[email protected]3b63f8f42011-03-28 01:54:156#include "base/memory/scoped_ptr.h"
[email protected]20305ec2011-01-21 04:55:527#include "base/synchronization/lock.h"
[email protected]ce072a72010-12-31 20:02:168#include "base/threading/platform_thread.h"
[email protected]ac9ba8fe2010-12-30 18:08:369#include "base/threading/simple_thread.h"
[email protected]34b99632011-01-01 01:01:0610#include "base/threading/thread_collision_warner.h"
[email protected]2d4537d52008-12-17 02:25:4411#include "testing/gtest/include/gtest/gtest.h"
12
13// '' : local class member function does not have a body
14MSVC_PUSH_DISABLE_WARNING(4822)
15
[email protected]19256652009-01-27 20:12:3816
17#if defined(NDEBUG)
18
19// Would cause a memory leak otherwise.
20#undef DFAKE_MUTEX
21#define DFAKE_MUTEX(obj) scoped_ptr<base::AsserterBase> obj
22
23// In Release, we expect the AsserterBase::warn() to not happen.
24#define EXPECT_NDEBUG_FALSE_DEBUG_TRUE EXPECT_FALSE
25
26#else
27
28// In Debug, we expect the AsserterBase::warn() to happen.
29#define EXPECT_NDEBUG_FALSE_DEBUG_TRUE EXPECT_TRUE
30
31#endif
32
33
[email protected]2d4537d52008-12-17 02:25:4434namespace {
35
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.
39class AssertReporter : public base::AsserterBase {
40 public:
41 AssertReporter()
42 : failed_(false) {}
43
[email protected]44106182012-04-06 03:53:0244 virtual void warn() OVERRIDE {
[email protected]2d4537d52008-12-17 02:25:4445 failed_ = true;
46 }
47
48 virtual ~AssertReporter() {}
49
50 bool fail_state() const { return failed_; }
51 void reset() { failed_ = false; }
52
53 private:
54 bool failed_;
55};
56
57} // namespace
58
59TEST(ThreadCollisionTest, BookCriticalSection) {
60 AssertReporter* local_reporter = new AssertReporter();
61
62 base::ThreadCollisionWarner warner(local_reporter);
63 EXPECT_FALSE(local_reporter->fail_state());
64
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());
71 }
72 }
73}
74
75TEST(ThreadCollisionTest, ScopedRecursiveBookCriticalSection) {
76 AssertReporter* local_reporter = new AssertReporter();
77
78 base::ThreadCollisionWarner warner(local_reporter);
79 EXPECT_FALSE(local_reporter->fail_state());
80
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.
89
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.
95}
96
97TEST(ThreadCollisionTest, ScopedBookCriticalSection) {
98 AssertReporter* local_reporter = new AssertReporter();
99
100 base::ThreadCollisionWarner warner(local_reporter);
101 EXPECT_FALSE(local_reporter->fail_state());
102
103 { // Pin section.
104 DFAKE_SCOPED_LOCK(warner);
105 EXPECT_FALSE(local_reporter->fail_state());
106 } // Unpin section.
107
108 { // Pin section.
109 DFAKE_SCOPED_LOCK(warner);
110 EXPECT_FALSE(local_reporter->fail_state());
[email protected]0d02a5f2009-01-26 19:29:07111 {
112 // Pin section again (not allowed by DFAKE_SCOPED_LOCK)
[email protected]2d4537d52008-12-17 02:25:44113 DFAKE_SCOPED_LOCK(warner);
[email protected]19256652009-01-27 20:12:38114 EXPECT_NDEBUG_FALSE_DEBUG_TRUE(local_reporter->fail_state());
[email protected]2d4537d52008-12-17 02:25:44115 // Reset the status of warner for further tests.
116 local_reporter->reset();
117 } // Unpin section.
118 } // Unpin section.
119
[email protected]0d02a5f2009-01-26 19:29:07120 {
121 // Pin section.
[email protected]2d4537d52008-12-17 02:25:44122 DFAKE_SCOPED_LOCK(warner);
123 EXPECT_FALSE(local_reporter->fail_state());
124 } // Unpin section.
125}
126
127TEST(ThreadCollisionTest, MTBookCriticalSectionTest) {
128 class NonThreadSafeQueue {
129 public:
130 explicit NonThreadSafeQueue(base::AsserterBase* asserter)
[email protected]1bba17e2009-01-27 17:51:36131 : push_pop_(asserter) {
[email protected]1bba17e2009-01-27 17:51:36132 }
[email protected]2d4537d52008-12-17 02:25:44133
134 void push(int value) {
135 DFAKE_SCOPED_LOCK_THREAD_LOCKED(push_pop_);
136 }
137
138 int pop() {
139 DFAKE_SCOPED_LOCK_THREAD_LOCKED(push_pop_);
140 return 0;
141 }
142
143 private:
144 DFAKE_MUTEX(push_pop_);
145
146 DISALLOW_COPY_AND_ASSIGN(NonThreadSafeQueue);
147 };
148
149 class QueueUser : public base::DelegateSimpleThread::Delegate {
150 public:
151 explicit QueueUser(NonThreadSafeQueue& queue)
152 : queue_(queue) {}
153
[email protected]44106182012-04-06 03:53:02154 virtual void Run() OVERRIDE {
[email protected]2d4537d52008-12-17 02:25:44155 queue_.push(0);
156 queue_.pop();
157 }
158
159 private:
160 NonThreadSafeQueue& queue_;
161 };
162
163 AssertReporter* local_reporter = new AssertReporter();
164
165 NonThreadSafeQueue queue(local_reporter);
166
167 QueueUser queue_user_a(queue);
168 QueueUser queue_user_b(queue);
169
170 base::DelegateSimpleThread thread_a(&queue_user_a, "queue_user_thread_a");
171 base::DelegateSimpleThread thread_b(&queue_user_b, "queue_user_thread_b");
172
173 thread_a.Start();
174 thread_b.Start();
175
176 thread_a.Join();
177 thread_b.Join();
178
[email protected]19256652009-01-27 20:12:38179 EXPECT_NDEBUG_FALSE_DEBUG_TRUE(local_reporter->fail_state());
[email protected]2d4537d52008-12-17 02:25:44180}
181
182TEST(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)
[email protected]1bba17e2009-01-27 17:51:36188 : push_pop_(asserter) {
[email protected]1bba17e2009-01-27 17:51:36189 }
[email protected]2d4537d52008-12-17 02:25:44190
191 void push(int value) {
192 DFAKE_SCOPED_LOCK(push_pop_);
[email protected]a1b75b942011-12-31 22:53:51193 base::PlatformThread::Sleep(base::TimeDelta::FromSeconds(5));
[email protected]2d4537d52008-12-17 02:25:44194 }
195
196 int pop() {
197 DFAKE_SCOPED_LOCK(push_pop_);
198 return 0;
199 }
200
201 private:
202 DFAKE_MUTEX(push_pop_);
203
204 DISALLOW_COPY_AND_ASSIGN(NonThreadSafeQueue);
205 };
206
207 class QueueUser : public base::DelegateSimpleThread::Delegate {
208 public:
209 explicit QueueUser(NonThreadSafeQueue& queue)
210 : queue_(queue) {}
211
[email protected]44106182012-04-06 03:53:02212 virtual void Run() OVERRIDE {
[email protected]2d4537d52008-12-17 02:25:44213 queue_.push(0);
214 queue_.pop();
215 }
216
217 private:
218 NonThreadSafeQueue& queue_;
219 };
220
221 AssertReporter* local_reporter = new AssertReporter();
222
223 NonThreadSafeQueue queue(local_reporter);
224
225 QueueUser queue_user_a(queue);
226 QueueUser queue_user_b(queue);
227
228 base::DelegateSimpleThread thread_a(&queue_user_a, "queue_user_thread_a");
229 base::DelegateSimpleThread thread_b(&queue_user_b, "queue_user_thread_b");
230
231 thread_a.Start();
232 thread_b.Start();
233
234 thread_a.Join();
235 thread_b.Join();
236
[email protected]19256652009-01-27 20:12:38237 EXPECT_NDEBUG_FALSE_DEBUG_TRUE(local_reporter->fail_state());
[email protected]2d4537d52008-12-17 02:25:44238}
239
240TEST(ThreadCollisionTest, MTSynchedScopedBookCriticalSectionTest) {
[email protected]ce292012009-11-05 18:46:47241 // Queue with a 2 seconds push execution time, hopefuly the two used threads
[email protected]2d4537d52008-12-17 02:25:44242 // in the test will enter the push at same time.
243 class NonThreadSafeQueue {
244 public:
245 explicit NonThreadSafeQueue(base::AsserterBase* asserter)
[email protected]1bba17e2009-01-27 17:51:36246 : push_pop_(asserter) {
[email protected]1bba17e2009-01-27 17:51:36247 }
[email protected]2d4537d52008-12-17 02:25:44248
249 void push(int value) {
250 DFAKE_SCOPED_LOCK(push_pop_);
[email protected]a1b75b942011-12-31 22:53:51251 base::PlatformThread::Sleep(base::TimeDelta::FromSeconds(2));
[email protected]2d4537d52008-12-17 02:25:44252 }
253
254 int pop() {
255 DFAKE_SCOPED_LOCK(push_pop_);
256 return 0;
257 }
258
259 private:
260 DFAKE_MUTEX(push_pop_);
261
262 DISALLOW_COPY_AND_ASSIGN(NonThreadSafeQueue);
263 };
264
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:
[email protected]20305ec2011-01-21 04:55:52269 QueueUser(NonThreadSafeQueue& queue, base::Lock& lock)
[email protected]2d4537d52008-12-17 02:25:44270 : queue_(queue),
271 lock_(lock) {}
272
[email protected]44106182012-04-06 03:53:02273 virtual void Run() OVERRIDE {
[email protected]2d4537d52008-12-17 02:25:44274 {
[email protected]20305ec2011-01-21 04:55:52275 base::AutoLock auto_lock(lock_);
[email protected]2d4537d52008-12-17 02:25:44276 queue_.push(0);
277 }
278 {
[email protected]20305ec2011-01-21 04:55:52279 base::AutoLock auto_lock(lock_);
[email protected]2d4537d52008-12-17 02:25:44280 queue_.pop();
281 }
282 }
283 private:
284 NonThreadSafeQueue& queue_;
[email protected]20305ec2011-01-21 04:55:52285 base::Lock& lock_;
[email protected]2d4537d52008-12-17 02:25:44286 };
287
288 AssertReporter* local_reporter = new AssertReporter();
289
290 NonThreadSafeQueue queue(local_reporter);
291
[email protected]20305ec2011-01-21 04:55:52292 base::Lock lock;
[email protected]2d4537d52008-12-17 02:25:44293
294 QueueUser queue_user_a(queue, lock);
295 QueueUser queue_user_b(queue, lock);
296
297 base::DelegateSimpleThread thread_a(&queue_user_a, "queue_user_thread_a");
298 base::DelegateSimpleThread thread_b(&queue_user_b, "queue_user_thread_b");
299
300 thread_a.Start();
301 thread_b.Start();
302
303 thread_a.Join();
304 thread_b.Join();
305
306 EXPECT_FALSE(local_reporter->fail_state());
307}
308
309TEST(ThreadCollisionTest, MTSynchedScopedRecursiveBookCriticalSectionTest) {
[email protected]ce292012009-11-05 18:46:47310 // Queue with a 2 seconds push execution time, hopefuly the two used threads
[email protected]2d4537d52008-12-17 02:25:44311 // in the test will enter the push at same time.
312 class NonThreadSafeQueue {
313 public:
314 explicit NonThreadSafeQueue(base::AsserterBase* asserter)
[email protected]1bba17e2009-01-27 17:51:36315 : push_pop_(asserter) {
[email protected]1bba17e2009-01-27 17:51:36316 }
[email protected]2d4537d52008-12-17 02:25:44317
318 void push(int) {
319 DFAKE_SCOPED_RECURSIVE_LOCK(push_pop_);
320 bar();
[email protected]a1b75b942011-12-31 22:53:51321 base::PlatformThread::Sleep(base::TimeDelta::FromSeconds(2));
[email protected]2d4537d52008-12-17 02:25:44322 }
323
324 int pop() {
325 DFAKE_SCOPED_RECURSIVE_LOCK(push_pop_);
326 return 0;
327 }
328
329 void bar() {
330 DFAKE_SCOPED_RECURSIVE_LOCK(push_pop_);
331 }
332
333 private:
334 DFAKE_MUTEX(push_pop_);
335
336 DISALLOW_COPY_AND_ASSIGN(NonThreadSafeQueue);
337 };
338
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:
[email protected]20305ec2011-01-21 04:55:52343 QueueUser(NonThreadSafeQueue& queue, base::Lock& lock)
[email protected]2d4537d52008-12-17 02:25:44344 : queue_(queue),
345 lock_(lock) {}
346
[email protected]44106182012-04-06 03:53:02347 virtual void Run() OVERRIDE {
[email protected]2d4537d52008-12-17 02:25:44348 {
[email protected]20305ec2011-01-21 04:55:52349 base::AutoLock auto_lock(lock_);
[email protected]2d4537d52008-12-17 02:25:44350 queue_.push(0);
351 }
352 {
[email protected]20305ec2011-01-21 04:55:52353 base::AutoLock auto_lock(lock_);
[email protected]2d4537d52008-12-17 02:25:44354 queue_.bar();
355 }
356 {
[email protected]20305ec2011-01-21 04:55:52357 base::AutoLock auto_lock(lock_);
[email protected]2d4537d52008-12-17 02:25:44358 queue_.pop();
359 }
360 }
361 private:
362 NonThreadSafeQueue& queue_;
[email protected]20305ec2011-01-21 04:55:52363 base::Lock& lock_;
[email protected]2d4537d52008-12-17 02:25:44364 };
365
366 AssertReporter* local_reporter = new AssertReporter();
367
368 NonThreadSafeQueue queue(local_reporter);
369
[email protected]20305ec2011-01-21 04:55:52370 base::Lock lock;
[email protected]2d4537d52008-12-17 02:25:44371
372 QueueUser queue_user_a(queue, lock);
373 QueueUser queue_user_b(queue, lock);
374
375 base::DelegateSimpleThread thread_a(&queue_user_a, "queue_user_thread_a");
376 base::DelegateSimpleThread thread_b(&queue_user_b, "queue_user_thread_b");
377
378 thread_a.Start();
379 thread_b.Start();
380
381 thread_a.Join();
382 thread_b.Join();
383
384 EXPECT_FALSE(local_reporter->fail_state());
385}