| OLD | NEW |
| 1 // Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 // Multi-threaded tests of ConditionVariable class. | 5 // Multi-threaded tests of ConditionVariable class. |
| 6 | 6 |
| 7 #include <time.h> | 7 #include <time.h> |
| 8 #include <algorithm> | 8 #include <algorithm> |
| 9 #include <vector> | 9 #include <vector> |
| 10 | 10 |
| (...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 70 // Worker threads only call the following methods. | 70 // Worker threads only call the following methods. |
| 71 // They should use the lock to get exclusive access. | 71 // They should use the lock to get exclusive access. |
| 72 int GetThreadId(); // Get an ID assigned to a thread.. | 72 int GetThreadId(); // Get an ID assigned to a thread.. |
| 73 bool EveryIdWasAllocated() const; // Indicates that all IDs were handed out. | 73 bool EveryIdWasAllocated() const; // Indicates that all IDs were handed out. |
| 74 TimeDelta GetAnAssignment(int thread_id); // Get a work task duration. | 74 TimeDelta GetAnAssignment(int thread_id); // Get a work task duration. |
| 75 void WorkIsCompleted(int thread_id); | 75 void WorkIsCompleted(int thread_id); |
| 76 | 76 |
| 77 int task_count() const; | 77 int task_count() const; |
| 78 bool allow_help_requests() const; // Workers can signal more workers. | 78 bool allow_help_requests() const; // Workers can signal more workers. |
| 79 bool shutdown() const; // Check if shutdown has been requested. | 79 bool shutdown() const; // Check if shutdown has been requested. |
| 80 int shutdown_task_count() const; | |
| 81 | 80 |
| 82 void thread_shutting_down(); | 81 void thread_shutting_down(); |
| 83 | 82 |
| 83 |
| 84 //---------------------------------------------------------------------------- | 84 //---------------------------------------------------------------------------- |
| 85 // Worker threads can call them but not needed to acquire a lock | 85 // Worker threads can call them but not needed to acquire a lock. |
| 86 Lock* lock(); | 86 Lock* lock(); |
| 87 | 87 |
| 88 ConditionVariable* work_is_available(); | 88 ConditionVariable* work_is_available(); |
| 89 ConditionVariable* all_threads_have_ids(); | 89 ConditionVariable* all_threads_have_ids(); |
| 90 ConditionVariable* no_more_tasks(); | 90 ConditionVariable* no_more_tasks(); |
| 91 | 91 |
| 92 //---------------------------------------------------------------------------- | 92 //---------------------------------------------------------------------------- |
| 93 // The rest of the methods are for use by the controlling master thread (the | 93 // The rest of the methods are for use by the controlling master thread (the |
| 94 // test case code). | 94 // test case code). |
| 95 void ResetHistory(); | 95 void ResetHistory(); |
| 96 int GetMinCompletionsByWorkerThread() const; | 96 int GetMinCompletionsByWorkerThread() const; |
| 97 int GetMaxCompletionsByWorkerThread() const; | 97 int GetMaxCompletionsByWorkerThread() const; |
| 98 int GetNumThreadsTakingAssignments() const; | 98 int GetNumThreadsTakingAssignments() const; |
| 99 int GetNumThreadsCompletingTasks() const; | 99 int GetNumThreadsCompletingTasks() const; |
| 100 int GetNumberOfCompletedTasks() const; | 100 int GetNumberOfCompletedTasks() const; |
| 101 | 101 |
| 102 void SetWorkTime(TimeDelta delay); | 102 void SetWorkTime(TimeDelta delay); |
| 103 void SetTaskCount(int count); | 103 void SetTaskCount(int count); |
| 104 void SetAllowHelp(bool allow); | 104 void SetAllowHelp(bool allow); |
| 105 | 105 |
| 106 // Caller must acquire lock before calling. |
| 106 void SetShutdown(); | 107 void SetShutdown(); |
| 107 | 108 |
| 109 // Compares the |shutdown_task_count_| to the |thread_count| and returns true |
| 110 // if they are equal. This check will acquire the |lock_| so the caller |
| 111 // should not hold the lock when calling this method. |
| 112 bool ThreadSafeCheckShutdown(int thread_count); |
| 113 |
| 108 private: | 114 private: |
| 109 // Both worker threads and controller use the following to synchronize. | 115 // Both worker threads and controller use the following to synchronize. |
| 110 Lock lock_; | 116 Lock lock_; |
| 111 ConditionVariable work_is_available_; // To tell threads there is work. | 117 ConditionVariable work_is_available_; // To tell threads there is work. |
| 112 | 118 |
| 113 // Conditions to notify the controlling process (if it is interested). | 119 // Conditions to notify the controlling process (if it is interested). |
| 114 ConditionVariable all_threads_have_ids_; // All threads are running. | 120 ConditionVariable all_threads_have_ids_; // All threads are running. |
| 115 ConditionVariable no_more_tasks_; // Task count is zero. | 121 ConditionVariable no_more_tasks_; // Task count is zero. |
| 116 | 122 |
| 117 const int thread_count_; | 123 const int thread_count_; |
| (...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 169 TimeDelta duration = TimeTicks::Now() - start; | 175 TimeDelta duration = TimeTicks::Now() - start; |
| 170 // We can't use EXPECT_GE here as the TimeDelta class does not support the | 176 // We can't use EXPECT_GE here as the TimeDelta class does not support the |
| 171 // required stream conversion. | 177 // required stream conversion. |
| 172 EXPECT_TRUE(duration >= WAIT_TIME); | 178 EXPECT_TRUE(duration >= WAIT_TIME); |
| 173 | 179 |
| 174 lock.Release(); | 180 lock.Release(); |
| 175 } | 181 } |
| 176 | 182 |
| 177 // This test is flaky due to excessive timing sensitivity. | 183 // This test is flaky due to excessive timing sensitivity. |
| 178 // http://code.google.com/p/chromium/issues/detail?id=3599 | 184 // http://code.google.com/p/chromium/issues/detail?id=3599 |
| 185 // TODO(jar): A recent change to the WorkQueue fixed flakyness for the test |
| 186 // LargeFastTaskTest. Specifically, the test was accessing the member variable |
| 187 // WorkQueue::shutdown_task_count_ without a lock held. The MultiThreadConsumer |
| 188 // test now ran successfully for 500 times on RalphL's machine. RalphL did not |
| 189 // want to blindly re-enable this test if you know of other issues with it, but |
| 190 // it appears that the flakyness is gone, but I'll leave that to you to verify. |
| 179 TEST_F(ConditionVariableTest, DISABLED_MultiThreadConsumerTest) { | 191 TEST_F(ConditionVariableTest, DISABLED_MultiThreadConsumerTest) { |
| 180 const int kThreadCount = 10; | 192 const int kThreadCount = 10; |
| 181 WorkQueue queue(kThreadCount); // Start the threads. | 193 WorkQueue queue(kThreadCount); // Start the threads. |
| 182 | 194 |
| 183 Lock private_lock; // Used locally for master to wait. | 195 Lock private_lock; // Used locally for master to wait. |
| 184 AutoLock private_held_lock(private_lock); | 196 AutoLock private_held_lock(private_lock); |
| 185 ConditionVariable private_cv(&private_lock); | 197 ConditionVariable private_cv(&private_lock); |
| 186 | 198 |
| 187 { | 199 { |
| 188 AutoLock auto_lock(*queue.lock()); | 200 AutoLock auto_lock(*queue.lock()); |
| (...skipping 140 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 329 EXPECT_EQ(0, queue.task_count()); | 341 EXPECT_EQ(0, queue.task_count()); |
| 330 EXPECT_EQ(2, queue.GetMaxCompletionsByWorkerThread()); | 342 EXPECT_EQ(2, queue.GetMaxCompletionsByWorkerThread()); |
| 331 EXPECT_EQ(2, queue.GetMinCompletionsByWorkerThread()); | 343 EXPECT_EQ(2, queue.GetMinCompletionsByWorkerThread()); |
| 332 EXPECT_EQ(20, queue.GetNumberOfCompletedTasks()); | 344 EXPECT_EQ(20, queue.GetNumberOfCompletedTasks()); |
| 333 | 345 |
| 334 queue.SetShutdown(); | 346 queue.SetShutdown(); |
| 335 } | 347 } |
| 336 queue.work_is_available()->Broadcast(); // Force check for shutdown. | 348 queue.work_is_available()->Broadcast(); // Force check for shutdown. |
| 337 | 349 |
| 338 SPIN_FOR_TIMEDELTA_OR_UNTIL_TRUE(TimeDelta::FromMinutes(1), | 350 SPIN_FOR_TIMEDELTA_OR_UNTIL_TRUE(TimeDelta::FromMinutes(1), |
| 339 queue.shutdown_task_count() == kThreadCount); | 351 queue.ThreadSafeCheckShutdown(kThreadCount)); |
| 340 PlatformThread::Sleep(10); // Be sure they're all shutdown. | 352 PlatformThread::Sleep(10); // Be sure they're all shutdown. |
| 341 } | 353 } |
| 342 | 354 |
| 343 TEST_F(ConditionVariableTest, LargeFastTaskTest) { | 355 TEST_F(ConditionVariableTest, LargeFastTaskTest) { |
| 344 const int kThreadCount = 200; | 356 const int kThreadCount = 200; |
| 345 WorkQueue queue(kThreadCount); // Start the threads. | 357 WorkQueue queue(kThreadCount); // Start the threads. |
| 346 | 358 |
| 347 Lock private_lock; // Used locally for master to wait. | 359 Lock private_lock; // Used locally for master to wait. |
| 348 AutoLock private_held_lock(private_lock); | 360 AutoLock private_held_lock(private_lock); |
| 349 ConditionVariable private_cv(&private_lock); | 361 ConditionVariable private_cv(&private_lock); |
| (...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 429 EXPECT_EQ(0, queue.task_count()); | 441 EXPECT_EQ(0, queue.task_count()); |
| 430 EXPECT_LE(4, queue.GetMaxCompletionsByWorkerThread()); | 442 EXPECT_LE(4, queue.GetMaxCompletionsByWorkerThread()); |
| 431 EXPECT_EQ(4 * kThreadCount, queue.GetNumberOfCompletedTasks()); | 443 EXPECT_EQ(4 * kThreadCount, queue.GetNumberOfCompletedTasks()); |
| 432 | 444 |
| 433 queue.SetShutdown(); | 445 queue.SetShutdown(); |
| 434 } | 446 } |
| 435 queue.work_is_available()->Broadcast(); // Force check for shutdown. | 447 queue.work_is_available()->Broadcast(); // Force check for shutdown. |
| 436 | 448 |
| 437 // Wait for shutdowns to complete. | 449 // Wait for shutdowns to complete. |
| 438 SPIN_FOR_TIMEDELTA_OR_UNTIL_TRUE(TimeDelta::FromMinutes(1), | 450 SPIN_FOR_TIMEDELTA_OR_UNTIL_TRUE(TimeDelta::FromMinutes(1), |
| 439 queue.shutdown_task_count() == kThreadCount); | 451 queue.ThreadSafeCheckShutdown(kThreadCount)); |
| 440 PlatformThread::Sleep(10); // Be sure they're all shutdown. | 452 PlatformThread::Sleep(10); // Be sure they're all shutdown. |
| 441 } | 453 } |
| 442 | 454 |
| 443 //------------------------------------------------------------------------------ | 455 //------------------------------------------------------------------------------ |
| 444 // Finally we provide the implementation for the methods in the WorkQueue class. | 456 // Finally we provide the implementation for the methods in the WorkQueue class. |
| 445 //------------------------------------------------------------------------------ | 457 //------------------------------------------------------------------------------ |
| 446 | 458 |
| 447 WorkQueue::WorkQueue(int thread_count) | 459 WorkQueue::WorkQueue(int thread_count) |
| 448 : lock_(), | 460 : lock_(), |
| 449 work_is_available_(&lock_), | 461 work_is_available_(&lock_), |
| (...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 512 DFAKE_SCOPED_RECURSIVE_LOCK(locked_methods_); | 524 DFAKE_SCOPED_RECURSIVE_LOCK(locked_methods_); |
| 513 return task_count_; | 525 return task_count_; |
| 514 } | 526 } |
| 515 | 527 |
| 516 bool WorkQueue::allow_help_requests() const { | 528 bool WorkQueue::allow_help_requests() const { |
| 517 DFAKE_SCOPED_RECURSIVE_LOCK(locked_methods_); | 529 DFAKE_SCOPED_RECURSIVE_LOCK(locked_methods_); |
| 518 return allow_help_requests_; | 530 return allow_help_requests_; |
| 519 } | 531 } |
| 520 | 532 |
| 521 bool WorkQueue::shutdown() const { | 533 bool WorkQueue::shutdown() const { |
| 534 lock_.AssertAcquired(); |
| 522 DFAKE_SCOPED_RECURSIVE_LOCK(locked_methods_); | 535 DFAKE_SCOPED_RECURSIVE_LOCK(locked_methods_); |
| 523 return shutdown_; | 536 return shutdown_; |
| 524 } | 537 } |
| 525 | 538 |
| 526 int WorkQueue::shutdown_task_count() const { | 539 // Because this method is called from the test's main thread we need to actually |
| 527 DFAKE_SCOPED_RECURSIVE_LOCK(locked_methods_); | 540 // take the lock. Threads will call the thread_shutting_down() method with the |
| 528 return shutdown_task_count_; | 541 // lock already acquired. |
| 542 bool WorkQueue::ThreadSafeCheckShutdown(int thread_count) { |
| 543 bool all_shutdown; |
| 544 AutoLock auto_lock(lock_); |
| 545 { |
| 546 // Declare in scope so DFAKE is guranteed to be destroyed before AutoLock. |
| 547 DFAKE_SCOPED_RECURSIVE_LOCK(locked_methods_); |
| 548 all_shutdown = (shutdown_task_count_ == thread_count); |
| 549 } |
| 550 return all_shutdown; |
| 529 } | 551 } |
| 530 | 552 |
| 531 void WorkQueue::thread_shutting_down() { | 553 void WorkQueue::thread_shutting_down() { |
| 554 lock_.AssertAcquired(); |
| 532 DFAKE_SCOPED_RECURSIVE_LOCK(locked_methods_); | 555 DFAKE_SCOPED_RECURSIVE_LOCK(locked_methods_); |
| 533 shutdown_task_count_++; | 556 shutdown_task_count_++; |
| 534 } | 557 } |
| 535 | 558 |
| 536 Lock* WorkQueue::lock() { | 559 Lock* WorkQueue::lock() { |
| 537 return &lock_; | 560 return &lock_; |
| 538 } | 561 } |
| 539 | 562 |
| 540 ConditionVariable* WorkQueue::work_is_available() { | 563 ConditionVariable* WorkQueue::work_is_available() { |
| 541 return &work_is_available_; | 564 return &work_is_available_; |
| (...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 599 | 622 |
| 600 void WorkQueue::SetTaskCount(int count) { | 623 void WorkQueue::SetTaskCount(int count) { |
| 601 task_count_ = count; | 624 task_count_ = count; |
| 602 } | 625 } |
| 603 | 626 |
| 604 void WorkQueue::SetAllowHelp(bool allow) { | 627 void WorkQueue::SetAllowHelp(bool allow) { |
| 605 allow_help_requests_ = allow; | 628 allow_help_requests_ = allow; |
| 606 } | 629 } |
| 607 | 630 |
| 608 void WorkQueue::SetShutdown() { | 631 void WorkQueue::SetShutdown() { |
| 632 lock_.AssertAcquired(); |
| 609 shutdown_ = true; | 633 shutdown_ = true; |
| 610 } | 634 } |
| 611 | 635 |
| 612 //------------------------------------------------------------------------------ | 636 //------------------------------------------------------------------------------ |
| 613 // Define the standard worker task. Several tests will spin out many of these | 637 // Define the standard worker task. Several tests will spin out many of these |
| 614 // threads. | 638 // threads. |
| 615 //------------------------------------------------------------------------------ | 639 //------------------------------------------------------------------------------ |
| 616 | 640 |
| 617 // The multithread tests involve several threads with a task to perform as | 641 // The multithread tests involve several threads with a task to perform as |
| 618 // directed by an instance of the class WorkQueue. | 642 // directed by an instance of the class WorkQueue. |
| (...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 669 | 693 |
| 670 { | 694 { |
| 671 AutoLock auto_lock(lock_); | 695 AutoLock auto_lock(lock_); |
| 672 // Send notification that we completed our "work." | 696 // Send notification that we completed our "work." |
| 673 WorkIsCompleted(thread_id); | 697 WorkIsCompleted(thread_id); |
| 674 } | 698 } |
| 675 } | 699 } |
| 676 } | 700 } |
| 677 | 701 |
| 678 } // namespace | 702 } // namespace |
| OLD | NEW |