| OLD | NEW |
| (Empty) | |
| 1 // Copyright (c) 2008 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/lock.h" |
| 6 #include "base/platform_thread.h" |
| 7 #include "base/simple_thread.h" |
| 8 #include "base/thread_collision_warner.h" |
| 9 #include "testing/gtest/include/gtest/gtest.h" |
| 10 |
| 11 |
| 12 namespace { |
| 13 |
| 14 // This is the asserter used with ThreadCollisionWarner instead of the default |
| 15 // DCheckAsserter. The method fail_state is used to know if a collision took |
| 16 // place. |
| 17 class AssertReporter : public base::AsserterBase { |
| 18 public: |
| 19 AssertReporter() |
| 20 : failed_(false) {} |
| 21 |
| 22 virtual void warn() { |
| 23 failed_ = true; |
| 24 } |
| 25 |
| 26 virtual ~AssertReporter() {} |
| 27 |
| 28 bool fail_state() const { return failed_; } |
| 29 void reset() { failed_ = false; } |
| 30 |
| 31 private: |
| 32 bool failed_; |
| 33 }; |
| 34 |
| 35 } // namespace |
| 36 |
| 37 TEST(ThreadCollisionTest, BookCriticalSection) { |
| 38 AssertReporter* local_reporter = new AssertReporter(); |
| 39 |
| 40 base::ThreadCollisionWarner warner(local_reporter); |
| 41 EXPECT_FALSE(local_reporter->fail_state()); |
| 42 |
| 43 { // Pin section. |
| 44 D_BOOK_CRITICAL_SECTION(warner); |
| 45 EXPECT_FALSE(local_reporter->fail_state()); |
| 46 { // Pin section. |
| 47 D_BOOK_CRITICAL_SECTION(warner); |
| 48 EXPECT_FALSE(local_reporter->fail_state()); |
| 49 } |
| 50 } |
| 51 } |
| 52 |
| 53 TEST(ThreadCollisionTest, ScopedRecursiveBookCriticalSection) { |
| 54 AssertReporter* local_reporter = new AssertReporter(); |
| 55 |
| 56 base::ThreadCollisionWarner warner(local_reporter); |
| 57 EXPECT_FALSE(local_reporter->fail_state()); |
| 58 |
| 59 { // Pin section. |
| 60 D_SCOPED_RECURSIVE_BOOK_CRITICAL_SECTION(warner); |
| 61 EXPECT_FALSE(local_reporter->fail_state()); |
| 62 { // Pin section again (allowed by D_SCOPED_RECURSIVE_BOOK_CRITICAL_SECTION
) |
| 63 D_SCOPED_RECURSIVE_BOOK_CRITICAL_SECTION(warner); |
| 64 EXPECT_FALSE(local_reporter->fail_state()); |
| 65 } // Unpin section. |
| 66 } // Unpin section. |
| 67 |
| 68 // Check that section is not pinned |
| 69 { // Pin section. |
| 70 D_SCOPED_BOOK_CRITICAL_SECTION(warner); |
| 71 EXPECT_FALSE(local_reporter->fail_state()); |
| 72 } // Unpin section. |
| 73 } |
| 74 |
| 75 TEST(ThreadCollisionTest, ScopedBookCriticalSection) { |
| 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 D_SCOPED_BOOK_CRITICAL_SECTION(warner); |
| 83 EXPECT_FALSE(local_reporter->fail_state()); |
| 84 } // Unpin section. |
| 85 |
| 86 { // Pin section. |
| 87 D_SCOPED_BOOK_CRITICAL_SECTION(warner); |
| 88 EXPECT_FALSE(local_reporter->fail_state()); |
| 89 { // Pin section again (not allowed by D_SCOPED_BOOK_CRITICAL_SECTION) |
| 90 D_SCOPED_BOOK_CRITICAL_SECTION(warner); |
| 91 EXPECT_TRUE(local_reporter->fail_state()); |
| 92 // Reset the status of warner for further tests. |
| 93 local_reporter->reset(); |
| 94 } // Unpin section. |
| 95 } // Unpin section. |
| 96 |
| 97 { // Pin section. |
| 98 D_SCOPED_BOOK_CRITICAL_SECTION(warner); |
| 99 EXPECT_FALSE(local_reporter->fail_state()); |
| 100 } // Unpin section. |
| 101 |
| 102 } |
| 103 |
| 104 TEST(ThreadCollisionTest, MTBookCriticalSectionTest) { |
| 105 class NonThreadSafeQueue { |
| 106 public: |
| 107 NonThreadSafeQueue(base::AsserterBase* asserter) |
| 108 : push_pop_(asserter) { } |
| 109 |
| 110 void push(int) { |
| 111 D_BOOK_CRITICAL_SECTION(push_pop_); |
| 112 } |
| 113 |
| 114 int pop() { |
| 115 D_BOOK_CRITICAL_SECTION(push_pop_); |
| 116 return 0; |
| 117 } |
| 118 |
| 119 private: |
| 120 base::ThreadCollisionWarner push_pop_; |
| 121 |
| 122 DISALLOW_COPY_AND_ASSIGN(NonThreadSafeQueue); |
| 123 }; |
| 124 |
| 125 class QueueUser : public base::DelegateSimpleThread::Delegate { |
| 126 public: |
| 127 QueueUser(NonThreadSafeQueue& queue) |
| 128 : queue_(queue) {} |
| 129 |
| 130 virtual void Run() { |
| 131 queue_.push(0); |
| 132 queue_.pop(); |
| 133 } |
| 134 |
| 135 private: |
| 136 NonThreadSafeQueue& queue_; |
| 137 }; |
| 138 |
| 139 AssertReporter* local_reporter = new AssertReporter(); |
| 140 |
| 141 NonThreadSafeQueue queue(local_reporter); |
| 142 |
| 143 QueueUser queue_user_a(queue); |
| 144 QueueUser queue_user_b(queue); |
| 145 |
| 146 base::DelegateSimpleThread thread_a(&queue_user_a, "queue_user_thread_a"); |
| 147 base::DelegateSimpleThread thread_b(&queue_user_b, "queue_user_thread_b"); |
| 148 |
| 149 thread_a.Start(); |
| 150 thread_b.Start(); |
| 151 |
| 152 thread_a.Join(); |
| 153 thread_b.Join(); |
| 154 |
| 155 EXPECT_TRUE(local_reporter->fail_state()); |
| 156 } |
| 157 |
| 158 TEST(ThreadCollisionTest, MTScopedBookCriticalSectionTest) { |
| 159 |
| 160 // Queue with a 5 seconds push execution time, hopefuly the two used threads |
| 161 // in the test will enter the push at same time. |
| 162 class NonThreadSafeQueue { |
| 163 public: |
| 164 NonThreadSafeQueue(base::AsserterBase* asserter) |
| 165 : push_pop_(asserter) { } |
| 166 |
| 167 void push(int) { |
| 168 D_SCOPED_BOOK_CRITICAL_SECTION(push_pop_); |
| 169 PlatformThread::Sleep(5000); |
| 170 } |
| 171 |
| 172 int pop() { |
| 173 D_SCOPED_BOOK_CRITICAL_SECTION(push_pop_); |
| 174 return 0; |
| 175 } |
| 176 |
| 177 private: |
| 178 base::ThreadCollisionWarner push_pop_; |
| 179 |
| 180 DISALLOW_COPY_AND_ASSIGN(NonThreadSafeQueue); |
| 181 }; |
| 182 |
| 183 class QueueUser : public base::DelegateSimpleThread::Delegate { |
| 184 public: |
| 185 QueueUser(NonThreadSafeQueue& queue) |
| 186 : queue_(queue) {} |
| 187 |
| 188 virtual void Run() { |
| 189 queue_.push(0); |
| 190 queue_.pop(); |
| 191 } |
| 192 |
| 193 private: |
| 194 NonThreadSafeQueue& queue_; |
| 195 }; |
| 196 |
| 197 AssertReporter* local_reporter = new AssertReporter(); |
| 198 |
| 199 NonThreadSafeQueue queue(local_reporter); |
| 200 |
| 201 QueueUser queue_user_a(queue); |
| 202 QueueUser queue_user_b(queue); |
| 203 |
| 204 base::DelegateSimpleThread thread_a(&queue_user_a, "queue_user_thread_a"); |
| 205 base::DelegateSimpleThread thread_b(&queue_user_b, "queue_user_thread_b"); |
| 206 |
| 207 thread_a.Start(); |
| 208 thread_b.Start(); |
| 209 |
| 210 thread_a.Join(); |
| 211 thread_b.Join(); |
| 212 |
| 213 EXPECT_TRUE(local_reporter->fail_state()); |
| 214 } |
| 215 |
| 216 TEST(ThreadCollisionTest, MTSynchedScopedBookCriticalSectionTest) { |
| 217 |
| 218 // Queue with a 5 seconds push execution time, hopefuly the two used threads |
| 219 // in the test will enter the push at same time. |
| 220 class NonThreadSafeQueue { |
| 221 public: |
| 222 NonThreadSafeQueue(base::AsserterBase* asserter) |
| 223 : push_pop_(asserter) { } |
| 224 |
| 225 void push(int) { |
| 226 D_SCOPED_BOOK_CRITICAL_SECTION(push_pop_); |
| 227 PlatformThread::Sleep(5000); |
| 228 } |
| 229 |
| 230 int pop() { |
| 231 D_SCOPED_BOOK_CRITICAL_SECTION(push_pop_); |
| 232 return 0; |
| 233 } |
| 234 |
| 235 private: |
| 236 base::ThreadCollisionWarner push_pop_; |
| 237 |
| 238 DISALLOW_COPY_AND_ASSIGN(NonThreadSafeQueue); |
| 239 }; |
| 240 |
| 241 // This time the QueueUser class protects the non thread safe queue with |
| 242 // a lock. |
| 243 class QueueUser : public base::DelegateSimpleThread::Delegate { |
| 244 public: |
| 245 QueueUser(NonThreadSafeQueue& queue, Lock& lock) |
| 246 : queue_(queue), |
| 247 lock_(lock) {} |
| 248 |
| 249 virtual void Run() { |
| 250 { |
| 251 AutoLock auto_lock(lock_); |
| 252 queue_.push(0); |
| 253 } |
| 254 { |
| 255 AutoLock auto_lock(lock_); |
| 256 queue_.pop(); |
| 257 } |
| 258 } |
| 259 private: |
| 260 NonThreadSafeQueue& queue_; |
| 261 Lock& lock_; |
| 262 }; |
| 263 |
| 264 AssertReporter* local_reporter = new AssertReporter(); |
| 265 |
| 266 NonThreadSafeQueue queue(local_reporter); |
| 267 |
| 268 Lock lock; |
| 269 |
| 270 QueueUser queue_user_a(queue, lock); |
| 271 QueueUser queue_user_b(queue, lock); |
| 272 |
| 273 base::DelegateSimpleThread thread_a(&queue_user_a, "queue_user_thread_a"); |
| 274 base::DelegateSimpleThread thread_b(&queue_user_b, "queue_user_thread_b"); |
| 275 |
| 276 thread_a.Start(); |
| 277 thread_b.Start(); |
| 278 |
| 279 thread_a.Join(); |
| 280 thread_b.Join(); |
| 281 |
| 282 EXPECT_FALSE(local_reporter->fail_state()); |
| 283 } |
| 284 |
| 285 TEST(ThreadCollisionTest, MTSynchedScopedRecursiveBookCriticalSectionTest) { |
| 286 |
| 287 // Queue with a 5 seconds push execution time, hopefuly the two used threads |
| 288 // in the test will enter the push at same time. |
| 289 class NonThreadSafeQueue { |
| 290 public: |
| 291 NonThreadSafeQueue(base::AsserterBase* asserter) |
| 292 : push_pop_(asserter) { } |
| 293 |
| 294 void push(int) { |
| 295 D_SCOPED_RECURSIVE_BOOK_CRITICAL_SECTION(push_pop_); |
| 296 bar(); |
| 297 PlatformThread::Sleep(5000); |
| 298 } |
| 299 |
| 300 int pop() { |
| 301 D_SCOPED_RECURSIVE_BOOK_CRITICAL_SECTION(push_pop_); |
| 302 return 0; |
| 303 } |
| 304 |
| 305 void bar() { |
| 306 D_SCOPED_RECURSIVE_BOOK_CRITICAL_SECTION(push_pop_); |
| 307 } |
| 308 |
| 309 private: |
| 310 base::ThreadCollisionWarner push_pop_; |
| 311 |
| 312 DISALLOW_COPY_AND_ASSIGN(NonThreadSafeQueue); |
| 313 }; |
| 314 |
| 315 // This time the QueueUser class protects the non thread safe queue with |
| 316 // a lock. |
| 317 class QueueUser : public base::DelegateSimpleThread::Delegate { |
| 318 public: |
| 319 QueueUser(NonThreadSafeQueue& queue, Lock& lock) |
| 320 : queue_(queue), |
| 321 lock_(lock) {} |
| 322 |
| 323 virtual void Run() { |
| 324 { |
| 325 AutoLock auto_lock(lock_); |
| 326 queue_.push(0); |
| 327 } |
| 328 { |
| 329 AutoLock auto_lock(lock_); |
| 330 queue_.bar(); |
| 331 } |
| 332 { |
| 333 AutoLock auto_lock(lock_); |
| 334 queue_.pop(); |
| 335 } |
| 336 } |
| 337 private: |
| 338 NonThreadSafeQueue& queue_; |
| 339 Lock& lock_; |
| 340 }; |
| 341 |
| 342 AssertReporter* local_reporter = new AssertReporter(); |
| 343 |
| 344 NonThreadSafeQueue queue(local_reporter); |
| 345 |
| 346 Lock lock; |
| 347 |
| 348 QueueUser queue_user_a(queue, lock); |
| 349 QueueUser queue_user_b(queue, lock); |
| 350 |
| 351 base::DelegateSimpleThread thread_a(&queue_user_a, "queue_user_thread_a"); |
| 352 base::DelegateSimpleThread thread_b(&queue_user_b, "queue_user_thread_b"); |
| 353 |
| 354 thread_a.Start(); |
| 355 thread_b.Start(); |
| 356 |
| 357 thread_a.Join(); |
| 358 thread_b.Join(); |
| 359 |
| 360 EXPECT_FALSE(local_reporter->fail_state()); |
| 361 } |
| 362 |
| OLD | NEW |