| OLD | NEW |
| (Empty) |
| 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. | |
| 4 | |
| 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" | |
| 12 | |
| 13 // '' : local class member function does not have a body | |
| 14 MSVC_PUSH_DISABLE_WARNING(4822) | |
| 15 | |
| 16 | |
| 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 | |
| 34 namespace { | |
| 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. | |
| 39 class AssertReporter : public base::AsserterBase { | |
| 40 public: | |
| 41 AssertReporter() | |
| 42 : failed_(false) {} | |
| 43 | |
| 44 void warn() override { failed_ = true; } | |
| 45 | |
| 46 ~AssertReporter() override {} | |
| 47 | |
| 48 bool fail_state() const { return failed_; } | |
| 49 void reset() { failed_ = false; } | |
| 50 | |
| 51 private: | |
| 52 bool failed_; | |
| 53 }; | |
| 54 | |
| 55 } // namespace | |
| 56 | |
| 57 TEST(ThreadCollisionTest, BookCriticalSection) { | |
| 58 AssertReporter* local_reporter = new AssertReporter(); | |
| 59 | |
| 60 base::ThreadCollisionWarner warner(local_reporter); | |
| 61 EXPECT_FALSE(local_reporter->fail_state()); | |
| 62 | |
| 63 { // Pin section. | |
| 64 DFAKE_SCOPED_LOCK_THREAD_LOCKED(warner); | |
| 65 EXPECT_FALSE(local_reporter->fail_state()); | |
| 66 { // Pin section. | |
| 67 DFAKE_SCOPED_LOCK_THREAD_LOCKED(warner); | |
| 68 EXPECT_FALSE(local_reporter->fail_state()); | |
| 69 } | |
| 70 } | |
| 71 } | |
| 72 | |
| 73 TEST(ThreadCollisionTest, ScopedRecursiveBookCriticalSection) { | |
| 74 AssertReporter* local_reporter = new AssertReporter(); | |
| 75 | |
| 76 base::ThreadCollisionWarner warner(local_reporter); | |
| 77 EXPECT_FALSE(local_reporter->fail_state()); | |
| 78 | |
| 79 { // Pin section. | |
| 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()); | |
| 85 } // Unpin section. | |
| 86 } // Unpin section. | |
| 87 | |
| 88 // Check that section is not pinned | |
| 89 { // Pin section. | |
| 90 DFAKE_SCOPED_LOCK(warner); | |
| 91 EXPECT_FALSE(local_reporter->fail_state()); | |
| 92 } // Unpin section. | |
| 93 } | |
| 94 | |
| 95 TEST(ThreadCollisionTest, ScopedBookCriticalSection) { | |
| 96 AssertReporter* local_reporter = new AssertReporter(); | |
| 97 | |
| 98 base::ThreadCollisionWarner warner(local_reporter); | |
| 99 EXPECT_FALSE(local_reporter->fail_state()); | |
| 100 | |
| 101 { // Pin section. | |
| 102 DFAKE_SCOPED_LOCK(warner); | |
| 103 EXPECT_FALSE(local_reporter->fail_state()); | |
| 104 } // Unpin section. | |
| 105 | |
| 106 { // Pin section. | |
| 107 DFAKE_SCOPED_LOCK(warner); | |
| 108 EXPECT_FALSE(local_reporter->fail_state()); | |
| 109 { | |
| 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(); | |
| 115 } // Unpin section. | |
| 116 } // Unpin section. | |
| 117 | |
| 118 { | |
| 119 // Pin section. | |
| 120 DFAKE_SCOPED_LOCK(warner); | |
| 121 EXPECT_FALSE(local_reporter->fail_state()); | |
| 122 } // Unpin section. | |
| 123 } | |
| 124 | |
| 125 TEST(ThreadCollisionTest, MTBookCriticalSectionTest) { | |
| 126 class NonThreadSafeQueue { | |
| 127 public: | |
| 128 explicit NonThreadSafeQueue(base::AsserterBase* asserter) | |
| 129 : push_pop_(asserter) { | |
| 130 } | |
| 131 | |
| 132 void push(int value) { | |
| 133 DFAKE_SCOPED_LOCK_THREAD_LOCKED(push_pop_); | |
| 134 } | |
| 135 | |
| 136 int pop() { | |
| 137 DFAKE_SCOPED_LOCK_THREAD_LOCKED(push_pop_); | |
| 138 return 0; | |
| 139 } | |
| 140 | |
| 141 private: | |
| 142 DFAKE_MUTEX(push_pop_); | |
| 143 | |
| 144 DISALLOW_COPY_AND_ASSIGN(NonThreadSafeQueue); | |
| 145 }; | |
| 146 | |
| 147 class QueueUser : public base::DelegateSimpleThread::Delegate { | |
| 148 public: | |
| 149 explicit QueueUser(NonThreadSafeQueue* queue) : queue_(queue) {} | |
| 150 | |
| 151 void Run() override { | |
| 152 queue_->push(0); | |
| 153 queue_->pop(); | |
| 154 } | |
| 155 | |
| 156 private: | |
| 157 NonThreadSafeQueue* queue_; | |
| 158 }; | |
| 159 | |
| 160 AssertReporter* local_reporter = new AssertReporter(); | |
| 161 | |
| 162 NonThreadSafeQueue queue(local_reporter); | |
| 163 | |
| 164 QueueUser queue_user_a(&queue); | |
| 165 QueueUser queue_user_b(&queue); | |
| 166 | |
| 167 base::DelegateSimpleThread thread_a(&queue_user_a, "queue_user_thread_a"); | |
| 168 base::DelegateSimpleThread thread_b(&queue_user_b, "queue_user_thread_b"); | |
| 169 | |
| 170 thread_a.Start(); | |
| 171 thread_b.Start(); | |
| 172 | |
| 173 thread_a.Join(); | |
| 174 thread_b.Join(); | |
| 175 | |
| 176 EXPECT_NDEBUG_FALSE_DEBUG_TRUE(local_reporter->fail_state()); | |
| 177 } | |
| 178 | |
| 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 { | |
| 183 public: | |
| 184 explicit NonThreadSafeQueue(base::AsserterBase* asserter) | |
| 185 : push_pop_(asserter) { | |
| 186 } | |
| 187 | |
| 188 void push(int value) { | |
| 189 DFAKE_SCOPED_LOCK(push_pop_); | |
| 190 base::PlatformThread::Sleep(base::TimeDelta::FromSeconds(5)); | |
| 191 } | |
| 192 | |
| 193 int pop() { | |
| 194 DFAKE_SCOPED_LOCK(push_pop_); | |
| 195 return 0; | |
| 196 } | |
| 197 | |
| 198 private: | |
| 199 DFAKE_MUTEX(push_pop_); | |
| 200 | |
| 201 DISALLOW_COPY_AND_ASSIGN(NonThreadSafeQueue); | |
| 202 }; | |
| 203 | |
| 204 class QueueUser : public base::DelegateSimpleThread::Delegate { | |
| 205 public: | |
| 206 explicit QueueUser(NonThreadSafeQueue* queue) : queue_(queue) {} | |
| 207 | |
| 208 void Run() override { | |
| 209 queue_->push(0); | |
| 210 queue_->pop(); | |
| 211 } | |
| 212 | |
| 213 private: | |
| 214 NonThreadSafeQueue* queue_; | |
| 215 }; | |
| 216 | |
| 217 AssertReporter* local_reporter = new AssertReporter(); | |
| 218 | |
| 219 NonThreadSafeQueue queue(local_reporter); | |
| 220 | |
| 221 QueueUser queue_user_a(&queue); | |
| 222 QueueUser queue_user_b(&queue); | |
| 223 | |
| 224 base::DelegateSimpleThread thread_a(&queue_user_a, "queue_user_thread_a"); | |
| 225 base::DelegateSimpleThread thread_b(&queue_user_b, "queue_user_thread_b"); | |
| 226 | |
| 227 thread_a.Start(); | |
| 228 thread_b.Start(); | |
| 229 | |
| 230 thread_a.Join(); | |
| 231 thread_b.Join(); | |
| 232 | |
| 233 EXPECT_NDEBUG_FALSE_DEBUG_TRUE(local_reporter->fail_state()); | |
| 234 } | |
| 235 | |
| 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 { | |
| 240 public: | |
| 241 explicit NonThreadSafeQueue(base::AsserterBase* asserter) | |
| 242 : push_pop_(asserter) { | |
| 243 } | |
| 244 | |
| 245 void push(int value) { | |
| 246 DFAKE_SCOPED_LOCK(push_pop_); | |
| 247 base::PlatformThread::Sleep(base::TimeDelta::FromSeconds(2)); | |
| 248 } | |
| 249 | |
| 250 int pop() { | |
| 251 DFAKE_SCOPED_LOCK(push_pop_); | |
| 252 return 0; | |
| 253 } | |
| 254 | |
| 255 private: | |
| 256 DFAKE_MUTEX(push_pop_); | |
| 257 | |
| 258 DISALLOW_COPY_AND_ASSIGN(NonThreadSafeQueue); | |
| 259 }; | |
| 260 | |
| 261 // This time the QueueUser class protects the non thread safe queue with | |
| 262 // a lock. | |
| 263 class QueueUser : public base::DelegateSimpleThread::Delegate { | |
| 264 public: | |
| 265 QueueUser(NonThreadSafeQueue* queue, base::Lock* lock) | |
| 266 : queue_(queue), lock_(lock) {} | |
| 267 | |
| 268 void Run() override { | |
| 269 { | |
| 270 base::AutoLock auto_lock(*lock_); | |
| 271 queue_->push(0); | |
| 272 } | |
| 273 { | |
| 274 base::AutoLock auto_lock(*lock_); | |
| 275 queue_->pop(); | |
| 276 } | |
| 277 } | |
| 278 private: | |
| 279 NonThreadSafeQueue* queue_; | |
| 280 base::Lock* lock_; | |
| 281 }; | |
| 282 | |
| 283 AssertReporter* local_reporter = new AssertReporter(); | |
| 284 | |
| 285 NonThreadSafeQueue queue(local_reporter); | |
| 286 | |
| 287 base::Lock lock; | |
| 288 | |
| 289 QueueUser queue_user_a(&queue, &lock); | |
| 290 QueueUser queue_user_b(&queue, &lock); | |
| 291 | |
| 292 base::DelegateSimpleThread thread_a(&queue_user_a, "queue_user_thread_a"); | |
| 293 base::DelegateSimpleThread thread_b(&queue_user_b, "queue_user_thread_b"); | |
| 294 | |
| 295 thread_a.Start(); | |
| 296 thread_b.Start(); | |
| 297 | |
| 298 thread_a.Join(); | |
| 299 thread_b.Join(); | |
| 300 | |
| 301 EXPECT_FALSE(local_reporter->fail_state()); | |
| 302 } | |
| 303 | |
| 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 { | |
| 308 public: | |
| 309 explicit NonThreadSafeQueue(base::AsserterBase* asserter) | |
| 310 : push_pop_(asserter) { | |
| 311 } | |
| 312 | |
| 313 void push(int) { | |
| 314 DFAKE_SCOPED_RECURSIVE_LOCK(push_pop_); | |
| 315 bar(); | |
| 316 base::PlatformThread::Sleep(base::TimeDelta::FromSeconds(2)); | |
| 317 } | |
| 318 | |
| 319 int pop() { | |
| 320 DFAKE_SCOPED_RECURSIVE_LOCK(push_pop_); | |
| 321 return 0; | |
| 322 } | |
| 323 | |
| 324 void bar() { | |
| 325 DFAKE_SCOPED_RECURSIVE_LOCK(push_pop_); | |
| 326 } | |
| 327 | |
| 328 private: | |
| 329 DFAKE_MUTEX(push_pop_); | |
| 330 | |
| 331 DISALLOW_COPY_AND_ASSIGN(NonThreadSafeQueue); | |
| 332 }; | |
| 333 | |
| 334 // This time the QueueUser class protects the non thread safe queue with | |
| 335 // a lock. | |
| 336 class QueueUser : public base::DelegateSimpleThread::Delegate { | |
| 337 public: | |
| 338 QueueUser(NonThreadSafeQueue* queue, base::Lock* lock) | |
| 339 : queue_(queue), lock_(lock) {} | |
| 340 | |
| 341 void Run() override { | |
| 342 { | |
| 343 base::AutoLock auto_lock(*lock_); | |
| 344 queue_->push(0); | |
| 345 } | |
| 346 { | |
| 347 base::AutoLock auto_lock(*lock_); | |
| 348 queue_->bar(); | |
| 349 } | |
| 350 { | |
| 351 base::AutoLock auto_lock(*lock_); | |
| 352 queue_->pop(); | |
| 353 } | |
| 354 } | |
| 355 private: | |
| 356 NonThreadSafeQueue* queue_; | |
| 357 base::Lock* lock_; | |
| 358 }; | |
| 359 | |
| 360 AssertReporter* local_reporter = new AssertReporter(); | |
| 361 | |
| 362 NonThreadSafeQueue queue(local_reporter); | |
| 363 | |
| 364 base::Lock lock; | |
| 365 | |
| 366 QueueUser queue_user_a(&queue, &lock); | |
| 367 QueueUser queue_user_b(&queue, &lock); | |
| 368 | |
| 369 base::DelegateSimpleThread thread_a(&queue_user_a, "queue_user_thread_a"); | |
| 370 base::DelegateSimpleThread thread_b(&queue_user_b, "queue_user_thread_b"); | |
| 371 | |
| 372 thread_a.Start(); | |
| 373 thread_b.Start(); | |
| 374 | |
| 375 thread_a.Join(); | |
| 376 thread_b.Join(); | |
| 377 | |
| 378 EXPECT_FALSE(local_reporter->fail_state()); | |
| 379 } | |
| OLD | NEW |