blob: 71447efd737ce8f34d4c606e674c443b00d3c420 [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
dcheng093de9b2016-04-04 21:25:515#include "base/threading/thread_collision_warner.h"
6
7#include <memory>
8
[email protected]2d4537d52008-12-17 02:25:449#include "base/compiler_specific.h"
avi9ceb8b82015-12-24 21:53:5910#include "base/macros.h"
[email protected]20305ec2011-01-21 04:55:5211#include "base/synchronization/lock.h"
[email protected]ce072a72010-12-31 20:02:1612#include "base/threading/platform_thread.h"
[email protected]ac9ba8fe2010-12-30 18:08:3613#include "base/threading/simple_thread.h"
[email protected]2d4537d52008-12-17 02:25:4414#include "testing/gtest/include/gtest/gtest.h"
15
16// '' : local class member function does not have a body
17MSVC_PUSH_DISABLE_WARNING(4822)
18
[email protected]19256652009-01-27 20:12:3819
20#if defined(NDEBUG)
21
22// Would cause a memory leak otherwise.
23#undef DFAKE_MUTEX
dcheng093de9b2016-04-04 21:25:5124#define DFAKE_MUTEX(obj) std::unique_ptr<base::AsserterBase> obj
[email protected]19256652009-01-27 20:12:3825
26// In Release, we expect the AsserterBase::warn() to not happen.
27#define EXPECT_NDEBUG_FALSE_DEBUG_TRUE EXPECT_FALSE
28
29#else
30
31// In Debug, we expect the AsserterBase::warn() to happen.
32#define EXPECT_NDEBUG_FALSE_DEBUG_TRUE EXPECT_TRUE
33
34#endif
35
36
[email protected]2d4537d52008-12-17 02:25:4437namespace {
38
39// This is the asserter used with ThreadCollisionWarner instead of the default
40// DCheckAsserter. The method fail_state is used to know if a collision took
41// place.
42class AssertReporter : public base::AsserterBase {
43 public:
44 AssertReporter()
45 : failed_(false) {}
46
dcheng56488182014-10-21 10:54:5147 void warn() override { failed_ = true; }
[email protected]2d4537d52008-12-17 02:25:4448
dcheng56488182014-10-21 10:54:5149 ~AssertReporter() override {}
[email protected]2d4537d52008-12-17 02:25:4450
51 bool fail_state() const { return failed_; }
52 void reset() { failed_ = false; }
53
54 private:
55 bool failed_;
56};
57
58} // namespace
59
60TEST(ThreadCollisionTest, BookCriticalSection) {
61 AssertReporter* local_reporter = new AssertReporter();
62
63 base::ThreadCollisionWarner warner(local_reporter);
64 EXPECT_FALSE(local_reporter->fail_state());
65
66 { // Pin section.
67 DFAKE_SCOPED_LOCK_THREAD_LOCKED(warner);
68 EXPECT_FALSE(local_reporter->fail_state());
69 { // Pin section.
70 DFAKE_SCOPED_LOCK_THREAD_LOCKED(warner);
71 EXPECT_FALSE(local_reporter->fail_state());
72 }
73 }
74}
75
76TEST(ThreadCollisionTest, ScopedRecursiveBookCriticalSection) {
77 AssertReporter* local_reporter = new AssertReporter();
78
79 base::ThreadCollisionWarner warner(local_reporter);
80 EXPECT_FALSE(local_reporter->fail_state());
81
82 { // Pin section.
83 DFAKE_SCOPED_RECURSIVE_LOCK(warner);
84 EXPECT_FALSE(local_reporter->fail_state());
85 { // Pin section again (allowed by DFAKE_SCOPED_RECURSIVE_LOCK)
86 DFAKE_SCOPED_RECURSIVE_LOCK(warner);
87 EXPECT_FALSE(local_reporter->fail_state());
88 } // Unpin section.
89 } // Unpin section.
90
91 // Check that section is not pinned
92 { // Pin section.
93 DFAKE_SCOPED_LOCK(warner);
94 EXPECT_FALSE(local_reporter->fail_state());
95 } // Unpin section.
96}
97
98TEST(ThreadCollisionTest, ScopedBookCriticalSection) {
99 AssertReporter* local_reporter = new AssertReporter();
100
101 base::ThreadCollisionWarner warner(local_reporter);
102 EXPECT_FALSE(local_reporter->fail_state());
103
104 { // Pin section.
105 DFAKE_SCOPED_LOCK(warner);
106 EXPECT_FALSE(local_reporter->fail_state());
107 } // Unpin section.
108
109 { // Pin section.
110 DFAKE_SCOPED_LOCK(warner);
111 EXPECT_FALSE(local_reporter->fail_state());
[email protected]0d02a5f2009-01-26 19:29:07112 {
113 // Pin section again (not allowed by DFAKE_SCOPED_LOCK)
[email protected]2d4537d52008-12-17 02:25:44114 DFAKE_SCOPED_LOCK(warner);
[email protected]19256652009-01-27 20:12:38115 EXPECT_NDEBUG_FALSE_DEBUG_TRUE(local_reporter->fail_state());
[email protected]2d4537d52008-12-17 02:25:44116 // Reset the status of warner for further tests.
117 local_reporter->reset();
118 } // Unpin section.
119 } // Unpin section.
120
[email protected]0d02a5f2009-01-26 19:29:07121 {
122 // Pin section.
[email protected]2d4537d52008-12-17 02:25:44123 DFAKE_SCOPED_LOCK(warner);
124 EXPECT_FALSE(local_reporter->fail_state());
125 } // Unpin section.
126}
127
128TEST(ThreadCollisionTest, MTBookCriticalSectionTest) {
129 class NonThreadSafeQueue {
130 public:
131 explicit NonThreadSafeQueue(base::AsserterBase* asserter)
[email protected]1bba17e2009-01-27 17:51:36132 : push_pop_(asserter) {
[email protected]1bba17e2009-01-27 17:51:36133 }
[email protected]2d4537d52008-12-17 02:25:44134
135 void push(int value) {
136 DFAKE_SCOPED_LOCK_THREAD_LOCKED(push_pop_);
137 }
138
139 int pop() {
140 DFAKE_SCOPED_LOCK_THREAD_LOCKED(push_pop_);
141 return 0;
142 }
143
144 private:
145 DFAKE_MUTEX(push_pop_);
146
147 DISALLOW_COPY_AND_ASSIGN(NonThreadSafeQueue);
148 };
149
150 class QueueUser : public base::DelegateSimpleThread::Delegate {
151 public:
danakj9fdfd052015-03-10 01:48:05152 explicit QueueUser(NonThreadSafeQueue* queue) : queue_(queue) {}
[email protected]2d4537d52008-12-17 02:25:44153
dcheng56488182014-10-21 10:54:51154 void Run() override {
danakj9fdfd052015-03-10 01:48:05155 queue_->push(0);
156 queue_->pop();
[email protected]2d4537d52008-12-17 02:25:44157 }
158
159 private:
danakj9fdfd052015-03-10 01:48:05160 NonThreadSafeQueue* queue_;
[email protected]2d4537d52008-12-17 02:25:44161 };
162
163 AssertReporter* local_reporter = new AssertReporter();
164
165 NonThreadSafeQueue queue(local_reporter);
166
danakj9fdfd052015-03-10 01:48:05167 QueueUser queue_user_a(&queue);
168 QueueUser queue_user_b(&queue);
[email protected]2d4537d52008-12-17 02:25:44169
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:
danakj9fdfd052015-03-10 01:48:05209 explicit QueueUser(NonThreadSafeQueue* queue) : queue_(queue) {}
[email protected]2d4537d52008-12-17 02:25:44210
dcheng56488182014-10-21 10:54:51211 void Run() override {
danakj9fdfd052015-03-10 01:48:05212 queue_->push(0);
213 queue_->pop();
[email protected]2d4537d52008-12-17 02:25:44214 }
215
216 private:
danakj9fdfd052015-03-10 01:48:05217 NonThreadSafeQueue* queue_;
[email protected]2d4537d52008-12-17 02:25:44218 };
219
220 AssertReporter* local_reporter = new AssertReporter();
221
222 NonThreadSafeQueue queue(local_reporter);
223
danakj9fdfd052015-03-10 01:48:05224 QueueUser queue_user_a(&queue);
225 QueueUser queue_user_b(&queue);
[email protected]2d4537d52008-12-17 02:25:44226
227 base::DelegateSimpleThread thread_a(&queue_user_a, "queue_user_thread_a");
228 base::DelegateSimpleThread thread_b(&queue_user_b, "queue_user_thread_b");
229
230 thread_a.Start();
231 thread_b.Start();
232
233 thread_a.Join();
234 thread_b.Join();
235
[email protected]19256652009-01-27 20:12:38236 EXPECT_NDEBUG_FALSE_DEBUG_TRUE(local_reporter->fail_state());
[email protected]2d4537d52008-12-17 02:25:44237}
238
239TEST(ThreadCollisionTest, MTSynchedScopedBookCriticalSectionTest) {
[email protected]ce292012009-11-05 18:46:47240 // Queue with a 2 seconds push execution time, hopefuly the two used threads
[email protected]2d4537d52008-12-17 02:25:44241 // in the test will enter the push at same time.
242 class NonThreadSafeQueue {
243 public:
244 explicit NonThreadSafeQueue(base::AsserterBase* asserter)
[email protected]1bba17e2009-01-27 17:51:36245 : push_pop_(asserter) {
[email protected]1bba17e2009-01-27 17:51:36246 }
[email protected]2d4537d52008-12-17 02:25:44247
248 void push(int value) {
249 DFAKE_SCOPED_LOCK(push_pop_);
[email protected]a1b75b942011-12-31 22:53:51250 base::PlatformThread::Sleep(base::TimeDelta::FromSeconds(2));
[email protected]2d4537d52008-12-17 02:25:44251 }
252
253 int pop() {
254 DFAKE_SCOPED_LOCK(push_pop_);
255 return 0;
256 }
257
258 private:
259 DFAKE_MUTEX(push_pop_);
260
261 DISALLOW_COPY_AND_ASSIGN(NonThreadSafeQueue);
262 };
263
264 // This time the QueueUser class protects the non thread safe queue with
265 // a lock.
266 class QueueUser : public base::DelegateSimpleThread::Delegate {
267 public:
danakj9fdfd052015-03-10 01:48:05268 QueueUser(NonThreadSafeQueue* queue, base::Lock* lock)
269 : queue_(queue), lock_(lock) {}
[email protected]2d4537d52008-12-17 02:25:44270
dcheng56488182014-10-21 10:54:51271 void Run() override {
[email protected]2d4537d52008-12-17 02:25:44272 {
danakj9fdfd052015-03-10 01:48:05273 base::AutoLock auto_lock(*lock_);
274 queue_->push(0);
[email protected]2d4537d52008-12-17 02:25:44275 }
276 {
danakj9fdfd052015-03-10 01:48:05277 base::AutoLock auto_lock(*lock_);
278 queue_->pop();
[email protected]2d4537d52008-12-17 02:25:44279 }
280 }
281 private:
danakj9fdfd052015-03-10 01:48:05282 NonThreadSafeQueue* queue_;
283 base::Lock* lock_;
[email protected]2d4537d52008-12-17 02:25:44284 };
285
286 AssertReporter* local_reporter = new AssertReporter();
287
288 NonThreadSafeQueue queue(local_reporter);
289
[email protected]20305ec2011-01-21 04:55:52290 base::Lock lock;
[email protected]2d4537d52008-12-17 02:25:44291
danakj9fdfd052015-03-10 01:48:05292 QueueUser queue_user_a(&queue, &lock);
293 QueueUser queue_user_b(&queue, &lock);
[email protected]2d4537d52008-12-17 02:25:44294
295 base::DelegateSimpleThread thread_a(&queue_user_a, "queue_user_thread_a");
296 base::DelegateSimpleThread thread_b(&queue_user_b, "queue_user_thread_b");
297
298 thread_a.Start();
299 thread_b.Start();
300
301 thread_a.Join();
302 thread_b.Join();
303
304 EXPECT_FALSE(local_reporter->fail_state());
305}
306
307TEST(ThreadCollisionTest, MTSynchedScopedRecursiveBookCriticalSectionTest) {
[email protected]ce292012009-11-05 18:46:47308 // Queue with a 2 seconds push execution time, hopefuly the two used threads
[email protected]2d4537d52008-12-17 02:25:44309 // in the test will enter the push at same time.
310 class NonThreadSafeQueue {
311 public:
312 explicit NonThreadSafeQueue(base::AsserterBase* asserter)
[email protected]1bba17e2009-01-27 17:51:36313 : push_pop_(asserter) {
[email protected]1bba17e2009-01-27 17:51:36314 }
[email protected]2d4537d52008-12-17 02:25:44315
316 void push(int) {
317 DFAKE_SCOPED_RECURSIVE_LOCK(push_pop_);
318 bar();
[email protected]a1b75b942011-12-31 22:53:51319 base::PlatformThread::Sleep(base::TimeDelta::FromSeconds(2));
[email protected]2d4537d52008-12-17 02:25:44320 }
321
322 int pop() {
323 DFAKE_SCOPED_RECURSIVE_LOCK(push_pop_);
324 return 0;
325 }
326
327 void bar() {
328 DFAKE_SCOPED_RECURSIVE_LOCK(push_pop_);
329 }
330
331 private:
332 DFAKE_MUTEX(push_pop_);
333
334 DISALLOW_COPY_AND_ASSIGN(NonThreadSafeQueue);
335 };
336
337 // This time the QueueUser class protects the non thread safe queue with
338 // a lock.
339 class QueueUser : public base::DelegateSimpleThread::Delegate {
340 public:
danakj9fdfd052015-03-10 01:48:05341 QueueUser(NonThreadSafeQueue* queue, base::Lock* lock)
342 : queue_(queue), lock_(lock) {}
[email protected]2d4537d52008-12-17 02:25:44343
dcheng56488182014-10-21 10:54:51344 void Run() override {
[email protected]2d4537d52008-12-17 02:25:44345 {
danakj9fdfd052015-03-10 01:48:05346 base::AutoLock auto_lock(*lock_);
347 queue_->push(0);
[email protected]2d4537d52008-12-17 02:25:44348 }
349 {
danakj9fdfd052015-03-10 01:48:05350 base::AutoLock auto_lock(*lock_);
351 queue_->bar();
[email protected]2d4537d52008-12-17 02:25:44352 }
353 {
danakj9fdfd052015-03-10 01:48:05354 base::AutoLock auto_lock(*lock_);
355 queue_->pop();
[email protected]2d4537d52008-12-17 02:25:44356 }
357 }
358 private:
danakj9fdfd052015-03-10 01:48:05359 NonThreadSafeQueue* queue_;
360 base::Lock* lock_;
[email protected]2d4537d52008-12-17 02:25:44361 };
362
363 AssertReporter* local_reporter = new AssertReporter();
364
365 NonThreadSafeQueue queue(local_reporter);
366
[email protected]20305ec2011-01-21 04:55:52367 base::Lock lock;
[email protected]2d4537d52008-12-17 02:25:44368
danakj9fdfd052015-03-10 01:48:05369 QueueUser queue_user_a(&queue, &lock);
370 QueueUser queue_user_b(&queue, &lock);
[email protected]2d4537d52008-12-17 02:25:44371
372 base::DelegateSimpleThread thread_a(&queue_user_a, "queue_user_thread_a");
373 base::DelegateSimpleThread thread_b(&queue_user_b, "queue_user_thread_b");
374
375 thread_a.Start();
376 thread_b.Start();
377
378 thread_a.Join();
379 thread_b.Join();
380
381 EXPECT_FALSE(local_reporter->fail_state());
382}